fix: hitting 'b' or 'h' in main menu raises exception

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
dw-0
2024-04-10 22:41:02 +02:00
parent 409aa3da25
commit bb769fdf6d
4 changed files with 45 additions and 45 deletions

View File

@@ -21,8 +21,7 @@ class KlipperNoFirmwareErrorMenu(BaseMenu):
super().__init__() super().__init__()
self.flash_options = FlashOptions() self.flash_options = FlashOptions()
self.options = {"": self.go_back} self.default_option = self.go_back
self.default_options = self.go_back
self.footer_type = FooterType.BLANK self.footer_type = FooterType.BLANK
self.input_label_txt = "Press ENTER to go back to [Advanced Menu]" self.input_label_txt = "Press ENTER to go back to [Advanced Menu]"
@@ -64,8 +63,7 @@ class KlipperNoBoardTypesErrorMenu(BaseMenu):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.options = {"": self.go_back} self.default_option = self.go_back
self.default_options = self.go_back
self.footer_type = FooterType.BLANK self.footer_type = FooterType.BLANK
self.input_label_txt = "Press ENTER to go back to [Main Menu]" self.input_label_txt = "Press ENTER to go back to [Main Menu]"

View File

@@ -48,10 +48,10 @@ class KlipperFlashMethodMenu(BaseMenu):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu self.previous_menu: BaseMenu = previous_menu
self.help_menu = KlipperFlashMethodHelpMenu
self.options = { self.options = {
"1": self.select_regular, "1": self.select_regular,
"2": self.select_sdcard, "2": self.select_sdcard,
"h": self.help_menu,
} }
self.input_label_txt = "Select flash method" self.input_label_txt = "Select flash method"
self.footer_type = FooterType.BACK_HELP self.footer_type = FooterType.BACK_HELP
@@ -99,9 +99,6 @@ class KlipperFlashMethodMenu(BaseMenu):
else: else:
KlipperNoFirmwareErrorMenu().run() KlipperNoFirmwareErrorMenu().run()
def help_menu(self, **kwargs):
KlipperFlashMethodHelpMenu(previous_menu=self).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
@@ -110,10 +107,10 @@ class KlipperFlashCommandMenu(BaseMenu):
super().__init__() super().__init__()
self.previous_menu: BaseMenu = previous_menu self.previous_menu: BaseMenu = previous_menu
self.help_menu = KlipperFlashCommandHelpMenu
self.options = { self.options = {
"1": self.select_flash, "1": self.select_flash,
"2": self.select_serialflash, "2": self.select_serialflash,
"h": self.help_menu,
} }
self.default_option = self.select_flash self.default_option = self.select_flash
self.input_label_txt = "Select flash command" self.input_label_txt = "Select flash command"
@@ -145,9 +142,6 @@ class KlipperFlashCommandMenu(BaseMenu):
def goto_next_menu(self, **kwargs): def goto_next_menu(self, **kwargs):
KlipperSelectMcuConnectionMenu(previous_menu=self).run() KlipperSelectMcuConnectionMenu(previous_menu=self).run()
def help_menu(self, **kwargs):
KlipperFlashCommandHelpMenu(previous_menu=self).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
@@ -157,11 +151,11 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
self.__standalone = standalone self.__standalone = standalone
self.previous_menu: BaseMenu = previous_menu self.previous_menu: BaseMenu = previous_menu
self.help_menu = KlipperMcuConnectionHelpMenu
self.options = { self.options = {
"1": self.select_usb, "1": self.select_usb,
"2": self.select_dfu, "2": self.select_dfu,
"3": self.select_usb_dfu, "3": self.select_usb_dfu,
"h": self.help_menu,
} }
self.input_label_txt = "Select connection type" self.input_label_txt = "Select connection type"
self.footer_type = FooterType.BACK_HELP self.footer_type = FooterType.BACK_HELP
@@ -229,9 +223,6 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
def goto_next_menu(self, **kwargs): def goto_next_menu(self, **kwargs):
KlipperSelectMcuIdMenu(previous_menu=self).run() KlipperSelectMcuIdMenu(previous_menu=self).run()
def help_menu(self, **kwargs):
KlipperMcuConnectionHelpMenu(previous_menu=self).run()
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic

View File

@@ -17,14 +17,6 @@ class FooterType(Enum):
BLANK = "BLANK" BLANK = "BLANK"
NAVI_OPTIONS = {
FooterType.QUIT: ["q"],
FooterType.BACK: ["b"],
FooterType.BACK_HELP: ["b", "h"],
FooterType.BLANK: [],
}
class ExitAppException(Exception): class ExitAppException(Exception):
pass pass

