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