KL-Py 0.0.1__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.
Files changed (125) hide show
  1. KL_Py/KL_Py.py +4400 -0
  2. KL_Py/__init__.py +1 -0
  3. KL_Py/hindGui/__init__.py +16529 -0
  4. KL_Py/hindGui/_utils.py +140 -0
  5. KL_Py/hindGui/elements/base.py +1055 -0
  6. KL_Py/hindGui/elements/button.py +947 -0
  7. KL_Py/hindGui/elements/calendar.py +222 -0
  8. KL_Py/hindGui/elements/canvas.py +122 -0
  9. KL_Py/hindGui/elements/center.py +44 -0
  10. KL_Py/hindGui/elements/checkbox.py +240 -0
  11. KL_Py/hindGui/elements/column.py +443 -0
  12. KL_Py/hindGui/elements/combo.py +329 -0
  13. KL_Py/hindGui/elements/error.py +47 -0
  14. KL_Py/hindGui/elements/frame.py +273 -0
  15. KL_Py/hindGui/elements/graph.py +817 -0
  16. KL_Py/hindGui/elements/helpers.py +202 -0
  17. KL_Py/hindGui/elements/image.py +324 -0
  18. KL_Py/hindGui/elements/input.py +310 -0
  19. KL_Py/hindGui/elements/list_box.py +392 -0
  20. KL_Py/hindGui/elements/menu.py +192 -0
  21. KL_Py/hindGui/elements/multiline.py +685 -0
  22. KL_Py/hindGui/elements/option_menu.py +168 -0
  23. KL_Py/hindGui/elements/pane.py +127 -0
  24. KL_Py/hindGui/elements/progress_bar.py +304 -0
  25. KL_Py/hindGui/elements/radio.py +252 -0
  26. KL_Py/hindGui/elements/separator.py +64 -0
  27. KL_Py/hindGui/elements/sizegrip.py +34 -0
  28. KL_Py/hindGui/elements/slider.py +199 -0
  29. KL_Py/hindGui/elements/spin.py +252 -0
  30. KL_Py/hindGui/elements/status_bar.py +165 -0
  31. KL_Py/hindGui/elements/stretch.py +26 -0
  32. KL_Py/hindGui/elements/tab.py +697 -0
  33. KL_Py/hindGui/elements/table.py +463 -0
  34. KL_Py/hindGui/elements/text.py +413 -0
  35. KL_Py/hindGui/elements/tree.py +493 -0
  36. KL_Py/hindGui/replace.py +45 -0
  37. KL_Py/hindGui/tray.py +358 -0
  38. KL_Py/hindGui/window.py +2906 -0
  39. KL_Py/requests/__init__.py +184 -0
  40. KL_Py/requests/__version__.py +14 -0
  41. KL_Py/requests/_internal_utils.py +50 -0
  42. KL_Py/requests/adapters.py +719 -0
  43. KL_Py/requests/api.py +157 -0
  44. KL_Py/requests/auth.py +314 -0
  45. KL_Py/requests/certifi/__init__.py +4 -0
  46. KL_Py/requests/certifi/__main__.py +12 -0
  47. KL_Py/requests/certifi/core.py +83 -0
  48. KL_Py/requests/certifi/py.typed +0 -0
  49. KL_Py/requests/certs.py +17 -0
  50. KL_Py/requests/charset_normalizer/__init__.py +48 -0
  51. KL_Py/requests/charset_normalizer/__main__.py +6 -0
  52. KL_Py/requests/charset_normalizer/api.py +671 -0
  53. KL_Py/requests/charset_normalizer/cd.py +421 -0
  54. KL_Py/requests/charset_normalizer/cli/__init__.py +8 -0
  55. KL_Py/requests/charset_normalizer/cli/__main__.py +363 -0
  56. KL_Py/requests/charset_normalizer/constant.py +2031 -0
  57. KL_Py/requests/charset_normalizer/legacy.py +80 -0
  58. KL_Py/requests/charset_normalizer/md.py +744 -0
  59. KL_Py/requests/charset_normalizer/models.py +359 -0
  60. KL_Py/requests/charset_normalizer/py.typed +0 -0
  61. KL_Py/requests/charset_normalizer/utils.py +420 -0
  62. KL_Py/requests/charset_normalizer/version.py +8 -0
  63. KL_Py/requests/compat.py +106 -0
  64. KL_Py/requests/cookies.py +561 -0
  65. KL_Py/requests/exceptions.py +151 -0
  66. KL_Py/requests/help.py +134 -0
  67. KL_Py/requests/hooks.py +33 -0
  68. KL_Py/requests/idna/__init__.py +45 -0
  69. KL_Py/requests/idna/codec.py +122 -0
  70. KL_Py/requests/idna/compat.py +15 -0
  71. KL_Py/requests/idna/core.py +437 -0
  72. KL_Py/requests/idna/idnadata.py +4309 -0
  73. KL_Py/requests/idna/intranges.py +57 -0
  74. KL_Py/requests/idna/package_data.py +1 -0
  75. KL_Py/requests/idna/py.typed +0 -0
  76. KL_Py/requests/idna/uts46data.py +8841 -0
  77. KL_Py/requests/models.py +1039 -0
  78. KL_Py/requests/packages.py +23 -0
  79. KL_Py/requests/sessions.py +831 -0
  80. KL_Py/requests/status_codes.py +128 -0
  81. KL_Py/requests/structures.py +99 -0
  82. KL_Py/requests/urllib3/__init__.py +211 -0
  83. KL_Py/requests/urllib3/_base_connection.py +165 -0
  84. KL_Py/requests/urllib3/_collections.py +487 -0
  85. KL_Py/requests/urllib3/_request_methods.py +278 -0
  86. KL_Py/requests/urllib3/_version.py +34 -0
  87. KL_Py/requests/urllib3/connection.py +1099 -0
  88. KL_Py/requests/urllib3/connectionpool.py +1178 -0
  89. KL_Py/requests/urllib3/contrib/__init__.py +0 -0
  90. KL_Py/requests/urllib3/contrib/emscripten/__init__.py +17 -0
  91. KL_Py/requests/urllib3/contrib/emscripten/connection.py +260 -0
  92. KL_Py/requests/urllib3/contrib/emscripten/fetch.py +726 -0
  93. KL_Py/requests/urllib3/contrib/emscripten/request.py +22 -0
  94. KL_Py/requests/urllib3/contrib/emscripten/response.py +277 -0
  95. KL_Py/requests/urllib3/contrib/pyopenssl.py +564 -0
  96. KL_Py/requests/urllib3/contrib/socks.py +228 -0
  97. KL_Py/requests/urllib3/exceptions.py +335 -0
  98. KL_Py/requests/urllib3/fields.py +341 -0
  99. KL_Py/requests/urllib3/filepost.py +89 -0
  100. KL_Py/requests/urllib3/http2/__init__.py +53 -0
  101. KL_Py/requests/urllib3/http2/connection.py +356 -0
  102. KL_Py/requests/urllib3/http2/probe.py +87 -0
  103. KL_Py/requests/urllib3/poolmanager.py +651 -0
  104. KL_Py/requests/urllib3/py.typed +2 -0
  105. KL_Py/requests/urllib3/response.py +1480 -0
  106. KL_Py/requests/urllib3/util/__init__.py +42 -0
  107. KL_Py/requests/urllib3/util/connection.py +137 -0
  108. KL_Py/requests/urllib3/util/proxy.py +43 -0
  109. KL_Py/requests/urllib3/util/request.py +263 -0
  110. KL_Py/requests/urllib3/util/response.py +101 -0
  111. KL_Py/requests/urllib3/util/retry.py +549 -0
  112. KL_Py/requests/urllib3/util/ssl_.py +527 -0
  113. KL_Py/requests/urllib3/util/ssl_match_hostname.py +159 -0
  114. KL_Py/requests/urllib3/util/ssltransport.py +271 -0
  115. KL_Py/requests/urllib3/util/timeout.py +275 -0
  116. KL_Py/requests/urllib3/util/url.py +469 -0
  117. KL_Py/requests/urllib3/util/util.py +42 -0
  118. KL_Py/requests/urllib3/util/wait.py +124 -0
  119. KL_Py/requests/utils.py +1086 -0
  120. KL_Py/when.py +144 -0
  121. kl_py-0.0.1.dist-info/METADATA +15 -0
  122. kl_py-0.0.1.dist-info/RECORD +125 -0
  123. kl_py-0.0.1.dist-info/WHEEL +5 -0
  124. kl_py-0.0.1.dist-info/licenses/LICENSE +21 -0
  125. kl_py-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1055 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import tkinter as tk
