hspylib-clitt 0.9.118__py3-none-any.whl → 0.9.119__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/build/lib/clitt/__classpath__.py +28 -0
- build/lib/build/lib/build/lib/build/lib/clitt/__init__.py +13 -0
- build/lib/build/lib/build/lib/build/lib/clitt/__main__.py +139 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/appman/__init__.py +13 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/appman/appman.py +305 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/appman/appman_enums.py +39 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/appman/templates/__init__.py +11 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/__init__.py +14 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widget.py +70 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widget_entry.py +54 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +14 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +110 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +246 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +272 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +146 -0
- build/lib/build/lib/build/lib/build/lib/clitt/addons/widman/widman.py +123 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/__init__.py +15 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/exception/__init__.py +11 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/exception/exceptions.py +19 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/emojis/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/emojis/emojis.py +41 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +40 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +18 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +55 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +76 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +93 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +69 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +59 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +42 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +39 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +37 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/preferences.py +87 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/term/__init__.py +14 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/term/commons.py +106 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/term/cursor.py +174 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/term/screen.py +106 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/term/terminal.py +202 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/__init__.py +20 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/line_input/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +229 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/line_input/line_input.py +31 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +43 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +192 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +14 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +54 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +31 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +26 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +148 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/__init__.py +16 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +111 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +47 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +117 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +196 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +98 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +57 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/__init__.py +19 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/access_type.py +26 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/field_builder.py +117 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/form_builder.py +72 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/form_field.py +180 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/input_type.py +30 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/input_validator.py +98 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/menu_input.py +292 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/minput.py +44 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +156 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mselect/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +170 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/mselect/mselect.py +36 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/table/__init__.py +12 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/table/table_enums.py +47 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/table/table_renderer.py +339 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/tui_application.py +52 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/tui_component.py +154 -0
- build/lib/build/lib/build/lib/build/lib/clitt/core/tui/tui_preferences.py +103 -0
- build/lib/build/lib/build/lib/build/lib/clitt/utils/__init__.py +11 -0
- build/lib/build/lib/build/lib/build/lib/clitt/utils/git_utils.py +66 -0
- 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/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.119.dist-info}/METADATA +2 -2
- hspylib_clitt-0.9.119.dist-info/RECORD +413 -0
- {hspylib_clitt-0.9.118.dist-info → hspylib_clitt-0.9.119.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.119.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib
|
|
6
|
+
@package: clitt.core.tui.table
|
|
7
|
+
@file: table_renderer.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.screen import Screen
|
|
16
|
+
from clitt.core.term.terminal import Terminal
|
|
17
|
+
from clitt.core.tui.table.table_enums import TextAlignment, TextCase
|
|
18
|
+
from clitt.core.tui.tui_preferences import TUIPreferences
|
|
19
|
+
from functools import cached_property, partial, reduce
|
|
20
|
+
from hspylib.core.preconditions import check_argument
|
|
21
|
+
from hspylib.core.tools.commons import file_is_not_empty
|
|
22
|
+
from hspylib.core.tools.text_tools import elide_text, ensure_endswith
|
|
23
|
+
from operator import add
|
|
24
|
+
from typing import Any, Callable, Iterable, List, Tuple, TypeAlias
|
|
25
|
+
|
|
26
|
+
import csv
|
|
27
|
+
import os
|
|
28
|
+
|
|
29
|
+
# fmt: off
|
|
30
|
+
AlignmentFn : TypeAlias = Callable[[str, int], str]
|
|
31
|
+
TestCaseFn : TypeAlias = Callable[[str], str]
|
|
32
|
+
# fmt: on
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TableRenderer:
|
|
36
|
+
"""Utility class to render terminal UI tables."""
|
|
37
|
+
|
|
38
|
+
DEFAULT_MINIMUM_CELL_SIZE = 6
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def import_csv(
|
|
42
|
+
filepath: str, caption: str | None = None, has_headers: bool = True, delimiter: chr = ","
|
|
43
|
+
) -> "TableRenderer":
|
|
44
|
+
"""Render the table based on a CSV file."""
|
|
45
|
+
check_argument(file_is_not_empty(filepath), f"File not found: {filepath}")
|
|
46
|
+
headers, data = None, []
|
|
47
|
+
with open(filepath, encoding="UTF8") as csv_file:
|
|
48
|
+
csv_reader = csv.reader(csv_file, delimiter=delimiter)
|
|
49
|
+
line_count = 0
|
|
50
|
+
for row in csv_reader:
|
|
51
|
+
line_count += 1
|
|
52
|
+
if line_count == 1:
|
|
53
|
+
if has_headers:
|
|
54
|
+
headers = row
|
|
55
|
+
continue
|
|
56
|
+
headers = [f"C{idx}" for idx, _ in enumerate(row)]
|
|
57
|
+
data.append(row)
|
|
58
|
+
return TableRenderer(headers, data, caption)
|
|
59
|
+
|
|
60
|
+
def __init__(self, headers: List[str], data: Iterable, caption: str | None = None):
|
|
61
|
+
"""
|
|
62
|
+
:param headers: table headers to be displayed.
|
|
63
|
+
:param data: table record set with the selected rows.
|
|
64
|
+
:param caption: table caption to be displayed.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
self._terminal: Terminal = Terminal.INSTANCE
|
|
68
|
+
self._headers: List[str] = headers
|
|
69
|
+
self._data: List[Any] = data if data else []
|
|
70
|
+
self._caption: str = caption
|
|
71
|
+
self._columns: range = range(self.columns)
|
|
72
|
+
self._min_cell_size: int = self.DEFAULT_MINIMUM_CELL_SIZE
|
|
73
|
+
self._header_alignment: TextAlignment = TextAlignment.CENTER
|
|
74
|
+
self._cell_alignment: TextAlignment = TextAlignment.LEFT
|
|
75
|
+
self._header_case: TextCase = TextCase.UPPER
|
|
76
|
+
self._adjust_cells = None
|
|
77
|
+
|
|
78
|
+
check_argument(self.columns >= 1, "Headers are required")
|
|
79
|
+
self._cell_sizes = [0 for _ in range(self.columns)]
|
|
80
|
+
self.adjust_cells_auto()
|
|
81
|
+
if data:
|
|
82
|
+
c_len = len(min(data, key=len))
|
|
83
|
+
check_argument(
|
|
84
|
+
c_len == self.columns, "Headers and Columns must have the same size: {} vs {}", c_len, self.columns
|
|
85
|
+
)
|
|
86
|
+
self._footer = f":: Displaying {c_len} of {c_len} records"
|
|
87
|
+
else:
|
|
88
|
+
self._footer = ":: No data to display"
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def terminal(self) -> Terminal:
|
|
92
|
+
return self._terminal
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def screen(self) -> Screen:
|
|
96
|
+
return self.terminal.screen
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def prefs(self) -> TUIPreferences:
|
|
100
|
+
return self.screen.preferences
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def column_sizes(self) -> List[int]:
|
|
104
|
+
return self._cell_sizes
|
|
105
|
+
|
|
106
|
+
@cached_property
|
|
107
|
+
def columns(self) -> int:
|
|
108
|
+
return len(self.headers)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def cell_alignment(self) -> AlignmentFn:
|
|
112
|
+
return self._cell_alignment.val()
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def header_alignment(self) -> AlignmentFn:
|
|
116
|
+
return self._header_alignment.val()
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def header_case(self) -> TestCaseFn:
|
|
120
|
+
return self._header_case.val()
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def caption(self) -> str:
|
|
124
|
+
return self._caption
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def footer(self) -> str:
|
|
128
|
+
return self._footer
|
|
129
|
+
|
|
130
|
+
@footer.setter
|
|
131
|
+
def footer(self, other: str) -> None:
|
|
132
|
+
self._footer = other
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def data(self) -> Iterable:
|
|
136
|
+
return self._data
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def headers(self) -> List[str]:
|
|
140
|
+
return self._headers
|
|
141
|
+
|
|
142
|
+
def set_header_alignment(self, alignment: TextAlignment) -> None:
|
|
143
|
+
"""Set table headers alignment.
|
|
144
|
+
:param alignment: table header text alignment function.
|
|
145
|
+
:return None
|
|
146
|
+
"""
|
|
147
|
+
self._header_alignment = alignment
|
|
148
|
+
|
|
149
|
+
def set_header_case(self, test_case: TextCase) -> None:
|
|
150
|
+
"""Set table headers alignment.
|
|
151
|
+
:param test_case: table header text case function.
|
|
152
|
+
:return None
|
|
153
|
+
"""
|
|
154
|
+
self._header_case = test_case
|
|
155
|
+
|
|
156
|
+
def set_cell_alignment(self, alignment: TextAlignment) -> None:
|
|
157
|
+
"""Set table cell alignment.
|
|
158
|
+
:param alignment: table cell text alignment function.
|
|
159
|
+
:return None
|
|
160
|
+
"""
|
|
161
|
+
self._cell_alignment = alignment
|
|
162
|
+
|
|
163
|
+
def set_cell_sizes(self, sizes: Tuple[int, ...]) -> None:
|
|
164
|
+
"""Render table based on a list of fixed sizes.
|
|
165
|
+
:param sizes: the list of specific cell sizes.
|
|
166
|
+
:return None
|
|
167
|
+
"""
|
|
168
|
+
max_cell_size = self.screen.columns if self._fits(sizes) else int(self.screen.columns / self.columns)
|
|
169
|
+
for idx, size in enumerate(sizes[: self.columns]):
|
|
170
|
+
self._cell_sizes[idx] = min(max_cell_size, max(self._min_cell_size, size))
|
|
171
|
+
|
|
172
|
+
def set_min_cell_size(self, size: int) -> None:
|
|
173
|
+
"""Set the minimum length of a cell.
|
|
174
|
+
:param size: minimum table cell size.
|
|
175
|
+
:return None
|
|
176
|
+
"""
|
|
177
|
+
self._min_cell_size = max(self.DEFAULT_MINIMUM_CELL_SIZE, size)
|
|
178
|
+
self.set_cell_sizes(*(max(self._cell_sizes[idx], size) for idx, _ in enumerate(self.headers)))
|
|
179
|
+
|
|
180
|
+
def adjust_cells_by_headers(self) -> None:
|
|
181
|
+
"""Adjust cell sizes based on the column header length.
|
|
182
|
+
:return None
|
|
183
|
+
"""
|
|
184
|
+
args = [max(self._min_cell_size, len(header)) for header in self.headers]
|
|
185
|
+
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
186
|
+
|
|
187
|
+
def adjust_cells_by_largest_header(self) -> None:
|
|
188
|
+
"""Adjust cell sizes based on the maximum length of a header.
|
|
189
|
+
:return None
|
|
190
|
+
"""
|
|
191
|
+
max_len = len(max(self.headers))
|
|
192
|
+
args = [max(self._min_cell_size, max_len) for _ in self.headers]
|
|
193
|
+
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
194
|
+
|
|
195
|
+
def adjust_cells_by_largest_cell(self) -> None:
|
|
196
|
+
"""Adjust cell sizes based on the maximum length of a cell.
|
|
197
|
+
:return None
|
|
198
|
+
"""
|
|
199
|
+
max_len = 0
|
|
200
|
+
for row in self.data:
|
|
201
|
+
max_len = max(max_len, len(max(list(map(str, row)), key=len)))
|
|
202
|
+
args = [max_len for _ in self.headers]
|
|
203
|
+
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
204
|
+
|
|
205
|
+
def adjust_cells_by_fixed_size(self, size: int) -> None:
|
|
206
|
+
"""Adjust cell sizes to a fixed size.
|
|
207
|
+
:param size: the fixed cell size.
|
|
208
|
+
:return None
|
|
209
|
+
"""
|
|
210
|
+
args = [size for _ in self.headers]
|
|
211
|
+
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
212
|
+
|
|
213
|
+
def adjust_cells_to_fit_screen(self) -> None:
|
|
214
|
+
"""Adjust cell sizes accordingly to fill the screen size
|
|
215
|
+
:return None
|
|
216
|
+
"""
|
|
217
|
+
distributed_size = int(self.screen.columns / self.columns) - 3
|
|
218
|
+
self.adjust_cells_by_fixed_size(distributed_size)
|
|
219
|
+
|
|
220
|
+
def adjust_cells_auto(self) -> None:
|
|
221
|
+
"""Ensure all cells and headers are visible with the minimum size possible.
|
|
222
|
+
:return None
|
|
223
|
+
"""
|
|
224
|
+
if not self.data:
|
|
225
|
+
self.adjust_cells_by_headers()
|
|
226
|
+
else:
|
|
227
|
+
sizes = self._cell_sizes
|
|
228
|
+
for cell, c_size in zip(self.data, sizes):
|
|
229
|
+
sizes = [
|
|
230
|
+
max(len(self.headers[idx]), max(sizes[idx], max(c_size, len(str(cell[idx])))))
|
|
231
|
+
for idx, _ in enumerate(self.headers)
|
|
232
|
+
]
|
|
233
|
+
args = [size for size in sizes]
|
|
234
|
+
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
235
|
+
|
|
236
|
+
def render(self) -> None:
|
|
237
|
+
"""Render the table.
|
|
238
|
+
:return None
|
|
239
|
+
"""
|
|
240
|
+
self._adjust_cells()
|
|
241
|
+
header_line, data_lines = self._format_header_row(), self._format_data_rows()
|
|
242
|
+
table_line = "+" + "+".join(f"{'-' * (self._cell_sizes[idx] + 2)}" for idx in self._columns) + "+"
|
|
243
|
+
self._render_table(table_line, header_line, data_lines)
|
|
244
|
+
|
|
245
|
+
def export_csv(self, filepath: str, delimiter: chr = ",", has_headers: bool = True) -> None:
|
|
246
|
+
"""Export the table to CSV format.
|
|
247
|
+
:return None
|
|
248
|
+
"""
|
|
249
|
+
csv_file = ensure_endswith(filepath, ".csv")
|
|
250
|
+
with open(csv_file, "w", encoding="UTF8") as csv_file:
|
|
251
|
+
writer = csv.writer(csv_file, delimiter=delimiter)
|
|
252
|
+
if has_headers:
|
|
253
|
+
writer.writerow(self.headers)
|
|
254
|
+
writer.writerows(self.data)
|
|
255
|
+
|
|
256
|
+
def _format_header_row(self) -> str:
|
|
257
|
+
"""Format the table header using the defined preferences.
|
|
258
|
+
:return the formatted header row.
|
|
259
|
+
"""
|
|
260
|
+
header_cols = [self.header_alignment(self._header_text(idx), self._cell_sizes[idx]) for idx in self._columns]
|
|
261
|
+
return f"| {' | '.join(header_cols)} |"
|
|
262
|
+
|
|
263
|
+
def _format_data_rows(self) -> List[str]:
|
|
264
|
+
"""Format the table rows using the defined preferences.
|
|
265
|
+
:return a list containing the formatted data rows.
|
|
266
|
+
"""
|
|
267
|
+
# fmt: off
|
|
268
|
+
return [
|
|
269
|
+
"| " +
|
|
270
|
+
' | '.join(
|
|
271
|
+
f"{self.cell_alignment(self._cell_text(row, column), self._cell_sizes[column])}"
|
|
272
|
+
for column in self._columns
|
|
273
|
+
) +
|
|
274
|
+
" |" for row in self.data
|
|
275
|
+
]
|
|
276
|
+
# fmt: on
|
|
277
|
+
|
|
278
|
+
def _display_data(self, data: Any, end: str = os.linesep) -> None:
|
|
279
|
+
"""Display data on the screen.
|
|
280
|
+
:param data the data to be printed.
|
|
281
|
+
:param end the terminating string.
|
|
282
|
+
:return None
|
|
283
|
+
"""
|
|
284
|
+
self.terminal.cursor.write(data, end)
|
|
285
|
+
|
|
286
|
+
def _fits(self, sizes: Tuple[int, ...]) -> bool:
|
|
287
|
+
"""Return whether the expected table size fits the screen or not.
|
|
288
|
+
:param sizes the expected sizes to check.
|
|
289
|
+
:return True if the table fits the screen; False otherwise.
|
|
290
|
+
"""
|
|
291
|
+
extra_len = 4 + ((self.columns - 1) * 3) # 4 for '| |' and 3 for each '-+-'
|
|
292
|
+
exp_table_size = reduce(add, sizes) + extra_len
|
|
293
|
+
return exp_table_size < self.screen.columns
|
|
294
|
+
|
|
295
|
+
def _header_text(self, column: int) -> str:
|
|
296
|
+
"""Return a header for the specified column.
|
|
297
|
+
:param column the specified table column.
|
|
298
|
+
:return the header text at (row, column).
|
|
299
|
+
"""
|
|
300
|
+
return self.header_case(elide_text(self.headers[column], self._cell_size(column)))
|
|
301
|
+
|
|
302
|
+
def _cell_text(self, row: tuple, column: int) -> str:
|
|
303
|
+
"""Return a text for the specified cell (row, column).
|
|
304
|
+
:param row the specified table row.
|
|
305
|
+
:param column the specified table column.
|
|
306
|
+
:return the cell text at (row, column).
|
|
307
|
+
"""
|
|
308
|
+
return elide_text(str(row[column]), self._cell_size(column))
|
|
309
|
+
|
|
310
|
+
def _cell_size(self, column: int) -> int:
|
|
311
|
+
"""Return the size of the specified column.
|
|
312
|
+
:param column the specified table column.
|
|
313
|
+
:return the cell size at (row, column).
|
|
314
|
+
"""
|
|
315
|
+
return self._cell_sizes[column]
|
|
316
|
+
|
|
317
|
+
def _render_table(self, table_line: str, header_line: str, data_rows: List[str]) -> None:
|
|
318
|
+
"""Renders the table data.
|
|
319
|
+
:param table_line: a formatted line composed by all columns.
|
|
320
|
+
:param header_line: a formatted line composed by the table header.
|
|
321
|
+
:param data_rows: the formatted table data rows.
|
|
322
|
+
:return None
|
|
323
|
+
"""
|
|
324
|
+
magic_num = 4 # this is the length of the starting and ending characters: '| |'
|
|
325
|
+
line_length, render_line = len(table_line) - magic_num, f"+{table_line[1:-1]}+"
|
|
326
|
+
self._display_data("")
|
|
327
|
+
if self.caption:
|
|
328
|
+
border_line = render_line.replace("+", "-")
|
|
329
|
+
self._display_data(border_line)
|
|
330
|
+
self._display_data("| " + self.prefs.caption_color.placeholder, end="")
|
|
331
|
+
self._display_data(f"{elide_text(self.caption, line_length): ^{line_length}}", end="")
|
|
332
|
+
self._display_data("%NC%" + " |")
|
|
333
|
+
self._display_data(render_line)
|
|
334
|
+
self._display_data(header_line)
|
|
335
|
+
self._display_data(render_line)
|
|
336
|
+
self._display_data(os.linesep.join(data_rows) if data_rows else f"| {'<empty>': ^{line_length}} |")
|
|
337
|
+
self._display_data(render_line)
|
|
338
|
+
if self.footer:
|
|
339
|
+
self._display_data(self.footer)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib-Clitt
|
|
6
|
+
@package: clitt.core.tui
|
|
7
|
+
@file: tui_application.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.screen import screen
|
|
16
|
+
from clitt.core.term.terminal import terminal
|
|
17
|
+
from hspylib.core.metaclass.classpath import AnyPath
|
|
18
|
+
from hspylib.core.metaclass.singleton import AbstractSingleton
|
|
19
|
+
from hspylib.modules.application.application import Application
|
|
20
|
+
from hspylib.modules.application.exit_status import ExitStatus
|
|
21
|
+
from hspylib.modules.application.version import Version
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TUIApplication(Application, metaclass=AbstractSingleton):
|
|
28
|
+
"""Terminal UI application base class."""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
name: str | None,
|
|
33
|
+
version: Version = Version.initial(),
|
|
34
|
+
description: str = None,
|
|
35
|
+
usage: str = None,
|
|
36
|
+
epilog: str = None,
|
|
37
|
+
resource_dir: AnyPath = None,
|
|
38
|
+
log_dir: AnyPath = None,
|
|
39
|
+
):
|
|
40
|
+
super().__init__(name, version, description, usage, epilog, resource_dir, log_dir)
|
|
41
|
+
self._app_name = os.path.basename(sys.argv[0]) if name is None else name
|
|
42
|
+
|
|
43
|
+
def _setup_arguments(self) -> None:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def _main(self, *params, **kwargs) -> ExitStatus:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def _cleanup(self) -> None:
|
|
50
|
+
if screen.alternate and self._exit_code == ExitStatus.SUCCESS:
|
|
51
|
+
screen.alternate = not screen.alternate
|
|
52
|
+
terminal.restore()
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib-Clitt
|
|
6
|
+
@package: clitt.core.tui
|
|
7
|
+
@file: tui_component.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 abc import ABC, abstractmethod
|
|
16
|
+
from clitt.core.icons.font_awesome.awesome import Awesome
|
|
17
|
+
from clitt.core.term.commons import Direction
|
|
18
|
+
from clitt.core.term.cursor import Cursor
|
|
19
|
+
from clitt.core.term.screen import Screen
|
|
20
|
+
from clitt.core.term.terminal import Terminal
|
|
21
|
+
from clitt.core.tui.tui_preferences import TUIPreferences
|
|
22
|
+
from hspylib.core.tools.text_tools import elide_text
|
|
23
|
+
from hspylib.modules.cli.keyboard import Keyboard
|
|
24
|
+
from typing import Any, List, Optional, TypeVar
|
|
25
|
+
|
|
26
|
+
T = TypeVar("T", bound=Any)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TUIComponent(ABC):
|
|
30
|
+
"""Provide a base class for terminal UI components."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, title: str):
|
|
33
|
+
self._re_render = True
|
|
34
|
+
self._done = False
|
|
35
|
+
self._title = title
|
|
36
|
+
self._terminal = Terminal.INSTANCE
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def terminal(self) -> Terminal:
|
|
40
|
+
return self._terminal
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def screen(self) -> Screen:
|
|
44
|
+
return self.terminal.screen
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def cursor(self) -> Cursor:
|
|
48
|
+
return self.terminal.screen.cursor
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def prefs(self) -> TUIPreferences:
|
|
52
|
+
return self.screen.preferences
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def title(self) -> str:
|
|
56
|
+
return self._title
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def rows(self) -> int:
|
|
60
|
+
return self.screen.lines
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def columns(self) -> int:
|
|
64
|
+
return self.screen.columns
|
|
65
|
+
|
|
66
|
+
def _prepare_render(self, auto_wrap: bool = False, show_cursor: bool = False) -> None:
|
|
67
|
+
"""Prepare the screen for renderization."""
|
|
68
|
+
self.screen.add_watcher(self.invalidate)
|
|
69
|
+
Terminal.set_auto_wrap(auto_wrap)
|
|
70
|
+
Terminal.set_show_cursor(show_cursor)
|
|
71
|
+
self.screen.clear()
|
|
72
|
+
self.cursor.save()
|
|
73
|
+
|
|
74
|
+
def _loop(self, break_keys: List[Keyboard] = None) -> Keyboard:
|
|
75
|
+
"""Loop and wait for a keypress. Render the component if required."""
|
|
76
|
+
|
|
77
|
+
break_keys = break_keys or Keyboard.break_keys()
|
|
78
|
+
keypress = Keyboard.VK_NONE
|
|
79
|
+
|
|
80
|
+
# Wait for user interaction
|
|
81
|
+
while not self._done and keypress not in break_keys:
|
|
82
|
+
|
|
83
|
+
# Menu Renderization
|
|
84
|
+
if self._re_render:
|
|
85
|
+
self.render()
|
|
86
|
+
# Navigation input
|
|
87
|
+
keypress = self.handle_keypress()
|
|
88
|
+
|
|
89
|
+
self.cursor.end()
|
|
90
|
+
self.cursor.erase(Direction.DOWN)
|
|
91
|
+
self.cursor.reset_mode()
|
|
92
|
+
self.cursor.writeln("\n")
|
|
93
|
+
|
|
94
|
+
return keypress
|
|
95
|
+
|
|
96
|
+
def draw_line(self, line_fmt: str, *args: Any) -> None:
|
|
97
|
+
"""Draws a formatted component line respecting the specified max_columns.
|
|
98
|
+
:param line_fmt: the line format.
|
|
99
|
+
:param args: the format arguments.
|
|
100
|
+
"""
|
|
101
|
+
self.writeln(elide_text(line_fmt.format(*args), self.columns) + "%NC%")
|
|
102
|
+
|
|
103
|
+
def draw_navbar(self, navbar: str) -> None:
|
|
104
|
+
"""Draws the component navigation bar respecting the specified max_columns.
|
|
105
|
+
:param navbar: the component's navigation bar.
|
|
106
|
+
"""
|
|
107
|
+
self.write(navbar)
|
|
108
|
+
|
|
109
|
+
def draw_selector(self, is_selected: bool = False, has_bg_color: bool = True) -> Awesome:
|
|
110
|
+
"""Draws and highlight the selected component line.
|
|
111
|
+
:param is_selected: whether to set a selected foreground color or not.
|
|
112
|
+
:param has_bg_color: whether to set a background or not.
|
|
113
|
+
"""
|
|
114
|
+
prefs = TUIPreferences.INSTANCE
|
|
115
|
+
if is_selected:
|
|
116
|
+
selector = prefs.selected_icon
|
|
117
|
+
if has_bg_color:
|
|
118
|
+
self.write(prefs.sel_bg_color.code)
|
|
119
|
+
self.write(prefs.highlight_color.code)
|
|
120
|
+
else:
|
|
121
|
+
selector = prefs.unselected_icon
|
|
122
|
+
self.write(prefs.text_color.code)
|
|
123
|
+
|
|
124
|
+
return selector
|
|
125
|
+
|
|
126
|
+
def write(self, obj: Any) -> None:
|
|
127
|
+
"""Write the string representation of the object to the screen."""
|
|
128
|
+
self.terminal.echo(obj, end="")
|
|
129
|
+
|
|
130
|
+
def writeln(self, obj: Any) -> None:
|
|
131
|
+
"""Write the string representation of the object to the screen, appending a new line."""
|
|
132
|
+
self.terminal.echo(obj)
|
|
133
|
+
|
|
134
|
+
def invalidate(self) -> None:
|
|
135
|
+
"""Invalidate current TUI renderization."""
|
|
136
|
+
self.screen.clear()
|
|
137
|
+
self.cursor.save()
|
|
138
|
+
self.render()
|
|
139
|
+
|
|
140
|
+
@abstractmethod
|
|
141
|
+
def execute(self) -> Optional[T | List[T]]:
|
|
142
|
+
"""Execute the main TUI component flow."""
|
|
143
|
+
|
|
144
|
+
@abstractmethod
|
|
145
|
+
def render(self) -> None:
|
|
146
|
+
"""Renders the TUI component."""
|
|
147
|
+
|
|
148
|
+
@abstractmethod
|
|
149
|
+
def navbar(self, **kwargs) -> str:
|
|
150
|
+
"""Get the TUI component's navigation bar (optional)."""
|
|
151
|
+
|
|
152
|
+
@abstractmethod
|
|
153
|
+
def handle_keypress(self) -> Keyboard:
|
|
154
|
+
"""Handle a keyboard press."""
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
@project: HsPyLib-Clitt
|
|
6
|
+
@package: clitt.core.tui
|
|
7
|
+
@file: tui_preferences.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.form_icons import FormIcons
|
|
17
|
+
from clitt.core.icons.font_awesome.nav_icons import Awesome, NavIcons
|
|
18
|
+
from clitt.core.preferences import Preferences
|
|
19
|
+
from hspylib.modules.cli.vt100.vt_color import VtColor
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TUIPreferences(Preferences):
|
|
23
|
+
"""Terminal UI Preferences class."""
|
|
24
|
+
|
|
25
|
+
INSTANCE = None
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__("hhs.clitt")
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def max_rows(self) -> int:
|
|
32
|
+
return max(3, self.get_preference("max.rows", 10))
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def items_per_line(self) -> int:
|
|
36
|
+
return max(2, self.get_preference("items.per.line", 6))
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def title_line_length(self) -> int:
|
|
40
|
+
return max(15, self.get_preference("title.line.len", 30))
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def title_color(self) -> VtColor:
|
|
44
|
+
return self.get_preference("title.color", VtColor.ORANGE)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def caption_color(self) -> VtColor:
|
|
48
|
+
return self.get_preference("caption.color", VtColor.WHITE)
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def text_color(self) -> VtColor:
|
|
52
|
+
return self.get_preference("text.color", VtColor.WHITE)
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def success_color(self) -> VtColor:
|
|
56
|
+
return self.get_preference("success.color", VtColor.GREEN)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def warning_color(self) -> VtColor:
|
|
60
|
+
return self.get_preference("warning.color", VtColor.YELLOW)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def error_color(self) -> VtColor:
|
|
64
|
+
return self.get_preference("error.color", VtColor.RED)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def highlight_color(self) -> VtColor:
|
|
68
|
+
return self.get_preference("highlight.color", VtColor.CYAN)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def navbar_color(self) -> VtColor:
|
|
72
|
+
return self.get_preference("navbar.color", VtColor.YELLOW)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def tooltip_color(self) -> VtColor:
|
|
76
|
+
return self.get_preference("tooltip.color", VtColor.GREEN)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def breadcrumb_color(self) -> VtColor:
|
|
80
|
+
return self.get_preference("breadcrumb.color", VtColor.compose(VtColor.BG_BLUE, VtColor.WHITE))
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def sel_bg_color(self) -> VtColor:
|
|
84
|
+
return self.get_preference("sel.bg.color", VtColor.BLUE)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def selected_icon(self) -> Awesome:
|
|
88
|
+
return self.get_preference("selected.icon", NavIcons.POINTER)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def unselected_icon(self) -> Awesome:
|
|
92
|
+
return self.get_preference("unselected.icon", Awesome.no_icon())
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def checked_icon(self) -> Awesome:
|
|
96
|
+
return self.get_preference("checked.icon", FormIcons.MARKED)
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def unchecked_icon(self) -> Awesome:
|
|
100
|
+
return self.get_preference("unchecked.icon", FormIcons.UNMARKED)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
assert (tui_preferences := TUIPreferences().INSTANCE) is not None, "Failed to create TUIPreferences instance"
|