                                                      str(initial_dimensions[1])))
          logger.debug("Geometry: %sx%s", *initial_dimensions)
  
  
  class _Style():  # pylint:disable=too-few-public-methods
      """ Set the overarching theme and customize widgets. """
      def __init__(self, default_font, root):
          self._images = _TkImage()
          self._root = root
          self._font = default_font
          default = os.path.join(PATHCACHE, "themes", "default.json")
          self._user_theme = get_serializer("json").load(default)
          self._style = ttk.Style()
          self._set_styles()
  
      @property
      def user_theme(self):
          """ dict: The currently selected user theme. """
          return self._user_theme
  
      def _set_styles(self):
          """ Configure widget theme and styles """
          self._config_settings_group()
          # Settings Popup
          self._style.configure("SPanel.Header1.TLabel",
                                font=(self._font[0], self._font[1] + 4, "bold"))
          self._style.configure("SPanel.Header2.TLabel",
                                font=(self._font[0], self._font[1] + 2, "bold"))
          # Console
          theme = self._user_theme["console"]
          console_sbar = {area: tuple(theme[f"scrollbar_{area}_{state}"]
                                      for state in ("normal", "disabled", "active"))
                          for area in ("background", "foreground", "border")}
          self._get_custom_scrollbar("Console",
                                     console_sbar,
                                     theme["scrollbar_trough"],
                                     theme["scrollbar_border"])
  
      def _config_settings_group(self):
          """ Configures the style of the control panel entry boxes. Used for inputting Faceswap
          options or controlling plugin settings. """
          theme = self._user_theme["group_panel"]
          for panel_type in ("CPanel", "SPanel"):
              if panel_type == "SPanel":  # Merge in Settings Panel overrides
                  theme = {**theme, **self._user_theme["group_settings"]}
              self._style.configure(f"{panel_type}.Holder.TFrame",
                                    background=theme["panel_background"])
              # Header Colors on option/group controls
              self._style.configure(f"{panel_type}.Group.TLabelframe.Label",
                                    foreground=theme["header_color"])
              self._style.configure(f"{panel_type}.Groupheader.TLabel",
                                    background=theme["header_color"],
                                    foreground=theme["header_font"],
                                    font=(self._font[0], self._font[1], "bold"))
              # Widgets and specific areas
              self._group_panel_widgets(panel_type, theme)
              self._group_panel_infoheader(panel_type, theme)
              self._config_settings_group_slider(panel_type, theme)
              sbar_theme = dict(background=(theme["control_color"],
                                            theme["control_disabled"],
                                            theme["control_active"]),
                                foreground=(theme["control_disabled"],
                                            theme["control_color"],
                                            theme["control_disabled"]),
                                border=(theme["header_color"],
                                        theme["control_color"],
                                        theme["header_color"]))
              self._get_custom_scrollbar(panel_type,
                                         sbar_theme,
                                         theme["scrollbar_trough"],
                                         theme["scrollbar_border"])
              self._config_settings_group_combobox(panel_type, theme)
  
      def _group_panel_infoheader(self, key, theme):
          """ Set the theme for the information header box that appears at the top of each group
          panel
  
          Parameters
          ----------
          key: str
              The section that the slider will belong to
          theme: dict
              The user configuration theme options
          """
          self._style.element_create(f"{key}.InfoHeader.Frame.border", "from", "alt")
          self._style.layout(f"{key}.InfoHeader.TFrame",
                             [(f"{key}.InfoHeader.Frame.border", {"sticky": "nswe"})])
          self._style.configure(f"{key}.InfoHeader.TFrame",
                                background=theme["info_color"],
                                relief=tk.SOLID,
                                borderwidth=1,
                                bordercolor=theme["info_border"])
  
          self._style.configure(f"{key}.InfoHeader.TLabel",
                                background=theme["info_color"],
                                foreground=theme["info_font"],
                                font=(self._font[0], self._font[1], "bold"))
          self._style.configure(f"{key}.InfoBody.TLabel",
                                background=theme["info_color"],
                                foreground=theme["info_font"])
  
      def _group_panel_widgets(self, key, theme):
          """ Configure the foreground and background colors of common widgets.
  
          Parameters
          ----------
          key: str
              The section that the slider will belong to
          theme: dict
              The user configuration theme options
          """
          # Put a border on a group's sub-frame
          self._style.element_create(f"{key}.Subframe.Group.Frame.border", "from", "alt")
          self._style.layout(f"{key}.Subframe.Group.TFrame",
                             [(f"{key}.Subframe.Group.Frame.border", {"sticky": "nswe"})])
          self._style.configure(f"{key}.Subframe.Group.TFrame",
                                background=theme["group_background"],
                                relief=tk.SOLID,
                                borderwidth=1,
                                bordercolor=theme["group_border"])
  
          # Background and Foreground of widgets and labels
          for lbl in ["TLabel", "TFrame", "TLabelframe", "TCheckbutton", "TRadiobutton",
                      "TLabelframe.Label"]:
              self._style.configure(f"{key}.Group.{lbl}",
                                    background=theme["group_background"],
                                    foreground=theme["group_font"])
  
      def _config_settings_group_slider(self, key, theme):
          """ Take a copy of the default ttk.Scale widget and replace the slider element with a
          version we can control the color and shape of.
  
          Parameters
          ----------
          key: str
              The section that the slider will belong to
          theme: dict
              The user configuration theme options
          """
          img_slider = self._images.get_image((10, 25), theme["control_color"])
          img_slider_alt = self._images.get_image((10, 25), theme["control_active"])
  
          self._style.element_create(f"{key}.Horizontal.Scale.trough", "from", "alt")
          self._style.element_create(f"{key}.Horizontal.Scale.slider",
                                     "image",
                                     img_slider,
                                     ("active", img_slider_alt))
  
          self._style.layout(
              f"{key}.Horizontal.TScale",
              [(f"{key}.Scale.focus", {
                  "expand": "1",
                  "sticky": "nswe",
                  "children": [
                      (f"{key}.Horizontal.Scale.trough", {
                          "expand": "1",
                          "sticky": "nswe",
                          "children": [
                              (f"{key}.Horizontal.Scale.track", {"sticky": "we"}),
                              (f"{key}.Horizontal.Scale.slider", {"side": "left", "sticky": ""})
                              ]
                          })
                  ]
              })])
  
          self._style.configure(f"{key}.Horizontal.TScale",
                                background=self._user_theme["group_panel"]["group_background"],
                                groovewidth=4,
                                troughcolor=self._user_theme["group_panel"]["group_background"])
  
      def _get_custom_scrollbar(self, key, theme, trough, border):
          """ Create a custom scroll bar widget so we can control the colors.
  
          Parameters
          ----------
          key: str
              The section that the slider will belong to
          theme: dict
              The theme options for a scroll bar. The dict should contain the keys: `background`,
              `foreground`, `border`, with each item containing a tuple of the colors for the states
              `normal`, `disabled` and `active` respectively
          trough: str
              The hex code for the scrollbar trough color
          border: str
              The hex code for the scrollbar border color
          """
          logger.debug("Creating scrollbar: (key: %s, theme: %s, trough: %s, border: %s)",
                       key, theme, trough, border)
          images = dict()
          for idx, state in enumerate(("normal", "disabled", "active")):
              # Create arrow and slider widgets for each state
              img_args = ((16, 16), theme["background"][idx])
              for dir_ in ("up", "down"):
                  images[f"img_{dir_}_{state}"] = self._images.get_image(
                      *img_args,
                      foreground=theme["foreground"][idx],
                      pattern="arrow",
                      direction=dir_,
                      thickness=4,
                      border_width=1,
                      border_color=theme["border"][idx])
              images[f"img_thumb_{state}"] = self._images.get_image(
                  *img_args,
                  border_width=1,
                  border_color=theme["border"][idx])
  
          for element in ("thumb", "uparrow", "downarrow"):
              # Create the elements with the new images
              lookup = element.replace("arrow", "")
              args = (f"{key}.Vertical.Scrollbar.{element}",
                      "image",
                      images[f"img_{lookup}_normal"],
                      ("disabled", images[f"img_{lookup}_disabled"]),
                      ("pressed !disabled", images[f"img_{lookup}_active"]),
                      ("active !disabled", images[f"img_{lookup}_active"]))
              kwargs = dict(border=1, sticky="ns") if element == "thumb" else dict()
              self._style.element_create(*args, **kwargs)
  
          # Get a configurable trough
          self._style.element_create(f"{key}.Vertical.Scrollbar.trough", "from", "clam")
  
          self._style.layout(
              f"{key}.Vertical.TScrollbar",
              [(f"{key}.Vertical.Scrollbar.trough", {
                  "sticky": "ns",
                  "children": [
                      (f"{key}.Vertical.Scrollbar.uparrow", {"side": "top", "sticky": ""}),
                      (f"{key}.Vertical.Scrollbar.downarrow", {"side": "bottom", "sticky": ""}),
                      (f"{key}.Vertical.Scrollbar.thumb", {"expand": "1", "sticky": "nswe"})
                  ]
              })])
          self._style.configure(f"{key}.Vertical.TScrollbar",
                                troughcolor=trough,
                                bordercolor=border,
                                troughrelief=tk.SOLID,
                                troughborderwidth=1)
  
      def _config_settings_group_combobox(self, key, theme):
          """ Combo-boxes are fairly complex to style.
  
          Parameters
          ----------
          key: str
              The section that the slider will belong to
          theme: dict
              The user configuration theme options
          """
          # All the stock down arrow images are bad
          images = dict()
          for state in ("active", "normal"):
              images[f"arrow_{state}"] = self._images.get_image(
                  (20, 20),
                  theme["control_color"] if state == "normal" else theme["control_active"],
                  foreground=theme["control_disabled"],
                  pattern="arrow",
                  thickness=2,
                  border_width=1,
                  border_color=theme["header_color"])
  
          self._style.element_create(f"{key}.Combobox.downarrow",
                                     "image",
                                     images["arrow_normal"],
                                     ("active", images["arrow_active"]),
                                     ("pressed", images["arrow_active"]),
                                     sticky="e",
                                     width=20)
  
          # None of the themes give us the border control we need, so create an image
          box = self._images.get_image((16, 16),
                                       theme["group_background"],
                                       border_width=1,
                                       border_color=theme["group_font"])
          self._style.element_create(f"{key}.Combobox.field",
                                     "image",
                                     box,
                                     border=1,
                                     padding=(6, 0, 0, 0))
  
          # Set a layout so we can access required params
          self._style.layout(f"{key}.TCombobox", [
              (f"{key}.Combobox.field", {
                  "children": [
                      (f"{key}.Combobox.downarrow", {"side": "right", "sticky": "ns"}),
                      (f"{key}.Combobox.padding", {
                          "expand": "1",
                          "sticky": "nswe",
                          "children": [(f"{key}.Combobox.focus", {
                              "expand": "1",
                              "sticky": "nswe",
                              "children": [(f"{key}.Combobox.textarea", {"sticky": "nswe"})]})]})],
                  "sticky": "nswe"})])
  
  
  class _TkImage():  # pylint:disable=too-few-public-methods
      """ Create a tk image for a given pattern and shape.
      """
      def __init__(self):
          self._cache = []  # We need to keep a reference to every image created
  
      # Numpy array patterns
      @classmethod
      def _get_solid(cls, dimensions):
          """ Return a solid background color pattern.
  
          Parameters
          ----------
          dimensions: tuple
              The (`width`, `height`) of the desired tk image
  
          Returns
          -------
          :class:`numpy.ndarray`
              A 2D, UINT8 array of shape (height, width) of all zeros
          """
          return np.zeros((dimensions[1], dimensions[0]), dtype="uint8")
  
      @classmethod
      def _get_arrow(cls, dimensions, thickness, direction):
          """ Return a background color with a "v" arrow in foreground color
  
          Parameters
          ----------
          dimensions: tuple
              The (`width`, `height`) of the desired tk image
          thickness: int
              The thickness of the pattern to be drawn
          direction: ["left", "up", "right", "down"]
              The direction that the pattern should be facing
  
          Returns
          -------
          :class:`numpy.ndarray`
              A 2D, UINT8 array of shape (height, width) of all zeros
          """
          square_size = min(dimensions[1], dimensions[0])
          if square_size < 16 or any(dim % 2 != 0 for dim in dimensions):
              raise FaceswapError("For arrow image, the minimum size across any axis must be 8 and "
                                  "dimensions must all be divisible by 2")
          crop_size = (square_size // 16) * 16
          draw_rows = int(6 * crop_size / 16)
          start_row = dimensions[1] // 2 - draw_rows // 2
          initial_indent = (2 * (crop_size // 16) + (dimensions[0] - crop_size) // 2)
  
          retval = np.zeros((dimensions[1], dimensions[0]), dtype="uint8")
          for i in range(start_row, start_row + draw_rows):
              indent = initial_indent + i - start_row
              join = (min(indent + thickness, dimensions[0] // 2),
                      max(dimensions[0] - indent - thickness, dimensions[0] // 2))
              retval[i, np.r_[indent:join[0], join[1]:dimensions[0] - indent]] = 1
          if direction in ("right", "left"):
              retval = np.rot90(retval)
          if direction in ("up", "left"):
              retval = np.flip(retval)
          return retval
  
      def get_image(self,
                    dimensions,
                    background,
                    foreground=None,
                    pattern="solid",
                    border_width=0,
                    border_color=None,
                    thickness=2,
                    direction="down"):
          """ Obtain a tk image.
  
          Generates the requested image and stores in cache.
  
          Parameters
          ----------
          dimensions: tuple
              The (`width`, `height`) of the desired tk image
          background: str
              The hex code for the background (main) color
          foreground: str, optional
              The hex code for the background (secondary) color. If ``None`` is provided then a
              solid background color image will be returned. Default: ``None``
          pattern: ["solid", "arrow"], optional
              The pattern to generate for the tk image. Default: `"solid"`
          border_width: int, optional
              The thickness of foreground border to apply. Default: 0
          border_color: int, optional
              The color of the border, if one is to be created. Default: ``None`` (use foreground
              color)
          thickness: int, optional
              The thickness of the pattern to be drawn. Default: `2`
          direction: ["left", "up", "right", "down"], optional
              The direction that the pattern should be facing. Default: `"down"`
          """
          foreground = foreground if foreground else background
          border_color = border_color if border_color else foreground
  
          args = [dimensions]
          if pattern.lower() == "arrow":
              args.extend([thickness, direction])
          if pattern.lower() == "border":
              args.extend([thickness])
          pattern = getattr(self, f"_get_{pattern.lower()}")(*args)
  
          if border_width > 0:
              border = np.ones_like(pattern) + 1
              border[border_width:-border_width,
                     border_width:-border_width] = pattern[border_width:-border_width,
                                                           border_width:-border_width]
              pattern = border
  
          return self._create_photoimage(background, foreground, border_color, pattern)
  
      def _create_photoimage(self, background, foreground, border, pattern):
          """ Create a tkinter PhotoImage and populate it with the requested color pattern.
  
          Parameters
          ----------
          background: str
              The hex code for the background (main) color
          foreground: str
              The hex code for the foreground (secondary) color
          border: str
              The hex code for the border color
          pattern: class:`numpy.ndarray`
              The pattern for the final image with background colors marked as 0 and foreground
              colors marked as 1
          """
          image = tk.PhotoImage(width=pattern.shape[1], height=pattern.shape[0])
          self._cache.append(image)
  
          pixels = "} {".join(" ".join(foreground
                                       if pxl == 1 else border if pxl == 2 else background
                                       for pxl in row)
                              for row in pattern)
          image.put("{" + pixels + "}")
          return image
  
  
  class LongRunningTask(Thread):
      """ Runs long running tasks in a background thread to prevent the GUI from becoming
      unresponsive.
  
      This is sub-classed from :class:`Threading.Thread` so check documentation there for base
 
</s> remove     wraplength: int, optional
 </s> add     wrap_length: int, optional </s> remove     retfile: str or object
 </s> add     return_file: str or object </s> remove     waittime: int, optional
 </s> add     wait_time: int, optional </s> remove     def __init__(self, parent, tab_name, helptext, waittime, command=None):
 </s> add     def __init__(self, parent, tab_name, helptext, wait_time, command=None): </s> remove         super().__init__(parent, tab_name, helptext, waittime, command)
 </s> add         super().__init__(parent, tab_name, helptext, wait_time, command)
                                                      str(initial_dimensions[1])))
          logger.debug("Geometry: %sx%s", *initial_dimensions)
  
  














































































































































































































































































































































































































































  class LongRunningTask(Thread):
      """ Runs long running tasks in a background thread to prevent the GUI from becoming
      unresponsive.
  
      This is sub-classed from :class:`Threading.Thread` so check documentation there for base
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 GUI fixes
  - Split themes and styles to own module
  - Fix border on console window
  - variable name updates to make pep8 happy 
lib/gui/utils.py