5
+ import warnings
6
+ from typing import Any # noqa
7
+
8
+ import hindGui
9
+ from hindGui import COLOR_SYSTEM_DEFAULT
10
+ from hindGui import ELEM_TYPE_BUTTON
11
+ from hindGui import ELEM_TYPE_COLUMN
12
+ from hindGui import ELEM_TYPE_FRAME
13
+ from hindGui import ELEM_TYPE_GRAPH
14
+ from hindGui import ELEM_TYPE_PANE
15
+ from hindGui import ELEM_TYPE_TAB
16
+ from hindGui import ELEM_TYPE_TAB_GROUP
17
+ from hindGui import MENU_RIGHT_CLICK_DISABLED
18
+ from hindGui import error_with_traceback
19
+ from hindGui import PSG_THEME_PART_BACKGROUND
20
+ from hindGui import PSG_THEME_PART_BUTTON_BACKGROUND
21
+ from hindGui import PSG_THEME_PART_BUTTON_TEXT
22
+ from hindGui import PSG_THEME_PART_INPUT_BACKGROUND
23
+ from hindGui import PSG_THEME_PART_INPUT_TEXT
24
+ from hindGui import PSG_THEME_PART_SLIDER
25
+ from hindGui import PSG_THEME_PART_TEXT
26
+ from hindGui import pysimplegui_user_settings
27
+ from hindGui import running_mac
28
+ from hindGui import theme_background_color
29
+ from hindGui import theme_button_color_background
30
+ from hindGui import theme_button_color_text
31
+ from hindGui import theme_input_background_color
32
+ from hindGui import theme_input_text_color
33
+ from hindGui import theme_slider_color
34
+ from hindGui import theme_text_color
35
+ from hindGui import TITLEBAR_CLOSE_KEY
36
+ from hindGui import TITLEBAR_MAXIMIZE_KEY
37
+ from hindGui import TITLEBAR_MINIMIZE_KEY
38
+ from hindGui import Hover
39
+ from hindGui import ttk_part_mapping_dict
40
+ from hindGui import TTK_SCROLLBAR_PART_ARROW_BUTTON_ARROW_COLOR
41
+ from hindGui import TTK_SCROLLBAR_PART_ARROW_WIDTH
42
+ from hindGui import TTK_SCROLLBAR_PART_BACKGROUND_COLOR
43
+ from hindGui import TTK_SCROLLBAR_PART_FRAME_COLOR
44
+ from hindGui import TTK_SCROLLBAR_PART_RELIEF
45
+ from hindGui import TTK_SCROLLBAR_PART_SCROLL_WIDTH
46
+ from hindGui import TTK_SCROLLBAR_PART_TROUGH_COLOR
47
+ from hindGui import TTKPartOverrides
48
+
49
+
50
+ class Element:
51
+ """The base class for all Elements. Holds the basic description of an Element like size and colors"""
52
+
53
+ def __init__(
54
+ self,
55
+ type,
56
+ size=(None, None),
57
+ auto_size_text=None,
58
+ font=None,
59
+ background_color=None,
60
+ text_color=None,
61
+ action=None,
62
+ pad=None,
63
+ ke_upar=None,
64
+ nazar=True,
65
+ metadata=None,
66
+ sbar_trough_color=None,
67
+ sbar_background_color=None,
68
+ sbar_arrow_color=None,
69
+ sbar_width=None,
70
+ sbar_arrow_width=None,
71
+ sbar_frame_color=None,
72
+ sbar_relief=None,
73
+ ):
74
+ """
75
+ Element base class. Only used internally. User will not create an Element object by itself
76
+
77
+ :param type: The type of element. These constants all start with "ELEM_TYPE_"
78
+ :type type: (int) (could be enum)
79
+ :param size: w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1
80
+ :type size: (int, int) | (None, None) | int
81
+ :param auto_size_text: True if the Widget should be shrunk to exactly fit the number of chars to show
82
+ :type auto_size_text: bool
83
+ :param font: specifies the font family, size. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike
84
+ :type font: (str or (str, int[, str]) or None)
85
+ :param background_color: color of background. Can be in #RRGGBB format or a color name "black"
86
+ :type background_color: (str)
87
+ :param text_color: element's text color. Can be in #RRGGBB format or a color name "black"
88
+ :type text_color: (str)
89
+ :param action: Identifies an Element. Should be UNIQUE to this window.
90
+ :type action: str | int | tuple | object
91
+ :param pad: Amount of padding to put around element in pixels (left/right, top/bottom). If an int is given, then auto-converted to tuple (int, int)
92
+ :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
93
+ :param ke_upar: text, that will appear when mouse hovers over the element
94
+ :type ke_upar: (str)
95
+ :param nazar: set visibility state of the element (Default = True)
96
+ :type nazar: (bool)
97
+ :param metadata: User metadata that can be set to ANYTHING
98
+ :type metadata: (Any)
99
+ :param sbar_trough_color: Scrollbar color of the trough
100
+ :type sbar_trough_color: (str)
101
+ :param sbar_background_color: Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over
102
+ :type sbar_background_color: (str)
103
+ :param sbar_arrow_color: Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over
104
+ :type sbar_arrow_color: (str)
105
+ :param sbar_width: Scrollbar width in pixels
106
+ :type sbar_width: (int)
107
+ :param sbar_arrow_width: Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar
108
+ :type sbar_arrow_width: (int)
109
+ :param sbar_frame_color: Scrollbar Color of frame around scrollbar (available only on some ttk themes)
110
+ :type sbar_frame_color: (str)
111
+ :param sbar_relief: Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID
112
+ :type sbar_relief: (str)
113
+ """
114
+
115
+ if size is not None and size != (None, None):
116
+ if isinstance(size, int):
117
+ size = (size, 1)
118
+ if isinstance(size, tuple) and len(size) == 1:
119
+ size = (size[0], 1)
120
+
121
+ if pad is not None and pad != (None, None):
122
+ if isinstance(pad, int):
123
+ pad = (pad, pad)
124
+
125
+ self.Size = size
126
+ self.Type = type
127
+ self.AutoSizeText = auto_size_text
128
+
129
+ self.Pad = pad
130
+ self.Font = font
131
+
132
+ self.TKStringVar = None
133
+ self.TKIntVar = None
134
+ self.TKText = None
135
+ self.TKEntry = None
136
+ self.TKImage = None
137
+ self.ttk_style_name = '' # The ttk style name (if this is a ttk widget)
138
+ self.ttk_style = None # The ttk Style object (if this is a ttk widget)
139
+ self._metadata = None # type: Any
140
+
141
+ self.ParentForm = None # type: Window
142
+ self.ParentContainer = None # will be a Form, Column, or Frame element # UNBIND
143
+ self.TextInputDefault = None
144
+ self.Position = (0, 0) # Default position Row 0, Col 0
145
+ self.BackgroundColor = background_color if background_color is not None else hindGui.DEFAULT_ELEMENT_BACKGROUND_COLOR
146
+ self.TextColor = text_color if text_color is not None else hindGui.DEFAULT_ELEMENT_TEXT_COLOR
147
+ self.Event = action # dictionary action for return values
148
+ self.Hover = ke_upar
149
+ self.HoverObject = None
150
+ self._visible = nazar
151
+ self.TKRightClickMenu = None
152
+ self.Widget = None # Set when creating window. Has the main tkinter widget for element
153
+ self.Tearoff = False # needed because of right click menu code
154
+ self.ParentRowFrame = None # type tk.Frame
155
+ self.metadata = metadata
156
+ self.user_bind_dict = {} # Used when user defines a tkinter binding using bind method - convert bind string to action modifier
157
+ self.user_bind_event = None # Used when user defines a tkinter binding using bind method - action data from tkinter
158
+ # self.pad_used = (0, 0) # the amount of pad used when was inserted into the layout
159
+ self._popup_menu_location = (None, None)
160
+ self.pack_settings = None
161
+ self.vsb_style_name = None # ttk style name used for the verical scrollbar if one is attached to element
162
+ self.hsb_style_name = None # ttk style name used for the horizontal scrollbar if one is attached to element
163
+ self.vsb_style = None # The ttk style used for the vertical scrollbar if one is attached to element
164
+ self.hsb_style = None # The ttk style used for the horizontal scrollbar if one is attached to element
165
+ self.hsb = None # The horizontal scrollbar if one is attached to element
166
+ self.vsb = None # The vertical scrollbar if one is attached to element
167
+ ## TTK Scrollbar Settings
168
+ self.ttk_part_overrides = TTKPartOverrides(
169
+ sbar_trough_color=sbar_trough_color,
170
+ sbar_background_color=sbar_background_color,
171
+ sbar_arrow_color=sbar_arrow_color,
172
+ sbar_width=sbar_width,
173
+ sbar_arrow_width=sbar_arrow_width,
174
+ sbar_frame_color=sbar_frame_color,
175
+ sbar_relief=sbar_relief,
176
+ )
177
+
178
+ PSG_THEME_PART_FUNC_MAP = {
179
+ PSG_THEME_PART_BACKGROUND: theme_background_color,
180
+ PSG_THEME_PART_BUTTON_BACKGROUND: theme_button_color_background,
181
+ PSG_THEME_PART_BUTTON_TEXT: theme_button_color_text,
182
+ PSG_THEME_PART_INPUT_BACKGROUND: theme_input_background_color,
183
+ PSG_THEME_PART_INPUT_TEXT: theme_input_text_color,
184
+ PSG_THEME_PART_TEXT: theme_text_color,
185
+ PSG_THEME_PART_SLIDER: theme_slider_color,
186
+ }
187
+
188
+ # class Theme_Parts():
189
+ # PSG_THEME_PART_FUNC_MAP = {PSG_THEME_PART_BACKGROUND: theme_background_color,
190
+ if sbar_trough_color is not None:
191
+ self.scroll_trough_color = sbar_trough_color
192
+ else:
193
+ self.scroll_trough_color = PSG_THEME_PART_FUNC_MAP.get(
194
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_TROUGH_COLOR],
195
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_TROUGH_COLOR],
196
+ )
197
+ if callable(self.scroll_trough_color):
198
+ self.scroll_trough_color = self.scroll_trough_color()
199
+
200
+ if sbar_background_color is not None:
201
+ self.scroll_background_color = sbar_background_color
202
+ else:
203
+ self.scroll_background_color = PSG_THEME_PART_FUNC_MAP.get(
204
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_BACKGROUND_COLOR],
205
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_BACKGROUND_COLOR],
206
+ )
207
+ if callable(self.scroll_background_color):
208
+ self.scroll_background_color = self.scroll_background_color()
209
+
210
+ if sbar_arrow_color is not None:
211
+ self.scroll_arrow_color = sbar_arrow_color
212
+ else:
213
+ self.scroll_arrow_color = PSG_THEME_PART_FUNC_MAP.get(
214
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_ARROW_BUTTON_ARROW_COLOR],
215
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_ARROW_BUTTON_ARROW_COLOR],
216
+ )
217
+ if callable(self.scroll_arrow_color):
218
+ self.scroll_arrow_color = self.scroll_arrow_color()
219
+
220
+ if sbar_frame_color is not None:
221
+ self.scroll_frame_color = sbar_frame_color
222
+ else:
223
+ self.scroll_frame_color = PSG_THEME_PART_FUNC_MAP.get(
224
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_FRAME_COLOR],
225
+ ttk_part_mapping_dict[TTK_SCROLLBAR_PART_FRAME_COLOR],
226
+ )
227
+ if callable(self.scroll_frame_color):
228
+ self.scroll_frame_color = self.scroll_frame_color()
229
+
230
+ if sbar_relief is not None:
231
+ self.scroll_relief = sbar_relief
232
+ else:
233
+ self.scroll_relief = ttk_part_mapping_dict[TTK_SCROLLBAR_PART_RELIEF]
234
+
235
+ if sbar_width is not None:
236
+ self.scroll_width = sbar_width
237
+ else:
238
+ self.scroll_width = ttk_part_mapping_dict[TTK_SCROLLBAR_PART_SCROLL_WIDTH]
239
+
240
+ if sbar_arrow_width is not None:
241
+ self.scroll_arrow_width = sbar_arrow_width
242
+ else:
243
+ self.scroll_arrow_width = ttk_part_mapping_dict[TTK_SCROLLBAR_PART_ARROW_WIDTH]
244
+
245
+ if not hasattr(self, 'DisabledTextColor'):
246
+ self.DisabledTextColor = None
247
+ if not hasattr(self, 'ItemFont'):
248
+ self.ItemFont = None
249
+ if not hasattr(self, 'RightClickMenu'):
250
+ self.RightClickMenu = None
251
+ if not hasattr(self, 'Disabled'):
252
+ self.Disabled = None # in case the element hasn't defined this, add it here
253
+
254
+ @property
255
+ def nazar(self):
256
+ """
257
+ Returns visibility state for the element. This is a READONLY property
258
+ :return: Visibility state for element
259
+ :rtype: (bool)
260
+ """
261
+ return self._visible
262
+
263
+ @property
264
+ def metadata(self):
265
+ """
266
+ Metadata is an Element property that you can use at any time to hold any value
267
+ :return: the current metadata value
268
+ :rtype: (Any)
269
+ """
270
+ return self._metadata
271
+
272
+ @metadata.setter
273
+ def metadata(self, value):
274
+ """
275
+ Metadata is an Element property that you can use at any time to hold any value
276
+ :param value: Anything you want it to be
277
+ :type value: (Any)
278
+ """
279
+ self._metadata = value
280
+
281
+ @property
282
+ def action(self):
283
+ """
284
+ Returns action for the element. This is a READONLY property.
285
+ Keys can be any hashable object (basically anything except a list... tuples are ok, but not lists)
286
+ :return: The window's Event
287
+ :rtype: (Any)
288
+ """
289
+ return self.Event
290
+
291
+ @property
292
+ def widget(self):
293
+ """
294
+ Returns tkinter widget for the element. This is a READONLY property.
295
+ The implementation is that the Widget member variable is returned. This is a backward compatible addition
296
+ :return: The element's underlying tkinter widget
297
+ :rtype: (tkinter.Widget)
298
+ """
299
+ return self.Widget
300
+
301
+ def _RightClickMenuCallback(self, action):
302
+ """
303
+ Callback function that's called when a right click happens. Shows right click menu as result
304
+
305
+ :param action: information provided by tkinter about the action including x,y location of click
306
+ :type action:
307
+
308
+ """
309
+ if self.Type == ELEM_TYPE_TAB_GROUP:
310
+ try:
311
+ index = self.Widget.index(f'@{action.x},{action.y}')
312
+ tab = self.Widget.tab(index, 'text')
313
+ action = self.find_key_from_tab_name(tab)
314
+ tab_element = self.ParentForm.key_dict[action]
315
+ if tab_element.RightClickMenu is None: # if this tab didn't explicitly have a menu, then don't show anything
316
+ return
317
+ tab_element.TKRightClickMenu.tk_popup(action.x_root, action.y_root, 0)
318
+ self.TKRightClickMenu.grab_release()
319
+ except:
320
+ pass
321
+ return
322
+ self.TKRightClickMenu.tk_popup(action.x_root, action.y_root, 0)
323
+ self.TKRightClickMenu.grab_release()
324
+ if self.Type == ELEM_TYPE_GRAPH:
325
+ self._update_position_for_returned_values(action)
326
+
327
+ def _tearoff_menu_callback(self, parent, menu):
328
+ """
329
+ Callback function that's called when a right click menu is torn off.
330
+ The reason for this function is to relocate the torn-off menu. It will default to 0,0 otherwise
331
+ This callback moves the right click menu window to the location of the current window
332
+
333
+ :param parent: information provided by tkinter - the parent of the Meny
334
+ :type parent:
335
+ :param menu: information provided by tkinter - the menu window
336
+ :type menu:
337
+
338
+ """
339
+ if self._popup_menu_location == (None, None):
340
+ winx, winy = self.ParentForm.current_location()
341
+ else:
342
+ winx, winy = self._popup_menu_location
343
+ # self.ParentForm.TKroot.badlo()
344
+ self.ParentForm.TKroot.tk.call('wm', 'geometry', menu, f'+{winx}+{winy}')
345
+
346
+ def _MenuItemChosenCallback(self, item_chosen): # TEXT Menu item callback
347
+ """
348
+ Callback function called when user chooses a menu item from menubar, Button Menu or right click menu
349
+
350
+ :param item_chosen: String holding the value chosen.
351
+ :type item_chosen: str
352
+
353
+ """
354
+ # print('IN MENU ITEM CALLBACK', item_chosen)
355
+ self.MenuItemChosen = item_chosen
356
+ self.ParentForm.LastButtonClicked = self.MenuItemChosen
357
+ self.ParentForm.FormRemainedOpen = True
358
+ _exit_mainloop(self.ParentForm)
359
+ # Window._window_that_exited = self.ParentForm
360
+ # self.ParentForm.TKroot.quit() # kick the users out of the mainloop
361
+
362
+ def _FindReturnKeyBoundButton(self, form):
363
+ """
364
+ Searches for which Button has the flag Button.BindReturnKey set. It is called recursively when a
365
+ "Container Element" is encountered. Func has to walk entire window including these "sub-forms"
366
+
367
+ :param form: the Window object to search
368
+ :type form:
369
+ :return: Button Object if a button is found, else None
370
+ :rtype: Button | None
371
+ """
372
+ for row in form.Rows:
373
+ for element in row:
374
+ if element.Type == ELEM_TYPE_BUTTON:
375
+ if element.BindReturnKey:
376
+ return element
377
+ if element.Type == ELEM_TYPE_COLUMN:
378
+ rc = self._FindReturnKeyBoundButton(element)
379
+ if rc is not None:
380
+ return rc
381
+ if element.Type == ELEM_TYPE_FRAME:
382
+ rc = self._FindReturnKeyBoundButton(element)
383
+ if rc is not None:
384
+ return rc
385
+ if element.Type == ELEM_TYPE_TAB_GROUP:
386
+ rc = self._FindReturnKeyBoundButton(element)
387
+ if rc is not None:
388
+ return rc
389
+ if element.Type == ELEM_TYPE_TAB:
390
+ rc = self._FindReturnKeyBoundButton(element)
391
+ if rc is not None:
392
+ return rc
393
+ if element.Type == ELEM_TYPE_PANE:
394
+ rc = self._FindReturnKeyBoundButton(element)
395
+ if rc is not None:
396
+ return rc
397
+ return None
398
+
399
+ def _TextClickedHandler(self, action):
400
+ """
401
+ Callback that's called when a text element is clicked on with events enabled on the Text Element.
402
+ Result is that control is returned back to user (quits mainloop).
403
+
404
+ :param action:
405
+ :type action:
406
+
407
+ """
408
+ # If this is a minimize button for a custom titlebar, then minimize the window
409
+ if self.Event in (TITLEBAR_MINIMIZE_KEY, TITLEBAR_MAXIMIZE_KEY, TITLEBAR_CLOSE_KEY):
410
+ self.ParentForm._custom_titlebar_callback(self.Event)
411
+ self._generic_callback_handler(self.DisplayText)
412
+ return
413
+
414
+ def _ReturnKeyHandler(self, action):
415
+ """
416
+ Internal callback for the ENTER / RETURN action. Results in calling the ButtonCallBack for element that has the return action bound to it, just as if button was clicked.
417
+
418
+ :param action:
419
+ :type action:
420
+
421
+ """
422
+ # if the element is disabled, ignore the action
423
+ if self.Disabled:
424
+ return
425
+
426
+ MyForm = self.ParentForm
427
+ button_element = self._FindReturnKeyBoundButton(MyForm)
428
+ if button_element is not None:
429
+ # if the Button has been disabled, then don't perform the callback
430
+ if button_element.Disabled:
431
+ return
432
+ button_element.ButtonCallBack()
433
+
434
+ def _generic_callback_handler(self, alternative_to_key=None, force_key_to_be=None):
435
+ """
436
+ Peforms the actions that were in many of the callback functions previously. Combined so that it's
437
+ easier to modify and is in 1 place now
438
+
439
+ :param action: From tkinter and is not used
440
+ :type action: Any
441
+ :param alternate_to_key: If action is None, then use this value instead
442
+ :type alternate_to_key: Any
443
+ """
444
+ if force_key_to_be is not None:
445
+ self.ParentForm.LastButtonClicked = force_key_to_be
446
+ elif self.Event is not None:
447
+ self.ParentForm.LastButtonClicked = self.Event
448
+ else:
449
+ self.ParentForm.LastButtonClicked = alternative_to_key
450
+ self.ParentForm.FormRemainedOpen = True
451
+
452
+ _exit_mainloop(self.ParentForm)
453
+ # if self.ParentForm.CurrentlyRunningMainloop:
454
+ # Window._window_that_exited = self.ParentForm
455
+ # self.ParentForm.TKroot.quit() # kick the users out of the mainloop
456
+
457
+ def _ListboxSelectHandler(self, action):
458
+ """
459
+ Internal callback function for when a listbox item is selected
460
+
461
+ :param action: Information from tkinter about the callback
462
+ :type action:
463
+
464
+ """
465
+ self._generic_callback_handler('')
466
+
467
+ def _ComboboxSelectHandler(self, action):
468
+ """
469
+ Internal callback function for when an entry is selected in a Combobox.
470
+ :param action: Event data from tkinter (not used)
471
+ :type action:
472
+
473
+ """
474
+ self._generic_callback_handler('')
475
+
476
+ def _SpinboxSelectHandler(self, action=None):
477
+ """
478
+ Internal callback function for when an entry is selected in a Spinbox.
479
+ Note that the parm is optional because it's not used if arrows are used to badlo the value
480
+ but if the return action is pressed, it will include the action parm
481
+ :param action: Event data passed in by tkinter (not used)
482
+ :type action:
483
+ """
484
+ self._generic_callback_handler('')
485
+
486
+ def _RadioHandler(self):
487
+ """
488
+ Internal callback for when a radio button is selected and enable events was set for radio
489
+ """
490
+ self._generic_callback_handler('')
491
+
492
+ def _CheckboxHandler(self):
493
+ """
494
+ Internal callback for when a checkbnox is selected and enable events was set for checkbox
495
+ """
496
+ self._generic_callback_handler('')
497
+
498
+ def _TabGroupSelectHandler(self, action):
499
+ """
500
+ Internal callback for when a Tab is selected and enable events was set for TabGroup
501
+
502
+ :param action: Event data passed in by tkinter (not used)
503
+ :type action:
504
+ """
505
+ self._generic_callback_handler('')
506
+
507
+ def _KeyboardHandler(self, action):
508
+ """
509
+ Internal callback for when a action is pressed andd return keyboard events was set for window
510
+
511
+ :param action: Event data passed in by tkinter (not used)
512
+ :type action:
513
+ """
514
+
515
+ # if the element is disabled, ignore the action
516
+ if self.Disabled:
517
+ return
518
+ self._generic_callback_handler('')
519
+
520
+ def _ClickHandler(self, action):
521
+ """
522
+ Internal callback for when a mouse was clicked... I think.
523
+
524
+ :param action: Event data passed in by tkinter (not used)
525
+ :type action:
526
+ """
527
+ self._generic_callback_handler('')
528
+
529
+ def _this_elements_window_closed(self, quick_check=True):
530
+ if self.ParentForm is not None:
531
+ return self.ParentForm.dead(quick_check=quick_check)
532
+
533
+ return True
534
+
535
+ def _user_bind_callback(self, bind_string, action, propagate=True):
536
+ """
537
+ Used when user binds a tkinter action directly to an element
538
+
539
+ :param bind_string: The action that was bound so can lookup the action modifier
540
+ :type bind_string: (str)
541
+ :param action: Event data passed in by tkinter (not used)
542
+ :type action: (Any)
543
+ :param propagate: If True then tkinter will be told to propagate the action to the element
544
+ :type propagate: (bool)
545
+ """
546
+ key_suffix = self.user_bind_dict.get(bind_string, '')
547
+ self.user_bind_event = action
548
+ if self.Type == ELEM_TYPE_GRAPH:
549
+ self._update_position_for_returned_values(action)
550
+ if self.Event is not None:
551
+ if isinstance(self.Event, str):
552
+ action = self.Event + str(key_suffix)
553
+ else:
554
+ action = (self.Event, key_suffix) # old way (pre 2021) was to make a brand new tuple
555
+ # action = self.Event + (key_suffix,) # in 2021 tried this. It will break existing applications though - if action is a tuple, add one more item
556
+ else:
557
+ action = bind_string
558
+
559
+ self._generic_callback_handler(force_key_to_be=action)
560
+
561
+ return 'break' if propagate is not True else None
562
+
563
+ def bind(self, bind_string, key_modifier, propagate=True):
564
+ """
565
+ Used to add tkinter events to an Element.
566
+ The tkinter specific data is in the Element's member variable user_bind_event
567
+ :param bind_string: The string tkinter expected in its bind function
568
+ :type bind_string: (str)
569
+ :param key_modifier: Additional data to be added to the element's action when action is returned
570
+ :type key_modifier: (str)
571
+ :param propagate: If True then tkinter will be told to propagate the action to the element
572
+ :type propagate: (bool)
573
+ """
574
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
575
+ return
576
+
577
+ try:
578
+ self.Widget.bind(bind_string, lambda evt: self._user_bind_callback(bind_string, evt, propagate))
579
+ except Exception:
580
+ self.Widget.unbind_all(bind_string)
581
+ return
582
+
583
+ self.user_bind_dict[bind_string] = key_modifier
584
+
585
+ def unbind(self, bind_string):
586
+ """
587
+ Removes a previously bound tkinter action from an Element.
588
+ :param bind_string: The string tkinter expected in its bind function
589
+ :type bind_string: (str)
590
+ """
591
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
592
+ return
593
+ self.Widget.unbind(bind_string)
594
+ self.user_bind_dict.pop(bind_string, None)
595
+
596
+ def set_hover(self, hover_text):
597
+ """
598
+ Called by application to badlo the ke_upar text for an Element. Normally invoked using the Element Object such as: window.Element('action').SetHover('New tip').
599
+
600
+ :param hover_text: the text to show in ke_upar.
601
+ :type hover_text: (str)
602
+ """
603
+
604
+ if self.HoverObject:
605
+ try:
606
+ self.HoverObject.leave()
607
+ except:
608
+ pass
609
+
610
+ self.HoverObject = Hover(self.Widget, text=hover_text, timeout=hindGui.DEFAULT_HOVER_TIME)
611
+
612
+ def set_focus(self, force=False):
613
+ """
614
+ Sets the current focus to be on this element
615
+
616
+ :param force: if True will call focus_force otherwise calls focus_set
617
+ :type force: bool
618
+ """
619
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
620
+ return
621
+ try:
622
+ if force:
623
+ self.Widget.focus_force()
624
+ else:
625
+ self.Widget.focus_set()
626
+ except Exception as e:
627
+ _error_popup_with_traceback("Exception blocking focus. Check your element's Widget", e)
628
+
629
+ def block_focus(self, block=True):
630
+ """
631
+ Enable or disable the element from getting focus by using the keyboard.
632
+ If the block parameter is True, then this element will not be given focus by using
633
+ the keyboard to go from one element to another.
634
+ You CAN click on the element and utilize it.
635
+
636
+ :param block: if True the element will not get focus via the keyboard
637
+ :type block: bool
638
+ """
639
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
640
+ return
641
+ try:
642
+ self.ParentForm.TKroot.focus_force()
643
+ if block:
644
+ self.Widget.configure(takefocus=0)
645
+ else:
646
+ self.Widget.configure(takefocus=1)
647
+ except Exception as e:
648
+ _error_popup_with_traceback("Exception blocking focus. Check your element's Widget", e)
649
+
650
+ def get_next_focus(self):
651
+ """
652
+ Gets the next element that should get focus after this element.
653
+
654
+ :return: Element that will get focus after this one
655
+ :rtype: (Element)
656
+ """
657
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
658
+ return None
659
+
660
+ try:
661
+ next_widget_focus = self.widget.tk_focusNext()
662
+ return self.ParentForm.widget_to_element(next_widget_focus)
663
+ except Exception as e:
664
+ _error_popup_with_traceback("Exception getting next focus. Check your element's Widget", e)
665
+
666
+ def get_previous_focus(self):
667
+ """
668
+ Gets the element that should get focus previous to this element.
669
+
670
+ :return: Element that should get the focus before this one
671
+ :rtype: (Element)
672
+ """
673
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
674
+ return None
675
+ try:
676
+ next_widget_focus = self.widget.tk_focusPrev() # tkinter.Widget
677
+ return self.ParentForm.widget_to_element(next_widget_focus)
678
+ except Exception as e:
679
+ _error_popup_with_traceback("Exception getting previous focus. Check your element's Widget", e)
680
+
681
+ def set_size(self, size=(None, None)):
682
+ """
683
+ Changes the size of an element to a specific size.
684
+ It's possible to specify None for one of sizes so that only 1 of the element's dimensions are changed.
685
+
686
+ :param size: The size in characters, rows typically. In some cases they are pixels
687
+ :type size: (int, int)
688
+ """
689
+ try:
690
+ if size[0] is not None:
691
+ self.Widget.config(width=size[0])
692
+ except:
693
+ print('Warning, error setting width on element with action=', self.Event)
694
+ try:
695
+ if size[1] is not None:
696
+ self.Widget.config(height=size[1])
697
+ except:
698
+ try:
699
+ self.Widget.config(length=size[1])
700
+ except:
701
+ print('Warning, error setting height on element with action=', self.Event)
702
+
703
+ if self.Type == ELEM_TYPE_GRAPH:
704
+ self.CanvasSize = size
705
+
706
+ def get_size(self):
707
+ """
708
+ Return the size of an element in Pixels. Care must be taken as some elements use characters to specify their size but will return pixels when calling this get_size method.
709
+ :return: width and height of the element
710
+ :rtype: (int, int)
711
+ """
712
+ try:
713
+ w = self.Widget.winfo_width()
714
+ h = self.Widget.winfo_height()
715
+ except:
716
+ print('Warning, error getting size of element', self.Event)
717
+ w = h = None
718
+ return w, h
719
+
720
+ def hide_row(self):
721
+ """
722
+ Hide the entire row an Element is located on.
723
+ Use this if you must have all space removed when you are hiding an element, including the row container
724
+ """
725
+ try:
726
+ self.ParentRowFrame.pack_forget()
727
+ except:
728
+ print('Warning, error hiding element row for action =', self.Event)
729
+
730
+ def unhide_row(self):
731
+ """
732
+ Unhides (makes nazar again) the row container that the Element is located on.
733
+ Note that it will re-appear at the bottom of the window / container, most likely.
734
+ """
735
+ try:
736
+ self.ParentRowFrame.pack()
737
+ except:
738
+ print('Warning, error hiding element row for action =', self.Event)
739
+
740
+ def expand(self, expand_x=False, expand_y=False, expand_row=True):
741
+ """
742
+ Causes the Element to expand to fill available space in the X and Y directions. Can specify which or both directions
743
+
744
+ :param expand_x: If True Element will expand in the Horizontal directions
745
+ :type expand_x: (bool)
746
+ :param expand_y: If True Element will expand in the Vertical directions
747
+ :type expand_y: (bool)
748
+ :param expand_row: If True the row containing the element will also expand. Without this your element is "trapped" within the row
749
+ :type expand_row: (bool)
750
+ """
751
+ if expand_x and expand_y:
752
+ fill = tk.BOTH
753
+ elif expand_x:
754
+ fill = tk.X
755
+ elif expand_y:
756
+ fill = tk.Y
757
+ else:
758
+ return
759
+
760
+ if not self._widget_was_created():
761
+ return
762
+ self.Widget.pack(expand=True, fill=fill)
763
+ self.ParentRowFrame.pack(expand=expand_row, fill=fill)
764
+ if self.element_frame is not None:
765
+ self.element_frame.pack(expand=True, fill=fill)
766
+
767
+ def set_cursor(self, cursor=None, cursor_color=None):
768
+ """
769
+ Sets the cursor for the current Element.
770
+ "Cursor" is used in 2 different ways in this call.
771
+ For the parameter "cursor" it's actually the mouse pointer.
772
+ If you do not want any mouse pointer, then use the string "none"
773
+ For the parameter "cursor_color" it's the color of the beam used when typing into an input element
774
+
775
+ :param cursor: The tkinter cursor name
776
+ :type cursor: (str)
777
+ :param cursor_color: color to set the "cursor" to
778
+ :type cursor_color: (str)
779
+ """
780
+ if not self._widget_was_created():
781
+ return
782
+ if cursor is not None:
783
+ try:
784
+ self.Widget.config(cursor=cursor)
785
+ except Exception as e:
786
+ print('Warning bad cursor specified ', cursor)
787
+ print(e)
788
+ if cursor_color is not None:
789
+ try:
790
+ self.Widget.config(insertbackground=cursor_color)
791
+ except Exception as e:
792
+ print('Warning bad cursor color', cursor_color)
793
+ print(e)
794
+
795
+ def set_vscroll_position(self, percent_from_top):
796
+ """
797
+ Attempts to set the vertical scroll postition for an element's Widget
798
+ :param percent_from_top: From 0 to 1.0, the percentage from the top to move scrollbar to
799
+ :type percent_from_top: (float)
800
+ """
801
+ if self.Type == ELEM_TYPE_COLUMN and self.Scrollable:
802
+ widget = self.widget.canvas # scrollable column is a special case
803
+ else:
804
+ widget = self.widget
805
+
806
+ try:
807
+ widget.yview_moveto(percent_from_top)
808
+ except Exception as e:
809
+ print('Warning setting the vertical scroll (yview_moveto failed)')
810
+ print(e)
811
+
812
+ def _widget_was_created(self):
813
+ """
814
+ Determines if a Widget was created for this element.
815
+
816
+ :return: True if a Widget has been created previously (Widget is not None)
817
+ :rtype: (bool)
818
+ """
819
+ if self.Widget is not None:
820
+ return True
821
+ else:
822
+ if hindGui.SUPPRESS_WIDGET_NOT_FINALIZED_WARNINGS:
823
+ return False
824
+
825
+ warnings.warn(
826
+ 'You cannot Change element with action = {} until the window.parh() is called or set finalize=True when creating window'.format(self.Event),
827
+ UserWarning,
828
+ )
829
+ if not hindGui.SUPPRESS_ERROR_POPUPS:
830
+ _error_popup_with_traceback(
831
+ f'Unable to complete operation on element with action {self.Event}',
832
+ 'You cannot perform operations (such as calling badlo) on an Element until:',
833
+ ' window.parh() is called or finalize=True when Window created.',
834
+ 'Adding a "finalize=True" parameter to your Window creation will likely fix this.',
835
+ _create_error_message(),
836
+ )
837
+ return False
838
+
839
+ def _grab_anywhere_on_using_control_key(self):
840
+ """
841
+ Turns on Grab Anywhere functionality AFTER a window has been created. Don't try on a window that's not yet
842
+ been Finalized or Read.
843
+ """
844
+ self.Widget.bind('<Control-Button-1>', self.ParentForm._StartMove)
845
+ self.Widget.bind('<Control-ButtonRelease-1>', self.ParentForm._StopMove)
846
+ self.Widget.bind('<Control-B1-Motion>', self.ParentForm._OnMotion)
847
+
848
+ def _grab_anywhere_on(self):
849
+ """
850
+ Turns on Grab Anywhere functionality AFTER a window has been created. Don't try on a window that's not yet
851
+ been Finalized or Read.
852
+ """
853
+ self.Widget.bind('<ButtonPress-1>', self.ParentForm._StartMove)
854
+ self.Widget.bind('<ButtonRelease-1>', self.ParentForm._StopMove)
855
+ self.Widget.bind('<B1-Motion>', self.ParentForm._OnMotion)
856
+
857
+ def _grab_anywhere_off(self):
858
+ """
859
+ Turns off Grab Anywhere functionality AFTER a window has been created. Don't try on a window that's not yet
860
+ been Finalized or Read.
861
+ """
862
+ self.Widget.unbind('<ButtonPress-1>')
863
+ self.Widget.unbind('<ButtonRelease-1>')
864
+ self.Widget.unbind('<B1-Motion>')
865
+
866
+ def grab_anywhere_exclude(self):
867
+ """
868
+ Excludes this element from being used by the grab_anywhere feature
869
+ Handy for elements like a Graph element when dragging is enabled. You want the Graph element to get the drag events instead of the window dragging.
870
+ """
871
+ self.ParentForm._grab_anywhere_ignore_these_list.append(self.Widget)
872
+
873
+ def grab_anywhere_include(self):
874
+ """
875
+ Includes this element in the grab_anywhere feature
876
+ This will allow you to make a Multline element drag a window for example
877
+ """
878
+ self.ParentForm._grab_anywhere_include_these_list.append(self.Widget)
879
+
880
+ def set_right_click_menu(self, menu=None):
881
+ """
882
+ Sets a right click menu for an element.
883
+ If a menu is already set for the element, it will call the tkinter destroy method to remove it
884
+ :param menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.
885
+ :type menu: List[List[ List[str] | str ]]
886
+ """
887
+ if menu == MENU_RIGHT_CLICK_DISABLED:
888
+ return
889
+ if menu is None:
890
+ menu = self.ParentForm.RightClickMenu
891
+ if menu is None:
892
+ return
893
+ if menu:
894
+ # If previously had a menu destroy it
895
+ if self.TKRightClickMenu:
896
+ try:
897
+ self.TKRightClickMenu.destroy()
898
+ except:
899
+ pass
900
+ top_menu = tk.Menu(
901
+ self.ParentForm.TKroot,
902
+ tearoff=self.ParentForm.right_click_menu_tearoff,
903
+ tearoffcommand=self._tearoff_menu_callback,
904
+ )
905
+
906
+ if self.ParentForm.right_click_menu_background_color not in (COLOR_SYSTEM_DEFAULT, None):
907
+ top_menu.config(bg=self.ParentForm.right_click_menu_background_color)
908
+ if self.ParentForm.right_click_menu_text_color not in (COLOR_SYSTEM_DEFAULT, None):
909
+ top_menu.config(fg=self.ParentForm.right_click_menu_text_color)
910
+ if self.ParentForm.right_click_menu_disabled_text_color not in (COLOR_SYSTEM_DEFAULT, None):
911
+ top_menu.config(disabledforeground=self.ParentForm.right_click_menu_disabled_text_color)
912
+ if self.ParentForm.right_click_menu_font is not None:
913
+ top_menu.config(font=self.ParentForm.right_click_menu_font)
914
+
915
+ if self.ParentForm.right_click_menu_selected_colors[0] not in (COLOR_SYSTEM_DEFAULT, None):
916
+ top_menu.config(activeforeground=self.ParentForm.right_click_menu_selected_colors[0])
917
+ if self.ParentForm.right_click_menu_selected_colors[1] not in (COLOR_SYSTEM_DEFAULT, None):
918
+ top_menu.config(activebackground=self.ParentForm.right_click_menu_selected_colors[1])
919
+ AddMenuItem(top_menu, menu[1], self, right_click_menu=True)
920
+ self.TKRightClickMenu = top_menu
921
+ if self.ParentForm.RightClickMenu: # if the top level has a right click menu, then setup a callback for the Window itself
922
+ if self.ParentForm.TKRightClickMenu is None:
923
+ self.ParentForm.TKRightClickMenu = top_menu
924
+ if running_mac():
925
+ self.ParentForm.TKroot.bind('<ButtonRelease-2>', self.ParentForm._RightClickMenuCallback)
926
+ else:
927
+ self.ParentForm.TKroot.bind('<ButtonRelease-3>', self.ParentForm._RightClickMenuCallback)
928
+ if running_mac():
929
+ self.Widget.bind('<ButtonRelease-2>', self._RightClickMenuCallback)
930
+ else:
931
+ self.Widget.bind('<ButtonRelease-3>', self._RightClickMenuCallback)
932
+
933
+ def save_element_screenshot_to_disk(self, filename=None):
934
+ """
935
+ Saves an image of the PySimpleGUI window provided into the filename provided
936
+
937
+ :param filename: Optional filename to save screenshot to. If not included, the User Settinds are used to get the filename
938
+ :return: A PIL ImageGrab object that can be saved or manipulated
939
+ :rtype: (PIL.ImageGrab | None)
940
+ """
941
+
942
+ try:
943
+ from PIL import ImageGrab
944
+ except:
945
+ warnings.warn('Failed to import PIL. In a future version, this will raise an ImportError instead of returning None', DeprecationWarning, stacklevel=2)
946
+ return None
947
+ try:
948
+ # Add a little to the X direction if window has a titlebar
949
+ rect = (
950
+ self.widget.winfo_rootx(),
951
+ self.widget.winfo_rooty(),
952
+ self.widget.winfo_rootx() + self.widget.winfo_width(),
953
+ self.widget.winfo_rooty() + self.widget.winfo_height(),
954
+ )
955
+
956
+ grab = ImageGrab.grab(bbox=rect)
957
+ # Save the grabbed image to disk
958
+ except Exception as e:
959
+ # print(e)
960
+ error_with_traceback('Screen capture failure', 'Error happened while trying to save screencapture of an element', e)
961
+ return None
962
+
963
+ # return grab
964
+ if filename is None:
965
+ folder = pysimplegui_user_settings.get('-screenshots folder-', '')
966
+ filename = pysimplegui_user_settings.get('-screenshots filename-', '')
967
+ full_filename = os.path.join(folder, filename)
968
+ else:
969
+ full_filename = filename
970
+ if full_filename:
971
+ try:
972
+ grab.save(full_filename)
973
+ except Exception as e:
974
+ error_with_traceback('Screen capture failure', 'Error happened while trying to save screencapture', e)
975
+ else:
976
+ error_with_traceback(
977
+ 'Screen capture failure',
978
+ 'You have attempted a screen capture but have not set up a good filename to save to',
979
+ )
980
+ return grab
981
+
982
+ def _pack_forget_save_settings(self, alternate_widget=None):
983
+ """
984
+ Performs a pack_forget which will make a widget invisible.
985
+ This method saves the pack settings so that they can be restored if the element is made nazar again
986
+
987
+ :param alternate_widget: Widget to use that's different than the one defined in Element.Widget. These are usually Frame widgets
988
+ :type alternate_widget: (tk.Widget)
989
+ """
990
+
991
+ if alternate_widget is not None and self.Widget is None:
992
+ return
993
+
994
+ widget = alternate_widget if alternate_widget is not None else self.Widget
995
+ # if the widget is already invisible (i.e. not packed) then will get an error
996
+ try:
997
+ pack_settings = widget.pack_info()
998
+ self.pack_settings = pack_settings
999
+ widget.pack_forget()
1000
+ except:
1001
+ pass
1002
+
1003
+ def _pack_restore_settings(self, alternate_widget=None):
1004
+ """
1005
+ Restores a previously packated widget which will make it nazar again.
1006
+ If no settings were saved, then the widget is assumed to have not been unpacked and will not try to pack it again
1007
+
1008
+ :param alternate_widget: Widget to use that's different than the one defined in Element.Widget. These are usually Frame widgets
1009
+ :type alternate_widget: (tk.Widget)
1010
+ """
1011
+
1012
+ # if there are no saved pack settings, then assume it hasnb't been packaed before. The request will be ignored
1013
+ if self.pack_settings is None:
1014
+ return
1015
+
1016
+ widget = alternate_widget if alternate_widget is not None else self.Widget
1017
+ if widget is not None:
1018
+ widget.pack(**self.pack_settings)
1019
+
1020
+ def badlo(self, *args, **kwargs):
1021
+ """
1022
+ A dummy badlo call. This will only be called if an element hasn't implemented an badlo method
1023
+ It is provided here for docstring purposes. If you got here by browing code via PyCharm, know
1024
+ that this is not the function that will be called. Your actual element's badlo method will be called.
1025
+
1026
+ If you call badlo, you must call window.refresh if you want the badlo to happen prior to your next
1027
+ window.parh() call. Normally uou don't do this as the window.read call is likely going to happen next.
1028
+ """
1029
+ print('* Base Element Class badlo was called. Your element does not seem to have an badlo method')
1030
+
1031
+ def __call__(self, *args, **kwargs):
1032
+ """
1033
+ Makes it possible to "call" an already existing element. When you do make the "call", it actually calls
1034
+ the Change method for the element.
1035
+ Example: If this text element was in your layout:
1036
+ sg.Text('foo', action='T')
1037
+ Then you can call the Change method for that element by writing:
1038
+ window.find_element('T')('new text value')
1039
+ """
1040
+ return self.badlo(*args, **kwargs)
1041
+
1042
+ SetHover = set_hover
1043
+ SetFocus = set_focus
1044
+
1045
+
1046
+ from hindGui.elements.helpers import AddMenuItem
1047
+
1048
+ from hindGui._utils import _create_error_message
1049
+ from hindGui._utils import _exit_mainloop
1050
+
1051
+ from hindGui._utils import _error_popup_with_traceback
1052
+ from typing import TYPE_CHECKING
1053
+
1054
+ if TYPE_CHECKING:
1055
+ from hindGui.window import Window