ae-gui 0.3.109__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.
- ae/gui/__init__.py +712 -0
- ae/gui/app.py +1498 -0
- ae/gui/img/Flag_de.png +0 -0
- ae/gui/img/add_item.png +0 -0
- ae/gui/img/app_tour.png +0 -0
- ae/gui/img/bubble_arrow.png +0 -0
- ae/gui/img/close_popup.png +0 -0
- ae/gui/img/copy_node.png +0 -0
- ae/gui/img/cut_node.png +0 -0
- ae/gui/img/delete_item.png +0 -0
- ae/gui/img/drag_item.png +0 -0
- ae/gui/img/edit_item.png +0 -0
- ae/gui/img/enter_item.png +0 -0
- ae/gui/img/export_node.png +0 -0
- ae/gui/img/filter_off.png +0 -0
- ae/gui/img/filter_on.png +0 -0
- ae/gui/img/flag_en.png +0 -0
- ae/gui/img/flag_es.png +0 -0
- ae/gui/img/help_circled.png +0 -0
- ae/gui/img/help_icon.png +0 -0
- ae/gui/img/icon_view.png +0 -0
- ae/gui/img/import_node.png +0 -0
- ae/gui/img/leave_item.png +0 -0
- ae/gui/img/light_1/add_item.png +0 -0
- ae/gui/img/light_1/app_tour.png +0 -0
- ae/gui/img/light_1/bubble_arrow.png +0 -0
- ae/gui/img/light_1/close_popup.png +0 -0
- ae/gui/img/light_1/copy_node.png +0 -0
- ae/gui/img/light_1/cut_node.png +0 -0
- ae/gui/img/light_1/delete_item.png +0 -0
- ae/gui/img/light_1/drag_item.png +0 -0
- ae/gui/img/light_1/edit_item.png +0 -0
- ae/gui/img/light_1/enter_item.png +0 -0
- ae/gui/img/light_1/export_node.png +0 -0
- ae/gui/img/light_1/filter_off.png +0 -0
- ae/gui/img/light_1/filter_on.png +0 -0
- ae/gui/img/light_1/help_circled.png +0 -0
- ae/gui/img/light_1/help_icon.png +0 -0
- ae/gui/img/light_1/icon_view.png +0 -0
- ae/gui/img/light_1/import_node.png +0 -0
- ae/gui/img/light_1/leave_item.png +0 -0
- ae/gui/img/light_1/list_view.png +0 -0
- ae/gui/img/light_1/open_node_info.png +0 -0
- ae/gui/img/light_1/paste_node.png +0 -0
- ae/gui/img/light_1/save_item.png +0 -0
- ae/gui/img/light_1/send_item.png +0 -0
- ae/gui/img/light_1/tap_pointer.png +0 -0
- ae/gui/img/list_view.png +0 -0
- ae/gui/img/open_node_info.png +0 -0
- ae/gui/img/paste_node.png +0 -0
- ae/gui/img/save_item.png +0 -0
- ae/gui/img/send_item.png +0 -0
- ae/gui/img/tap_pointer.png +0 -0
- ae/gui/loc/de/Msg.txt +245 -0
- ae/gui/loc/en/Msg.txt +214 -0
- ae/gui/loc/es/Msg.txt +240 -0
- ae/gui/snd/added.wav +0 -0
- ae/gui/snd/debug_draw.wav +0 -0
- ae/gui/snd/debug_save.wav +0 -0
- ae/gui/snd/deleted.wav +0 -0
- ae/gui/snd/edited.wav +0 -0
- ae/gui/snd/enter_item.wav +0 -0
- ae/gui/snd/error.wav +0 -0
- ae/gui/snd/filter_off.wav +0 -0
- ae/gui/snd/filter_on.wav +0 -0
- ae/gui/snd/leave_item.wav +0 -0
- ae/gui/snd/touched.wav +0 -0
- ae/gui/tours.py +459 -0
- ae/gui/utils.py +571 -0
- ae_gui-0.3.109.dist-info/METADATA +153 -0
- ae_gui-0.3.109.dist-info/RECORD +74 -0
- ae_gui-0.3.109.dist-info/WHEEL +5 -0
- ae_gui-0.3.109.dist-info/licenses/LICENSE.md +676 -0
- ae_gui-0.3.109.dist-info/top_level.txt +1 -0
ae/gui/__init__.py
ADDED
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
"""
|
|
2
|
+
helper functions and base application classes for GUI applications
|
|
3
|
+
==================================================================
|
|
4
|
+
|
|
5
|
+
this ae portion is providing base constants, helper functions and classes, independent of any GUI framework,
|
|
6
|
+
to implement upon them Python applications with a graphical user interfaces (GUI).
|
|
7
|
+
|
|
8
|
+
in concrete this portion is providing the generic functionality for:
|
|
9
|
+
|
|
10
|
+
* app- and user-specific configurations
|
|
11
|
+
* persistent app state variables
|
|
12
|
+
* a multilingual context-sensitive help system
|
|
13
|
+
* generic and app-specific app tours
|
|
14
|
+
* app flows (to monitor and control user interaction and app context)
|
|
15
|
+
* app state and key press events
|
|
16
|
+
* app colors and (light/dark) themes
|
|
17
|
+
|
|
18
|
+
this portion is composed of the following modules:
|
|
19
|
+
|
|
20
|
+
* :mod:`~ae.gui.app`: an abstract app class to implement GUI-framework-specific main app classes upon
|
|
21
|
+
* :mod:`~ae.gui.tours`: base classes to offer guiding app tours
|
|
22
|
+
* :mod:`~ae.gui.utils`: generic GUI-specific constants and helper functions
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
base resources for your gui app
|
|
26
|
+
-------------------------------
|
|
27
|
+
|
|
28
|
+
this portion is also providing base resources of commonly used i18n translation texts, images, and audio sounds.
|
|
29
|
+
|
|
30
|
+
generic i18n translation texts are provided by this portion in the `loc` folder, and can be extended and overloaded
|
|
31
|
+
with app-specific translation texts.
|
|
32
|
+
|
|
33
|
+
.. hint::
|
|
34
|
+
the data-driven approach allows ad-hoc-changes of your app's help texts without the need of code changes or
|
|
35
|
+
recompilation.
|
|
36
|
+
|
|
37
|
+
the license free image resources provided by this portion are taken from:
|
|
38
|
+
|
|
39
|
+
* `iconmonstr <https://iconmonstr.com/interface/>`_.
|
|
40
|
+
|
|
41
|
+
the audio/sounds provides by this portion are taken from:
|
|
42
|
+
|
|
43
|
+
* `Erokia <https://freesound.org/people/Erokia/>`_ at `freesound.org <https://freesound.org>`_.
|
|
44
|
+
* `plasterbrain <https://freesound.org/people/plasterbrain/>`_ at `freesound.org <https://freesound.org>`_.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
extended console application environment
|
|
48
|
+
----------------------------------------
|
|
49
|
+
|
|
50
|
+
the abstract base class :class:`~ae.gui.app.MainAppBase`, provided by this portion, inherits directly from the
|
|
51
|
+
:class:`ae console application environment class <ae.console.ConsoleApp>` of the ae namespace.
|
|
52
|
+
such inherited helper methods are used to log, configure, and control the run-time of your GUI app
|
|
53
|
+
via command line arguments.
|
|
54
|
+
|
|
55
|
+
.. hint::
|
|
56
|
+
please see the documentation of :ref:`config-options` and :ref:`config-files` in the :mod:`ae.console` namespace
|
|
57
|
+
portion/module for more detailed information.
|
|
58
|
+
|
|
59
|
+
the class :class:`~ae.gui.app.MainAppBase` adds on top of the :class:`~ae.console.ConsoleApp` the concepts of:
|
|
60
|
+
|
|
61
|
+
* :ref:`application events`
|
|
62
|
+
* :ref:`application status`
|
|
63
|
+
* :ref:`application flow`
|
|
64
|
+
* a :ref:`context-sensitive help system`
|
|
65
|
+
* :ref:`user guiding application tours`
|
|
66
|
+
* :ref:`generic key press events`.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
application events
|
|
70
|
+
------------------
|
|
71
|
+
|
|
72
|
+
some of the events described in this section are fired on application startup and shutdown.
|
|
73
|
+
|
|
74
|
+
additional events get fired e.g., in relation to the app states (documented further down in the section
|
|
75
|
+
:ref:`app state events`) or on start or stop of an :ref:`app tour <app tour start and stop events>`.
|
|
76
|
+
|
|
77
|
+
the following application events are fired exactly one time at startup in the following order:
|
|
78
|
+
|
|
79
|
+
* `on_app_init`: fired **after** :class:`ConsoleApp` app instance got initialized (detected config files)
|
|
80
|
+
and **before** the image and sound resources and app states get loaded and the GUI framework app class instance
|
|
81
|
+
gets initialized.
|
|
82
|
+
* `on_app_run`: fired **from within** the method :meth:`~ae.gui.app.MainAppBase.run_app`, **after** the parsing of
|
|
83
|
+
the command line arguments and options, and **before** all portion resources got imported.
|
|
84
|
+
* `on_app_build`: fired **after** all portion resources got loaded/imported, and **before** the framework event
|
|
85
|
+
loop of the used GUI framework gets started.
|
|
86
|
+
* `on_app_started`: fired **after** all app initializations, and the start of and the initial processing of the
|
|
87
|
+
framework event loop.
|
|
88
|
+
|
|
89
|
+
.. note::
|
|
90
|
+
the application events `on_app_build` and `on_app_started` have to be fired by the used GUI framework.
|
|
91
|
+
|
|
92
|
+
.. hint::
|
|
93
|
+
depending on the used GUI framework, there can be more app start events. e.g., the :mod:`ae.kivy.apps` module
|
|
94
|
+
fires the events :meth:`~ae.kivy.apps.KivyMainApp.on_app_built` and :meth:`~ae.kivy.apps.KivyMainApp.on_app_start`
|
|
95
|
+
(all of them fired after :meth:`~ae.kivy.apps.KivyMainApp.on_app_run` and
|
|
96
|
+
:meth:`~ae.kivy.apps.KivyMainApp.on_app_build`). more detailed info is available in the
|
|
97
|
+
section :ref:`kivy application events`.
|
|
98
|
+
|
|
99
|
+
when an application gets stopped, then the following events get fired in the following order:
|
|
100
|
+
|
|
101
|
+
* `on_app_exit`: fired **after* framework win got closed and just **before** the event loop of the GUI framework
|
|
102
|
+
will be stopped and the app shutdown.
|
|
103
|
+
* `on_app_quit`: fired **after** the event loop of the GUI framework got stopped and before
|
|
104
|
+
the :meth:`AppBase.shutdown` method will be called.
|
|
105
|
+
|
|
106
|
+
.. note::
|
|
107
|
+
the `on_app_exit` events will only be fired if the app is explicitly calling the
|
|
108
|
+
:meth:`~ae.gui.app.MainAppBase.stop_app` method.
|
|
109
|
+
|
|
110
|
+
.. hint::
|
|
111
|
+
depending on the used GUI framework, there can be more events. e.g., the :mod:`~ae.kivy.apps` module fires
|
|
112
|
+
the event :meth:`~ae.kivy.apps.KivyMainApp.on_app_stop`, and one clock tick later
|
|
113
|
+
the event :meth:`~ae.kivy.apps.KivyMainApp.on_app_stopped`
|
|
114
|
+
(both of them before :meth:`~ae.kivy.apps.KivyMainApp.on_app_quit` get fired).
|
|
115
|
+
see also :ref:`kivy application events`.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
application status
|
|
119
|
+
------------------
|
|
120
|
+
|
|
121
|
+
any application- and user-specific configurations like e.g., the last app window position/size, the app
|
|
122
|
+
theme/font/language or the last selected app flow, could be included in the app status variables.
|
|
123
|
+
|
|
124
|
+
this namespace portion adds/introduces the section `aeAppState` to the app :ref:`config-files`, where any
|
|
125
|
+
status variable values can be stored persistently to be recovered on the next startup of your application.
|
|
126
|
+
|
|
127
|
+
.. hint::
|
|
128
|
+
the section name `aeAppState` is declared by the :data:`APP_STATE_SECTION_NAME` constant. to access this
|
|
129
|
+
config section directly, use this constant instead of the hardcoded section name.
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
.. _app-state-variables:
|
|
133
|
+
|
|
134
|
+
app state variables
|
|
135
|
+
^^^^^^^^^^^^^^^^^^^
|
|
136
|
+
|
|
137
|
+
this module is providing/pre-defining the following application state variables:
|
|
138
|
+
|
|
139
|
+
* :attr:`~ae.gui.app.MainAppBase.app_state_version`: the version of the app states implementation
|
|
140
|
+
* :attr:`~ae.gui.app.MainAppBase.create_ink`: color to add/create new app data/items
|
|
141
|
+
* :attr:`~ae.gui.app.MainAppBase.delete_ink`: color to delete app data/item
|
|
142
|
+
* :attr:`~ae.gui.app.MainAppBase.error_ink`: color to display error messages/popups
|
|
143
|
+
* :attr:`~ae.gui.app.MainAppBase.flow_id`: current working flow id
|
|
144
|
+
* :attr:`~ae.gui.app.MainAppBase.flow_id_ink`: color to display/highlight widget(s) with the current flow id
|
|
145
|
+
* :attr:`~ae.gui.app.MainAppBase.flow_path`: stack of entered/opened app flows
|
|
146
|
+
* :attr:`~ae.gui.app.MainAppBase.flow_path_ink`: color to display the current flow path
|
|
147
|
+
* :attr:`~ae.gui.app.MainAppBase.font_size`: size of the main app font (also used to calculate the grid row height)
|
|
148
|
+
* :attr:`~ae.gui.app.MainAppBase.info_ink`: color to display info messages
|
|
149
|
+
* :attr:`~ae.gui.app.MainAppBase.lang_code`: id of the selected user language
|
|
150
|
+
* :attr:`~ae.gui.app.MainAppBase.light_theme`: light/dark background (for app themes)
|
|
151
|
+
* :attr:`~ae.gui.app.MainAppBase.read_ink`: color to display read-only data/items
|
|
152
|
+
* :attr:`~ae.gui.app.MainAppBase.selected_ink`: color to highlight currently selected app data/items
|
|
153
|
+
* :attr:`~ae.gui.app.MainAppBase.sound_volume`: audio volume of sound resources
|
|
154
|
+
* :attr:`~ae.gui.app.MainAppBase.theme_names`: list of user-generated themes (set of foreground/background colors)
|
|
155
|
+
* :attr:`~ae.gui.app.MainAppBase.unselected_ink`: color to display currently unselected app data/items
|
|
156
|
+
* :attr:`~ae.gui.app.MainAppBase.update_ink`: color to display/highlight an updated app data/item
|
|
157
|
+
* :attr:`~ae.gui.app.MainAppBase.vibration_volume`: intensity of vibration resources (on mobile devices)
|
|
158
|
+
* :attr:`~ae.gui.app.MainAppBase.warn_ink`: color to display warning messages/popups
|
|
159
|
+
* :attr:`~ae.gui.app.MainAppBase.win_rectangle`: the current window rectangle (position and size)
|
|
160
|
+
|
|
161
|
+
.. hint::
|
|
162
|
+
the two built-in app state variables are :attr:`~ae.gui.app.MainAppBase.flow_id` and
|
|
163
|
+
:attr:`~ae.gui.app.MainAppBase.flow_path` will be explained in more detail in the next section.
|
|
164
|
+
|
|
165
|
+
which app state variables are finally available in your app project depends (fully data-driven) on the app state
|
|
166
|
+
:ref:`config-variables` detected in all the :ref:`config-files` that are found/available at run-time of your app. the
|
|
167
|
+
names of all the available application state variables can be determined with the main app helper method
|
|
168
|
+
:meth:`~ae.gui.app.MainAppBase.app_state_keys`.
|
|
169
|
+
|
|
170
|
+
.. note::
|
|
171
|
+
if no config-file is provided, then this package ensures at least the proper initialization of the above
|
|
172
|
+
app state variables.
|
|
173
|
+
|
|
174
|
+
the :meth:`~ae.gui.app.MainBaseApp.load_app_states` method is called on instantiation from the implemented
|
|
175
|
+
main app class to load the values of all app state variables from the :ref:`config-files`, and is then calling
|
|
176
|
+
:meth:~ae.gui.app.MainAppBase.setup_app_states` for pass them into their corresponding instance attributes.
|
|
177
|
+
|
|
178
|
+
use the main app instance attribute to read/get the actual value of a single app state variable. the actual
|
|
179
|
+
app state variables dict is determining the method :meth:`~ae.gui.app.MainBaseApp.retrieve_app_states`, and can be saved
|
|
180
|
+
into the :ref:`config-files` for the next app run via the method :meth:`~ae.gui.app.MainBaseApp.save_app_states`.
|
|
181
|
+
this could be done e.g., after the app state has changed or at least on quiting the application.
|
|
182
|
+
|
|
183
|
+
always call the method :meth:`~ae.gui.app.MainBaseApp.change_app_state` to change an app state value to ensure:
|
|
184
|
+
|
|
185
|
+
(1) the propagation to any duplicated (observable/bound) framework property and
|
|
186
|
+
(2) the event notification of the related (optionally declared) main app instance method.
|
|
187
|
+
|
|
188
|
+
so e.g., if your application is supporting a user-defined font size, using the provided/pre-defined app state variable
|
|
189
|
+
:attr:`~ae.gui.app.MainAppBase.font_size`, then the :meth:`~ae.gui.app.MainBaseApp.change_app_state` method has to
|
|
190
|
+
be called with the :paramref:`~ae.gui.app.MainAppBase.change_app_state.app_state_name` argument set to `font_size`,
|
|
191
|
+
and the :paramref:`~ae.gui.app.MainAppBase.change_app_state.state_value` argument set to the new font size.
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
app theme variables
|
|
195
|
+
^^^^^^^^^^^^^^^^^^^
|
|
196
|
+
|
|
197
|
+
to allow the app user to quickly change the appearance of the app, some of the app state variables are classified
|
|
198
|
+
as app theme variables via the :attr:`~ae.gui.app.MainAppBase.theme_specific_cfg_vars` attribute, including by default
|
|
199
|
+
e.g., the font size (:attr:`~ae.gui.app.MainAppBase.font_size`), the used colors and if it is a light or dark theme
|
|
200
|
+
(:attr:`~ae.gui.app.MainAppBase.light_theme`).
|
|
201
|
+
|
|
202
|
+
to create or update an existing app theme call the method :meth:`~ae.gui.app.MainAppBase.theme_save`.
|
|
203
|
+
the method :meth:`~ae.gui.app.MainAppBase.theme_load` loads an existing theme from its config-file theme section.
|
|
204
|
+
|
|
205
|
+
.. hint::
|
|
206
|
+
the theme config section name consists of the prefix :data:`THEME_SECTION_PREFIX` followed by the name of the theme.
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
.. _app-state-constants:
|
|
210
|
+
|
|
211
|
+
app state constants
|
|
212
|
+
^^^^^^^^^^^^^^^^^^^
|
|
213
|
+
|
|
214
|
+
this portion is also providing some pre-defined constants that can be optionally used in your application in relation to
|
|
215
|
+
the app states data store and for the app state config variables :attr:`~ae.gui.app.MainAppBase.app_state_version`,
|
|
216
|
+
:attr:`~ae.gui.app.MainAppBase.font_size` and :attr:`~ae.gui.app.MainAppBase.light_theme`:
|
|
217
|
+
|
|
218
|
+
* :data:`APP_STATE_SECTION_NAME`: app states config section name
|
|
219
|
+
* :data:`APP_STATE_VERSION_VAR_NAME`: app state variable name of the current app state variable version
|
|
220
|
+
* :data:`MIN_FONT_SIZE`: minimum font size
|
|
221
|
+
* :data:`MAX_FONT_SIZE`: maximum font size
|
|
222
|
+
* :data:`DEFAULT_FONT_SIZE`: default font size
|
|
223
|
+
* :data:`THEME_LIGHT_BACKGROUND_COLOR`: light theme background color
|
|
224
|
+
* :data:`THEME_LIGHT_FONT_COLOR`: light theme foreground/font color
|
|
225
|
+
* :data:`THEME_DARK_BACKGROUND_COLOR`: dark theme background color
|
|
226
|
+
* :data:`THEME_DARK_FONT_COLOR`: dark theme foreground/font color
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
app state events
|
|
230
|
+
^^^^^^^^^^^^^^^^
|
|
231
|
+
|
|
232
|
+
there are three types of notification events get fired in relation to the app state variables, using the
|
|
233
|
+
following method names of the main app instance:
|
|
234
|
+
|
|
235
|
+
* `on_<app_state_name>`: fired if the value of an app state variable is changing
|
|
236
|
+
* `on_<app_state_name>_save`: fired if an app state gets saved to the config file
|
|
237
|
+
* `on_app_state_version_upgrade`: fired if the user upgrades a previously installed app to a higher version
|
|
238
|
+
|
|
239
|
+
the method name of the first app state change event consists of the prefix ``on_`` followed by the variable name
|
|
240
|
+
of the app state. so e.g., on a change of the `font_size` app state the notification event `on_font_size` will be
|
|
241
|
+
fired/called (if it exists as a method of the main app instance). these events don't provide any event arguments.
|
|
242
|
+
|
|
243
|
+
the second event gets fired for each app state value just after the app states getting retrieved from the main app
|
|
244
|
+
instance, and before they get stored into the main config file. the method name of this event includes also the name of
|
|
245
|
+
the app state with the suffix `_save`, so e.g., for the app state `flow_id` the event method name will result in
|
|
246
|
+
:meth:`on_app_state_flow_id_save`. this event is providing one event argument with the value of the app state. if the
|
|
247
|
+
event method returns a value that is not `None`, then this value will be stored/saved.
|
|
248
|
+
|
|
249
|
+
the third event gets fired on app startup when the app state version (in APP_STATE_VERSION_VAR_NAME, respective
|
|
250
|
+
`app_state_version`) got upgraded to a higher value. then this event handler method will be called providing the
|
|
251
|
+
version number for each version to upgrade, starting with the version of the previously installed main config file,
|
|
252
|
+
until the upgrade version of the main config file gets reached. so if e.g., the previously installed app state version
|
|
253
|
+
was `3` and the new version number is `6`, then this event will be fired 3 times with the arguments 3, 4, and 5.
|
|
254
|
+
this functionality can be used e.g., to change or add app state variables or to adapt the app environment.
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
application flow
|
|
258
|
+
----------------
|
|
259
|
+
|
|
260
|
+
to control the current state and user interaction flow (or context) of your application, and to persist it until the
|
|
261
|
+
next app start, :class:`MainBaseApp` provides two :ref:`app-state-variables`: :attr:`~ae.gui.app.MainAppBase.flow_id`
|
|
262
|
+
to store the currently working flow and :attr:`~ae.gui.app.MainAppBase.flow_path` to store the history of
|
|
263
|
+
entered/opened flows.
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
app flow id and path
|
|
267
|
+
^^^^^^^^^^^^^^^^^^^^
|
|
268
|
+
|
|
269
|
+
an application flow is represented by an id string that defines three things: (1) the action to enter into the flow, (2)
|
|
270
|
+
the data or object that gets currently worked on and (3) an optional key string that is identifying/indexing a widget or
|
|
271
|
+
data item of your application context/flow.
|
|
272
|
+
|
|
273
|
+
.. note::
|
|
274
|
+
never concatenate a flow id string manually, use the :func:`id_of_flow` function instead.
|
|
275
|
+
|
|
276
|
+
the flow id is initially an empty string. as soon as the user is starting a new work flow or is changing
|
|
277
|
+
the app context (e.g., the current selection of a data item or the opening of a popup), your
|
|
278
|
+
application could call the method :meth:`~ae.gui.app.MainBaseApp.change_flow` passing the flow id string into the
|
|
279
|
+
:paramref:`~ae.gui.app.MainAppBase.change_flow.new_flow_id` argument.
|
|
280
|
+
|
|
281
|
+
for more complex applications you can specify a path of nested flows. this flow path gets represented by the app state
|
|
282
|
+
variable :attr:`~ae.gui.app.MainAppBase.flow_path`, which is a list of flow id strings.
|
|
283
|
+
|
|
284
|
+
to enter into a deeper/nested flow, you call :meth:`~ae.gui.app.MainBaseApp.change_flow` with one of the actions
|
|
285
|
+
defined in :data:`ACTIONS_EXTENDING_FLOW_PATH`.
|
|
286
|
+
|
|
287
|
+
to go back to a previous flow in the flow path, call :meth:`~ae.gui.app.MainBaseApp.change_flow` passing one of
|
|
288
|
+
the actions defined in :data:`ACTIONS_REDUCING_FLOW_PATH`.
|
|
289
|
+
|
|
290
|
+
.. hint::
|
|
291
|
+
check the ACTIONS_* constants declared on top of the module :mod:`~ae.gui.app` for this and other app flow action
|
|
292
|
+
classifications.
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
application flow change events
|
|
296
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
297
|
+
|
|
298
|
+
the flow actions specified by :data:`~ae.gui.app.ACTIONS_CHANGING_FLOW_WITHOUT_CONFIRMATION` don't need a
|
|
299
|
+
flow change confirmation event handler, which are in concrete:
|
|
300
|
+
|
|
301
|
+
* `'enter'` or `'leave'`: extend/reduce the flow path.
|
|
302
|
+
* `'focus'`: pass/change the input focus.
|
|
303
|
+
* `'suggest'`: for autocompletion or other suggestions.
|
|
304
|
+
|
|
305
|
+
all other flow actions need a confirmation before they get changed by :meth:`~ae.gui.app.MainAppBase.change_flow`,
|
|
306
|
+
either by a custom flow change confirmation method/event-handler or by declaring a related popup class. the name
|
|
307
|
+
of the event handler and of the popup class gets determined from the flow id.
|
|
308
|
+
|
|
309
|
+
.. hint::
|
|
310
|
+
the name of the flow change confirmation method that gets fired when the app wants to change the flow (via the
|
|
311
|
+
method :meth:`~ae.gui.app.MainAppBase.change_flow`) gets determined by the function
|
|
312
|
+
:func:`flow_change_confirmation_event_name`, whereas the name of the popup class gets determined by the function
|
|
313
|
+
:func:`flow_popup_class_name`.
|
|
314
|
+
|
|
315
|
+
if the flow-specific change confirmation event handler does not exist or returns in a boolean `False` or a `None`
|
|
316
|
+
value, then the main app instance method :meth:`~ae.gui.app.MainAppBase.on_flow_change` will be called.
|
|
317
|
+
if this call also returns `False`, then the action of the new flow id will be searched within
|
|
318
|
+
:data:`~ae.gui.app.ACTIONS_CHANGING_FLOW_WITHOUT_CONFIRMATION` and if not found, then the
|
|
319
|
+
flow change will be rejected and :meth:`~ae.gui.app.MainAppBase.change_flow` returns `False`.
|
|
320
|
+
|
|
321
|
+
if in contrary, either the flow change confirmation event handler exists and does return `True`,
|
|
322
|
+
or the method :meth:`~ae.gui.app.MainAppBase.on_flow_change` returns True,
|
|
323
|
+
or the flow action of the new flow id is in :data:`~ae.gui.app.ACTIONS_CHANGING_FLOW_WITHOUT_CONFIRMATION`
|
|
324
|
+
then the flow id and path will be changed accordingly.
|
|
325
|
+
|
|
326
|
+
after a positive flow id/path change confirmation, the method :meth:`~ae.gui.app.MainAppBase.change_flow` checks if
|
|
327
|
+
the optional `event_kwargs` key `changed_event_name` got specified, and if yes, then it calls this method.
|
|
328
|
+
|
|
329
|
+
finally, if a confirmed flow change results in a `'focus'` flow action, then the event `on_flow_widget_focused` will be
|
|
330
|
+
fired. this event can be used by the GUI framework to set the focus to the widget associated with the new focus flow id.
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
flow actions `'open'` and `'close'`
|
|
334
|
+
__________________________________
|
|
335
|
+
|
|
336
|
+
to display an instance of a properly named popup class, initiate the change the app flow to an appropriate
|
|
337
|
+
flow id (with an `'open'` flow action). in this case no change confirmation event handler is needed, because
|
|
338
|
+
:meth:`~ae.gui.app.MainAppBase.on_flow_change` is then automatically opening the popup.
|
|
339
|
+
|
|
340
|
+
when the popup is visible, the flow path will be extended with the respective flow id.
|
|
341
|
+
|
|
342
|
+
calling the `close` method of the popup will hide it. on closing the popup, the flow id will be reset and the opening
|
|
343
|
+
flow id will be removed from the flow path.
|
|
344
|
+
|
|
345
|
+
all popup classes are providing the events `on_pre_open`, `on_open`, `on_pre_dismiss` and `on_dismiss`.
|
|
346
|
+
the `on_dismiss` event handler can be used for data validation: returning a non-False value from it will cancel
|
|
347
|
+
the close.
|
|
348
|
+
|
|
349
|
+
.. hint::
|
|
350
|
+
see the documentation of each popup class for more details on the features of popup classes (for Kivy apps e.g.
|
|
351
|
+
:class:`~ae.kivy.widgets.FlowDropDown`, :class:`~ae.kivy.widgets.FlowPopup` or
|
|
352
|
+
:class:`~ae.kivy.widgets.FlowSelector`).
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
context-sensitive help system
|
|
356
|
+
-----------------------------
|
|
357
|
+
|
|
358
|
+
the generic functionality of a context-sensitive help system is provided by this portion. only the user interface
|
|
359
|
+
widgets to display the help texts have to be implemented and provided by the finally used GUI-framework.
|
|
360
|
+
|
|
361
|
+
.. hint::
|
|
362
|
+
help message texts are based on the multilingual translation messages, provided by the
|
|
363
|
+
ae namespace portion :mod:`ae.i18n`.
|
|
364
|
+
|
|
365
|
+
more details on these and other features of this help system, e.g., the usage of f-strings in the help texts, are
|
|
366
|
+
documented in the doc string of the :mod:`ae.i18n` module.
|
|
367
|
+
|
|
368
|
+
an example demonstrating the features of this context help system can be found in the repository of
|
|
369
|
+
the `kivy lisz demo app <https://gitlab.com/ae-group/kivy_lisz>`_.
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
i18n help ids and texts
|
|
373
|
+
^^^^^^^^^^^^^^^^^^^^^^^
|
|
374
|
+
|
|
375
|
+
each multilingual help text is associated to a unique help id, the message id.
|
|
376
|
+
|
|
377
|
+
the help texts of an app are spread over multiple translation message files, which are text files
|
|
378
|
+
declaring a single dict literal, where the message ids are the dict keys.
|
|
379
|
+
|
|
380
|
+
each package/portion required by an app can declare and register its translation message files for their help texts.
|
|
381
|
+
your app can provide additional i18n translation message files for the app's help texts.
|
|
382
|
+
|
|
383
|
+
separate message files are created for each supported language. the multilingual ae namespace portions are providing
|
|
384
|
+
help texts for the languages English, Spanish and German. additional languages can be provided by your app, also
|
|
385
|
+
for the help texts of the imported ae namespace portions.
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
help ids of flow-changing widgets
|
|
389
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
390
|
+
|
|
391
|
+
the help id to identify the help texts for each widget is composed by the :func:`id_of_flow_help`, using the
|
|
392
|
+
prefix marker string defined by the constant :data:`~ae.gui.utils.FLOW_HELP_ID_PREFIX` followed by the flow id
|
|
393
|
+
of the flow widget.
|
|
394
|
+
|
|
395
|
+
.. hint:: more information regarding the flow id you find in the section :ref:`application flow`.
|
|
396
|
+
|
|
397
|
+
for example, the help/message id for a flow button with the flow action `'open'`, the object `'item'`
|
|
398
|
+
and the (optional) flow key `'456'` is resulting in the following help text message id::
|
|
399
|
+
|
|
400
|
+
'help_flow#open_item:456'
|
|
401
|
+
|
|
402
|
+
if there is no need for a detailed message id that is taking the flow key into account, then use a help id
|
|
403
|
+
without the flow key. the method :meth:`~ae.gui.app.MainAppBase.help_display` does first search for a message id
|
|
404
|
+
including the flow key in the available help text files, and if not found, it will automatically fall back to use
|
|
405
|
+
a message id without the flow key::
|
|
406
|
+
|
|
407
|
+
'help_flow#open_item'
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
help ids of app-state-changing widgets
|
|
411
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
412
|
+
|
|
413
|
+
the help message id for a widget changing an app state is composed by the method :func:`id_of_state_help`,
|
|
414
|
+
using the prefix marker string defined by the :data:`~ae.gui.utils.APP_STATE_HELP_ID_PREFIX` constant,
|
|
415
|
+
followed by the name of the app state.
|
|
416
|
+
|
|
417
|
+
so, the help id for a widget changing the `font_size` app state is resulting in the following help id::
|
|
418
|
+
|
|
419
|
+
'help_app_state#font_size'
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
help message text f-strings
|
|
423
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
424
|
+
|
|
425
|
+
help message texts can be f-strings with access to the widget properties via the `self` variable, which
|
|
426
|
+
gets automatically prepared within the `help_vars` context dict by this portion.
|
|
427
|
+
|
|
428
|
+
so, the help message text of the following translation message item gets displayed with the actual slider value
|
|
429
|
+
of the widget that allows the user to change the font size::
|
|
430
|
+
|
|
431
|
+
{
|
|
432
|
+
'help_app_state#font_size': \"\"\"move the slider to adjust the font size
|
|
433
|
+
|
|
434
|
+
the current font size is {self.value}\"\"\",
|
|
435
|
+
...
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
pre- and post-change help texts
|
|
440
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
441
|
+
|
|
442
|
+
to display a different help message before and after the change of the flow id or the app state, use
|
|
443
|
+
instead of a simple message text, a message dict with the two keys `''` (an empty string) and `'after'`,
|
|
444
|
+
and then put the message texts as their values, like shown in the following example::
|
|
445
|
+
|
|
446
|
+
{
|
|
447
|
+
'help_id': {
|
|
448
|
+
'': "help text displayed before the flow/app-state change.",
|
|
449
|
+
'after': "help text displayed after the flow/app-state change",
|
|
450
|
+
},
|
|
451
|
+
...
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if you want to move/change the help target to another widget after a change, then the
|
|
455
|
+
'`next_help_id'` message dict key can be appended to the message dict::
|
|
456
|
+
|
|
457
|
+
{
|
|
458
|
+
'help_id': {
|
|
459
|
+
'': "help text",
|
|
460
|
+
...
|
|
461
|
+
'next_help_id': "id_of_the_next_help_message",
|
|
462
|
+
},
|
|
463
|
+
...
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
in this case the help target will automatically change to the widget specified by the flow id in the '`next_help_id'`
|
|
467
|
+
key, if the user was tapping the second time on the first/initial help target widget.
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
pluralize-able help texts
|
|
471
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
472
|
+
|
|
473
|
+
additional a message dict keys can be used to auto-select pluralized help texts. for that add a `count`
|
|
474
|
+
item to the `help_vars` context property of the help target widget and then define a help text for all
|
|
475
|
+
the possible count cases in the message dict like shown in the following example::
|
|
476
|
+
|
|
477
|
+
{
|
|
478
|
+
'help_id': {
|
|
479
|
+
'': "fallback help text if count is None",
|
|
480
|
+
'zero': "help text if {count} == 0",
|
|
481
|
+
'one': "help text if {count} == 1",
|
|
482
|
+
'many': "help text if {count} > 1",
|
|
483
|
+
'negative': "help text if {count} < 0",
|
|
484
|
+
},
|
|
485
|
+
...
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
the provided `count` value can also be included/displayed in the help text, so the help message text of
|
|
489
|
+
the`'zero'` count case in the above example will result in "help text if 0 == 0".
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
help layout implementation example
|
|
493
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
494
|
+
|
|
495
|
+
the layout of the user interface for this help system has to be provided externally on top of this module.
|
|
496
|
+
it can either be implemented directly in your app project or in a separate GUI-framework-specific package/portion.
|
|
497
|
+
|
|
498
|
+
use :class:`~ae.gui.app.MainAppBase` as the base class of the GUI framework specific main application class
|
|
499
|
+
to implementing all its abstract methods, like e.g., :meth:`~ae.gui.app.MainAppBase.init_app` and
|
|
500
|
+
:meth:`~ae.gui.app.MainAppBase.ensure_top_most_z_index`::
|
|
501
|
+
|
|
502
|
+
from ae.gui.app import MainAppBase
|
|
503
|
+
|
|
504
|
+
class MyMainApp(MainAppBase):
|
|
505
|
+
def init_app(self, framework_app_class=None):
|
|
506
|
+
self.framework_app = framework_app_class()
|
|
507
|
+
...
|
|
508
|
+
return self.framework_app.run, self.framework_app.stop
|
|
509
|
+
|
|
510
|
+
def ensure_top_most_z_index(self, widget):
|
|
511
|
+
framework_method_to_push_widget_to_top_most(widget)
|
|
512
|
+
...
|
|
513
|
+
|
|
514
|
+
to activate the help mode, the widget to display the help texts has to be assigned to the main app instance attribute
|
|
515
|
+
:attr:`~ae.gui.app.MainAppBase.help_layout` and to its related framework app property via
|
|
516
|
+
the :meth:`~ae.gui.app.MainAppBase.change_observable` method::
|
|
517
|
+
|
|
518
|
+
main_app.change_observable('help_layout', HelpScreenContainerOrWindow())
|
|
519
|
+
|
|
520
|
+
.. hint::
|
|
521
|
+
for example, see :attr:`~ae.kivy.apps.FrameworkApp.help_layout` as the help layout property implemented for the
|
|
522
|
+
`Kivy framework <https://kivy.org/>`.
|
|
523
|
+
|
|
524
|
+
the :attr:`~ae.gui.app.MainAppBase.help_layout` property is also used as a flag of the help mode activity.
|
|
525
|
+
by assigning `None` to this observable attribute, the help mode will get deactivated::
|
|
526
|
+
|
|
527
|
+
main_app.change_observable('help_layout', None)
|
|
528
|
+
|
|
529
|
+
use the attribute :attr:`~ae.gui.app.MainAppBase.help_activator` to specify the widget that allows the user
|
|
530
|
+
to toggle the help mode activation. the :meth:`~ae.gui.app.MainAppBase.help_display` is using it as the fallback widget
|
|
531
|
+
if no help target (or widget to be explained) got found.
|
|
532
|
+
|
|
533
|
+
.. hint::
|
|
534
|
+
the de-/activation method :meth:`~ae.kivy.apps.KivyMainApp.help_activation_toggle` together with the classes
|
|
535
|
+
:class:`~ae.kivy.behaviors.HelpBehavior`, :class:`~ae.kivy.widgets.HelpToggler` and
|
|
536
|
+
:class:`~ae.kivy.widgets.Tooltip` are demonstrating a typical implementation of help activator
|
|
537
|
+
and help text tooltip widgets.
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
user guiding application tours
|
|
541
|
+
------------------------------
|
|
542
|
+
|
|
543
|
+
the following classes provided by this portion build a solid fundament to implement tours for your app:
|
|
544
|
+
|
|
545
|
+
* :class:`~ae.gui.tours.TourBase`: abstract base class of all app tours.
|
|
546
|
+
* :class:`~ae.gui.tours.TourDropdownFromButton`: abstract base class for tours on dropdown/menu widgets.
|
|
547
|
+
* :class:`~ae.gui.tours.OnboardingTour`: minimal app onboarding tour, extendable with app-specific tour pages.
|
|
548
|
+
* :class:`~ae.gui.tours.UserPreferencesTour`: minimal user preferences dropdown tour.
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
app tour start and stop events
|
|
552
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
553
|
+
|
|
554
|
+
the following main app event methods get called (if they exist) in relation to the start/stop of an app tour:
|
|
555
|
+
|
|
556
|
+
* `on_tour_init`: fired when the app tour instance got initialized and the app states backup got saved.
|
|
557
|
+
* `on_tour_start`: fired after the tour start method gets called.
|
|
558
|
+
* `on_tour_exit`: fired after an app tour got finished and the app states got restored to the values of the tour start.
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
UI-specific implementation
|
|
562
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
563
|
+
|
|
564
|
+
to complete the implementation of the app tours, the UI-specific framework has to provide a tour layout class, which is
|
|
565
|
+
highlighting the explained widget, displaying a tooltip and another widget to display the tour page texts.
|
|
566
|
+
|
|
567
|
+
.. hint::
|
|
568
|
+
the :class:`~ae.kivy.tours.TourOverlay` class, provided by the ae portion :mod:`ae.kivy`, is a
|
|
569
|
+
good example of a GUI-framework-specific implementation of a tour layout class for the
|
|
570
|
+
`Kivy framework <https://kivy.org/>`_.
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
generic key press events
|
|
574
|
+
------------------------
|
|
575
|
+
|
|
576
|
+
to provide key press events to the applications that will use the new GUI framework, you have to catch the key press
|
|
577
|
+
events of the framework, convert/normalize them, and then call the method
|
|
578
|
+
:meth:`~ae.gui.app.MainAppBase.key_press_from_framework` with the normalized modifiers and key args.
|
|
579
|
+
|
|
580
|
+
the :paramref:`~ae.gui.app.MainAppBase.key_press_from_framework.modifiers` arg is a string that can contain several
|
|
581
|
+
of the following sub-strings, always in the alphabetic order (like listed below):
|
|
582
|
+
|
|
583
|
+
* Alt
|
|
584
|
+
* Ctrl
|
|
585
|
+
* Meta
|
|
586
|
+
* Shift
|
|
587
|
+
|
|
588
|
+
the :paramref:`~ae.gui.app.MainAppBase.key_press_from_framework.key` arg is a string specifying the last pressed key.
|
|
589
|
+
if the key is not representing a single character but a command key, then `key` will be one of the following
|
|
590
|
+
key name strings:
|
|
591
|
+
|
|
592
|
+
* escape
|
|
593
|
+
* tab
|
|
594
|
+
* backspace
|
|
595
|
+
* enter
|
|
596
|
+
* del
|
|
597
|
+
* enter
|
|
598
|
+
* up
|
|
599
|
+
* down
|
|
600
|
+
* right
|
|
601
|
+
* left
|
|
602
|
+
* home
|
|
603
|
+
* end
|
|
604
|
+
* pgup
|
|
605
|
+
* pgdown
|
|
606
|
+
|
|
607
|
+
on call of :meth:`~ae.gui.app.MainAppBase.key_press_from_framework` this method will dispatch the key press
|
|
608
|
+
event to your application. first it will check the app instance if it has declared a method with the name
|
|
609
|
+
`on_key_press_of_<modifiers>_<key>` and if so, it will call this method.
|
|
610
|
+
|
|
611
|
+
if this method does return False (or any other value resulting in False), then the method
|
|
612
|
+
:meth:`~ae.gui.app.MainAppBase.key_press_from_framework` will check for a method with the same name in lower-case,
|
|
613
|
+
and if it exits, it will call this method.
|
|
614
|
+
|
|
615
|
+
if also the second method is not declared or does return False, then it will try to call the event handler method
|
|
616
|
+
`on_key_press` of the main app instance (if it exists) with the modifiers and the key as arguments.
|
|
617
|
+
|
|
618
|
+
if the `on_key_press` method does also return False, then :meth:`~ae.gui.app.MainAppBase.key_press_from_framework`
|
|
619
|
+
will finally pass the key press event to the original key press handler of the GUI framework for further processing.
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
integrate a new gui framework
|
|
623
|
+
-----------------------------
|
|
624
|
+
|
|
625
|
+
the abstract class :class:`~ae.gui.app.MainAppBase`, provided by the module :mod:`ae.gui.app`, is a generic base
|
|
626
|
+
for the implementation of any Python GUI framework.
|
|
627
|
+
|
|
628
|
+
to integrate a new Python GUI framework, you have to declare a new class that inherits from the class
|
|
629
|
+
:class:`~ae.gui.app.MainAppBase` and implements at least their five abstract methods:
|
|
630
|
+
|
|
631
|
+
* :meth:`~ae.gui.app.MainAppBase.call_method_delayed`
|
|
632
|
+
* :meth:`~ae.gui.app.MainAppBase.call_method_repeatedly`
|
|
633
|
+
* :meth:`~ae.gui.app.MainAppBase.ensure_top_most_z_index`
|
|
634
|
+
* :meth:`~ae.gui.app.MainAppBase.help_activation_toggle`
|
|
635
|
+
* :meth:`~ae.gui.app.MainAppBase.init_app`
|
|
636
|
+
|
|
637
|
+
additionally and to load the resources of the app (after the portion resources got loaded), the event `on_app_build`
|
|
638
|
+
has to be fired, executing the :meth:`MainAppBase.on_app_build` method. this could be done directly from within
|
|
639
|
+
the implementation of the abstract method :meth:`~ae.gui.app.MainAppBase.init_app` or by forwarding/redirecting one
|
|
640
|
+
of the app instance events of the used GUI framework.
|
|
641
|
+
|
|
642
|
+
am example of a minimal implementation of the :meth:`~ae.gui.app.MainAppBase.init_app` method
|
|
643
|
+
could look like the following::
|
|
644
|
+
|
|
645
|
+
def init_app(self):
|
|
646
|
+
self.call_method('on_app_build')
|
|
647
|
+
return None, None
|
|
648
|
+
|
|
649
|
+
most GUI frameworks are providing classes that need to be instantiated on application startup, like e.g., the instance
|
|
650
|
+
of the GUI framework app class, the root widget or layout of the main GUI framework window(s). to keep a reference to
|
|
651
|
+
these instances within your main app class, the attributes :attr:`~ae.gui.app.MainAppBase.framework_app`,
|
|
652
|
+
:attr:`~ae.gui.app.MainAppBase.framework_root` and :attr:`~ae.gui.app.MainAppBase.framework_win` of the
|
|
653
|
+
class :class:`MainAppBase` can be used.
|
|
654
|
+
|
|
655
|
+
the initialization of the attributes :attr:`~ae.gui.app.MainAppBase.framework_app`,
|
|
656
|
+
:attr:`~ae.gui.app.MainAppBase.framework_root` and
|
|
657
|
+
:attr:`~ae.gui.app.MainAppBase.framework_win` is optional and can be done e.g., within the implementation of
|
|
658
|
+
:meth:`~ae.gui.app.MainAppBase.init_app` or in the `on_app_build` application event fired later
|
|
659
|
+
by the framework app instance.
|
|
660
|
+
|
|
661
|
+
.. note::
|
|
662
|
+
if :attr:`~ae.gui.app.MainAppBase.framework_win` is set to a window instance, then the window instance has
|
|
663
|
+
to provide a `close` method, which will be called automatically by the :meth:`~ae.gui.app.MainAppBase.stop_app`.
|
|
664
|
+
|
|
665
|
+
a typical framework-specific main app class implementation example and its `init_app` method looks like::
|
|
666
|
+
|
|
667
|
+
from new_gui_framework import NewFrameworkApp, MainWindowClassOfNewFramework
|
|
668
|
+
|
|
669
|
+
class NewFrameworkMainApp(MainAppBase):
|
|
670
|
+
def init_app(self):
|
|
671
|
+
self.framework_app = NewFrameworkAppClass()
|
|
672
|
+
self.framework_win = MainWindowClassOfNewFramework()
|
|
673
|
+
|
|
674
|
+
# return callables to start/stop the event loop of the GUI framework
|
|
675
|
+
return self.framework_app.start, self.framework_app.stop
|
|
676
|
+
|
|
677
|
+
in this example the `on_app_build` application event gets fired either from within the `start` method of the framework
|
|
678
|
+
app instance or by an event provided by the used GUI framework.
|
|
679
|
+
|
|
680
|
+
the method :meth:`~ae.gui.app.MainAppBase.init_app` will be executed only once at the main app class instantiation.
|
|
681
|
+
only the main app instance has to initialize the GUI framework to prepare the app startup and has to return at least
|
|
682
|
+
a callable to start the event loop of the GUI framework.
|
|
683
|
+
|
|
684
|
+
to initiate the app startup, the :meth:`~MainAppClass.run_app` method has to be called from the main module of your
|
|
685
|
+
app project. :meth:`~ae.gui.app.MainAppBase.run_app` will then start the GUI event loop by calling the first callable
|
|
686
|
+
that got returned by :meth:`~ae.gui.app.MainAppBase.init_app`.
|
|
687
|
+
|
|
688
|
+
.. hint::
|
|
689
|
+
an actual overview about the available GUI-framework-specific ae namespace portions can be found in the
|
|
690
|
+
documentation of the ae namespace demo app portion :mod:`ae.lisz_app_data`.
|
|
691
|
+
|
|
692
|
+
check out the ae namespace portion :mod:`ae.kivy` for a more detailed integration example of the
|
|
693
|
+
`Kivy framework <https://kivy.org/>`_.
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
TODO:
|
|
697
|
+
implement OS-independent detection of dark/light screen mode and automatic notification on day/night mode switch.
|
|
698
|
+
- see https://github.com/albertosottile/darkdetect for macOS, MSWindows and Ubuntu
|
|
699
|
+
- see https://github.com/kvdroid/Kvdroid/blob/master/kvdroid/tools/darkmode.py for Android
|
|
700
|
+
|
|
701
|
+
"""
|
|
702
|
+
from ae.i18n import register_package_translations # type: ignore
|
|
703
|
+
|
|
704
|
+
from .utils import register_package_images, register_package_sounds
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
__version__ = '0.3.109'
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
register_package_images()
|
|
711
|
+
register_package_sounds()
|
|
712
|
+
register_package_translations()
|