                          self.save_now = True
                  except KeyboardInterrupt:
                      break
          else:
              input() # TODO how to catch a specific key instead of Enter?
              # there isnt a good multiplatform solution: https://stackoverflow.com/questions/3523174/raw-input-in-python-without-pressing-enter
  
          print("Exit requested! The trainer will complete its current cycle, save the models and quit (it can take up a couple of seconds depending on your training speed). If you want to kill it now, press Ctrl + c")
          self.stop = True
          thr.join() # waits until thread finishes
  
 
</s> remove # Users without tkinter distrubtion packages or without an X-Console will error out
# importing tkinter. Therefore run a check on these and only import if required 
tk = None
ttk = None
filedialog = None

def import_tkinter(command):
    ''' Perform checks when importing tkinter module to ensure that GUI will load '''
    global tk
    global ttk
    global filedialog
    try:
        import tkinter
        from tkinter import ttk
        from tkinter import filedialog
        tk = tkinter
    except ImportError:
        if 'gui' in command:
            print(  'It looks like TkInter isn''t installed for your OS, so the GUI has been '
                    'disabled. To enable the GUI please install the TkInter application.\n'
                    'You can try:\n'
                    '  Windows/macOS:      Install ActiveTcl Community Edition from '
                    'www.activestate.com\n'
                    '  Ubuntu/Mint/Debian: sudo apt install python3-tk\n'
                    '  Arch:               sudo pacman -S tk\n'
                    '  CentOS/Redhat:      sudo yum install tkinter\n'
                    '  Fedora:             sudo dnf install python3-tkinter\n')
        return False
    return True    

def check_display(command):
    # Check whether there is a display to output the GUI. If running on Windows
    # then assume not running in headless mode
    if not os.environ.get('DISPLAY', None) and os.name != 'nt':
        if 'gui' in command:
            print ('Could not detect a display. The GUI has been disabled')
        return False
    return True
 </s> add PATHSCRIPT = os.path.realpath(os.path.dirname(sys.argv[0])) </s> remove                 optlist.extend((opt, optval))
        sys.argv = optlist
        process = Thread(target=self.launch_faceswap, args=(self.command,))
        process.start()

    def launch_faceswap(self, command):
        ''' Launch the script inside a subprocess to keep the GUI active '''
        self.statustext.set('Executing: ' + command.title())
 </s> add                 self.args.extend((opt, optval))

    def execute_script(self):
        """ Execute the requested Faceswap Script """
        kwargs = {'stdout': PIPE,
                  'stderr': PIPE,
                  'bufsize': 1,
                  'universal_newlines': True}
        if os.name == 'nt':
            kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP
        self.process = Popen(self.args, **kwargs)
        self.thread_stdout()
        self.thread_stderr()

    def read_stdout(self):
        """ Read stdout from the subprocess. If training, pass the loss
        values to Queue """
        while True:
            output = self.process.stdout.readline()
            if output == '' and self.process.poll() is not None:
                break
            if output:
                if self.command == 'train' and str.startswith(output, '['):
                    self.capture_loss(output)
                print(output.strip())
        returncode = self.process.poll()
        self.utils.runningtask = False
        self.utils.change_action_button()
        self.set_final_status(returncode)
        print('Process exited.')

    def read_stderr(self):
        """ Read stdout from the subprocess. If training, pass the loss
        values to Queue """
        while True:
            output = self.process.stderr.readline()
            if output == '' and self.process.poll() is not None:
                break
            print(output.strip(), file=sys.stderr)

    def thread_stdout(self):
        """ Put the subprocess stdout so that it can be read without
        blocking """
        thread = Thread(target=self.read_stdout)
        thread.daemon = True
        thread.start()

    def thread_stderr(self):
        """ Put the subprocess stderr so that it can be read without
        blocking """
        thread = Thread(target=self.read_stderr)
        thread.daemon = True
        thread.start()

    def capture_loss(self, string):
        """ Capture loss values from stdout """
        #TODO: Remove this hideous hacky fix. When the subprocess is terminated and
        # the loss dictionary is reset, 1 set of loss values ALWAYS slips through
        # and appends to the lossdict AFTER the subprocess has closed meaning that
        # checks on whether the dictionary is empty fail.
        # Therefore if the size of current loss dictionary is smaller than the
        # previous loss dictionary, assume that the process has been terminated
        # and reset it.
        # I have tried and failed to empty the subprocess stdout with:
        #   sys.exit() on the stdout/err threads (no effect)
        #   sys.stdout/stderr.flush (no effect)
        #   thread.join (locks the whole process up, because the stdout thread
        #       stubbonly refuses to release it's last line)

        currentlenloss = len(self.utils.lossdict)
        if self.lenloss > currentlenloss:
            self.utils.lossdict = dict()
            self.lenloss = 0
            return
        self.lenloss = currentlenloss

        loss = re.findall(r'([a-zA-Z_]+):.*?(\d+\.\d+)', string)

        if len(loss) < 2:
            return

        if not self.utils.lossdict:
            self.utils.lossdict.update((item[0], []) for item in loss)

        for item in loss:
            self.utils.lossdict[item[0]].append(float(item[1]))

    def terminate(self):
        """ Terminate the subprocess """
        if self.command == 'train':
            print('Sending Exit Signal', flush=True)
            try:
                now = time()
                if os.name == 'nt':
                    os.kill(self.process.pid, signal.CTRL_BREAK_EVENT)
                else:
                    self.process.send_signal(signal.SIGINT)
                while True:
                    timeelapsed = time() - now
                    if self.process.poll() is not None:
                        break
                    if timeelapsed > 30:
                        raise ValueError('Timeout reached sending Exit Signal')
                return
            except ValueError as err:
                print(err)
        print('Terminating Process...') </s> remove class FaceswapGui(object):
    ''' The Graphical User Interface '''
    def __init__(self, options, parser):
        self.gui = tk.Tk()
 </s> add # An error will be thrown when importing tkinter for users without tkinter
