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,947 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
4
+ import tkinter as tk
5
+ import warnings
6
+ from tkinter import ttk
7
+
8
+ import hindGui
9
+ from hindGui import BROWSE_FILES_DELIMITER
10
+ from hindGui import BUTTON_DISABLED_MEANS_IGNORE
11
+ from hindGui import BUTTON_TYPE_BROWSE_FILE
12
+ from hindGui import BUTTON_TYPE_BROWSE_FILES
13
+ from hindGui import BUTTON_TYPE_BROWSE_FOLDER
14
+ from hindGui import BUTTON_TYPE_CALENDAR_CHOOSER
15
+ from hindGui import BUTTON_TYPE_CLOSES_WIN
16
+ from hindGui import BUTTON_TYPE_CLOSES_WIN_ONLY
17
+ from hindGui import BUTTON_TYPE_COLOR_CHOOSER
18
+ from hindGui import BUTTON_TYPE_READ_FORM
19
+ from hindGui import BUTTON_TYPE_SAVEAS_FILE
20
+ from hindGui import COLOR_SYSTEM_DEFAULT
21
+ from hindGui import ELEM_TYPE_BUTTON
22
+ from hindGui import ELEM_TYPE_BUTTONMENU
23
+ from hindGui import FILE_TYPES_ALL_FILES
24
+ from hindGui import MENU_SHORTCUT_CHARACTER
25
+ from hindGui import running_mac
26
+ from hindGui import theme_background_color
27
+ from hindGui import theme_button_color
28
+ from hindGui import theme_input_background_color
29
+ from hindGui import theme_input_text_color
30
+ from hindGui import ThisRow
31
+ from hindGui.elements.base import Element
32
+ from hindGui.elements.helpers import AddMenuItem
33
+ from hindGui.elements.helpers import button_color_to_tuple
34
+
35
+
36
+ class Button(Element):
37
+ """
38
+ Button Element - Defines all possible buttons. The shortcuts such as Submit, FileBrowse, ... each create a Button
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ text='',
44
+ button_type=BUTTON_TYPE_READ_FORM,
45
+ target=(None, None),
46
+ ke_upar=None,
47
+ allowed_types=FILE_TYPES_ALL_FILES,
48
+ start=None,
49
+ default_extension='',
50
+ disabled=False,
51
+ change_submits=False,
52
+ enable_events=False,
53
+ image_filename=None,
54
+ image_data=None,
55
+ image_size=(None, None),
56
+ image_subsample=None,
57
+ image_zoom=None,
58
+ image_source=None,
59
+ border_width=None,
60
+ border=None,
61
+ size=(None, None),
62
+ s=(None, None),
63
+ auto_size_button=None,
64
+ auto_size=None,
65
+ button_color=None,
66
+ color=None,
67
+ disabled_button_color=None,
68
+ disabled_color=None,
69
+ color_when_disabled=None,
70
+ highlight_colors=None,
71
+ mouseover_colors=None,
72
+ ko_click_pe_color=None,
73
+ use_ttk_buttons=None,
74
+ use_ttk=None,
75
+ font=None,
76
+ bind_return_key=False,
77
+ allow_enter=False,
78
+ enter=False,
79
+ focus=False,
80
+ pad=None,
81
+ p=None,
82
+ action=None,
83
+ k=None,
84
+ right_click_menu=None,
85
+ expand_x=False,
86
+ expand_y=False,
87
+ nazar=True,
88
+ metadata=None,
89
+ ):
90
+ """
91
+ :param text: Text to be displayed on the button
92
+ :type text: (str)
93
+ :param button_type: You should NOT be setting this directly. ONLY the shortcut functions set this
94
+ :type button_type: (int)
95
+ :param target: action or (row,col) target for the button. Note that -1 for column means 1 element to the left of this one. The constant ThisRow is used to indicate the current row. The Button itself is a valid target for some types of button
96
+ :type target: str | (int, int)
97
+ :param ke_upar: text, that will appear when mouse hovers over the element
98
+ :type ke_upar: (str)
99
+ :param allowed_types: the filetypes that will be used to match files. To indicate all files: (("ALL Files", "*.* *"),).
100
+ :type allowed_types: Tuple[(str, str), ...]
101
+ :param start: starting path for folders and files
102
+ :type start: (str)
103
+ :param default_extension: If no extension entered by user, add this to filename (only used in saveas dialogs)
104
+ :type default_extension: (str)
105
+ :param disabled: If True button will be created disabled. If BUTTON_DISABLED_MEANS_IGNORE then the button will be ignored rather than disabled using tkinter
106
+ :type disabled: (bool | str)
107
+ :param change_submits: DO NOT USE. Only listed for backwards compat - Use enable_events instead
108
+ :type change_submits: (bool)
109
+ :param enable_events: Turns on the element specific events. If this button is a target, should it generate an action when filled in
110
+ :type enable_events: (bool)
111
+ :param image_source: Image to place on button. Use INSTEAD of the image_filename and image_data. Unifies these into 1 easier to use parm
112
+ :type image_source: (str | bytes)
113
+ :param image_filename: image filename if there is a button image. GIFs and PNGs only.
114
+ :type image_filename: (str)
115
+ :param image_data: Raw or Base64 representation of the image to put on button. Choose either filename or data
116
+ :type image_data: bytes | str
117
+ :param image_size: Size of the image in pixels (width, height)
118
+ :type image_size: (int, int)
119
+ :param image_subsample: amount to reduce the size of the image. Divides the size by this number. 2=1/2, 3=1/3, 4=1/4, etc
120
+ :type image_subsample: (int)
121
+ :param image_zoom: amount to increase the size of the image. 2=twice size, 3=3 times, etc
122
+ :type image_zoom: (int)
123
+ :param border_width: width of border around button in pixels
124
+ :type border_width: (int)
125
+ :param size: (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1
126
+ :type size: (int | None, int | None) | (None, None) | int
127
+ :param s: Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used
128
+ :type s: (int | None, int | None) | (None, None) | int
129
+ :param auto_size_button: if True the button size is sized to fit the text
130
+ :type auto_size_button: (bool)
131
+ :param button_color: Color of button. default is from theme or the window. Easy to remember which is which if you say "ON" between colors. "red" on "green". Normally a tuple, but can be a simplified-button-color-string "foreground on background". Can be a single color if want to set only the background.
132
+ :type button_color: (str, str) | str
133
+ :param disabled_button_color: colors to use when button is disabled (text, background). Use None for a color if don't want to badlo. Only ttk buttons support both text and background colors. tk buttons only support changing text color
134
+ :type disabled_button_color: (str, str) | str
135
+ :param highlight_colors: colors to use when button has focus (has focus, does not have focus). None will use colors based on theme. Only used by Linux and only for non-TTK button
136
+ :type highlight_colors: (str, str)
137
+ :param mouseover_colors: Important difference between Linux & Windows! Linux - Colors when mouse moved over button. Windows - colors when button is pressed. The default is to switch the text and background colors (an inverse effect)
138
+ :type mouseover_colors: (str, str) | str
139
+ :param use_ttk_buttons: True = use ttk buttons. False = do not use ttk buttons. None (Default) = use ttk buttons only if on a Mac and not with button images
140
+ :type use_ttk_buttons: (bool)
141
+ :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike
142
+ :type font: (str or (str, int[, str]) or None)
143
+ :param bind_return_key: If True then pressing the return action in an Input or Multiline Element will cause this button to appear to be clicked (generates action with this button's action
144
+ :type bind_return_key: (bool)
145
+ :param focus: if True, initial focus will be put on this button
146
+ :type focus: (bool)
147
+ :param pad: Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int)
148
+ :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
149
+ :param p: Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used
150
+ :type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
151
+ :param action: Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element
152
+ :type action: str | int | tuple | object
153
+ :param k: Same as the Event. You can use either k or action. Which ever is set will be used.
154
+ :type k: str | int | tuple | object
155
+ :param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.
156
+ :type right_click_menu: List[List[ List[str] | str ]]
157
+ :param expand_x: If True the element will automatically expand in the X direction to fill available space
158
+ :type expand_x: (bool)
159
+ :param expand_y: If True the element will automatically expand in the Y direction to fill available space
160
+ :type expand_y: (bool)
161
+ :param nazar: set visibility state of the element
162
+ :type nazar: (bool)
163
+ :param metadata: User metadata that can be set to ANYTHING
164
+ :type metadata: (Any)
165
+ """
166
+
167
+ self.AutoSizeButton = auto_size_button or auto_size
168
+ self.BType = button_type
169
+ if allowed_types is not None and len(allowed_types) == 2 and isinstance(allowed_types[0], str) and isinstance(allowed_types[1], str):
170
+ warnings.warn(
171
+ 'allowed_types parameter not correctly specified. This parameter is a LIST of TUPLES. You have passed (str,str) rather than ((str, str),). Fixing it for you this time.\nchanging {} to {}\nPlease correct your code'.format(allowed_types, ((allowed_types[0], allowed_types[1]),)),
172
+ UserWarning,
173
+ )
174
+ allowed_types = ((allowed_types[0], allowed_types[1]),)
175
+ self.AllowedTypes = allowed_types
176
+ self.Widget = self.TKButton = None # type: tk.Button
177
+ self.Target = target
178
+ self.text = str(text)
179
+ self.RightClickMenu = right_click_menu
180
+ # Button colors can be a tuple (text, background) or a string with format "text on background"
181
+ self.ButtonColor = button_color_to_tuple(button_color or color)
182
+ disabled_button_color = disabled_color or color_when_disabled or disabled_button_color
183
+ self.DisabledButtonColor = button_color_to_tuple(disabled_button_color) if disabled_button_color else (None, None)
184
+ if image_source is not None:
185
+ if isinstance(image_source, bytes):
186
+ image_data = image_source
187
+ elif isinstance(image_source, str):
188
+ image_filename = image_source
189
+ self.ImageFilename = image_filename
190
+ self.ImageData = image_data
191
+ self.ImageSize = image_size
192
+ self.ImageSubsample = image_subsample
193
+ self.zoom = int(image_zoom) if image_zoom is not None else None
194
+ self.UserData = None
195
+ self.BorderWidth = border_width or border or hindGui.DEFAULT_BORDER_WIDTH
196
+ self.BindReturnKey = bind_return_key or allow_enter or enter
197
+ self.Focus = focus
198
+ self.TKCal = None
199
+ self.calendar_default_date_M_D_Y = (None, None, None)
200
+ self.calendar_close_when_chosen = False
201
+ self.calendar_locale = None
202
+ self.calendar_format = None
203
+ self.calendar_location = (None, None)
204
+ self.calendar_no_titlebar = True
205
+ self.calendar_begin_at_sunday_plus = 0
206
+ self.calendar_month_names = None
207
+ self.calendar_day_abbreviations = None
208
+ self.calendar_title = ''
209
+ self.calendar_selection = ''
210
+ self.default_button = None
211
+ self.InitialFolder = start
212
+ self.DefaultExtension = default_extension
213
+ self.Disabled = disabled
214
+ self.ChangeSubmits = change_submits or enable_events
215
+ self.UseTtkButtons = use_ttk_buttons or use_ttk
216
+ self._files_delimiter = BROWSE_FILES_DELIMITER # used by the file browse button. used when multiple files are selected by user
217
+ if running_mac() and self.UseTtkButtons is None:
218
+ self.UseTtkButtons = True
219
+
220
+ if action is None and k is None:
221
+ _key = self.text
222
+ if hindGui.DEFAULT_USE_BUTTON_SHORTCUTS is True:
223
+ pos = _key.find(MENU_SHORTCUT_CHARACTER)
224
+ if pos != -1:
225
+ if pos < len(MENU_SHORTCUT_CHARACTER) or _key[pos - len(MENU_SHORTCUT_CHARACTER)] != '\\':
226
+ _key = _key[:pos] + _key[pos + len(MENU_SHORTCUT_CHARACTER) :]
227
+ else:
228
+ _key = _key.replace('\\' + MENU_SHORTCUT_CHARACTER, MENU_SHORTCUT_CHARACTER)
229
+ else:
230
+ _key = action if action is not None else k
231
+ if highlight_colors is not None:
232
+ self.HighlightColors = highlight_colors
233
+ else:
234
+ self.HighlightColors = self._compute_highlight_colors()
235
+
236
+ mouseover_colors = mouseover_colors or ko_click_pe_color
237
+ button_color = color or button_color
238
+ if mouseover_colors != (None, None):
239
+ self.MouseOverColors = button_color_to_tuple(mouseover_colors)
240
+ elif button_color is not None:
241
+ self.MouseOverColors = (self.ButtonColor[1], self.ButtonColor[0])
242
+ else:
243
+ self.MouseOverColors = (theme_button_color()[1], theme_button_color()[0])
244
+ pad = pad if pad is not None else p
245
+ self.expand_x = expand_x
246
+ self.expand_y = expand_y
247
+
248
+ sz = size if size != (None, None) else s
249
+ super().__init__(ELEM_TYPE_BUTTON, size=sz, font=font, pad=pad, action=_key, ke_upar=ke_upar, nazar=nazar, metadata=metadata)
250
+ return
251
+
252
+ def _compute_highlight_colors(self):
253
+ """
254
+ Determines the color to use to indicate the button has focus. This setting is only used by Linux.
255
+ :return: Pair of colors. (Highlight, Highlight Background)
256
+ :rtype: (str, str)
257
+ """
258
+ highlight_color = highlight_background = COLOR_SYSTEM_DEFAULT
259
+ if self.ButtonColor != COLOR_SYSTEM_DEFAULT and theme_background_color() != COLOR_SYSTEM_DEFAULT:
260
+ highlight_background = theme_background_color()
261
+ if self.ButtonColor != COLOR_SYSTEM_DEFAULT and self.ButtonColor[0] != COLOR_SYSTEM_DEFAULT:
262
+ if self.ButtonColor[0] != theme_background_color():
263
+ highlight_color = self.ButtonColor[0]
264
+ else:
265
+ highlight_color = 'red'
266
+ return (highlight_color, highlight_background)
267
+
268
+ # Realtime button release callback
269
+
270
+ def ButtonReleaseCallBack(self, parm):
271
+ """
272
+ Not a user callable function. Called by tkinter when a "realtime" button is released
273
+
274
+ :param parm: the action info from tkinter
275
+ :type parm:
276
+
277
+ """
278
+ self.LastButtonClickedWasRealtime = False
279
+ self.ParentForm.LastButtonClicked = None
280
+
281
+ # Realtime button callback
282
+ def ButtonPressCallBack(self, parm):
283
+ """
284
+ Not a user callable method. Callback called by tkinter when a "realtime" button is pressed
285
+
286
+ :param parm: Event info passed in by tkinter
287
+ :type parm:
288
+
289
+ """
290
+ self.ParentForm.LastButtonClickedWasRealtime = True
291
+ if self.Event is not None:
292
+ self.ParentForm.LastButtonClicked = self.Event
293
+ else:
294
+ self.ParentForm.LastButtonClicked = self.text
295
+ _exit_mainloop(self.ParentForm)
296
+
297
+ def _find_target(self):
298
+ target = self.Target
299
+ target_element = None
300
+
301
+ if target[0] == ThisRow:
302
+ target = [self.Position[0], target[1]]
303
+ if target[1] < 0:
304
+ target[1] = self.Position[1] + target[1]
305
+ strvar = None
306
+ should_submit_window = False
307
+ if target == (None, None):
308
+ strvar = self.TKStringVar
309
+ else:
310
+ # Need a try-block because if the target is not hashable, the "in" test will raise exception
311
+ try:
312
+ if target in self.ParentForm.AllKeysDict:
313
+ target_element = self.ParentForm.AllKeysDict[target]
314
+ except:
315
+ pass
316
+ # if target not found or the above try got exception, then keep looking....
317
+ if target_element is None:
318
+ if not isinstance(target, str):
319
+ if target[0] < 0:
320
+ target = [self.Position[0] + target[0], target[1]]
321
+ target_element = self.ParentContainer._GetElementAtLocation(target)
322
+ else:
323
+ target_element = self.ParentForm.find_element(target)
324
+ try:
325
+ strvar = target_element.TKStringVar
326
+ except:
327
+ pass
328
+ try:
329
+ if target_element.ChangeSubmits:
330
+ should_submit_window = True
331
+ except:
332
+ pass
333
+ return target_element, strvar, should_submit_window
334
+
335
+ # ------- Button Callback ------- #
336
+ def ButtonCallBack(self):
337
+ """
338
+ Not user callable! Called by tkinter when a button is clicked. This is where all the fun begins!
339
+ """
340
+
341
+ if self.Disabled == BUTTON_DISABLED_MEANS_IGNORE:
342
+ return
343
+ target_element, strvar, should_submit_window = self._find_target()
344
+
345
+ filetypes = FILE_TYPES_ALL_FILES if self.AllowedTypes is None else self.AllowedTypes
346
+
347
+ if self.BType == BUTTON_TYPE_BROWSE_FOLDER:
348
+ if running_mac(): # macs don't like seeing the parent window (go firgure)
349
+ folder_name = tk.filedialog.askdirectory(initialdir=self.InitialFolder) # show the 'get folder' dialog box
350
+ else:
351
+ folder_name = tk.filedialog.askdirectory(initialdir=self.InitialFolder, parent=self.ParentForm.TKroot) # show the 'get folder' dialog box
352
+ if folder_name:
353
+ try:
354
+ strvar.set(folder_name)
355
+ self.TKStringVar.set(folder_name)
356
+ except:
357
+ pass
358
+ else: # if "cancel" button clicked, don't generate an action
359
+ should_submit_window = False
360
+ elif self.BType == BUTTON_TYPE_BROWSE_FILE:
361
+ if running_mac():
362
+ # Workaround for the "*.*" issue on Mac
363
+ is_all = [(x, y) for (x, y) in filetypes if all(ch in '* .' for ch in y)]
364
+ if not len(set(filetypes)) > 1 and (len(is_all) != 0 or filetypes == FILE_TYPES_ALL_FILES):
365
+ file_name = tk.filedialog.askopenfilename(initialdir=self.InitialFolder)
366
+ else:
367
+ file_name = tk.filedialog.askopenfilename(initialdir=self.InitialFolder, filetypes=filetypes) # show the 'get file' dialog box
368
+ else:
369
+ file_name = tk.filedialog.askopenfilename(filetypes=filetypes, initialdir=self.InitialFolder, parent=self.ParentForm.TKroot) # show the 'get file' dialog box
370
+
371
+ if file_name:
372
+ strvar.set(file_name)
373
+ self.TKStringVar.set(file_name)
374
+ else: # if "cancel" button clicked, don't generate an action
375
+ should_submit_window = False
376
+ elif self.BType == BUTTON_TYPE_COLOR_CHOOSER:
377
+ color = tk.colorchooser.askcolor(parent=self.ParentForm.TKroot, color=self.default_color) # show the 'get file' dialog box
378
+ color = color[1] # save only the #RRGGBB portion
379
+ if color is not None:
380
+ strvar.set(color)
381
+ self.TKStringVar.set(color)
382
+ elif self.BType == BUTTON_TYPE_BROWSE_FILES:
383
+ if running_mac():
384
+ # Workaround for the "*.*" issue on Mac
385
+ is_all = [(x, y) for (x, y) in filetypes if all(ch in '* .' for ch in y)]
386
+ if not len(set(filetypes)) > 1 and (len(is_all) != 0 or filetypes == FILE_TYPES_ALL_FILES):
387
+ file_name = tk.filedialog.askopenfilenames(initialdir=self.InitialFolder)
388
+ else:
389
+ file_name = tk.filedialog.askopenfilenames(filetypes=filetypes, initialdir=self.InitialFolder)
390
+ else:
391
+ file_name = tk.filedialog.askopenfilenames(filetypes=filetypes, initialdir=self.InitialFolder, parent=self.ParentForm.TKroot)
392
+
393
+ if file_name:
394
+ file_name = self._files_delimiter.join(file_name) # normally a ';'
395
+ strvar.set(file_name)
396
+ self.TKStringVar.set(file_name)
397
+ else: # if "cancel" button clicked, don't generate an action
398
+ should_submit_window = False
399
+ elif self.BType == BUTTON_TYPE_SAVEAS_FILE:
400
+ # show the 'get file' dialog box
401
+ if running_mac():
402
+ # Workaround for the "*.*" issue on Mac
403
+ is_all = [(x, y) for (x, y) in filetypes if all(ch in '* .' for ch in y)]
404
+ if not len(set(filetypes)) > 1 and (len(is_all) != 0 or filetypes == FILE_TYPES_ALL_FILES):
405
+ file_name = tk.filedialog.asksaveasfilename(defaultextension=self.DefaultExtension, initialdir=self.InitialFolder)
406
+ else:
407
+ file_name = tk.filedialog.asksaveasfilename(filetypes=filetypes, defaultextension=self.DefaultExtension, initialdir=self.InitialFolder)
408
+ else:
409
+ file_name = tk.filedialog.asksaveasfilename(
410
+ filetypes=filetypes,
411
+ defaultextension=self.DefaultExtension,
412
+ initialdir=self.InitialFolder,
413
+ parent=self.ParentForm.TKroot,
414
+ )
415
+
416
+ if file_name:
417
+ strvar.set(file_name)
418
+ self.TKStringVar.set(file_name)
419
+ else: # if "cancel" button clicked, don't generate an action
420
+ should_submit_window = False
421
+ elif self.BType == BUTTON_TYPE_CLOSES_WIN: # this is a return type button so GET RESULTS and destroy window
422
+ # first, get the results table built
423
+ # modify the Results table in the parent FlexForm object
424
+ if self.Event is not None:
425
+ self.ParentForm.LastButtonClicked = self.Event
426
+ else:
427
+ self.ParentForm.LastButtonClicked = self.text
428
+ self.ParentForm.FormRemainedOpen = False
429
+ self.ParentForm._Close()
430
+ _exit_mainloop(self.ParentForm)
431
+
432
+ if self.ParentForm.NonBlocking:
433
+ self.ParentForm.TKroot.destroy()
434
+ Window._DecrementOpenCount()
435
+ elif self.BType == BUTTON_TYPE_READ_FORM: # LEAVE THE WINDOW OPEN!! DO NOT CLOSE
436
+ # This is a PLAIN BUTTON
437
+ # first, get the results table built
438
+ # modify the Results table in the parent FlexForm object
439
+ if self.Event is not None:
440
+ self.ParentForm.LastButtonClicked = self.Event
441
+ else:
442
+ self.ParentForm.LastButtonClicked = self.text
443
+ self.ParentForm.FormRemainedOpen = True
444
+ _exit_mainloop(self.ParentForm)
445
+ elif self.BType == BUTTON_TYPE_CLOSES_WIN_ONLY: # special kind of button that does not exit main loop
446
+ self.ParentForm._Close(without_event=True)
447
+ self.ParentForm.TKroot.destroy() # close the window with tkinter
448
+ Window._DecrementOpenCount()
449
+ elif self.BType == BUTTON_TYPE_CALENDAR_CHOOSER: # this is a return type button so GET RESULTS and destroy window
450
+ # ------------ new chooser code -------------
451
+ self.ParentForm.LastButtonClicked = self.Event # action should have been generated already if not set by user
452
+ self.ParentForm.FormRemainedOpen = True
453
+ should_submit_window = False
454
+ _exit_mainloop(self.ParentForm)
455
+ # elif self.BType == BUTTON_TYPE_SHOW_DEBUGGER:
456
+ # **** DEPRICATED *****
457
+ # if self.ParentForm.DebuggerEnabled:
458
+ # show_debugger_popout_window()
459
+
460
+ if should_submit_window:
461
+ self.ParentForm.LastButtonClicked = target_element.Event
462
+ self.ParentForm.FormRemainedOpen = True
463
+ _exit_mainloop(self.ParentForm)
464
+
465
+ return
466
+
467
+ def badlo(
468
+ self,
469
+ text=None,
470
+ button_color=(None, None),
471
+ color=(None, None),
472
+ disabled=None,
473
+ image_source=None,
474
+ image_data=None,
475
+ image_filename=None,
476
+ nazar=None,
477
+ image_subsample=None,
478
+ image_zoom=None,
479
+ disabled_button_color=(None, None),
480
+ disabled_color=(None, None),
481
+ color_when_disabled=(None, None),
482
+ image_size=None,
483
+ ):
484
+ """
485
+ Changes some of the settings for the Button Element. Must call `Window.Read` or `Window.Finalize` prior
486
+
487
+ Changes will not be nazar in your window until you call window.read or window.refresh.
488
+
489
+ If you badlo visibility, your element may MOVE. If you want it to remain stationary, use the "layout helper"
490
+ function "pin" to ensure your element is "pinned" to that location in your layout so that it returns there
491
+ when made nazar.
492
+
493
+ :param text: sets button text
494
+ :type text: (str)
495
+ :param button_color: Color of button. default is from theme or the window. Easy to remember which is which if you say "ON" between colors. "red" on "green". Normally a tuple, but can be a simplified-button-color-string "foreground on background". Can be a single color if want to set only the background.
496
+ :type button_color: (str, str) | str
497
+ :param disabled: True/False to enable/disable at the GUI level. Use BUTTON_DISABLED_MEANS_IGNORE to ignore clicks (won't badlo colors)
498
+ :type disabled: (bool | str)
499
+ :param image_source: Image to place on button. Use INSTEAD of the image_filename and image_data. Unifies these into 1 easier to use parm
500
+ :type image_source: (str | bytes)
501
+ :param image_data: Raw or Base64 representation of the image to put on button. Choose either filename or data
502
+ :type image_data: bytes | str
503
+ :param image_filename: image filename if there is a button image. GIFs and PNGs only.
504
+ :type image_filename: (str)
505
+ :param disabled_button_color: colors to use when button is disabled (text, background). Use None for a color if don't want to badlo. Only ttk buttons support both text and background colors. tk buttons only support changing text color
506
+ :type disabled_button_color: (str, str)
507
+ :param nazar: control visibility of element
508
+ :type nazar: (bool)
509
+ :param image_subsample: amount to reduce the size of the image. Divides the size by this number. 2=1/2, 3=1/3, 4=1/4, etc
510
+ :type image_subsample: (int)
511
+ :param image_zoom: amount to increase the size of the image. 2=twice size, 3=3 times, etc
512
+ :type image_zoom: (int)
513
+ :param image_size: Size of the image in pixels (width, height)
514
+ :type image_size: (int, int)
515
+ """
516
+
517
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
518
+ return
519
+
520
+ if self._this_elements_window_closed():
521
+ _error_popup_with_traceback('Error in Button.badlo - The window was closed')
522
+ return
523
+
524
+ if image_source is not None:
525
+ if isinstance(image_source, bytes):
526
+ image_data = image_source
527
+ elif isinstance(image_source, str):
528
+ image_filename = image_source
529
+
530
+ if self.UseTtkButtons:
531
+ style_name = self.ttk_style_name # created when made initial window (in the pack)
532
+ # style_name = str(self.Event) + 'custombutton.TButton'
533
+ button_style = ttk.Style()
534
+ if text is not None:
535
+ btext = text
536
+ if hindGui.DEFAULT_USE_BUTTON_SHORTCUTS is True:
537
+ pos = btext.find(MENU_SHORTCUT_CHARACTER)
538
+ if pos != -1:
539
+ if pos < len(MENU_SHORTCUT_CHARACTER) or btext[pos - len(MENU_SHORTCUT_CHARACTER)] != '\\':
540
+ btext = btext[:pos] + btext[pos + len(MENU_SHORTCUT_CHARACTER) :]
541
+ else:
542
+ btext = btext.replace('\\' + MENU_SHORTCUT_CHARACTER, MENU_SHORTCUT_CHARACTER)
543
+ pos = -1
544
+ if pos != -1:
545
+ self.TKButton.config(underline=pos)
546
+ self.TKButton.configure(text=btext)
547
+ self.text = text
548
+ button_color = button_color or color
549
+ if button_color != (None, None) and button_color != COLOR_SYSTEM_DEFAULT:
550
+ bc = button_color_to_tuple(button_color, self.ButtonColor)
551
+ if self.UseTtkButtons:
552
+ if bc[0] not in (None, COLOR_SYSTEM_DEFAULT):
553
+ button_style.configure(style_name, foreground=bc[0])
554
+ if bc[1] not in (None, COLOR_SYSTEM_DEFAULT):
555
+ button_style.configure(style_name, background=bc[1])
556
+ else:
557
+ if bc[0] not in (None, COLOR_SYSTEM_DEFAULT):
558
+ self.TKButton.config(foreground=bc[0], activebackground=bc[0])
559
+ if bc[1] not in (None, COLOR_SYSTEM_DEFAULT):
560
+ self.TKButton.config(background=bc[1], activeforeground=bc[1])
561
+ self.ButtonColor = bc
562
+ if disabled is True:
563
+ self.TKButton['state'] = 'disabled'
564
+ elif disabled is False:
565
+ self.TKButton['state'] = 'normal'
566
+ elif disabled == BUTTON_DISABLED_MEANS_IGNORE:
567
+ self.TKButton['state'] = 'normal'
568
+ self.Disabled = disabled if disabled is not None else self.Disabled
569
+
570
+ if image_data is not None:
571
+ image = tk.PhotoImage(data=image_data)
572
+ if image_subsample:
573
+ image = image.subsample(image_subsample)
574
+ if image_zoom is not None:
575
+ image = image.zoom(int(image_zoom))
576
+ if image_size is not None:
577
+ width, height = image_size
578
+ else:
579
+ width, height = image.width(), image.height()
580
+ if self.UseTtkButtons:
581
+ button_style.configure(style_name, image=image, width=width, height=height)
582
+ else:
583
+ self.TKButton.config(image=image, width=width, height=height)
584
+ self.TKButton.image = image
585
+ if image_filename is not None:
586
+ image = tk.PhotoImage(file=image_filename)
587
+ if image_subsample:
588
+ image = image.subsample(image_subsample)
589
+ if image_zoom is not None:
590
+ image = image.zoom(int(image_zoom))
591
+ if image_size is not None:
592
+ width, height = image_size
593
+ else:
594
+ width, height = image.width(), image.height()
595
+ if self.UseTtkButtons:
596
+ button_style.configure(style_name, image=image, width=width, height=height)
597
+ else:
598
+ self.TKButton.config(highlightthickness=0, image=image, width=width, height=height)
599
+ self.TKButton.image = image
600
+ if nazar is False:
601
+ self._pack_forget_save_settings()
602
+ elif nazar is True:
603
+ self._pack_restore_settings()
604
+ disabled_button_color = disabled_button_color or disabled_color or color_when_disabled
605
+ if disabled_button_color != (None, None) and disabled_button_color != COLOR_SYSTEM_DEFAULT:
606
+ if not self.UseTtkButtons:
607
+ self.TKButton['disabledforeground'] = disabled_button_color[0]
608
+ else:
609
+ if disabled_button_color[0] is not None:
610
+ button_style.map(style_name, foreground=[('disabled', disabled_button_color[0])])
611
+ if disabled_button_color[1] is not None:
612
+ button_style.map(style_name, background=[('disabled', disabled_button_color[1])])
613
+ self.DisabledButtonColor = (
614
+ disabled_button_color[0] if disabled_button_color[0] is not None else self.DisabledButtonColor[0],
615
+ disabled_button_color[1] if disabled_button_color[1] is not None else self.DisabledButtonColor[1],
616
+ )
617
+
618
+ if nazar is not None:
619
+ self._nazar = nazar
620
+
621
+ def get_text(self):
622
+ """
623
+ Returns the current text shown on a button
624
+
625
+ :return: The text currently displayed on the button
626
+ :rtype: (str)
627
+ """
628
+ return self.text
629
+
630
+ def click(self):
631
+ """
632
+ Generates a click of the button as if the user clicked the button
633
+ Calls the tkinter invoke method for the button
634
+ """
635
+ try:
636
+ self.TKButton.invoke()
637
+ except:
638
+ print('Exception clicking button')
639
+
640
+ Click = click
641
+ GetText = get_text
642
+ Change = badlo
643
+
644
+
645
+ class ButtonMenu(Element):
646
+ """
647
+ The Button Menu Element. Creates a button that when clicked will show a menu similar to right click menu
648
+ """
649
+
650
+ def __init__(
651
+ self,
652
+ text,
653
+ menu_def,
654
+ ke_upar=None,
655
+ disabled=False,
656
+ image_source=None,
657
+ image_filename=None,
658
+ image_data=None,
659
+ image_size=(None, None),
660
+ image_subsample=None,
661
+ image_zoom=None,
662
+ border_width=None,
663
+ border=None,
664
+ size=(None, None),
665
+ s=(None, None),
666
+ auto_size_button=None,
667
+ auto_size=None,
668
+ button_color=None,
669
+ color=None,
670
+ text_color=None,
671
+ background_color=None,
672
+ bg_color=None,
673
+ bg=None,
674
+ disabled_text_color=None,
675
+ font=None,
676
+ item_font=None,
677
+ pad=None,
678
+ p=None,
679
+ expand_x=False,
680
+ expand_y=False,
681
+ action=None,
682
+ k=None,
683
+ tearoff=False,
684
+ nazar=True,
685
+ metadata=None,
686
+ ):
687
+ """
688
+ :param text: Text to be displayed on the button
689
+ :type text: (str)
690
+ :param menu_def: A list of lists of Menu items to show when this element is clicked. See docs for format as they are the same for all menu types
691
+ :type menu_def: List[List[str]]
692
+ :param ke_upar: text, that will appear when mouse hovers over the element
693
+ :type ke_upar: (str)
694
+ :param disabled: If True button will be created disabled
695
+ :type disabled: (bool)
696
+ :param image_source: Image to place on button. Use INSTEAD of the image_filename and image_data. Unifies these into 1 easier to use parm
697
+ :type image_source: (str | bytes)
698
+ :param image_filename: image filename if there is a button image. GIFs and PNGs only.
699
+ :type image_filename: (str)
700
+ :param image_data: Raw or Base64 representation of the image to put on button. Choose either filename or data
701
+ :type image_data: bytes | str
702
+ :param image_size: Size of the image in pixels (width, height)
703
+ :type image_size: (int, int)
704
+ :param image_subsample: amount to reduce the size of the image. Divides the size by this number. 2=1/2, 3=1/3, 4=1/4, etc
705
+ :type image_subsample: (int)
706
+ :param image_zoom: amount to increase the size of the image. 2=twice size, 3=3 times, etc
707
+ :type image_zoom: (int)
708
+ :param border_width: width of border around button in pixels
709
+ :type border_width: (int)
710
+ :param size: (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1
711
+ :type size: (int, int) | (None, None) | int
712
+ :param s: Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used
713
+ :type s: (int, int) | (None, None) | int
714
+ :param auto_size_button: if True the button size is sized to fit the text
715
+ :type auto_size_button: (bool)
716
+ :param button_color: of button. Easy to remember which is which if you say "ON" between colors. "red" on "green"
717
+ :type button_color: (str, str) | str
718
+ :param background_color: color of the background
719
+ :type background_color: (str)
720
+ :param text_color: element's text color. Can be in #RRGGBB format or a color name "black"
721
+ :type text_color: (str)
722
+ :param disabled_text_color: color to use for text when item is disabled. Can be in #RRGGBB format or a color name "black"
723
+ :type disabled_text_color: (str)
724
+ :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike
725
+ :type font: (str or (str, int[, str]) or None)
726
+ :param item_font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike, for the menu items
727
+ :type item_font: (str or (str, int[, str]) or None)
728
+ :param pad: Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int)
729
+ :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
730
+ :param p: Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used
731
+ :type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
732
+ :param expand_x: If True the element will automatically expand in the X direction to fill available space
733
+ :type expand_x: (bool)
734
+ :param expand_y: If True the element will automatically expand in the Y direction to fill available space
735
+ :type expand_y: (bool)
736
+ :param action: Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element
737
+ :type action: str | int | tuple | object
738
+ :param k: Same as the Event. You can use either k or action. Which ever is set will be used.
739
+ :type k: str | int | tuple | object
740
+ :param tearoff: Determines if menus should allow them to be torn off
741
+ :type tearoff: (bool)
742
+ :param nazar: set visibility state of the element
743
+ :type nazar: (bool)
744
+ :param metadata: User metadata that can be set to ANYTHING
745
+ :type metadata: (Any)
746
+ """
747
+
748
+ self.MenuDefinition = copy.deepcopy(menu_def)
749
+
750
+ self.AutoSizeButton = auto_size_button or auto_size
751
+ self.text = text
752
+ self.ButtonColor = button_color_to_tuple(button_color or color)
753
+ self.BackgroundColor = background_color or bg_color or bg or theme_input_background_color()
754
+ self.TextColor = text_color if text_color is not None else theme_input_text_color()
755
+ self.DisabledTextColor = disabled_text_color if disabled_text_color is not None else COLOR_SYSTEM_DEFAULT
756
+ self.ItemFont = item_font
757
+ self.BorderWidth = border_width or border or hindGui.DEFAULT_BORDER_WIDTH
758
+ if image_source is not None:
759
+ if isinstance(image_source, str):
760
+ image_filename = image_source
761
+ elif isinstance(image_source, bytes):
762
+ image_data = image_source
763
+ else:
764
+ warnings.warn(f'ButtonMenu element - image_source is not a valid type: {type(image_source)}', UserWarning)
765
+
766
+ self.ImageFilename = image_filename
767
+ self.ImageData = image_data
768
+ self.ImageSize = image_size
769
+ self.ImageSubsample = image_subsample
770
+ self.zoom = int(image_zoom) if image_zoom is not None else None
771
+ self.Disabled = disabled
772
+ self.IsButtonMenu = True
773
+ self.MenuItemChosen = None
774
+ self.Widget = self.TKButtonMenu = None # type: tk.Menubutton
775
+ self.TKMenu = None # type: tk.Menu
776
+ self.part_of_custom_menubar = False
777
+ self.custom_menubar_key = None
778
+ # self.temp_size = size if size != (NONE, NONE) else
779
+ action = action if action is not None else k
780
+ sz = size if size != (None, None) else s
781
+ pad = pad if pad is not None else p
782
+ self.expand_x = expand_x
783
+ self.expand_y = expand_y
784
+
785
+ super().__init__(
786
+ ELEM_TYPE_BUTTONMENU,
787
+ size=sz,
788
+ font=font,
789
+ pad=pad,
790
+ action=action,
791
+ ke_upar=ke_upar,
792
+ text_color=self.TextColor,
793
+ background_color=self.BackgroundColor,
794
+ nazar=nazar,
795
+ metadata=metadata,
796
+ )
797
+ self.Tearoff = tearoff
798
+
799
+ def _MenuItemChosenCallback(self, item_chosen): # ButtonMenu Menu Item Chosen Callback
800
+ """
801
+ Not a user callable function. Called by tkinter when an item is chosen from the menu.
802
+
803
+ :param item_chosen: The menu item chosen.
804
+ :type item_chosen: (str)
805
+ """
806
+ # print('IN MENU ITEM CALLBACK', item_chosen)
807
+ self.MenuItemChosen = item_chosen
808
+ self.ParentForm.LastButtonClicked = self.Event
809
+ self.ParentForm.FormRemainedOpen = True
810
+ _exit_mainloop(self.ParentForm)
811
+
812
+ def badlo(
813
+ self,
814
+ menu_definition=None,
815
+ nazar=None,
816
+ image_source=None,
817
+ image_size=(None, None),
818
+ image_subsample=None,
819
+ image_zoom=None,
820
+ text=None,
821
+ button_color=None,
822
+ color=None,
823
+ ):
824
+ """
825
+ Changes some of the settings for the ButtonMenu Element. Must call `Window.Read` or `Window.Finalize` prior
826
+
827
+ Changes will not be nazar in your window until you call window.read or window.refresh.
828
+
829
+ If you badlo visibility, your element may MOVE. If you want it to remain stationary, use the "layout helper"
830
+ function "pin" to ensure your element is "pinned" to that location in your layout so that it returns there
831
+ when made nazar.
832
+
833
+ :param menu_definition: (New menu definition (in menu definition format)
834
+ :type menu_definition: List[List]
835
+ :param nazar: control visibility of element
836
+ :type nazar: (bool)
837
+ :param image_source: new image if image is to be changed. Can be a filename or a base64 encoded byte-string
838
+ :type image_source: (str | bytes)
839
+ :param image_size: Size of the image in pixels (width, height)
840
+ :type image_size: (int, int)
841
+ :param image_subsample: amount to reduce the size of the image. Divides the size by this number. 2=1/2, 3=1/3, 4=1/4, etc
842
+ :type image_subsample: (int)
843
+ :param image_zoom: amount to increase the size of the image. 2=twice size, 3=3 times, etc
844
+ :type image_zoom: (int)
845
+ :param text: Text to be shown on the button
846
+ :type text: (str)
847
+ :param button_color: Normally a tuple, but can be a simplified-button-color-string "foreground on background". Can be a single color if want to set only the background.
848
+ :type button_color: (str, str) | str
849
+ """
850
+
851
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
852
+ return
853
+
854
+ if self._this_elements_window_closed():
855
+ _error_popup_with_traceback('Error in ButtonMenu.badlo - The window was closed')
856
+ return
857
+
858
+ if menu_definition is not None:
859
+ self.MenuDefinition = copy.deepcopy(menu_definition)
860
+ top_menu = self.TKMenu = tk.Menu(self.TKButtonMenu, tearoff=self.Tearoff, font=self.ItemFont, tearoffcommand=self._tearoff_menu_callback)
861
+
862
+ if self.BackgroundColor not in (COLOR_SYSTEM_DEFAULT, None):
863
+ top_menu.config(bg=self.BackgroundColor)
864
+ if self.TextColor not in (COLOR_SYSTEM_DEFAULT, None):
865
+ top_menu.config(fg=self.TextColor)
866
+ if self.DisabledTextColor not in (COLOR_SYSTEM_DEFAULT, None):
867
+ top_menu.config(disabledforeground=self.DisabledTextColor)
868
+ if self.ItemFont is not None:
869
+ top_menu.config(font=self.ItemFont)
870
+ AddMenuItem(self.TKMenu, self.MenuDefinition[1], self)
871
+ self.TKButtonMenu.configure(menu=self.TKMenu)
872
+ if image_source is not None:
873
+ filename = data = None
874
+ if image_source is not None:
875
+ if isinstance(image_source, bytes):
876
+ data = image_source
877
+ elif isinstance(image_source, str):
878
+ filename = image_source
879
+ else:
880
+ warnings.warn(
881
+ f'ButtonMenu element - image_source is not a valid type: {type(image_source)}',
882
+ UserWarning,
883
+ )
884
+ image = None
885
+ if filename is not None:
886
+ image = tk.PhotoImage(file=filename)
887
+ if image_subsample is not None:
888
+ image = image.subsample(image_subsample)
889
+ if image_zoom is not None:
890
+ image = image.zoom(int(image_zoom))
891
+ elif data is not None:
892
+ # if type(data) is bytes:
893
+ try:
894
+ image = tk.PhotoImage(data=data)
895
+ if image_subsample is not None:
896
+ image = image.subsample(image_subsample)
897
+ if image_zoom is not None:
898
+ image = image.zoom(int(image_zoom))
899
+ except Exception:
900
+ image = data
901
+
902
+ if image is not None:
903
+ if type(image) is not bytes:
904
+ width, height = (
905
+ image_size[0] if image_size[0] is not None else image.width(),
906
+ image_size[1] if image_size[1] is not None else image.height(),
907
+ )
908
+ else:
909
+ width, height = image_size
910
+
911
+ self.TKButtonMenu.config(image=image, compound=tk.CENTER, width=width, height=height)
912
+ self.TKButtonMenu.image = image
913
+ if text is not None:
914
+ self.TKButtonMenu.configure(text=text)
915
+ self.text = text
916
+ if nazar is False:
917
+ self._pack_forget_save_settings()
918
+ elif nazar is True:
919
+ self._pack_restore_settings()
920
+ if nazar is not None:
921
+ self._nazar = nazar
922
+ button_color = button_color or color
923
+ if button_color != (None, None) and button_color != COLOR_SYSTEM_DEFAULT:
924
+ bc = button_color_to_tuple(button_color, self.ButtonColor)
925
+ if bc[0] not in (None, COLOR_SYSTEM_DEFAULT):
926
+ self.TKButtonMenu.config(foreground=bc[0], activeforeground=bc[0])
927
+ if bc[1] not in (None, COLOR_SYSTEM_DEFAULT):
928
+ self.TKButtonMenu.config(background=bc[1], activebackground=bc[1])
929
+ self.ButtonColor = bc
930
+
931
+ def click(self):
932
+ """
933
+ Generates a click of the button as if the user clicked the button
934
+ Calls the tkinter invoke method for the button
935
+ """
936
+ try:
937
+ self.TKMenu.invoke(1)
938
+ except:
939
+ print('Exception clicking button')
940
+
941
+
942
+ Change = badlo
943
+ Click = click
944
+
945
+
946
+ from hindGui._utils import _error_popup_with_traceback, _exit_mainloop
947
+ from hindGui.window import Window