#!/usr/bin python3 """ Display Page parent classes for display section of the Faceswap GUI """ import logging import tkinter as tk from tkinter import ttk from .tooltip import Tooltip from .utils import get_images logger = logging.getLogger(__name__) # pylint: disable=invalid-name class DisplayPage(ttk.Frame): """ Parent frame holder for each tab. Defines uniform structure for each tab to inherit from """ def __init__(self, parent, tabname, helptext): logger.debug("Initializing %s: (tabname: '%s', helptext: %s", self.__class__.__name__, tabname, helptext) ttk.Frame.__init__(self, parent) self.pack(fill=tk.BOTH, side=tk.TOP, anchor=tk.NW) self.runningtask = parent.runningtask self.helptext = helptext self.tabname = tabname self.vars = {"info": tk.StringVar()} self.add_optional_vars(self.set_vars()) self.subnotebook = self.add_subnotebook() self.optsframe = self.add_options_frame() self.add_options_info() self.add_frame_separator() self.set_mainframe_single_tab_style() parent.add(self, text=self.tabname.title()) logger.debug("Initialized %s", self.__class__.__name__,) def add_optional_vars(self, varsdict): """ Add page specific variables """ if isinstance(varsdict, dict): for key, val in varsdict.items(): logger.debug("Adding: (%s: %s)", key, val) self.vars[key] = val @staticmethod def set_vars(): """ Override to return a dict of page specific variables """ return dict() def add_subnotebook(self): """ Add the main frame notebook """ logger.debug("Adding subnotebook") notebook = ttk.Notebook(self) notebook.pack(side=tk.TOP, anchor=tk.NW, fill=tk.BOTH, expand=True) return notebook def add_options_frame(self): """ Add the display tab options """ logger.debug("Adding options frame") optsframe = ttk.Frame(self) optsframe.pack(side=tk.BOTTOM, padx=5, pady=5, fill=tk.X) return optsframe def add_options_info(self): """ Add the info bar """ logger.debug("Adding options info") lblinfo = ttk.Label(self.optsframe, textvariable=self.vars["info"], anchor=tk.W, width=70) lblinfo.pack(side=tk.LEFT, padx=5, pady=5, anchor=tk.W) def set_info(self, msg): """ Set the info message """ logger.debug("Setting info: %s", msg) self.vars["info"].set(msg) def add_frame_separator(self): """ Add a separator between top and bottom frames """ logger.debug("Adding frame seperator") sep = ttk.Frame(self, height=2, relief=tk.RIDGE) sep.pack(fill=tk.X, pady=(5, 0), side=tk.BOTTOM) @staticmethod def set_mainframe_single_tab_style(): """ Configure ttk notebook style to represent a single frame """ logger.debug("Setting main frame single tab style") nbstyle = ttk.Style() nbstyle.configure("single.TNotebook", borderwidth=0) nbstyle.layout("single.TNotebook.Tab", []) def subnotebook_add_page(self, tabtitle, widget=None): """ Add a page to the sub notebook """ logger.debug("Adding subnotebook page: %s", tabtitle) frame = widget if widget else ttk.Frame(self.subnotebook) frame.pack(padx=5, pady=5, fill=tk.BOTH, expand=True) self.subnotebook.add(frame, text=tabtitle) self.subnotebook_configure() return frame def subnotebook_configure(self): """ Configure notebook to display or hide tabs """ if len(self.subnotebook.children) == 1: logger.debug("Setting single page style") self.subnotebook.configure(style="single.TNotebook") else: logger.debug("Setting multi page style") self.subnotebook.configure(style="TNotebook") def subnotebook_hide(self): """ Hide the subnotebook. Used for hiding Optional displays """ if self.subnotebook and self.subnotebook.winfo_ismapped(): logger.debug("Hiding subnotebook") self.subnotebook.pack_forget() self.subnotebook.destroy() self.subnotebook = None def subnotebook_show(self): """ Show subnotebook. Used for displaying Optional displays """ if not self.subnotebook: logger.debug("Showing subnotebook") self.subnotebook = self.add_subnotebook() def subnotebook_get_widgets(self): """ Return each widget that sits within each subnotebook frame """ logger.debug("Getting subnotebook widgets") for child in self.subnotebook.winfo_children(): for widget in child.winfo_children(): yield widget def subnotebook_get_titles_ids(self): """ Return tabs ids and titles """ tabs = dict() for tab_id in range(0, self.subnotebook.index("end")): tabs[self.subnotebook.tab(tab_id, "text")] = tab_id logger.debug(tabs) return tabs def subnotebook_page_from_id(self, tab_id): """ Return subnotebook tab widget from it's ID """ tab_name = self.subnotebook.tabs()[tab_id].split(".")[-1] logger.debug(tab_name) return self.subnotebook.children[tab_name] class DisplayOptionalPage(DisplayPage): """ Parent Context Sensitive Display Tab """ def __init__(self, parent, tabname, helptext, waittime): DisplayPage.__init__(self, parent, tabname, helptext) self.display_item = None self.set_info_text() self.add_options() parent.select(self) self.update_idletasks() self.update_page(waittime) @staticmethod def set_vars(): """ Analysis specific vars """ enabled = tk.BooleanVar() enabled.set(True) ready = tk.BooleanVar() ready.set(False) modified = tk.DoubleVar() modified.set(None) tk_vars = {"enabled": enabled, "ready": ready, "modified": modified} logger.debug(tk_vars) return tk_vars # INFO LABEL def set_info_text(self): """ Set waiting for display text """ if not self.vars["enabled"].get(): msg = "{} disabled".format(self.tabname.title()) elif self.vars["enabled"].get() and not self.vars["ready"].get(): msg = "Waiting for {}...".format(self.tabname) else: msg = "Displaying {}".format(self.tabname) logger.debug(msg) self.set_info(msg) # DISPLAY OPTIONS BAR def add_options(self): """ Add the additional options """ self.add_option_save() self.add_option_enable() def add_option_save(self): """ Add save button to save page output to file """ logger.debug("Adding save option") btnsave = ttk.Button(self.optsframe, image=get_images().icons["save"], command=self.save_items) btnsave.pack(padx=2, side=tk.RIGHT) Tooltip(btnsave, text="Save {}(s) to file".format(self.tabname), wraplength=200) def add_option_enable(self): """ Add checkbutton to enable/disable page """ logger.debug("Adding enable option") chkenable = ttk.Checkbutton(self.optsframe, variable=self.vars["enabled"], text="Enable {}".format(self.tabname), command=self.on_chkenable_change) chkenable.pack(side=tk.RIGHT, padx=5, anchor=tk.W) Tooltip(chkenable, text="Enable or disable {} display".format(self.tabname), wraplength=200) def save_items(self): """ Save items. Override for display specific saving """ raise NotImplementedError() def on_chkenable_change(self): """ Update the display immediately on a checkbutton change """ logger.debug("Enabled checkbox changed") if self.vars["enabled"].get(): self.subnotebook_show() else: self.subnotebook_hide() self.set_info_text() def update_page(self, waittime): """ Update the latest preview item """ if not self.runningtask.get(): return if self.vars["enabled"].get(): logger.trace("Updating page") self.display_item_set() self.load_display() self.after(waittime, lambda t=waittime: self.update_page(t)) def display_item_set(self): """ Override for display specific loading """ raise NotImplementedError() def load_display(self): """ Load the display """ if not self.display_item: return logger.debug("Loading display") self.display_item_process() self.vars["ready"].set(True) self.set_info_text() def display_item_process(self): """ Override for display specific loading """ raise NotImplementedError()