From f56f19710dc7771c9b59ea119016caaaa27d8e5c Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Tue, 8 Aug 2023 12:27:25 -0400 Subject: [PATCH] allow user to interactively resize screen before UI runs --- .../backend/install/invokeai_configure.py | 15 +++-- invokeai/frontend/install/model_install.py | 13 ++-- invokeai/frontend/install/widgets.py | 59 +++++++++++-------- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 692eff8867..18fb2352f3 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -52,11 +52,11 @@ from invokeai.frontend.install.widgets import ( CenteredButtonPress, FileBox, IntTitleSlider, - FloatTitleSlider, set_min_terminal_size, CyclingForm, MIN_COLS, MIN_LINES, + WindowTooSmallException, ) from invokeai.backend.install.legacy_arg_parsing import legacy_parser from invokeai.backend.install.model_install_backend import ( @@ -395,7 +395,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle. ) self.max_cache_size = self.add_widget_intelligent( IntTitleSlider, - name="RAM cache size (GB). Make this at least large enough to hold a single model. Larger sizes will allow you to switch between models quickly without reading from disk.", + name="RAM cache size (GB). Make this at least large enough to hold a single full model.", value=old_opts.max_cache_size, out_of=MAX_RAM, lowest=3, @@ -440,7 +440,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle. self.autoimport_dirs = {} self.autoimport_dirs["autoimport_dir"] = self.add_widget_intelligent( FileBox, - name=f"Folder to recursively scan for new checkpoints, ControlNets, LoRAs and TI models", + name="Folder to recursively scan for new checkpoints, ControlNets, LoRAs and TI models", value=str(config.root_path / config.autoimport_dir), select_dir=True, must_exist=False, @@ -635,9 +635,10 @@ def run_console_ui(program_opts: Namespace, initfile: Path = None) -> (Namespace invokeai_opts = default_startup_options(initfile) invokeai_opts.root = program_opts.root - # The third argument is needed in the Windows 11 environment to - # launch a console window running this program. - set_min_terminal_size(MIN_COLS, MIN_LINES) + if not set_min_terminal_size(MIN_COLS, MIN_LINES): + raise WindowTooSmallException( + "Could not increase terminal size. Try running again with a larger window or smaller font size." + ) # the install-models application spawns a subprocess to install # models, and will crash unless this is set before running. @@ -842,6 +843,8 @@ def main(): postscript(errors=errors) if not opt.yes_to_all: input("Press any key to continue...") + except WindowTooSmallException as e: + logger.error(str(e)) except KeyboardInterrupt: print("\nGoodbye! Come back soon.") diff --git a/invokeai/frontend/install/model_install.py b/invokeai/frontend/install/model_install.py index 0633553a3d..55e45931e3 100644 --- a/invokeai/frontend/install/model_install.py +++ b/invokeai/frontend/install/model_install.py @@ -28,7 +28,6 @@ from npyscreen import widget from invokeai.backend.util.logging import InvokeAILogger from invokeai.backend.install.model_install_backend import ( - ModelInstallList, InstallSelections, ModelInstall, SchedulerPredictionType, @@ -41,12 +40,12 @@ from invokeai.frontend.install.widgets import ( SingleSelectColumns, TextBox, BufferBox, - FileBox, set_min_terminal_size, select_stable_diffusion_config_file, CyclingForm, MIN_COLS, MIN_LINES, + WindowTooSmallException, ) from invokeai.app.services.config import InvokeAIAppConfig @@ -156,7 +155,7 @@ class addModelsForm(CyclingForm, npyscreen.FormMultiPage): BufferBox, name="Log Messages", editable=False, - max_height=15, + max_height=6, ) self.nextrely += 1 @@ -693,7 +692,11 @@ def select_and_download_models(opt: Namespace): # needed to support the probe() method running under a subprocess torch.multiprocessing.set_start_method("spawn") - set_min_terminal_size(MIN_COLS, MIN_LINES) + if not set_min_terminal_size(MIN_COLS, MIN_LINES): + raise WindowTooSmallException( + "Could not increase terminal size. Try running again with a larger window or smaller font size." + ) + installApp = AddModelApplication(opt) try: installApp.run() @@ -787,6 +790,8 @@ def main(): curses.echo() curses.endwin() logger.info("Goodbye! Come back soon.") + except WindowTooSmallException as e: + logger.error(str(e)) except widget.NotEnoughSpaceForWidget as e: if str(e).startswith("Height of 1 allocated"): logger.error("Insufficient vertical space for the interface. Please make your window taller and try again") diff --git a/invokeai/frontend/install/widgets.py b/invokeai/frontend/install/widgets.py index c1481035d5..156503f0b8 100644 --- a/invokeai/frontend/install/widgets.py +++ b/invokeai/frontend/install/widgets.py @@ -21,31 +21,40 @@ MIN_COLS = 130 MIN_LINES = 38 +class WindowTooSmallException(Exception): + pass + + # ------------------------------------- -def set_terminal_size(columns: int, lines: int): - ts = get_terminal_size() - width = max(columns, ts.columns) - height = max(lines, ts.lines) - +def set_terminal_size(columns: int, lines: int) -> bool: OS = platform.uname().system - if OS == "Windows": - pass - # not working reliably - ask user to adjust the window - # _set_terminal_size_powershell(width,height) - elif OS in ["Darwin", "Linux"]: - _set_terminal_size_unix(width, height) + screen_ok = False + while not screen_ok: + ts = get_terminal_size() + width = max(columns, ts.columns) + height = max(lines, ts.lines) - # check whether it worked.... - ts = get_terminal_size() - pause = False - if ts.columns < columns: - print("\033[1mThis window is too narrow for the user interface.\033[0m") - pause = True - if ts.lines < lines: - print("\033[1mThis window is too short for the user interface.\033[0m") - pause = True - if pause: - input("Maximize the window then press any key to continue..") + if OS == "Windows": + pass + # not working reliably - ask user to adjust the window + # _set_terminal_size_powershell(width,height) + elif OS in ["Darwin", "Linux"]: + _set_terminal_size_unix(width, height) + + # check whether it worked.... + ts = get_terminal_size() + if ts.columns < columns or ts.lines < lines: + print( + f"\033[1mThis window is too small for the interface. InvokeAI requires {columns}x{lines} (w x h) characters, but window is {ts.columns}x{ts.lines}\033[0m" + ) + resp = input( + "Maximize the window and/or decrease the font size then press any key to continue. Type [Q] to give up.." + ) + if resp.upper().startswith("Q"): + break + else: + screen_ok = True + return screen_ok def _set_terminal_size_powershell(width: int, height: int): @@ -80,14 +89,14 @@ def _set_terminal_size_unix(width: int, height: int): sys.stdout.flush() -def set_min_terminal_size(min_cols: int, min_lines: int): +def set_min_terminal_size(min_cols: int, min_lines: int) -> bool: # make sure there's enough room for the ui term_cols, term_lines = get_terminal_size() if term_cols >= min_cols and term_lines >= min_lines: - return + return True cols = max(term_cols, min_cols) lines = max(term_lines, min_lines) - set_terminal_size(cols, lines) + return set_terminal_size(cols, lines) class IntSlider(npyscreen.Slider):