View File

@@ -12,10 +12,10 @@ from __future__ import annotations
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from abc import abstractmethod, ABC from abc import abstractmethod
from typing import Dict, Union, Callable, Type, Tuple from typing import Dict, Union, Callable, Type, Tuple
from core.menus import FooterType, NAVI_OPTIONS, ExitAppException, GoBackException from core.menus import FooterType, ExitAppException, GoBackException
from utils.constants import ( from utils.constants import (
COLOR_GREEN, COLOR_GREEN,
COLOR_YELLOW, COLOR_YELLOW,
@@ -96,22 +96,51 @@ def print_blank_footer():
print("\=======================================================/") print("\=======================================================/")
Options = Dict[str, Callable] class PostInitCaller(type):
def __call__(cls, *args, **kwargs):
obj = type.__call__(cls, *args, **kwargs)
obj.__post_init__()
return obj
class BaseMenu(ABC): # noinspection PyUnusedLocal
options: Options = {} # noinspection PyMethodMayBeStatic
class BaseMenu(metaclass=PostInitCaller):
options: Dict[str, Callable] = {}
options_offset: int = 0 options_offset: int = 0
default_option: Union[Callable, None] = None default_option: Union[Callable, None] = None
input_label_txt: str = "Perform action" input_label_txt: str = "Perform action"
header: bool = False header: bool = False
previous_menu: Union[Type[BaseMenu], BaseMenu] = None previous_menu: Union[Type[BaseMenu], BaseMenu] = None
help_menu: Type[BaseMenu] = None
footer_type: FooterType = FooterType.BACK footer_type: FooterType = FooterType.BACK
def __init__(self): def __init__(self, **kwargs):
if type(self) is BaseMenu: if type(self) is BaseMenu:
raise NotImplementedError("BaseMenu cannot be instantiated directly.") raise NotImplementedError("BaseMenu cannot be instantiated directly.")
def __post_init__(self):
# conditionally add options based on footer type
if self.footer_type is FooterType.QUIT:
self.options["q"] = self.__exit
if self.footer_type is FooterType.BACK:
self.options["b"] = self.__go_back
if self.footer_type is FooterType.BACK_HELP:
self.options["b"] = self.__go_back
self.options["h"] = self.__go_to_help
# if defined, add the default option to the options dict
if self.default_option is not None:
self.options[""] = self.default_option
def __go_back(self, **kwargs):
raise GoBackException()
def __go_to_help(self, **kwargs):
self.help_menu(previous_menu=self).run()
def __exit(self, **kwargs):
raise ExitAppException()
@abstractmethod @abstractmethod
def print_menu(self) -> None: def print_menu(self) -> None:
raise NotImplementedError("Subclasses must implement the print_menu method") raise NotImplementedError("Subclasses must implement the print_menu method")
@@ -144,20 +173,8 @@ class BaseMenu(ABC):
usr_input = usr_input.lower() usr_input = usr_input.lower()
option = self.options.get(usr_input, None) option = self.options.get(usr_input, None)
# check if usr_input contains a character used for basic navigation, e.g. b, h or q # if option/usr_input is None/empty string, we execute the menus default option if specified
# and if the current menu has the appropriate footer to allow for that action if (option is None or usr_input == "") and self.default_option is not None:
is_valid_navigation = self.footer_type in NAVI_OPTIONS
user_navigated = usr_input in NAVI_OPTIONS[self.footer_type]
if is_valid_navigation and user_navigated:
if usr_input == "q":
raise ExitAppException()
elif usr_input == "b":
raise GoBackException()
elif usr_input == "h":
return option, usr_input
# if usr_input is None or an empty string, we execute the menues default option if specified
if usr_input == "" and self.default_option is not None:
return self.default_option, usr_input return self.default_option, usr_input
# user selected a regular option # user selected a regular option
@@ -168,8 +185,10 @@ class BaseMenu(ABC):
while True: while True:
print(f"{COLOR_CYAN}###### {self.input_label_txt}: {RESET_FORMAT}", end="") print(f"{COLOR_CYAN}###### {self.input_label_txt}: {RESET_FORMAT}", end="")
usr_input = input().lower() usr_input = input().lower()
validated_input = self.validate_user_input(usr_input)
method_to_call = validated_input[0]
if (validated_input := self.validate_user_input(usr_input)) is not None: if method_to_call is not None:
return validated_input return validated_input
else: else:
Logger.print_error("Invalid input!", False) Logger.print_error("Invalid input!", False)