# distribution packages or without an X-Console. Therefore if importing fails
# no attempt will be made to instantiate the gui.
try:
    import tkinter as tk
    from tkinter import ttk
    from tkinter import filedialog
    from tkinter import messagebox
    from tkinter import TclError
except ImportError:
    tk = None
    ttk = None
    filedialog = None
    messagebox = None
    TclError = None

class Utils(object):
    """ Inter-class object holding items that are required across classes """

    def __init__(self, options, calling_file="faceswap.py"): </s> remove         ''' Save the current GUI state to a config file in json format '''
        cfgfile = filedialog.asksaveasfile( mode='w',
                                            filetypes=self.filetypes, 
                                            defaultextension='.fsw')
 </s> add         """ Save the current GUI state to a config file in json format """
        cfgfile = filedialog.asksaveasfile(mode='w',
                                           filetypes=self.filetypes,
                                           defaultextension='.fsw') </s> remove             https://github.com/deepfakes/faceswap-playground"
        )
        parser.set_defaults(func=self.process)        
 </s> add                     https://github.com/deepfakes/faceswap-playground")

        parser.add_argument('-d', '--debug',
                            action='store_true',
                            dest='debug',
                            default=False,
                            help='Output to Shell console instead of GUI console')
        parser.set_defaults(func=self.process)
            try:
                input() # TODO how to catch a specific key instead of Enter?
                # there isnt a good multiplatform solution: https://stackoverflow.com/questions/3523174/raw-input-in-python-without-pressing-enter
            except KeyboardInterrupt:
                pass
                          self.save_now = True
                  except KeyboardInterrupt:
                      break
          else:
            try:
                input() # TODO how to catch a specific key instead of Enter?
                # there isnt a good multiplatform solution: https://stackoverflow.com/questions/3523174/raw-input-in-python-without-pressing-enter
            except KeyboardInterrupt:
                pass
            try:
                input() # TODO how to catch a specific key instead of Enter?
                # there isnt a good multiplatform solution: https://stackoverflow.com/questions/3523174/raw-input-in-python-without-pressing-enter
            except KeyboardInterrupt:
                pass
  
          print("Exit requested! The trainer will complete its current cycle, save the models and quit (it can take up a couple of seconds depending on your training speed). If you want to kill it now, press Ctrl + c")
          self.stop = True
          thr.join() # waits until thread finishes
  
keep keep keep keep replace replace keep keep keep keep keep
 GUI v0.2.1b (#352)

* Code refactor

* Console Added

* Add graphing with matplotlib

* Add GUI preview support

* Improve import handling.

* Add GUI integration for tools.py (Launch tools.py with the gui command)

* Reformat to conform to PEP8.

* Add Tooltips, 

* Make panels user adjustable

* Fix convert.py Sharpen default value 
scripts/train.py