hspylib-clitt 0.9.118__py3-none-any.whl → 0.9.120__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hspylib-clitt might be problematic. Click here for more details.
- build/lib/build/lib/build/lib/clitt/__classpath__.py +28 -0
- build/lib/build/lib/build/lib/clitt/__init__.py +13 -0
- build/lib/build/lib/build/lib/clitt/__main__.py +139 -0
- build/lib/build/lib/build/lib/clitt/addons/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/addons/appman/__init__.py +13 -0
- build/lib/build/lib/build/lib/clitt/addons/appman/appman.py +305 -0
- build/lib/build/lib/build/lib/clitt/addons/appman/appman_enums.py +39 -0
- build/lib/build/lib/build/lib/clitt/addons/appman/templates/__init__.py +11 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/__init__.py +14 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widget.py +70 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widget_entry.py +54 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +14 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +110 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +246 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +272 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +146 -0
- build/lib/build/lib/build/lib/clitt/addons/widman/widman.py +123 -0
- build/lib/build/lib/build/lib/clitt/core/__init__.py +15 -0
- build/lib/build/lib/build/lib/clitt/core/exception/__init__.py +11 -0
- build/lib/build/lib/build/lib/clitt/core/exception/exceptions.py +19 -0
- build/lib/build/lib/build/lib/clitt/core/icons/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/core/icons/emojis/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/core/icons/emojis/emojis.py +41 -0
- build/lib/build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +40 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +18 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +55 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +76 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +93 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +69 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +59 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +42 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +39 -0
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +37 -0
- build/lib/build/lib/build/lib/clitt/core/preferences.py +87 -0
- build/lib/build/lib/build/lib/clitt/core/term/__init__.py +14 -0
- build/lib/build/lib/build/lib/clitt/core/term/commons.py +106 -0
- build/lib/build/lib/build/lib/clitt/core/term/cursor.py +174 -0
- build/lib/build/lib/build/lib/clitt/core/term/screen.py +106 -0
- build/lib/build/lib/build/lib/clitt/core/term/terminal.py +202 -0
- build/lib/build/lib/build/lib/clitt/core/tui/__init__.py +20 -0
- build/lib/build/lib/build/lib/clitt/core/tui/line_input/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +229 -0
- build/lib/build/lib/build/lib/clitt/core/tui/line_input/line_input.py +31 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +43 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +192 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +14 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +54 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +31 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +26 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +148 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/__init__.py +16 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +111 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +47 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +117 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +196 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +98 -0
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +57 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/__init__.py +19 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/access_type.py +26 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/field_builder.py +117 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/form_builder.py +72 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/form_field.py +180 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/input_type.py +30 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/input_validator.py +98 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/menu_input.py +292 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/minput.py +44 -0
- build/lib/build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +156 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mselect/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +170 -0
- build/lib/build/lib/build/lib/clitt/core/tui/mselect/mselect.py +36 -0
- build/lib/build/lib/build/lib/clitt/core/tui/table/__init__.py +12 -0
- build/lib/build/lib/build/lib/clitt/core/tui/table/table_enums.py +47 -0
- build/lib/build/lib/build/lib/clitt/core/tui/table/table_renderer.py +339 -0
- build/lib/build/lib/build/lib/clitt/core/tui/tui_application.py +52 -0
- build/lib/build/lib/build/lib/clitt/core/tui/tui_component.py +154 -0
- build/lib/build/lib/build/lib/clitt/core/tui/tui_preferences.py +103 -0
- build/lib/build/lib/build/lib/clitt/utils/__init__.py +11 -0
- build/lib/build/lib/build/lib/clitt/utils/git_utils.py +66 -0
- build/lib/build/lib/clitt/__classpath__.py +28 -0
- build/lib/build/lib/clitt/__init__.py +13 -0
- build/lib/build/lib/clitt/__main__.py +139 -0
- build/lib/build/lib/clitt/addons/__init__.py +12 -0
- build/lib/build/lib/clitt/addons/appman/__init__.py +13 -0
- build/lib/build/lib/clitt/addons/appman/appman.py +305 -0
- build/lib/build/lib/clitt/addons/appman/appman_enums.py +39 -0
- build/lib/build/lib/clitt/addons/appman/templates/__init__.py +11 -0
- build/lib/build/lib/clitt/addons/widman/__init__.py +14 -0
- build/lib/build/lib/clitt/addons/widman/widget.py +70 -0
- build/lib/build/lib/clitt/addons/widman/widget_entry.py +54 -0
- build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +14 -0
- build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +110 -0
- build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +246 -0
- build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +272 -0
- build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +146 -0
- build/lib/build/lib/clitt/addons/widman/widman.py +123 -0
- build/lib/build/lib/clitt/core/__init__.py +15 -0
- build/lib/build/lib/clitt/core/exception/__init__.py +11 -0
- build/lib/build/lib/clitt/core/exception/exceptions.py +19 -0
- build/lib/build/lib/clitt/core/icons/__init__.py +12 -0
- build/lib/build/lib/clitt/core/icons/emojis/__init__.py +12 -0
- build/lib/build/lib/clitt/core/icons/emojis/emojis.py +41 -0
- build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +40 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +18 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +55 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +76 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +93 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +69 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +59 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +42 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +39 -0
- build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +37 -0
- build/lib/build/lib/clitt/core/preferences.py +87 -0
- build/lib/build/lib/clitt/core/term/__init__.py +14 -0
- build/lib/build/lib/clitt/core/term/commons.py +106 -0
- build/lib/build/lib/clitt/core/term/cursor.py +174 -0
- build/lib/build/lib/clitt/core/term/screen.py +106 -0
- build/lib/build/lib/clitt/core/term/terminal.py +202 -0
- build/lib/build/lib/clitt/core/tui/__init__.py +20 -0
- build/lib/build/lib/clitt/core/tui/line_input/__init__.py +12 -0
- build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +229 -0
- build/lib/build/lib/clitt/core/tui/line_input/line_input.py +31 -0
- build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +12 -0
- build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +43 -0
- build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +192 -0
- build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +14 -0
- build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +54 -0
- build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +31 -0
- build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +26 -0
- build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +148 -0
- build/lib/build/lib/clitt/core/tui/menu/__init__.py +16 -0
- build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +111 -0
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +47 -0
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +117 -0
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +196 -0
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +98 -0
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +57 -0
- build/lib/build/lib/clitt/core/tui/minput/__init__.py +19 -0
- build/lib/build/lib/clitt/core/tui/minput/access_type.py +26 -0
- build/lib/build/lib/clitt/core/tui/minput/field_builder.py +117 -0
- build/lib/build/lib/clitt/core/tui/minput/form_builder.py +72 -0
- build/lib/build/lib/clitt/core/tui/minput/form_field.py +180 -0
- build/lib/build/lib/clitt/core/tui/minput/input_type.py +30 -0
- build/lib/build/lib/clitt/core/tui/minput/input_validator.py +98 -0
- build/lib/build/lib/clitt/core/tui/minput/menu_input.py +292 -0
- build/lib/build/lib/clitt/core/tui/minput/minput.py +44 -0
- build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +156 -0
- build/lib/build/lib/clitt/core/tui/mselect/__init__.py +12 -0
- build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +170 -0
- build/lib/build/lib/clitt/core/tui/mselect/mselect.py +36 -0
- build/lib/build/lib/clitt/core/tui/table/__init__.py +12 -0
- build/lib/build/lib/clitt/core/tui/table/table_enums.py +47 -0
- build/lib/build/lib/clitt/core/tui/table/table_renderer.py +339 -0
- build/lib/build/lib/clitt/core/tui/tui_application.py +52 -0
- build/lib/build/lib/clitt/core/tui/tui_component.py +154 -0
- build/lib/build/lib/clitt/core/tui/tui_preferences.py +103 -0
- build/lib/build/lib/clitt/utils/__init__.py +11 -0
- build/lib/build/lib/clitt/utils/git_utils.py +66 -0
- build/lib/clitt/__classpath__.py +28 -0
- build/lib/clitt/__init__.py +13 -0
- build/lib/clitt/__main__.py +139 -0
- build/lib/clitt/addons/__init__.py +12 -0
- build/lib/clitt/addons/appman/__init__.py +13 -0
- build/lib/clitt/addons/appman/appman.py +305 -0
- build/lib/clitt/addons/appman/appman_enums.py +39 -0
- build/lib/clitt/addons/appman/templates/__init__.py +11 -0
- build/lib/clitt/addons/widman/__init__.py +14 -0
- build/lib/clitt/addons/widman/widget.py +70 -0
- build/lib/clitt/addons/widman/widget_entry.py +54 -0
- build/lib/clitt/addons/widman/widgets/__init__.py +14 -0
- build/lib/clitt/addons/widman/widgets/widget_free.py +110 -0
- build/lib/clitt/addons/widman/widgets/widget_punch.py +246 -0
- build/lib/clitt/addons/widman/widgets/widget_send_msg.py +272 -0
- build/lib/clitt/addons/widman/widgets/widget_time_calc.py +146 -0
- build/lib/clitt/addons/widman/widman.py +123 -0
- build/lib/clitt/core/__init__.py +15 -0
- build/lib/clitt/core/exception/__init__.py +11 -0
- build/lib/clitt/core/exception/exceptions.py +19 -0
- build/lib/clitt/core/icons/__init__.py +12 -0
- build/lib/clitt/core/icons/emojis/__init__.py +12 -0
- build/lib/clitt/core/icons/emojis/emojis.py +41 -0
- build/lib/clitt/core/icons/emojis/face_smiling.py +40 -0
- build/lib/clitt/core/icons/font_awesome/__init__.py +18 -0
- build/lib/clitt/core/icons/font_awesome/app_icons.py +55 -0
- build/lib/clitt/core/icons/font_awesome/awesome.py +76 -0
- build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +93 -0
- build/lib/clitt/core/icons/font_awesome/form_icons.py +69 -0
- build/lib/clitt/core/icons/font_awesome/game_icons.py +59 -0
- build/lib/clitt/core/icons/font_awesome/nav_icons.py +42 -0
- build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +39 -0
- build/lib/clitt/core/icons/font_awesome/widget_icons.py +37 -0
- build/lib/clitt/core/preferences.py +87 -0
- build/lib/clitt/core/term/__init__.py +14 -0
- build/lib/clitt/core/term/commons.py +106 -0
- build/lib/clitt/core/term/cursor.py +174 -0
- build/lib/clitt/core/term/screen.py +106 -0
- build/lib/clitt/core/term/terminal.py +202 -0
- build/lib/clitt/core/tui/__init__.py +20 -0
- build/lib/clitt/core/tui/line_input/__init__.py +12 -0
- build/lib/clitt/core/tui/line_input/keyboard_input.py +229 -0
- build/lib/clitt/core/tui/line_input/line_input.py +31 -0
- build/lib/clitt/core/tui/mchoose/__init__.py +12 -0
- build/lib/clitt/core/tui/mchoose/mchoose.py +43 -0
- build/lib/clitt/core/tui/mchoose/menu_choose.py +192 -0
- build/lib/clitt/core/tui/mdashboard/__init__.py +14 -0
- build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +54 -0
- build/lib/clitt/core/tui/mdashboard/dashboard_item.py +31 -0
- build/lib/clitt/core/tui/mdashboard/mdashboard.py +26 -0
- build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +148 -0
- build/lib/clitt/core/tui/menu/__init__.py +16 -0
- build/lib/clitt/core/tui/menu/tui_menu.py +111 -0
- build/lib/clitt/core/tui/menu/tui_menu_action.py +47 -0
- build/lib/clitt/core/tui/menu/tui_menu_factory.py +117 -0
- build/lib/clitt/core/tui/menu/tui_menu_item.py +196 -0
- build/lib/clitt/core/tui/menu/tui_menu_ui.py +98 -0
- build/lib/clitt/core/tui/menu/tui_menu_view.py +57 -0
- build/lib/clitt/core/tui/minput/__init__.py +19 -0
- build/lib/clitt/core/tui/minput/access_type.py +26 -0
- build/lib/clitt/core/tui/minput/field_builder.py +117 -0
- build/lib/clitt/core/tui/minput/form_builder.py +72 -0
- build/lib/clitt/core/tui/minput/form_field.py +180 -0
- build/lib/clitt/core/tui/minput/input_type.py +30 -0
- build/lib/clitt/core/tui/minput/input_validator.py +98 -0
- build/lib/clitt/core/tui/minput/menu_input.py +292 -0
- build/lib/clitt/core/tui/minput/minput.py +44 -0
- build/lib/clitt/core/tui/minput/minput_utils.py +156 -0
- build/lib/clitt/core/tui/mselect/__init__.py +12 -0
- build/lib/clitt/core/tui/mselect/menu_select.py +170 -0
- build/lib/clitt/core/tui/mselect/mselect.py +36 -0
- build/lib/clitt/core/tui/table/__init__.py +12 -0
- build/lib/clitt/core/tui/table/table_enums.py +47 -0
- build/lib/clitt/core/tui/table/table_renderer.py +339 -0
- build/lib/clitt/core/tui/tui_application.py +52 -0
- build/lib/clitt/core/tui/tui_component.py +154 -0
- build/lib/clitt/core/tui/tui_preferences.py +103 -0
- build/lib/clitt/utils/__init__.py +11 -0
- build/lib/clitt/utils/git_utils.py +66 -0
- clitt/.version +1 -1
- clitt/__init__.py +3 -3
- clitt/addons/__init__.py +3 -3
- clitt/addons/appman/__init__.py +3 -3
- clitt/addons/appman/templates/__init__.py +3 -3
- clitt/addons/widman/__init__.py +3 -3
- clitt/addons/widman/widgets/__init__.py +3 -3
- clitt/core/__init__.py +3 -3
- clitt/core/exception/__init__.py +3 -3
- clitt/core/icons/__init__.py +3 -3
- clitt/core/icons/emojis/__init__.py +3 -3
- clitt/core/icons/font_awesome/__init__.py +3 -3
- clitt/core/term/__init__.py +3 -3
- clitt/core/term/commons.py +11 -12
- clitt/core/tui/__init__.py +3 -3
- clitt/core/tui/line_input/__init__.py +3 -3
- clitt/core/tui/line_input/keyboard_input.py +22 -22
- clitt/core/tui/mchoose/__init__.py +3 -3
- clitt/core/tui/mdashboard/__init__.py +3 -3
- clitt/core/tui/menu/__init__.py +3 -3
- clitt/core/tui/minput/__init__.py +3 -3
- clitt/core/tui/mselect/__init__.py +3 -3
- clitt/core/tui/table/__init__.py +3 -3
- clitt/utils/__init__.py +3 -3
- {hspylib_clitt-0.9.118.dist-info → hspylib_clitt-0.9.120.dist-info}/METADATA +2 -2
- hspylib_clitt-0.9.120.dist-info/RECORD +334 -0
- {hspylib_clitt-0.9.118.dist-info → hspylib_clitt-0.9.120.dist-info}/top_level.txt +1 -0
- hspylib_clitt-0.9.118.dist-info/RECORD +0 -97
- {hspylib_clitt-0.9.118.dist-info → hspylib_clitt-0.9.120.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.menu
|
|
7
|
+
@file: tui_menu_factory.py
|
|
8
|
+
@created: Tue, 4 May 2021
|
|
9
|
+
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
+
@site: https://github.com/yorevs/hspylib
|
|
11
|
+
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
+
|
|
13
|
+
Copyright·(c)·2024,·HSPyLib
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from clitt.core.tui.menu.tui_menu import TUIMenu
|
|
17
|
+
from clitt.core.tui.menu.tui_menu_action import OnTrigger_Cb, TUIMenuAction
|
|
18
|
+
from clitt.core.tui.menu.tui_menu_item import TUIMenuItem
|
|
19
|
+
from clitt.core.tui.menu.tui_menu_view import TUIMenuView
|
|
20
|
+
from hspylib.core.preconditions import check_not_none
|
|
21
|
+
from typing import List, TypeAlias, Union
|
|
22
|
+
|
|
23
|
+
MenuBuilder: TypeAlias = Union[
|
|
24
|
+
"TUIMenuFactory.TUIMenuBuilder", "TUIMenuFactory.TUIMenuItemBuilder", "TUIMenuFactory.TUIMenuViewBuilder"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TUIMenuFactory:
|
|
29
|
+
"""TODO"""
|
|
30
|
+
|
|
31
|
+
_main_menu = None
|
|
32
|
+
|
|
33
|
+
class TUIMenuBuilder:
|
|
34
|
+
"""TODO"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, parent: "TUIMenuFactory", main_menu: TUIMenuItem):
|
|
37
|
+
check_not_none((parent, main_menu))
|
|
38
|
+
self._parent = parent
|
|
39
|
+
self._main_menu: TUIMenuItem = main_menu
|
|
40
|
+
|
|
41
|
+
def with_item(self, title: str, tooltip: str | None = None) -> "TUIMenuFactory.TUIMenuItemBuilder":
|
|
42
|
+
return TUIMenuFactory.TUIMenuItemBuilder(self, self._main_menu, title, tooltip)
|
|
43
|
+
|
|
44
|
+
def with_action(self, title: str, tooltip: str | None = None) -> "TUIMenuFactory.TUIMenuActionBuilder":
|
|
45
|
+
return TUIMenuFactory.TUIMenuActionBuilder(self, self._main_menu, title, tooltip)
|
|
46
|
+
|
|
47
|
+
def with_view(self, title: str, tooltip: str | None = None) -> "TUIMenuFactory.TUIMenuViewBuilder":
|
|
48
|
+
return TUIMenuFactory.TUIMenuViewBuilder(self, self._main_menu, title, tooltip)
|
|
49
|
+
|
|
50
|
+
def then(self) -> "TUIMenuFactory":
|
|
51
|
+
return self._parent
|
|
52
|
+
|
|
53
|
+
class TUIMenuItemBuilder:
|
|
54
|
+
"""TODO"""
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self, parent: MenuBuilder, parent_item: TUIMenuItem, title: str = None, tooltip: str | None = None
|
|
58
|
+
):
|
|
59
|
+
check_not_none((parent, parent_item))
|
|
60
|
+
self._parent = parent
|
|
61
|
+
self._menu_item = TUIMenuItem(parent_item, title, tooltip)
|
|
62
|
+
self._items: List[TUIMenu] = []
|
|
63
|
+
parent_item.add_items(self._menu_item)
|
|
64
|
+
|
|
65
|
+
def with_item(self, title: str, tooltip: str | None = None) -> "TUIMenuFactory.TUIMenuItemBuilder":
|
|
66
|
+
return TUIMenuFactory.TUIMenuItemBuilder(self, self._menu_item, title, tooltip)
|
|
67
|
+
|
|
68
|
+
def with_action(self, title: str, tooltip: str | None = None) -> "TUIMenuFactory.TUIMenuActionBuilder":
|
|
69
|
+
return TUIMenuFactory.TUIMenuActionBuilder(self, self._menu_item, title, tooltip)
|
|
70
|
+
|
|
71
|
+
def with_view(self, title: str, tooltip: str | None = None) -> "TUIMenuFactory.TUIMenuViewBuilder":
|
|
72
|
+
return TUIMenuFactory.TUIMenuViewBuilder(self, self._menu_item, title, tooltip)
|
|
73
|
+
|
|
74
|
+
def then(self) -> MenuBuilder:
|
|
75
|
+
return self._parent
|
|
76
|
+
|
|
77
|
+
class TUIMenuViewBuilder:
|
|
78
|
+
"""TODO"""
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self, parent: MenuBuilder, parent_item: TUIMenuItem, title: str = None, tooltip: str | None = None
|
|
82
|
+
):
|
|
83
|
+
check_not_none((parent, parent_item))
|
|
84
|
+
self._parent = parent
|
|
85
|
+
self._menu_view = TUIMenuView(parent_item, title, tooltip)
|
|
86
|
+
parent_item.add_items(self._menu_view)
|
|
87
|
+
|
|
88
|
+
def on_render(self, on_render: str | OnTrigger_Cb) -> "TUIMenuFactory.TUIMenuItemBuilder":
|
|
89
|
+
self._menu_view.on_render(on_render)
|
|
90
|
+
return self._parent
|
|
91
|
+
|
|
92
|
+
class TUIMenuActionBuilder:
|
|
93
|
+
"""TODO"""
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self, parent: MenuBuilder, parent_item: TUIMenuItem, title: str = None, tooltip: str | None = None
|
|
97
|
+
):
|
|
98
|
+
check_not_none((parent, parent_item))
|
|
99
|
+
self._parent = parent
|
|
100
|
+
self._menu_action = TUIMenuAction(parent_item, title, tooltip)
|
|
101
|
+
self._parent_item = parent_item
|
|
102
|
+
parent_item.add_items(self._menu_action)
|
|
103
|
+
|
|
104
|
+
def on_trigger(self, action: OnTrigger_Cb) -> "TUIMenuFactory.TUIMenuItemBuilder":
|
|
105
|
+
check_not_none(action)
|
|
106
|
+
self._menu_action.on_trigger(action)
|
|
107
|
+
return self._parent
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def create_main_menu(cls, title: str = None, tooltip: str | None = None) -> "TUIMenuBuilder":
|
|
111
|
+
cls._main_menu = TUIMenuItem(title=title, tooltip=tooltip)
|
|
112
|
+
factory = TUIMenuFactory()
|
|
113
|
+
|
|
114
|
+
return cls.TUIMenuBuilder(factory, cls._main_menu)
|
|
115
|
+
|
|
116
|
+
def build(self) -> TUIMenuItem:
|
|
117
|
+
return self._main_menu
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.menu
|
|
7
|
+
@file: tui_menu_item.py
|
|
8
|
+
@created: Tue, 4 May 2021
|
|
9
|
+
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
+
@site: https://github.com/yorevs/hspylib
|
|
11
|
+
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
+
|
|
13
|
+
Copyright·(c)·2024,·HSPyLib
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from clitt.core.icons.font_awesome.nav_icons import NavIcons
|
|
17
|
+
from clitt.core.term.commons import Direction, Portion
|
|
18
|
+
from clitt.core.tui.menu.tui_menu import TUIMenu
|
|
19
|
+
from clitt.core.tui.menu.tui_menu_ui import TUIMenuUi
|
|
20
|
+
from functools import cached_property
|
|
21
|
+
from hspylib.core.tools.dict_tools import get_or_default
|
|
22
|
+
from hspylib.modules.cli.keyboard import Keyboard
|
|
23
|
+
from typing import List, Optional
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TUIMenuItem(TUIMenu):
|
|
27
|
+
"""Represent a menu item with submenus. Each sub-item must belong to the TUIMenu class and can be an instance of
|
|
28
|
+
TUIMenuItem, TUIMenuAction or TUIMenuView.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
ROW_OFFSET = 5
|
|
32
|
+
|
|
33
|
+
NAV_ICONS = NavIcons.compose(NavIcons.UP, NavIcons.DOWN)
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
parent: Optional[TUIMenu] = None,
|
|
38
|
+
title: str = "Sub Menu",
|
|
39
|
+
tooltip: str = None,
|
|
40
|
+
items: List[TUIMenu] = None,
|
|
41
|
+
):
|
|
42
|
+
super().__init__(parent, title, tooltip or f"Access the '{title}' menu")
|
|
43
|
+
self._show_from: int = 0
|
|
44
|
+
self._show_to: int = self.screen.lines - self.ROW_OFFSET
|
|
45
|
+
self._diff_index: int = self._show_to - self._show_from
|
|
46
|
+
self._sel_index: int = 0
|
|
47
|
+
self._items: List[TUIMenu] = items or []
|
|
48
|
+
self._max_line_length = max(len(str(menu)) for menu in self._items) if self._items else len(str(self))
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def items(self) -> List[TUIMenu]:
|
|
52
|
+
return self._items
|
|
53
|
+
|
|
54
|
+
def add_items(self, *items: TUIMenu) -> None:
|
|
55
|
+
"""Add submenu items to the menu."""
|
|
56
|
+
list(map(self._items.append, items))
|
|
57
|
+
|
|
58
|
+
def execute(self) -> Optional[TUIMenu]:
|
|
59
|
+
# Wait for user interaction
|
|
60
|
+
while not self._done:
|
|
61
|
+
if not self._items:
|
|
62
|
+
return self._on_trigger(self._parent)
|
|
63
|
+
|
|
64
|
+
# Menu Renderization
|
|
65
|
+
if self._re_render:
|
|
66
|
+
self.render()
|
|
67
|
+
|
|
68
|
+
# Navigation input
|
|
69
|
+
if self.handle_keypress() == Keyboard.VK_ENTER:
|
|
70
|
+
return self._on_trigger(self._parent)
|
|
71
|
+
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
def render(self) -> None:
|
|
75
|
+
length = len(self._items)
|
|
76
|
+
self.cursor.restore()
|
|
77
|
+
TUIMenuUi.render_app_title()
|
|
78
|
+
|
|
79
|
+
if length > 0:
|
|
80
|
+
for idx in range(self._show_from, self._show_to):
|
|
81
|
+
if idx >= length:
|
|
82
|
+
break # When the number of items is lower than the max_rows, skip the other lines
|
|
83
|
+
option_line = str(self._items[idx])
|
|
84
|
+
self.cursor.erase(Portion.LINE)
|
|
85
|
+
# Print the selector if the index is currently selected
|
|
86
|
+
selector = self.draw_selector(is_selected=(idx == self._sel_index), has_bg_color=False)
|
|
87
|
+
# fmt: off
|
|
88
|
+
line_fmt = (
|
|
89
|
+
" {:>" + f"{len(str(length))}" + "} "
|
|
90
|
+
+ "{:>" + f"{len(selector)}" + "} "
|
|
91
|
+
+ "{:<" + f"{self._max_line_length}" + "} "
|
|
92
|
+
)
|
|
93
|
+
# fmt: on
|
|
94
|
+
self.draw_line(line_fmt, idx + 1, selector, option_line)
|
|
95
|
+
|
|
96
|
+
self.draw_navbar(self.navbar(to=length))
|
|
97
|
+
self._re_render = False
|
|
98
|
+
|
|
99
|
+
def navbar(self, **kwargs) -> str:
|
|
100
|
+
menu = get_or_default(self.items, self._sel_index, None)
|
|
101
|
+
tooltip = menu.tooltip if menu else None
|
|
102
|
+
return (
|
|
103
|
+
f"%EOL%%GREEN%{self.breadcrumb()} "
|
|
104
|
+
f"{tooltip + ' ' if tooltip else ''}%ED0%%NC%"
|
|
105
|
+
f"%EOL%{self.prefs.navbar_color.placeholder}%EOL%"
|
|
106
|
+
f"[Enter] Select Navigate [{self.NAV_ICONS}] "
|
|
107
|
+
f"[Esc] Quit [1..{kwargs['to']}] Goto: %NC%%EL0%%EOL%%EOL%"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def handle_keypress(self) -> Keyboard:
|
|
111
|
+
"""Handle a keyboard press."""
|
|
112
|
+
if keypress := Keyboard.wait_keystroke():
|
|
113
|
+
match keypress:
|
|
114
|
+
case Keyboard.VK_ESC:
|
|
115
|
+
self._done = True
|
|
116
|
+
case Keyboard.VK_UP:
|
|
117
|
+
self._handle_key_up()
|
|
118
|
+
case Keyboard.VK_DOWN:
|
|
119
|
+
self._handle_key_down()
|
|
120
|
+
case Keyboard.VK_TAB:
|
|
121
|
+
self._handle_tab()
|
|
122
|
+
case Keyboard.VK_SHIFT_TAB:
|
|
123
|
+
self._handle_shift_tab()
|
|
124
|
+
case _ as key if key in self._digits:
|
|
125
|
+
self._handle_digit(keypress)
|
|
126
|
+
self._re_render = True
|
|
127
|
+
|
|
128
|
+
return keypress
|
|
129
|
+
|
|
130
|
+
def _handle_key_up(self) -> None:
|
|
131
|
+
"""Handle a key up (arrow up) press."""
|
|
132
|
+
if self._sel_index == self._show_from and self._show_from > 0:
|
|
133
|
+
self._show_from -= 1
|
|
134
|
+
self._show_to -= 1
|
|
135
|
+
if self._sel_index - 1 >= 0:
|
|
136
|
+
self._sel_index -= 1
|
|
137
|
+
self._re_render = True
|
|
138
|
+
|
|
139
|
+
def _handle_key_down(self) -> None:
|
|
140
|
+
"""Handle a key down (arrow down) press."""
|
|
141
|
+
length = len(self.items)
|
|
142
|
+
if self._sel_index + 1 == self._show_to and self._show_to < length:
|
|
143
|
+
self._show_from += 1
|
|
144
|
+
self._show_to += 1
|
|
145
|
+
if self._sel_index + 1 < length:
|
|
146
|
+
self._sel_index += 1
|
|
147
|
+
self._re_render = True
|
|
148
|
+
|
|
149
|
+
def _handle_tab(self) -> None:
|
|
150
|
+
"""Handle a tab keypress."""
|
|
151
|
+
length = len(self.items)
|
|
152
|
+
page_index = min(self._show_to + self._diff_index, length)
|
|
153
|
+
self._show_to = max(page_index, self._diff_index)
|
|
154
|
+
self._show_from = self._show_to - self._diff_index
|
|
155
|
+
self._sel_index = self._show_from
|
|
156
|
+
self._re_render = True
|
|
157
|
+
|
|
158
|
+
def _handle_shift_tab(self) -> None:
|
|
159
|
+
"""Handle a shift tab keypress."""
|
|
160
|
+
page_index = max(self._show_from - self._diff_index, 0)
|
|
161
|
+
self._show_from = min(page_index, self._diff_index)
|
|
162
|
+
self._show_to = self._show_from + self._diff_index
|
|
163
|
+
self._sel_index = self._show_from
|
|
164
|
+
self._re_render = True
|
|
165
|
+
|
|
166
|
+
def _handle_digit(self, digit: Keyboard) -> None:
|
|
167
|
+
"""Handle a digit keypress.
|
|
168
|
+
:param digit: the digit pressed.
|
|
169
|
+
"""
|
|
170
|
+
length = len(self._items)
|
|
171
|
+
typed_index = digit.value
|
|
172
|
+
self.write(digit.value) # echo the digit typed
|
|
173
|
+
index_len = 1
|
|
174
|
+
while len(typed_index) < len(str(length)):
|
|
175
|
+
keystroke = Keyboard.wait_keystroke()
|
|
176
|
+
if not keystroke or not keystroke.isdigit():
|
|
177
|
+
typed_index = None if keystroke != Keyboard.VK_ENTER else typed_index
|
|
178
|
+
break
|
|
179
|
+
typed_index = f"{typed_index}{keystroke.value if keystroke else ''}"
|
|
180
|
+
self.write(f"{keystroke.value if keystroke else ''}")
|
|
181
|
+
index_len += 1
|
|
182
|
+
# Erase the index typed by the user
|
|
183
|
+
self.cursor.move(index_len, Direction.LEFT)
|
|
184
|
+
self.cursor.erase(Direction.RIGHT)
|
|
185
|
+
if typed_index and 1 <= int(typed_index) <= length:
|
|
186
|
+
self._show_to = max(int(typed_index), self._diff_index)
|
|
187
|
+
self._show_from = self._show_to - self._diff_index
|
|
188
|
+
self._sel_index = int(typed_index) - 1
|
|
189
|
+
self._re_render = True
|
|
190
|
+
|
|
191
|
+
def _default_trigger_cb(self, source: TUIMenu) -> Optional["TUIMenu"]:
|
|
192
|
+
return get_or_default(self._items, self._sel_index, self._parent)
|
|
193
|
+
|
|
194
|
+
@cached_property
|
|
195
|
+
def _digits(self) -> List[Keyboard]:
|
|
196
|
+
return Keyboard.digits()
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.menu
|
|
7
|
+
@file: tui_menu_ui.py
|
|
8
|
+
@created: Tue, 4 May 2021
|
|
9
|
+
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
+
@site: https://github.com/yorevs/hspylib
|
|
11
|
+
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
+
|
|
13
|
+
Copyright·(c)·2024,·HSPyLib
|
|
14
|
+
"""
|
|
15
|
+
from clitt.core.term.terminal import Terminal
|
|
16
|
+
from clitt.core.tui.menu.tui_menu import TUIMenu
|
|
17
|
+
from clitt.core.tui.tui_preferences import TUIPreferences
|
|
18
|
+
from hspylib.core.metaclass.singleton import Singleton
|
|
19
|
+
from hspylib.core.preconditions import check_not_none
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TUIMenuUi(metaclass=Singleton):
|
|
23
|
+
"""Provide a menu for terminal UIs. Each sub-item must belong to the TUIMenu class and can be an instance of
|
|
24
|
+
TUIMenuItem, TUIMenuAction or TUIMenuView.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
APP_TITLE = "Main Menu"
|
|
28
|
+
|
|
29
|
+
# fmt: off
|
|
30
|
+
PREFS = TUIPreferences.INSTANCE
|
|
31
|
+
|
|
32
|
+
SCREEN = Terminal.INSTANCE.screen
|
|
33
|
+
|
|
34
|
+
MENU_LINE = f"{'--' * PREFS.title_line_length}"
|
|
35
|
+
|
|
36
|
+
MENU_TITLE_FMT = (
|
|
37
|
+
f"{PREFS.title_color}"
|
|
38
|
+
f"+{MENU_LINE}+%EOL%"
|
|
39
|
+
"|{title:^" + str(2 * PREFS.title_line_length) + "s}|%EOL%"
|
|
40
|
+
f"+{MENU_LINE}+%EOL%%NC%"
|
|
41
|
+
)
|
|
42
|
+
# fmt: on
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def render_app_title(cls, app_title: str = None) -> None:
|
|
46
|
+
"""Render the application title."""
|
|
47
|
+
cls.SCREEN.clear()
|
|
48
|
+
cls.SCREEN.cursor.writeln(cls.MENU_TITLE_FMT.format(title=app_title or cls.APP_TITLE))
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def back(source: TUIMenu) -> TUIMenu:
|
|
52
|
+
"""Return the parent menu from the source of the event.
|
|
53
|
+
:param source: the source menu of the event.
|
|
54
|
+
"""
|
|
55
|
+
return source.parent
|
|
56
|
+
|
|
57
|
+
def __init__(self, main_menu: TUIMenu, title: str = "Main Menu"):
|
|
58
|
+
check_not_none(main_menu)
|
|
59
|
+
super().__init__()
|
|
60
|
+
TUIMenuUi.APP_TITLE = title
|
|
61
|
+
self._done: bool = False
|
|
62
|
+
self._curr_menu: TUIMenu = main_menu
|
|
63
|
+
self._prev_menu = None
|
|
64
|
+
self._next_menu = None
|
|
65
|
+
|
|
66
|
+
def execute(self) -> None:
|
|
67
|
+
"""Execute the terminal menu UI flow."""
|
|
68
|
+
|
|
69
|
+
self._prepare_render()
|
|
70
|
+
|
|
71
|
+
while not self._done:
|
|
72
|
+
if self._curr_menu:
|
|
73
|
+
self._next_menu = self._curr_menu.execute()
|
|
74
|
+
if self._next_menu:
|
|
75
|
+
self._change_menu(
|
|
76
|
+
self._next_menu
|
|
77
|
+
if isinstance(self._next_menu, TUIMenu)
|
|
78
|
+
else next((menu for menu in self._next_menu if menu), None)
|
|
79
|
+
)
|
|
80
|
+
else:
|
|
81
|
+
self._done = True
|
|
82
|
+
else:
|
|
83
|
+
self._done = True
|
|
84
|
+
|
|
85
|
+
def _prepare_render(self, auto_wrap: bool = True, show_cursor: bool = False, clear_screen: bool = True) -> None:
|
|
86
|
+
"""Prepare the screen for renderization."""
|
|
87
|
+
Terminal.set_auto_wrap(auto_wrap)
|
|
88
|
+
Terminal.set_show_cursor(show_cursor)
|
|
89
|
+
if clear_screen:
|
|
90
|
+
self.SCREEN.clear()
|
|
91
|
+
self.SCREEN.cursor.save()
|
|
92
|
+
|
|
93
|
+
def _change_menu(self, new_menu: TUIMenu) -> None:
|
|
94
|
+
"""Change the current menu and keep track about the previous one.
|
|
95
|
+
:param new_menu: the menu to be changed to.
|
|
96
|
+
"""
|
|
97
|
+
self._prev_menu = self._curr_menu
|
|
98
|
+
self._curr_menu = new_menu
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.menu
|
|
7
|
+
@file: tui_menu_view.py
|
|
8
|
+
@created: Tue, 4 May 2021
|
|
9
|
+
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
+
@site: https://github.com/yorevs/hspylib
|
|
11
|
+
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
+
|
|
13
|
+
Copyright·(c)·2024,·HSPyLib
|
|
14
|
+
"""
|
|
15
|
+
from clitt.core.term.commons import Direction
|
|
16
|
+
from clitt.core.tui.menu.tui_menu import OnTrigger_Cb, TUIMenu
|
|
17
|
+
from clitt.core.tui.menu.tui_menu_ui import TUIMenuUi
|
|
18
|
+
from typing import Callable, Optional
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TUIMenuView(TUIMenu):
|
|
22
|
+
"""Represent a menu view without submenus. Each view can have a view to be displayed. If no view is provided, it
|
|
23
|
+
will behave like an action.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
parent: TUIMenu,
|
|
29
|
+
title: Optional[str] = None,
|
|
30
|
+
tooltip: Optional[str] = None,
|
|
31
|
+
display_text: Optional[str] = None,
|
|
32
|
+
):
|
|
33
|
+
super().__init__(parent, title or "Menu View", tooltip or f"Access the '{title}' view")
|
|
34
|
+
self._on_render: OnTrigger_Cb = self._display_content
|
|
35
|
+
self._content: str = display_text or f"%ED0%This is a view: {self.title}"
|
|
36
|
+
|
|
37
|
+
def on_render(self, on_render: str | OnTrigger_Cb) -> None:
|
|
38
|
+
if isinstance(on_render, str):
|
|
39
|
+
self._content = on_render
|
|
40
|
+
self._on_render = self._display_content
|
|
41
|
+
elif isinstance(on_render, Callable):
|
|
42
|
+
self._on_render = on_render
|
|
43
|
+
self._content = f"This is a view: {self.title}"
|
|
44
|
+
|
|
45
|
+
def execute(self) -> Optional[TUIMenu]:
|
|
46
|
+
self.render()
|
|
47
|
+
return self._on_trigger(self)
|
|
48
|
+
|
|
49
|
+
def render(self) -> None:
|
|
50
|
+
TUIMenuUi.render_app_title()
|
|
51
|
+
self._on_render()
|
|
52
|
+
self.draw_navbar(self.navbar())
|
|
53
|
+
|
|
54
|
+
def _display_content(self) -> None:
|
|
55
|
+
self.cursor.erase(Direction.DOWN)
|
|
56
|
+
self.writeln(self._content)
|
|
57
|
+
self.wait_keystroke()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# _*_ coding: utf-8 _*_
|
|
2
|
+
#
|
|
3
|
+
# hspylib-clitt v0.9.120
|
|
4
|
+
#
|
|
5
|
+
# Package: main.build.lib.build.lib.build.lib.clitt.core.tui.minput
|
|
6
|
+
"""Package initialization."""
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'access_type',
|
|
10
|
+
'field_builder',
|
|
11
|
+
'form_builder',
|
|
12
|
+
'form_field',
|
|
13
|
+
'input_type',
|
|
14
|
+
'input_validator',
|
|
15
|
+
'menu_input',
|
|
16
|
+
'minput',
|
|
17
|
+
'minput_utils'
|
|
18
|
+
]
|
|
19
|
+
__version__ = '0.9.120'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.minput
|
|
7
|
+
@file: access_type.py
|
|
8
|
+
@created: Thu, 20 May 2021
|
|
9
|
+
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
+
@site: https://github.com/yorevs/hspylib
|
|
11
|
+
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
+
|
|
13
|
+
Copyright·(c)·2024,·HSPyLib
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from hspylib.core.enums.enumeration import Enumeration
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AccessType(Enumeration):
|
|
20
|
+
"""MenuInput input field access types."""
|
|
21
|
+
|
|
22
|
+
# fmt: off
|
|
23
|
+
NO_ACCESS = "no-access"
|
|
24
|
+
READ_ONLY = "read-only"
|
|
25
|
+
READ_WRITE = "read-write"
|
|
26
|
+
# fmt: on
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.minput
|
|
7
|
+
@file: field_builder.py
|
|
8
|
+
@created: Thu, 20 May 2021
|
|
9
|
+
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
+
@site: https://github.com/yorevs/hspylib
|
|
11
|
+
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
+
|
|
13
|
+
Copyright·(c)·2024,·HSPyLib
|
|
14
|
+
"""
|
|
15
|
+
from clitt.core.tui.minput.access_type import AccessType
|
|
16
|
+
from clitt.core.tui.minput.form_field import FieldValidator_Fn, FormField
|
|
17
|
+
from clitt.core.tui.minput.input_type import InputType
|
|
18
|
+
from clitt.core.tui.minput.input_validator import InputValidator
|
|
19
|
+
from clitt.core.tui.minput.minput_utils import get_selected, MASK_SYMBOLS, unpack_masked, VALUE_SEPARATORS
|
|
20
|
+
from functools import reduce
|
|
21
|
+
from hspylib.core.preconditions import check_argument
|
|
22
|
+
from hspylib.core.tools.commons import to_bool
|
|
23
|
+
from hspylib.core.tools.text_tools import snakecase
|
|
24
|
+
from operator import add
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
import re
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FieldBuilder:
|
|
31
|
+
"""MenuInput form field builder."""
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def _validate_field(field: FormField) -> bool:
|
|
35
|
+
match field.itype:
|
|
36
|
+
case InputType.MASKED:
|
|
37
|
+
value, mask = unpack_masked(field.value)
|
|
38
|
+
valid = reduce(add, list(map(mask[len(value) :].count, MASK_SYMBOLS))) == 0
|
|
39
|
+
case InputType.CHECKBOX:
|
|
40
|
+
valid = isinstance(field.value, bool)
|
|
41
|
+
case InputType.SELECT:
|
|
42
|
+
_, value = get_selected(field.value)
|
|
43
|
+
length = len(str(value or ""))
|
|
44
|
+
valid = field.min_length <= length <= field.max_length
|
|
45
|
+
case _:
|
|
46
|
+
length = len(str(field.value or ""))
|
|
47
|
+
valid = field.min_length <= length <= field.max_length
|
|
48
|
+
return valid
|
|
49
|
+
|
|
50
|
+
def __init__(self, parent: Any):
|
|
51
|
+
self._parent = parent
|
|
52
|
+
self._label = "Label"
|
|
53
|
+
self._dest = None
|
|
54
|
+
self._itype = InputType.TEXT
|
|
55
|
+
self._access_type = AccessType.READ_WRITE
|
|
56
|
+
self._min_max_length = 5, 30
|
|
57
|
+
self._value = ""
|
|
58
|
+
self._validator = InputValidator.anything(), self._validate_field
|
|
59
|
+
|
|
60
|
+
def label(self, label: str) -> "FieldBuilder":
|
|
61
|
+
self._label = label
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
def dest(self, dest: str) -> "FieldBuilder":
|
|
65
|
+
self._dest = dest
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def itype(self, itype: str) -> "FieldBuilder":
|
|
69
|
+
self._itype = InputType.of_value(itype)
|
|
70
|
+
return self
|
|
71
|
+
|
|
72
|
+
def min_max_length(self, min_length: int, max_length: int) -> "FieldBuilder":
|
|
73
|
+
check_argument(max_length >= min_length, "Invalid field length: ({}-{})", min_length, max_length)
|
|
74
|
+
check_argument(max_length > 0 and min_length >= 0, "Invalid field length: ({}-{})", min_length, max_length)
|
|
75
|
+
self._min_max_length = min_length, max_length
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
def access_type(self, access_type: str) -> "FieldBuilder":
|
|
79
|
+
self._access_type = AccessType.of_value(access_type)
|
|
80
|
+
return self
|
|
81
|
+
|
|
82
|
+
def value(self, value: Any | None) -> "FieldBuilder":
|
|
83
|
+
self._value = value
|
|
84
|
+
return self
|
|
85
|
+
|
|
86
|
+
def validator(
|
|
87
|
+
self, input_validator: InputValidator = None, field_validator: FieldValidator_Fn = None
|
|
88
|
+
) -> "FieldBuilder":
|
|
89
|
+
self._validator = input_validator, field_validator or self._validate_field
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
def build(self) -> Any:
|
|
93
|
+
if self._itype == InputType.CHECKBOX:
|
|
94
|
+
self._value = to_bool(str(self._value))
|
|
95
|
+
elif self._itype == InputType.SELECT:
|
|
96
|
+
parts = re.split(VALUE_SEPARATORS, re.sub("[<>]", "", str(self._value or "")))
|
|
97
|
+
self._min_max_length = len(min(parts, key=len)), len(max(parts, key=len))
|
|
98
|
+
elif self._itype == InputType.MASKED:
|
|
99
|
+
_, mask = unpack_masked(str(self._value))
|
|
100
|
+
min_max = reduce(add, list(map(mask.count, MASK_SYMBOLS)))
|
|
101
|
+
self._min_max_length = min_max, min_max
|
|
102
|
+
self._dest = self._dest or snakecase(self._label)
|
|
103
|
+
self._parent.fields.append(
|
|
104
|
+
FormField(
|
|
105
|
+
self._label,
|
|
106
|
+
self._dest,
|
|
107
|
+
self._itype,
|
|
108
|
+
self._min_max_length[0],
|
|
109
|
+
self._min_max_length[1],
|
|
110
|
+
self._access_type,
|
|
111
|
+
self._value,
|
|
112
|
+
self._validator[0],
|
|
113
|
+
self._validator[1],
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return self._parent
|