diff --git a/CHANGELOG.md b/CHANGELOG.md index 000d3cc..2d22401 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Version 0.10.3 + +- feat(menu): add placeholder for the menu when it's empty + ## Version 0.10.2 - fix(regression): keep the menu responsive even with rapid switches of the screen-manager diff --git a/pyproject.toml b/pyproject.toml index aee4c17..7e3a661 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ubo-gui" -version = "0.10.2" +version = "0.10.3" description = "GUI sdk for Ubo Pod" authors = ["Sassan Haradji "] license = "Apache-2.0" diff --git a/ubo_gui/menu/__init__.py b/ubo_gui/menu/__init__.py index 3e14dfe..155956f 100644 --- a/ubo_gui/menu/__init__.py +++ b/ubo_gui/menu/__init__.py @@ -291,8 +291,10 @@ def go_back(self: MenuWidget) -> None: def render_items(self: MenuWidget, *_: object) -> None: """Render the items of the current menu.""" self.clear_widget_subscriptions() + if not self.current_menu: + return if self.page_index == 0 and isinstance(self.current_menu, HeadedMenu): - header_menu_page_widget = HeaderMenuPageWidget( + list_widget = HeaderMenuPageWidget( self.current_menu_items[:1], name=f'Page {self.get_depth()} 0', ) @@ -302,12 +304,12 @@ def handle_heading_change(heading: str) -> None: 'Handle `heading` change...', extra={ 'new_heading': heading, - 'old_heading': header_menu_page_widget.heading, + 'old_heading': list_widget.heading, 'subscription_level': 'widget', }, ) - if heading != header_menu_page_widget.heading: - header_menu_page_widget.heading = heading + if heading != list_widget.heading: + list_widget.heading = heading self.widget_subscriptions.add( process_subscribable_value( @@ -321,12 +323,12 @@ def handle_sub_heading_change(sub_heading: str) -> None: 'Handle `sub_heading` change...', extra={ 'new_sub_heading': sub_heading, - 'old_sub_heading': header_menu_page_widget.sub_heading, + 'old_sub_heading': list_widget.sub_heading, 'subscription_level': 'widget', }, ) - if sub_heading != header_menu_page_widget.sub_heading: - header_menu_page_widget.sub_heading = sub_heading + if sub_heading != list_widget.sub_heading: + list_widget.sub_heading = sub_heading self.widget_subscriptions.add( process_subscribable_value( @@ -335,17 +337,37 @@ def handle_sub_heading_change(sub_heading: str) -> None: ), ) - self.current_screen = header_menu_page_widget + self.current_screen = list_widget else: offset = ( -(PAGE_SIZE - 1) if isinstance(self.current_menu, HeadedMenu) else 0 ) - self.current_screen = NormalMenuPageWidget( + list_widget = NormalMenuPageWidget( self.current_menu_items[ self.page_index * 3 + offset : self.page_index * 3 + 3 + offset ], name=f'Page {self.get_depth()} 0', ) + self.current_screen = list_widget + + def handle_placeholder_change(placeholder: str | None) -> None: + logger.debug( + 'Handle `placeholder` change...', + extra={ + 'new_placeholder': placeholder, + 'old_placeholder': list_widget.placeholder, + 'subscription_level': 'widget', + }, + ) + if placeholder != list_widget.placeholder: + list_widget.placeholder = placeholder + + self.widget_subscriptions.add( + process_subscribable_value( + self.current_menu.placeholder, + handle_placeholder_change, + ), + ) def render(self: MenuWidget, *_: object) -> None: """Return the current screen page.""" diff --git a/ubo_gui/menu/types.py b/ubo_gui/menu/types.py index ce9f1ed..53765ff 100644 --- a/ubo_gui/menu/types.py +++ b/ubo_gui/menu/types.py @@ -43,7 +43,7 @@ class BaseMenu(Immutable): title: str | Callable[[], str] items: Sequence[Item] | Callable[[], Sequence[Item]] - _id: str | None = None + placeholder: str | None | Callable[[], str | None] = None class HeadedMenu(BaseMenu): diff --git a/ubo_gui/menu/widgets/header_menu_page_widget.kv b/ubo_gui/menu/widgets/header_menu_page_widget.kv index f912d8e..b57cca4 100644 --- a/ubo_gui/menu/widgets/header_menu_page_widget.kv +++ b/ubo_gui/menu/widgets/header_menu_page_widget.kv @@ -40,6 +40,23 @@ size_hint: 1, None height: dp(10) - ItemWidget: - item: root.items[0] if len(root.items) > 0 else None + Label: + text: '' if root.items else ('Nothing here yet' if root.placeholder is None else root.placeholder) + text_size: self.size + font_size: dp(20) + halign: 'center' + valign: 'middle' + height: dp(50) if len(root.items) == 0 else 0 size_hint: 1, None + color: .6, .6, .6 + bold: True + italic: True + + BoxLayout: + height: self.minimum_height if root.items else 0 + size_hint_y: None if root.items else 0 + orientation: 'vertical' + + ItemWidget: + item: root.items[0] if len(root.items) > 0 else None + size_hint: 1, None diff --git a/ubo_gui/menu/widgets/header_menu_page_widget.py b/ubo_gui/menu/widgets/header_menu_page_widget.py index cf5d985..7ee5202 100644 --- a/ubo_gui/menu/widgets/header_menu_page_widget.py +++ b/ubo_gui/menu/widgets/header_menu_page_widget.py @@ -21,12 +21,11 @@ class HeaderMenuPageWidget(PageWidget): heading = StringProperty() sub_heading = StringProperty() + placeholder = StringProperty(allownone=True) def __init__( self: HeaderMenuPageWidget, items: Sequence[Item], - heading: str = '', - sub_heading: str = '', **kwargs: Any, # noqa: ANN401 ) -> None: """Initialize a `HeaderMenuPageWidget`. @@ -36,12 +35,6 @@ def __init__( items: `Sequence`[[`Item`]] The item to be shown in this page - heading: `str` - The heading of the page - - sub_heading: `str` - The sub-heading of the page - kwargs: Any Stuff that will get directly passed to the `__init__` method of Kivy's `Screen`. @@ -51,8 +44,6 @@ def __init__( msg = '`HeaderMenuPageWidget` is initialized with more than one item' raise ValueError(msg) super().__init__(items, **kwargs) - self.heading = heading - self.sub_heading = sub_heading def get_item(self: HeaderMenuPageWidget, index: int) -> Item | None: """Get the item at the given index.""" diff --git a/ubo_gui/menu/widgets/normal_menu_page_widget.kv b/ubo_gui/menu/widgets/normal_menu_page_widget.kv index a079cb9..1e4f170 100644 --- a/ubo_gui/menu/widgets/normal_menu_page_widget.kv +++ b/ubo_gui/menu/widgets/normal_menu_page_widget.kv @@ -6,16 +6,31 @@ pos: self.pos size: self.size orientation: 'vertical' - spacing: dp(7) - ItemWidget: - item: root.items[0] if len(root.items) > 0 else None - size_hint: 1, None + Label: + text: '' if root.items else ('Nothing here yet' if root.placeholder is None else root.placeholder) + text_size: self.size + font_size: dp(20) + halign: 'center' + valign: 'middle' + color: .6, .6, .6 + bold: True + italic: True - ItemWidget: - item: root.items[1] if len(root.items) > 1 else None - size_hint: 1, None + BoxLayout: + height: self.minimum_height if root.items else 0 + size_hint_y: None if root.items else 0 + orientation: 'vertical' + spacing: dp(7) - ItemWidget: - item: root.items[2] if len(root.items) > 2 else None - size_hint: 1, None + ItemWidget: + item: root.items[0] if len(root.items) > 0 else None + size_hint: 1, None + + ItemWidget: + item: root.items[1] if len(root.items) > 1 else None + size_hint: 1, None + + ItemWidget: + item: root.items[2] if len(root.items) > 2 else None + size_hint: 1, None diff --git a/ubo_gui/menu/widgets/normal_menu_page_widget.py b/ubo_gui/menu/widgets/normal_menu_page_widget.py index df535c2..4b72a45 100644 --- a/ubo_gui/menu/widgets/normal_menu_page_widget.py +++ b/ubo_gui/menu/widgets/normal_menu_page_widget.py @@ -3,6 +3,7 @@ import pathlib from kivy.lang.builder import Builder +from kivy.properties import StringProperty from ubo_gui.page import PageWidget @@ -10,6 +11,8 @@ class NormalMenuPageWidget(PageWidget): """renders a normal page of a `Menu`.""" + placeholder = StringProperty(allownone=True) + Builder.load_file( pathlib.Path(__file__)