BonPrinter v1.2.0
Thermal Printer tool
Loading...
Searching...
No Matches
monitor.py
Go to the documentation of this file.
1"""!
2********************************************************************************
3@file monitor.py
4@brief handle windows size and scale factor and update items
5********************************************************************************
6"""
7
8import logging
9from typing import Optional, TYPE_CHECKING
10import darkdetect
11
12from Source.version import __title__
13from Source.Util.app_data import ETheme, I_DEFAULT_WIN_WIDTH, I_DEFAULT_WIN_HEIGHT, read_window_state, save_window_state, \
14 read_theme_settings, write_theme_settings, ICON_LOCK_LIGHT, ICON_LOCK_DARK, ICON_STATUS_LIGHT, ICON_STATUS_DARK, \
15 ICON_OPEN_FOLDER_LIGHT, ICON_OPEN_FOLDER_DARK, ICON_COMBINE_LIGHT, ICON_COMBINE_DARK, \
16 ICON_PRINT_FILE_LIGHT, ICON_PRINT_FILE_DARK, ICON_REPORT_LIGHT, ICON_REPORT_DARK, \
17 ICON_PRINT_PREVIEW_LIGHT, ICON_PRINT_PREVIEW_DARK, ICON_USER_LIGHT, ICON_USER_DARK, \
18 ICON_USER_EDIT_LIGHT, ICON_USER_EDIT_DARK, ICON_USER_IMPORT_LIGHT, ICON_USER_IMPORT_DARK, ICON_USER_EXPORT_LIGHT, ICON_USER_EXPORT_DARK, \
19 ICON_USER_RESET_LIGHT, ICON_USER_RESET_DARK, ICON_ARTICLES_LIGHT, ICON_ARTICLES_DARK, ICON_ARTICLES_EDIT_LIGHT, ICON_ARTICLES_EDIT_DARK, \
20 ICON_ARTICLES_IMPORT_LIGHT, ICON_ARTICLES_IMPORT_DARK, ICON_ARTICLES_EXPORT_LIGHT, ICON_ARTICLES_EXPORT_DARK, \
21 ICON_ARTICLES_RESET_LIGHT, ICON_ARTICLES_RESET_DARK, ICON_CHANGE_FOLDER_LIGHT, ICON_CHANGE_FOLDER_DARK, \
22 ICON_PRINTER_LIGHT, ICON_PRINTER_DARK, ICON_PAPER_LIGHT, ICON_PAPER_DARK, ICON_THEME_LIGHT, ICON_THEME_DARK, ICON_LANGUAGE_LIGHT, ICON_LANGUAGE_DARK, \
23 ICON_LANGUAGE_ENGLISH, ICON_LANGUAGE_GERMAN, ICON_LOG_LIGHT, ICON_LOG_DARK, ICON_HELP_LIGHT, ICON_HELP_DARK, \
24 ICON_APP, ICON_RESET_LIGHT, ICON_RESET_DARK, ItemNumber, D_ITEM_NUMBER_ROW, D_ITEM_NUMBER_COLUMN, ITEM_NUMBER_COLUMN_MIN
25
26from Source.Util.gui_toolkit import config_window, get_window_size, get_window_geometry, get_window_state, get_style, \
27 config_menu, config_btn, config_text, get_text, config_table, get_stylesheet, create_font, DIALOG, FONT
28
29from Source.Model.day_light import get_sun_light_status
30
31if TYPE_CHECKING:
32 from Source.Controller.main_window import MainWindow
33
34log = logging.getLogger(__title__)
35
36D_FONT_SIZE = {
37 "articles_button": 9,
38 "calc_button": 18,
39 "multi_button": 18,
40 "clear_button": 18,
41 "print_button": 22,
42 "table": 12,
43 "table_vertical": 25,
44 "total": 30,
45 "lock_button": 30,
46 "ec_button": 45,
47 "report_dialog": 16,
48 "report_button": 16,
49 "report_text": 9
50}
51
52S_DEFAULT_FONT = "MS Shell Dlg 2"
53
54
56 """!
57 @brief Class to scale text and item positions.
58 @param ui : main window object
59 """
60
61 def __init__(self, ui: "MainWindow") -> None:
62 self.ui = ui
63 self.table_font = create_font(S_DEFAULT_FONT, D_FONT_SIZE["table"])
64 self.default_stylesheet = get_stylesheet(self.ui)
65 self.default_button_stylesheet = get_stylesheet(self.ui.btn_lock)
66 config_window(self.ui, min_width=I_DEFAULT_WIN_WIDTH, min_height=I_DEFAULT_WIN_HEIGHT)
67 # window geometry and state
68 default_geometry = get_window_geometry(self.ui)
69 default_state = get_window_state(self.ui)
70 o_geometry, o_state = read_window_state()
71 if (o_geometry is not None) and (o_state is not None):
72 try:
73 config_window(self.ui, geometry=o_geometry, state=o_state)
74 except BaseException as e:
75 log.warning("Invalid WindowsSetting, using default values (%s)", str(e))
76 config_window(self.ui, geometry=default_geometry, state=default_state)
77 # Theme
78 self.e_style = read_theme_settings()
79 log.debug("Select Theme: %s", self.e_style)
80 self.e_actual_theme = ETheme.LIGHT
82
83 def check_for_style_change(self, e_style: Optional[ETheme] = None) -> None:
84 """!
85 @brief Check for style change
86 @param e_style : style to set
87 """
88 if e_style is None:
89 e_style = self.e_style
90 old_style = self.e_actual_theme
91 match e_style:
92 case ETheme.AUTO:
93 self.e_actual_theme = ETheme.LIGHT if get_sun_light_status() else ETheme.DARK
94 case ETheme.LIGHT:
95 self.e_actual_theme = ETheme.LIGHT
96 case ETheme.DARK:
97 self.e_actual_theme = ETheme.DARK
98 case ETheme.CLASSIC:
99 self.e_actual_theme = ETheme.CLASSIC
100 case ETheme.SYSTEM:
101 self.e_actual_theme = ETheme.LIGHT if darkdetect.isLight() else ETheme.DARK
102 case _:
103 self.ui.set_status(f"Invalid theme change: {e_style}", True) # state not possible
104 if old_style != self.e_actual_theme:
105 self.update_icons()
106 self.set_dialog_style(self.ui)
107
108 def update_darkmode_status(self, e_style: ETheme) -> None:
109 """!
110 @brief Update dark mode status.
111 @param e_style : select theme mode
112 """
113 self.e_style = e_style
114 write_theme_settings(self.e_style)
116 self.set_dialog_style(self.ui)
118 self.update_icons()
119 self.ui.model.c_sound.update_sound_status(self.ui.model.c_sound.b_sound, b_update_settings=False)
120 if hasattr(self.ui, 'status_timer'): # object does not exist before
121 self.ui.update_screen()
122
123 def set_change_theme_status(self) -> None:
124 """!
125 @brief Set dialog theme style.
126 """
127 match self.e_style:
128 case ETheme.AUTO:
129 self.ui.set_status(["Automatic Theme set", "Automatischer Modus aktiviert"])
130 case ETheme.LIGHT:
131 self.ui.set_status(["Light Theme set", "Heller Modus aktiviert"])
132 case ETheme.DARK:
133 self.ui.set_status(["Dark Theme set", "Dunkler Modus aktiviert"])
134 case ETheme.CLASSIC:
135 self.ui.set_status(["Classic Theme set", "Klassischer Modus aktiviert"])
136 case ETheme.SYSTEM:
137 self.ui.set_status(["System Default Theme set", "System Standard Modus aktiviert"])
138 case _:
139 self.ui.set_status(f"Invalid theme setting: {self.e_style}", True) # state not possible
140
141 def set_dialog_style(self, dialog: "DIALOG | MainWindow") -> None:
142 """!
143 @brief Set dialog theme style.
144 @param dialog : set style to this dialog
145 """
146 match self.e_actual_theme:
147 case ETheme.LIGHT:
148 config_window(dialog, style=get_style(dark_mode=False))
149 case ETheme.DARK:
150 config_window(dialog, style=get_style(dark_mode=True))
151 case ETheme.CLASSIC:
152 config_window(dialog, style=self.default_stylesheet)
153 case _:
154 self.ui.set_status(f"Invalid actual theme: {self.e_actual_theme}", True) # state not possible
155
156 def is_light_theme(self) -> bool:
157 """!
158 @brief get status for active light theme (or classic -> not dark).
159 @return status if theme is light
160 """
161 light_status = bool(self.e_actual_theme != ETheme.DARK)
162 return light_status
163
164 def update_icons(self) -> None:
165 """!
166 @brief Update icons to change between light and dark items depend on theme state.
167 """
168 b_light_theme = self.is_light_theme()
169 config_btn(self.ui.btn_lock, icon=ICON_LOCK_LIGHT if b_light_theme else ICON_LOCK_DARK)
170 config_menu(self.ui.action_show_interim, icon=ICON_STATUS_LIGHT if b_light_theme else ICON_STATUS_DARK)
171 config_menu(self.ui.action_open_folder, icon=ICON_OPEN_FOLDER_LIGHT if b_light_theme else ICON_OPEN_FOLDER_DARK)
172 config_menu(self.ui.menu_combine_report, icon=ICON_COMBINE_LIGHT if b_light_theme else ICON_COMBINE_DARK)
173 config_menu(self.ui.action_print_file, icon=ICON_PRINT_FILE_LIGHT if b_light_theme else ICON_PRINT_FILE_DARK)
174 config_menu(self.ui.action_create_billing, icon=ICON_REPORT_LIGHT if b_light_theme else ICON_REPORT_DARK)
175 config_menu(self.ui.action_article_preview, icon=ICON_PRINT_PREVIEW_LIGHT if b_light_theme else ICON_PRINT_PREVIEW_DARK)
176 config_menu(self.ui.menu_user, icon=ICON_USER_LIGHT if b_light_theme else ICON_USER_DARK)
177 config_menu(self.ui.action_user_edit, icon=ICON_USER_EDIT_LIGHT if b_light_theme else ICON_USER_EDIT_DARK)
178 config_menu(self.ui.action_user_import, icon=ICON_USER_IMPORT_LIGHT if b_light_theme else ICON_USER_IMPORT_DARK)
179 config_menu(self.ui.action_user_export, icon=ICON_USER_EXPORT_LIGHT if b_light_theme else ICON_USER_EXPORT_DARK)
180 config_menu(self.ui.action_user_new, icon=ICON_USER_RESET_LIGHT if b_light_theme else ICON_USER_RESET_DARK)
181 config_menu(self.ui.menu_articles, icon=ICON_ARTICLES_LIGHT if b_light_theme else ICON_ARTICLES_DARK)
182 config_menu(self.ui.action_articles_edit, icon=ICON_ARTICLES_EDIT_LIGHT if b_light_theme else ICON_ARTICLES_EDIT_DARK)
183 config_menu(self.ui.action_articles_import, icon=ICON_ARTICLES_IMPORT_LIGHT if b_light_theme else ICON_ARTICLES_IMPORT_DARK)
184 config_menu(self.ui.action_articles_export, icon=ICON_ARTICLES_EXPORT_LIGHT if b_light_theme else ICON_ARTICLES_EXPORT_DARK)
185 config_menu(self.ui.action_articles_new, icon=ICON_ARTICLES_RESET_LIGHT if b_light_theme else ICON_ARTICLES_RESET_DARK)
186 config_menu(self.ui.action_change_path, icon=ICON_CHANGE_FOLDER_LIGHT if b_light_theme else ICON_CHANGE_FOLDER_DARK)
187 config_menu(self.ui.menu_com_port, icon=ICON_PRINTER_LIGHT if b_light_theme else ICON_PRINTER_DARK)
188 config_menu(self.ui.menu_paper_width, icon=ICON_PAPER_LIGHT if b_light_theme else ICON_PAPER_DARK)
189 config_menu(self.ui.menu_style, icon=ICON_THEME_LIGHT if b_light_theme else ICON_THEME_DARK)
190 config_menu(self.ui.menu_language, icon=ICON_LANGUAGE_LIGHT if b_light_theme else ICON_LANGUAGE_DARK)
191 # TODO Icon nur einmalig setzen?
192 config_menu(self.ui.action_english, icon=ICON_LANGUAGE_ENGLISH)
193 config_menu(self.ui.action_german, icon=ICON_LANGUAGE_GERMAN)
194 config_menu(self.ui.menu_log_verbosity, icon=ICON_LOG_LIGHT if b_light_theme else ICON_LOG_DARK)
195 config_menu(self.ui.action_help, icon=ICON_HELP_LIGHT if b_light_theme else ICON_HELP_DARK)
196 config_menu(self.ui.action_about_app, icon=ICON_APP)
197 config_menu(self.ui.action_reset, icon=ICON_RESET_LIGHT if b_light_theme else ICON_RESET_DARK)
198
199 def get_font(self, s_item: str, ext_factor: Optional[float] = None, x_scale_factor: Optional[float] = None,
200 y_scale_factor: Optional[float] = None, font: str = S_DEFAULT_FONT) -> FONT:
201 """!
202 @brief Get font size depend of scale factor.
203 @param s_item : item in D_FONT_SIZE with specified font size
204 @param ext_factor : extended factor (for extended button view)
205 @param x_scale_factor : x scale factor
206 @param y_scale_factor : y scale factor
207 @param font : font
208 @return return font size
209 """
210 f_size = float(D_FONT_SIZE[s_item])
211 x_size = f_size if (x_scale_factor is None) else f_size * x_scale_factor
212 y_size = f_size if (y_scale_factor is None) else f_size * y_scale_factor
213 f_size = min(x_size, y_size)
214 if ext_factor is not None:
215 f_size *= ext_factor
216 if s_item == "total":
217 text = get_text(self.ui.text_total)
218 lines = text.split('\n')
219 line_count = len(lines)
220 f_size /= line_count
221 return create_font(font, int(f_size))
222
223 def resize_window(self, b_update_only_total_font: bool = False) -> None:
224 """!
225 @brief set position and size of items
226 @param b_update_only_total_font : status if update only text font size
227 """
228 i_actual_width, i_actual_height = get_window_size(self.ui)
229
230 if (i_actual_width >= I_DEFAULT_WIN_WIDTH) and (i_actual_height >= I_DEFAULT_WIN_HEIGHT):
231 if self.ui.model.c_auth.get_article_view_state():
232 item_number_size = self.ui.model.c_config.item_number_size # extended button view only in item mode with > 30
233 else:
234 item_number_size = ItemNumber.MIN
235 ext_factor = ITEM_NUMBER_COLUMN_MIN / D_ITEM_NUMBER_COLUMN[item_number_size]
236 x_scale_factor = i_actual_width / I_DEFAULT_WIN_WIDTH
237 y_scale_factor = i_actual_height / I_DEFAULT_WIN_HEIGHT
238 self.table_font = self.get_font("table", x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor) # save as global to use when update table
239
240 if b_update_only_total_font:
241 config_text(self.ui.text_total, font=self.get_font("total", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor)) # update only total font size
242 else:
243 # x position data
244 i_btn_row_cnt = D_ITEM_NUMBER_ROW[item_number_size]
245 table_width = (1 / 3) * i_actual_width
246 total_button_width = i_actual_width - table_width
247 x_single_button = int(total_button_width / i_btn_row_cnt)
248
249 # y position data
250 i_btn_column_cnt = D_ITEM_NUMBER_COLUMN[item_number_size]
251 total_button_high = i_actual_height - 85 # subtract size of status and menu bar
252 y_single_button = int(total_button_high / (i_btn_column_cnt + 1)) # +1 for lowest button row
253 y_order_gap = total_button_high - (y_single_button * (i_btn_column_cnt + 1))
254
255 # item buttons
256 i_row_idx = 0
257 for i, btn in enumerate(self.ui.l_bnt_fnc):
258 if i < item_number_size:
259 if i != 0:
260 if (i % i_btn_column_cnt) == 0:
261 i_row_idx += 1
262 i_column_idx = i % i_btn_column_cnt
263 x_pos = i_row_idx * x_single_button
264 y_pos = total_button_high - ((i_column_idx * y_single_button) + (2 * y_single_button) + y_order_gap)
265 config_btn(btn, size=(x_pos, y_pos, x_single_button, y_single_button),
266 font=self.get_font("articles_button", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor))
267
268 x_table = i_actual_width - (x_single_button * i_btn_row_cnt)
269 y_table = y_single_button * i_btn_column_cnt
270 y_single_button += y_order_gap
271 y_lowest_pos = total_button_high - y_single_button
272
273 # lock button
274 i_icon_size = int(min(D_FONT_SIZE["lock_button"] * x_scale_factor, D_FONT_SIZE["lock_button"] * y_scale_factor))
275 config_btn(self.ui.btn_lock, size=(0, y_lowest_pos, x_single_button, y_single_button), icon_size=i_icon_size,
276 icon=ICON_LOCK_LIGHT if self.is_light_theme() else ICON_LOCK_DARK) # TODO icon nur in TKINTER nötig
277 # multi button
278 config_btn(self.ui.btn_multi, size=(x_single_button, y_lowest_pos, x_single_button, y_single_button),
279 font=self.get_font("multi_button", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor))
280 # calc button
281 config_btn(self.ui.btn_calc, size=(2 * x_single_button, y_lowest_pos, x_single_button, y_single_button),
282 font=self.get_font("calc_button", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor))
283 # clear button
284 i_icon_size = int(min(D_FONT_SIZE["ec_button"] * x_scale_factor, D_FONT_SIZE["ec_button"] * y_scale_factor))
285 config_btn(self.ui.btn_clear, size=(3 * x_single_button, y_lowest_pos, x_single_button, y_single_button),
286 font=self.get_font("clear_button", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor), icon_size=i_icon_size)
287 # print button
288 x_start_print = i_btn_column_cnt
289 if item_number_size == ItemNumber.MAX:
290 x_start_print -= 3
291 i_print_width_factor = 4
292 elif item_number_size == ItemNumber.EXT:
293 x_start_print -= 2
294 i_print_width_factor = 3
295 else:
296 x_start_print -= 1
297 i_print_width_factor = 2
298 config_btn(self.ui.btn_print, size=(x_start_print * x_single_button, y_lowest_pos, i_print_width_factor * x_single_button, y_single_button),
299 font=self.get_font("print_button", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor))
300 # total text
301 config_text(self.ui.text_total, size=((i_btn_column_cnt + 1) * x_single_button, y_lowest_pos, x_table, y_single_button),
302 font=self.get_font("total", ext_factor=ext_factor, x_scale_factor=x_scale_factor, y_scale_factor=y_scale_factor))
303 # table
304 config_table(self.ui.table_items, row_description=self.ui.model.c_language.get_table_row_description(), font=self.table_font, auto_size=True,
305 size=((i_btn_column_cnt + 1) * x_single_button, 0, x_table, y_table),
306 min_section_size=int(D_FONT_SIZE["table_vertical"] * y_scale_factor))
Class to scale text and item positions.
Definition monitor.py:55
None resize_window(self, bool b_update_only_total_font=False)
set position and size of items
Definition monitor.py:223
FONT get_font(self, str s_item, Optional[float] ext_factor=None, Optional[float] x_scale_factor=None, Optional[float] y_scale_factor=None, str font=S_DEFAULT_FONT)
Get font size depend of scale factor.
Definition monitor.py:200
bool is_light_theme(self)
get status for active light theme (or classic -> not dark).
Definition monitor.py:156
None update_darkmode_status(self, ETheme e_style)
Update dark mode status.
Definition monitor.py:108
None check_for_style_change(self, Optional[ETheme] e_style=None)
Check for style change.
Definition monitor.py:83
None update_icons(self)
Update icons to change between light and dark items depend on theme state.
Definition monitor.py:164
None set_change_theme_status(self)
Set dialog theme style.
Definition monitor.py:123
None set_dialog_style(self, "DIALOG | MainWindow" dialog)
Set dialog theme style.
Definition monitor.py:141
None __init__(self, "MainWindow" ui)
Definition monitor.py:61