          """ Build a single tab within the plugin's configuration pop-up.
  
          Parameters
          ----------
          container: :class:`ttk.Notebook`
              The notebook to place the category options into
          category: str
              The name of the categories to build options for
  
          Returns
          -------
          :class:'~lib.gui.control_helper.ControlPanel` or :class:`ttk.Notebook`
              The control panel options in a Control Panel frame (for single plugin configurations)
 
</s> remove         Returns
        -------
        :class:'~lib.gui.control_helper.ControlPanel` or :class:`ttk.Notebook`
            The control panel options in a Control Panel frame (for single plugin configurations)
            or a Notebook containing tabs with Control Panel frames (for multi-plugin
            configurations)
 </s> add     def _set_display(self, section, subsections):
        """ Set the correct display page for the given section and subsections.

        Parameters
        ----------
        section: str
            The main section to be navigated to (or root node)
        subsections: list
            The full list of subsections ending on the required node </s> remove         logger.debug("Building plugin config page: '%s'", category)
        plugins = sorted(list(key for key in self._config_cpanel_dict[category].keys()))
        panel_kwargs = dict(columns=2, max_columns=2, option_columns=2, blank_nones=False)
        if any(plugin != category for plugin in plugins):
            page = ttk.Notebook(container)
            for plugin in plugins:
                cp_options = list(self._config_cpanel_dict[category][plugin].values())
                frame = ControlPanel(page,
                                     cp_options,
                                     header_text=self._plugin_info[plugin],
                                     **panel_kwargs)
                title = plugin[plugin.rfind(".") + 1:]
                title = title.replace("_", " ").title()
                page.add(frame, text=title)
            page.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
 </s> add         key = "|".join([section] + subsections)
        if self._displayed_frame is not None:
            self._displayed_frame.pack_forget()

        if key not in self._cache:
            self._cache_page(key)

        self._displayed_frame = self._cache[key]
        self._displayed_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

    def _cache_page(self, key):
        """ Create the control panel options for the requested configuration and cache.

        Parameters
        ----------
        key: str
            The lookup key to the settings cache
        """
        panel_kwargs = dict(columns=1, max_columns=1, option_columns=4, blank_nones=False)
        info = self._config_cpanel_dict.get(key, None)
        if info is None:
            logger.debug("key '%s' does not exist in options. Creating links page.", key)
            self._cache[key] = self._create_links_page(key) </s> remove         conf = dict()
        for section in self._config.config.sections():
            self._config.section = section
            category = section.split(".")[0]
            options = self._config.defaults[section]
            section = section.split(".")[-1]
            conf.setdefault(category, dict())[section] = OrderedDict()
            for key, val in options.items():
                if key == "helptext":
                    self._plugin_info[section] = val
                    continue
                initial_value = self._config.config_dict[key]
                initial_value = "none" if initial_value is None else initial_value
                conf[category][section][key] = ControlPanelOption(
                    title=key,
                    dtype=val["type"],
                    group=val["group"],
                    default=val["default"],
                    initial_value=initial_value,
                    choices=val["choices"],
                    is_radio=val["gui_radio"],
                    rounding=val["rounding"],
                    min_max=val["min_max"],
                    helptext=val["helptext"])
        logger.debug("Formatted Config for GUI: %s", conf)
        return conf

    def _build(self):
        """ Build the configuration pop-up window"""
        logger.debug("Building plugin config popup")
        container = ttk.Notebook(self._page_frame)
        categories = sorted(list(self._config_cpanel_dict.keys()))
        if "global" in categories:  # Move global to first item
            categories.insert(0, categories.pop(categories.index("global")))
        for category in categories:
            page = self._build_page(container, category)
            container.add(page, text=category.title())

        self._add_frame_separator()
        self._add_actions()

        container.pack(fill=tk.BOTH, expand=True)
        logger.debug("Built plugin config popup")

    def _build_page(self, container, category):
        """ Build a single tab within the plugin's configuration pop-up.
 </s> add         retval = dict()
        for plugin, conf in self._configs.items():
            for section in conf.config.sections():
                conf.section = section
                category = section.split(".")[0]
                sect = section.split(".")[-1]
                # Elevate global to root
                key = plugin if sect == "global" else "{}|{}|{}".format(plugin, category, sect)
                retval[key] = dict(helptext=None, options=OrderedDict())

                for option, params in conf.defaults[section].items():
                    if option == "helptext":
                        retval[key]["helptext"] = params
                        continue
                    initial_value = conf.config_dict[option]
                    initial_value = "none" if initial_value is None else initial_value
                    retval[key]["options"][option] = ControlPanelOption(
                        title=option,
                        dtype=params["type"],
                        group=params["group"],
                        default=params["default"],
                        initial_value=initial_value,
                        choices=params["choices"],
                        is_radio=params["gui_radio"],
                        rounding=params["rounding"],
                        min_max=params["min_max"],
                        helptext=params["helptext"])
        logger.debug("Formatted Config for GUI: %s", retval)
        return retval

    def _build_header(self):
        """ Build the dynamic header text. """
        header_frame = ttk.Frame(self)
        var = tk.StringVar()
        lbl = ttk.Label(header_frame, textvariable=var, anchor=tk.W, style="H2.TLabel")
        lbl.pack(fill=tk.X, expand=True, side=tk.TOP)
        header_frame.pack(fill=tk.X, padx=5, pady=(5, 0), side=tk.TOP)
        self._vars["header"] = var

    def select_options(self, section, subsections):
        """ Display the page for the given section and subsections. </s> remove         The name of the configuration file. Used for the pop-up title bar.
    configuration: :class:`~lib.config.FaceswapConfig`
        The configuration options for the requested pop-up window
 </s> add         The name of the section that is being navigated to. Used for opening on the correct
        page in the Tree View.
    configurations: dict
        Dictionary containing the :class:`~lib.config.FaceswapConfig` object for each
        configuration section for the requested pop-up window </s> remove     Parameters
    ----------
    name: str
        The name of the configuration file. Used for the pop-up title bar.
    configuration: :class:`~lib.config.FaceswapConfig`
        The configuration options for the requested pop-up window
    """
    logger.debug("name: %s, configuration: %s", name, configuration)
    if POPUP:
        p_key = list(POPUP.keys())[0]
        logger.debug("Closing open popup: '%s'", p_key)
        POPUP[p_key].destroy()
        del POPUP[p_key]
    window = _ConfigurePlugins(name, configuration)
    POPUP[name] = window
    logger.debug("Current pop-up: %s", POPUP)
 </s> add     def open_popup(self, name=None):
        """ Launch the popup, ensuring only one instance is ever open

        Parameters
        ----------
        name: str, Optional
            The name of the configuration file. Used for selecting the correct section if required.
            Set to ``None`` if no initial section should be selected. Default: ``None``
        """
        if not self._configs:
            self._scan_for_configs()
        logger.debug("name: %s", name)
        if self._popup is not None:
            logger.info("Popup already open. Returning: %s", _POPUP)
            return
        self._popup = _ConfigurePlugins(name, self._configs)

    def close_popup(self):
        """ Destroy the open popup and remove it from tracking. """
        if self._popup is None:
            logger.info("No popup to close. Returning")
            return
        self._popup.destroy()
        del self._popup
        self._popup = None

    def _scan_for_configs(self):
        """ Scan the plugin folders for configuration settings. Add in the GUI configuration also.

        Populates the attribute :attr:`_configs`.
        """
        root_path = os.path.abspath(os.path.dirname(sys.argv[0]))
        plugins_path = os.path.join(root_path, "plugins")
        logger.debug("Scanning path: '%s'", plugins_path)
        for dirpath, _, filenames in os.walk(plugins_path):
            if "_config.py" in filenames:
                plugin_type = os.path.split(dirpath)[-1]
                config = self._load_config(plugin_type)
                self._configs[plugin_type] = config
        self._configs["gui"] = get_config().user_config
        logger.debug("Configs loaded: %s", sorted(list(self._configs.keys())))

    @classmethod
    def _load_config(cls, plugin_type):
        """ Load the config from disk. If the file doesn't exist, then it will be generated.

        Parameters
        ----------
        plugin_type: str
            The plugin type (i.e. extract, train convert) that the config should be loaded for

        Returns
        -------
        :class:`lib.config.FaceswapConfig`
            The Configuration for the selected plugin
        """
        # Load config to generate default if doesn't exist
        mod = ".".join(("plugins", plugin_type, "_config"))
        module = import_module(mod)
        config = module.Config(None)
        logger.debug("Found '%s' config at '%s'", plugin_type, config.configfile)
        return config


_STATE = _State()
open_popup = _STATE.open_popup
        section: str
            The main section to be navigated to (or root node)
        subsections: list
            The full list of subsections ending on the required node
        """
        labels = ["global"] if not subsections else subsections
        self._vars["header"].set(" - ".join(sect.replace("_", " ").title() for sect in labels))
        self._set_display(section, subsections)
          """ Build a single tab within the plugin's configuration pop-up.
  
          Parameters
          ----------
        section: str
            The main section to be navigated to (or root node)
        subsections: list
            The full list of subsections ending on the required node
        """
        labels = ["global"] if not subsections else subsections
        self._vars["header"].set(" - ".join(sect.replace("_", " ").title() for sect in labels))
        self._set_display(section, subsections)
        section: str
            The main section to be navigated to (or root node)
        subsections: list
            The full list of subsections ending on the required node
        """
        labels = ["global"] if not subsections else subsections
        self._vars["header"].set(" - ".join(sect.replace("_", " ").title() for sect in labels))
        self._set_display(section, subsections)
        section: str
            The main section to be navigated to (or root node)
        subsections: list
            The full list of subsections ending on the required node
        """
        labels = ["global"] if not subsections else subsections
        self._vars["header"].set(" - ".join(sect.replace("_", " ").title() for sect in labels))
        self._set_display(section, subsections)
        section: str
            The main section to be navigated to (or root node)
        subsections: list
            The full list of subsections ending on the required node
        """
        labels = ["global"] if not subsections else subsections
        self._vars["header"].set(" - ".join(sect.replace("_", " ").title() for sect in labels))
        self._set_display(section, subsections)
  
          Returns
          -------
          :class:'~lib.gui.control_helper.ControlPanel` or :class:`ttk.Notebook`
              The control panel options in a Control Panel frame (for single plugin configurations)
keep keep keep keep replace replace replace replace keep keep keep keep keep
 GUI: Consolidate settings to single menu 
lib/gui/popup_configure.py