1
0
Fork 0
mirror of https://github.com/deepfakes/faceswap synced 2025-06-08 11:53:26 -04:00
faceswap/lib/gui/menu.py

207 lines
8.3 KiB
Python

#!/usr/bin python3
""" The Menu Bars for faceswap GUI """
import locale
import logging
import os
import sys
import tkinter as tk
from importlib import import_module
from subprocess import Popen, PIPE, STDOUT
from lib.Serializer import JSONSerializer
from .utils import get_config
from .popup_configure import popup_config
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
class MainMenuBar(tk.Menu):
""" GUI Main Menu Bar """
def __init__(self, master=None):
logger.debug("Initializing %s", self.__class__.__name__)
super().__init__(master)
self.root = master
self.config = get_config()
self.file_menu = tk.Menu(self, tearoff=0)
self.recent_menu = tk.Menu(self.file_menu, tearoff=0, postcommand=self.refresh_recent_menu)
self.edit_menu = tk.Menu(self, tearoff=0)
self.tools_menu = tk.Menu(self, tearoff=0)
self.build_file_menu()
self.build_edit_menu()
self.build_tools_menu()
logger.debug("Initialized %s", self.__class__.__name__)
def build_file_menu(self):
""" Add the file menu to the menu bar """
logger.debug("Building File menu")
self.file_menu.add_command(
label="Load full config...", underline=0, command=self.config.load)
self.file_menu.add_command(
label="Save full config...", underline=0, command=self.config.save)
self.file_menu.add_separator()
self.file_menu.add_cascade(label="Open recent", underline=6, menu=self.recent_menu)
self.file_menu.add_separator()
self.file_menu.add_command(
label="Reset all to default", underline=0, command=self.config.cli_opts.reset)
self.file_menu.add_command(
label="Clear all", underline=0, command=self.config.cli_opts.clear)
self.file_menu.add_separator()
self.file_menu.add_command(label="Quit", underline=0, command=self.root.close_app)
self.add_cascade(label="File", menu=self.file_menu, underline=0)
logger.debug("Built File menu")
def build_recent_menu(self):
""" Load recent files into menu bar """
logger.debug("Building Recent Files menu")
serializer = JSONSerializer
menu_file = os.path.join(self.config.pathcache, ".recent.json")
if not os.path.isfile(menu_file):
self.clear_recent_files(serializer, menu_file)
with open(menu_file, "rb") as inp:
recent_files = serializer.unmarshal(inp.read().decode("utf-8"))
logger.debug("Loaded recent files: %s", recent_files)
for recent_item in recent_files:
filename, command = recent_item
logger.debug("processing: ('%s', %s)", filename, command)
if not os.path.isfile(filename):
logger.debug("File does not exist")
continue
lbl_command = command if command else "All"
self.recent_menu.add_command(
label="{} ({})".format(filename, lbl_command.title()),
command=lambda fnm=filename, cmd=command: self.config.load(cmd, fnm))
self.recent_menu.add_separator()
self.recent_menu.add_command(
label="Clear recent files",
underline=0,
command=lambda srl=serializer, mnu=menu_file: self.clear_recent_files(srl, mnu))
logger.debug("Built Recent Files menu")
@staticmethod
def clear_recent_files(serializer, menu_file):
""" Creates or clears recent file list """
logger.debug("clearing recent files list: '%s'", menu_file)
recent_files = serializer.marshal(list())
with open(menu_file, "wb") as out:
out.write(recent_files.encode("utf-8"))
def refresh_recent_menu(self):
""" Refresh recent menu on save/load of files """
self.recent_menu.delete(0, "end")
self.build_recent_menu()
def build_edit_menu(self):
""" Add the edit menu to the menu bar """
logger.debug("Building Edit menu")
configs = self.scan_for_configs()
for name in sorted(list(configs.keys())):
label = "Configure {} Plugins...".format(name.title())
config = configs[name]
self.edit_menu.add_command(
label=label,
underline=10,
command=lambda conf=(name, config), root=self.root: popup_config(conf, root))
self.add_cascade(label="Edit", menu=self.edit_menu, underline=0)
logger.debug("Built Edit menu")
def scan_for_configs(self):
""" Scan for config.ini file locations """
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)
configs = dict()
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)
configs[plugin_type] = config
logger.debug("Configs loaded: %s", sorted(list(configs.keys())))
return configs
@staticmethod
def load_config(plugin_type):
""" Load the config to generate config file if it doesn't exist and get filename """
# 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
def build_tools_menu(self):
""" Add the file menu to the menu bar """
logger.debug("Building Tools menu")
self.tools_menu.add_command(
label="Check for updates...", underline=0, command=self.check_updates)
self.tools_menu.add_command(
label="Output System Information", underline=0, command=self.output_sysinfo)
self.add_cascade(label="Tools", menu=self.tools_menu, underline=0)
logger.debug("Built Tools menu")
@staticmethod
def output_sysinfo():
""" Output system information to console """
get_config().tk_vars["consoleclear"].set(True)
from lib.sysinfo import SysInfo
print(SysInfo().full_info())
@staticmethod
def check_updates():
""" Check for updates and clone repo """
get_config().tk_vars["consoleclear"].set(True)
encoding = locale.getpreferredencoding()
# Do the check
cmd = Popen("git remote update && git status -uno", shell=True, stdout=PIPE, stderr=STDOUT)
stdout, _ = cmd.communicate()
retcode = cmd.poll()
logger.debug("Check output: %s", stdout.decode(encoding))
logger.debug("Check returncode: %s", retcode)
if retcode != 0:
print("Git is not installed or you are not running a cloned repo. "
"Unable to check for updates")
return
chk = stdout.decode(encoding).splitlines()
update = False
for line in chk:
if line.lower().startswith("your branch is ahead"):
print("Your branch is ahead of the remote repo. Not updating")
break
if line.lower().startswith("your branch is up to date"):
print("Faceswap is up to date.")
break
if line.lower().startswith("your branch is behind"):
update = True
break
if "have diverged" in line.lower():
print("Your branch has diverged from the remote repo. Not updating")
break
logger.debug("update: %s", update)
if not update:
return
# Do the update
print("A new version is available. Updating...")
cmd = Popen("git pull", shell=True, stdout=PIPE, stderr=STDOUT, bufsize=1)
while True:
output = cmd.stdout.readline().decode(encoding)
if output == "" and cmd.poll() is not None:
break
if output:
logger.debug("Update output: '%s'", output.strip())
print(output.strip())
retcode = cmd.poll()
logger.debug("Update returncode: %s", retcode)
if retcode != 0:
print("An error occurred during update. return code: {}".format(retcode))
return
print("\nPlease restart Faceswap to complete the update.")