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.
- KL_Py/KL_Py.py +4400 -0
- KL_Py/__init__.py +1 -0
- KL_Py/hindGui/__init__.py +16529 -0
- KL_Py/hindGui/_utils.py +140 -0
- KL_Py/hindGui/elements/base.py +1055 -0
- KL_Py/hindGui/elements/button.py +947 -0
- KL_Py/hindGui/elements/calendar.py +222 -0
- KL_Py/hindGui/elements/canvas.py +122 -0
- KL_Py/hindGui/elements/center.py +44 -0
- KL_Py/hindGui/elements/checkbox.py +240 -0
- KL_Py/hindGui/elements/column.py +443 -0
- KL_Py/hindGui/elements/combo.py +329 -0
- KL_Py/hindGui/elements/error.py +47 -0
- KL_Py/hindGui/elements/frame.py +273 -0
- KL_Py/hindGui/elements/graph.py +817 -0
- KL_Py/hindGui/elements/helpers.py +202 -0
- KL_Py/hindGui/elements/image.py +324 -0
- KL_Py/hindGui/elements/input.py +310 -0
- KL_Py/hindGui/elements/list_box.py +392 -0
- KL_Py/hindGui/elements/menu.py +192 -0
- KL_Py/hindGui/elements/multiline.py +685 -0
- KL_Py/hindGui/elements/option_menu.py +168 -0
- KL_Py/hindGui/elements/pane.py +127 -0
- KL_Py/hindGui/elements/progress_bar.py +304 -0
- KL_Py/hindGui/elements/radio.py +252 -0
- KL_Py/hindGui/elements/separator.py +64 -0
- KL_Py/hindGui/elements/sizegrip.py +34 -0
- KL_Py/hindGui/elements/slider.py +199 -0
- KL_Py/hindGui/elements/spin.py +252 -0
- KL_Py/hindGui/elements/status_bar.py +165 -0
- KL_Py/hindGui/elements/stretch.py +26 -0
- KL_Py/hindGui/elements/tab.py +697 -0
- KL_Py/hindGui/elements/table.py +463 -0
- KL_Py/hindGui/elements/text.py +413 -0
- KL_Py/hindGui/elements/tree.py +493 -0
- KL_Py/hindGui/replace.py +45 -0
- KL_Py/hindGui/tray.py +358 -0
- KL_Py/hindGui/window.py +2906 -0
- KL_Py/requests/__init__.py +184 -0
- KL_Py/requests/__version__.py +14 -0
- KL_Py/requests/_internal_utils.py +50 -0
- KL_Py/requests/adapters.py +719 -0
- KL_Py/requests/api.py +157 -0
- KL_Py/requests/auth.py +314 -0
- KL_Py/requests/certifi/__init__.py +4 -0
- KL_Py/requests/certifi/__main__.py +12 -0
- KL_Py/requests/certifi/core.py +83 -0
- KL_Py/requests/certifi/py.typed +0 -0
- KL_Py/requests/certs.py +17 -0
- KL_Py/requests/charset_normalizer/__init__.py +48 -0
- KL_Py/requests/charset_normalizer/__main__.py +6 -0
- KL_Py/requests/charset_normalizer/api.py +671 -0
- KL_Py/requests/charset_normalizer/cd.py +421 -0
- KL_Py/requests/charset_normalizer/cli/__init__.py +8 -0
- KL_Py/requests/charset_normalizer/cli/__main__.py +363 -0
- KL_Py/requests/charset_normalizer/constant.py +2031 -0
- KL_Py/requests/charset_normalizer/legacy.py +80 -0
- KL_Py/requests/charset_normalizer/md.py +744 -0
- KL_Py/requests/charset_normalizer/models.py +359 -0
- KL_Py/requests/charset_normalizer/py.typed +0 -0
- KL_Py/requests/charset_normalizer/utils.py +420 -0
- KL_Py/requests/charset_normalizer/version.py +8 -0
- KL_Py/requests/compat.py +106 -0
- KL_Py/requests/cookies.py +561 -0
- KL_Py/requests/exceptions.py +151 -0
- KL_Py/requests/help.py +134 -0
- KL_Py/requests/hooks.py +33 -0
- KL_Py/requests/idna/__init__.py +45 -0
- KL_Py/requests/idna/codec.py +122 -0
- KL_Py/requests/idna/compat.py +15 -0
- KL_Py/requests/idna/core.py +437 -0
- KL_Py/requests/idna/idnadata.py +4309 -0
- KL_Py/requests/idna/intranges.py +57 -0
- KL_Py/requests/idna/package_data.py +1 -0
- KL_Py/requests/idna/py.typed +0 -0
- KL_Py/requests/idna/uts46data.py +8841 -0
- KL_Py/requests/models.py +1039 -0
- KL_Py/requests/packages.py +23 -0
- KL_Py/requests/sessions.py +831 -0
- KL_Py/requests/status_codes.py +128 -0
- KL_Py/requests/structures.py +99 -0
- KL_Py/requests/urllib3/__init__.py +211 -0
- KL_Py/requests/urllib3/_base_connection.py +165 -0
- KL_Py/requests/urllib3/_collections.py +487 -0
- KL_Py/requests/urllib3/_request_methods.py +278 -0
- KL_Py/requests/urllib3/_version.py +34 -0
- KL_Py/requests/urllib3/connection.py +1099 -0
- KL_Py/requests/urllib3/connectionpool.py +1178 -0
- KL_Py/requests/urllib3/contrib/__init__.py +0 -0
- KL_Py/requests/urllib3/contrib/emscripten/__init__.py +17 -0
- KL_Py/requests/urllib3/contrib/emscripten/connection.py +260 -0
- KL_Py/requests/urllib3/contrib/emscripten/fetch.py +726 -0
- KL_Py/requests/urllib3/contrib/emscripten/request.py +22 -0
- KL_Py/requests/urllib3/contrib/emscripten/response.py +277 -0
- KL_Py/requests/urllib3/contrib/pyopenssl.py +564 -0
- KL_Py/requests/urllib3/contrib/socks.py +228 -0
- KL_Py/requests/urllib3/exceptions.py +335 -0
- KL_Py/requests/urllib3/fields.py +341 -0
- KL_Py/requests/urllib3/filepost.py +89 -0
- KL_Py/requests/urllib3/http2/__init__.py +53 -0
- KL_Py/requests/urllib3/http2/connection.py +356 -0
- KL_Py/requests/urllib3/http2/probe.py +87 -0
- KL_Py/requests/urllib3/poolmanager.py +651 -0
- KL_Py/requests/urllib3/py.typed +2 -0
- KL_Py/requests/urllib3/response.py +1480 -0
- KL_Py/requests/urllib3/util/__init__.py +42 -0
- KL_Py/requests/urllib3/util/connection.py +137 -0
- KL_Py/requests/urllib3/util/proxy.py +43 -0
- KL_Py/requests/urllib3/util/request.py +263 -0
- KL_Py/requests/urllib3/util/response.py +101 -0
- KL_Py/requests/urllib3/util/retry.py +549 -0
- KL_Py/requests/urllib3/util/ssl_.py +527 -0
- KL_Py/requests/urllib3/util/ssl_match_hostname.py +159 -0
- KL_Py/requests/urllib3/util/ssltransport.py +271 -0
- KL_Py/requests/urllib3/util/timeout.py +275 -0
- KL_Py/requests/urllib3/util/url.py +469 -0
- KL_Py/requests/urllib3/util/util.py +42 -0
- KL_Py/requests/urllib3/util/wait.py +124 -0
- KL_Py/requests/utils.py +1086 -0
- KL_Py/when.py +144 -0
- kl_py-0.0.1.dist-info/METADATA +15 -0
- kl_py-0.0.1.dist-info/RECORD +125 -0
- kl_py-0.0.1.dist-info/WHEEL +5 -0
- kl_py-0.0.1.dist-info/licenses/LICENSE +21 -0
- 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
|