Ui: add open_filename helper
* native look & feel on Linux (Gnome and KDE) * falls back to tkinter
This commit is contained in:
		
							parent
							
								
									d9418d5ce1
								
							
						
					
					
						commit
						fa3925cd74
					
				
							
								
								
									
										21
									
								
								Launcher.py
								
								
								
								
							
							
						
						
									
										21
									
								
								Launcher.py
								
								
								
								
							| 
						 | 
				
			
			@ -20,7 +20,6 @@ from Utils import is_frozen, user_path, local_path, init_logging, open_filename,
 | 
			
		|||
from shutil import which
 | 
			
		||||
import shlex
 | 
			
		||||
from enum import Enum, auto
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def open_host_yaml():
 | 
			
		||||
| 
						 | 
				
			
			@ -38,22 +37,16 @@ def open_host_yaml():
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def open_patch():
 | 
			
		||||
    suffixes = []
 | 
			
		||||
    for c in components:
 | 
			
		||||
        if isfile(get_exe(c)[-1]):
 | 
			
		||||
            suffixes += c.file_identifier.suffixes if c.type == Type.CLIENT and \
 | 
			
		||||
                                                      isinstance(c.file_identifier, SuffixIdentifier) else []
 | 
			
		||||
    try:
 | 
			
		||||
        import tkinter
 | 
			
		||||
        import tkinter.filedialog
 | 
			
		||||
        filename = open_filename('Select patch', (('Patches', suffixes),))
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        logging.error("Could not load tkinter, which is likely not installed. "
 | 
			
		||||
                      "This attempt was made because Launcher.open_patch was used.")
 | 
			
		||||
        raise e
 | 
			
		||||
        messagebox('Error', str(e), error=True)
 | 
			
		||||
    else:
 | 
			
		||||
        root = tkinter.Tk()
 | 
			
		||||
        root.withdraw()
 | 
			
		||||
        suffixes = []
 | 
			
		||||
        for c in components:
 | 
			
		||||
            if isfile(get_exe(c)[-1]):
 | 
			
		||||
                suffixes += c.file_identifier.suffixes if c.type == Type.CLIENT and \
 | 
			
		||||
                                                          isinstance(c.file_identifier, SuffixIdentifier) else []
 | 
			
		||||
        filename = tkinter.filedialog.askopenfilename(filetypes=(('Patches', ' '.join(suffixes)),))
 | 
			
		||||
        file, _, component = identify(filename)
 | 
			
		||||
        if file and component:
 | 
			
		||||
            launch([*get_exe(component), file], component.cli)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1945,18 +1945,8 @@ async def main(args: argparse.Namespace):
 | 
			
		|||
 | 
			
		||||
    try:
 | 
			
		||||
        if not data_filename:
 | 
			
		||||
            try:
 | 
			
		||||
                import tkinter
 | 
			
		||||
                import tkinter.filedialog
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                logging.error("Could not load tkinter, which is likely not installed. "
 | 
			
		||||
                              "This attempt was made because no .archipelago file was provided as argument. "
 | 
			
		||||
                              "Either provide a file or ensure the tkinter package is installed.")
 | 
			
		||||
                raise e
 | 
			
		||||
            else:
 | 
			
		||||
                root = tkinter.Tk()
 | 
			
		||||
                root.withdraw()
 | 
			
		||||
                data_filename = tkinter.filedialog.askopenfilename(filetypes=(("Multiworld data", "*.archipelago *.zip"),))
 | 
			
		||||
            filetypes = (("Multiworld data", (".archipelago", ".zip")),)
 | 
			
		||||
            data_filename = Utils.open_filename("Select multiworld data", filetypes)
 | 
			
		||||
 | 
			
		||||
        ctx.load(data_filename, args.use_embedded_options)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										30
									
								
								Utils.py
								
								
								
								
							
							
						
						
									
										30
									
								
								Utils.py
								
								
								
								
							| 
						 | 
				
			
			@ -525,6 +525,36 @@ def get_fuzzy_results(input_word: str, wordlist: typing.Sequence[str], limit: ty
 | 
			
		|||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def open_filename(title: str, filetypes: typing.Sequence[typing.Tuple[str, typing.Sequence[str]]]) \
 | 
			
		||||
        -> typing.Optional[str]:
 | 
			
		||||
    def run(*args: str):
 | 
			
		||||
        return subprocess.run(args, capture_output=True, text=True).stdout.split('\n', 1)[0] or None
 | 
			
		||||
 | 
			
		||||
    if is_linux:
 | 
			
		||||
        # prefer native dialog
 | 
			
		||||
        kdialog = shutil.which('kdialog')
 | 
			
		||||
        if kdialog:
 | 
			
		||||
            k_filters = '|'.join((f'{text} (*{" *".join(ext)})' for (text, ext) in filetypes))
 | 
			
		||||
            return run(kdialog, f'--title={title}', '--getopenfilename', '.', k_filters)
 | 
			
		||||
        zenity = shutil.which('zenity')
 | 
			
		||||
        if zenity:
 | 
			
		||||
            z_filters = (f'--file-filter={text} ({", ".join(ext)}) | *{" *".join(ext)}' for (text, ext) in filetypes)
 | 
			
		||||
            return run(zenity, f'--title={title}', '--file-selection', *z_filters)
 | 
			
		||||
 | 
			
		||||
    # fall back to tk
 | 
			
		||||
    try:
 | 
			
		||||
        import tkinter
 | 
			
		||||
        import tkinter.filedialog
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        logging.error('Could not load tkinter, which is likely not installed. '
 | 
			
		||||
                      f'This attempt was made because open_filename was used for "{title}".')
 | 
			
		||||
        raise e
 | 
			
		||||
    else:
 | 
			
		||||
        root = tkinter.Tk()
 | 
			
		||||
        root.withdraw()
 | 
			
		||||
        return tkinter.filedialog.askopenfilename(title=title, filetypes=((t[0], ' '.join(t[1])) for t in filetypes))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def messagebox(title: str, text: str, error: bool = False) -> None:
 | 
			
		||||
    def is_kivy_running():
 | 
			
		||||
        if 'kivy' in sys.modules:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue