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,697 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tkinter as tk
|
|
4
|
+
import warnings
|
|
5
|
+
from tkinter import ttk
|
|
6
|
+
|
|
7
|
+
import hindGui
|
|
8
|
+
from hindGui import _add_right_click_menu
|
|
9
|
+
from hindGui import _random_error_emoji
|
|
10
|
+
from hindGui import COLOR_SYSTEM_DEFAULT
|
|
11
|
+
from hindGui import ELEM_TYPE_TAB
|
|
12
|
+
from hindGui import ELEM_TYPE_TAB_GROUP
|
|
13
|
+
from hindGui import Element
|
|
14
|
+
from hindGui import LOOK_AND_FEEL_TABLE
|
|
15
|
+
from hindGui import PackFormIntoFrame
|
|
16
|
+
from hindGui import error
|
|
17
|
+
from hindGui import error_with_traceback
|
|
18
|
+
from hindGui import Hover
|
|
19
|
+
from hindGui._utils import _error_popup_with_traceback
|
|
20
|
+
from hindGui.window import Window
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Tab(Element):
|
|
24
|
+
"""
|
|
25
|
+
Tab Element is another "Container" element that holds a layout and displays a tab with text. Used with TabGroup only
|
|
26
|
+
Tabs are never placed directly into a layout. They are always "Contained" in a TabGroup layout
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
title,
|
|
32
|
+
layout,
|
|
33
|
+
title_color=None,
|
|
34
|
+
background_color=None,
|
|
35
|
+
font=None,
|
|
36
|
+
pad=None,
|
|
37
|
+
p=None,
|
|
38
|
+
disabled=False,
|
|
39
|
+
border_width=None,
|
|
40
|
+
action=None,
|
|
41
|
+
k=None,
|
|
42
|
+
ke_upar=None,
|
|
43
|
+
right_click_menu=None,
|
|
44
|
+
expand_x=False,
|
|
45
|
+
expand_y=False,
|
|
46
|
+
nazar=True,
|
|
47
|
+
element_justification='left',
|
|
48
|
+
image_source=None,
|
|
49
|
+
image_subsample=None,
|
|
50
|
+
image_zoom=None,
|
|
51
|
+
metadata=None,
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
:param title: text to show on the tab
|
|
55
|
+
:type title: (str)
|
|
56
|
+
:param layout: The element layout that will be shown in the tab
|
|
57
|
+
:type layout: List[List[Element]]
|
|
58
|
+
:param title_color: color of the tab text (note not currently working on tkinter)
|
|
59
|
+
:type title_color: (str)
|
|
60
|
+
:param background_color: color of background of the entire layout
|
|
61
|
+
:type background_color: (str)
|
|
62
|
+
:param font: NOT USED in the tkinter port
|
|
63
|
+
:type font: (str or (str, int[, str]) or None)
|
|
64
|
+
: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)
|
|
65
|
+
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
|
|
66
|
+
: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
|
|
67
|
+
:type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
|
|
68
|
+
:param disabled: If True button will be created disabled
|
|
69
|
+
:type disabled: (bool)
|
|
70
|
+
:param border_width: NOT USED in tkinter port
|
|
71
|
+
:type border_width: (int)
|
|
72
|
+
:param action: Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window
|
|
73
|
+
:type action: str | int | tuple | object
|
|
74
|
+
:param k: Same as the Key. You can use either k or action. Which ever is set will be used.
|
|
75
|
+
:type k: str | int | tuple | object
|
|
76
|
+
:param ke_upar: text, that will appear when mouse hovers over the element
|
|
77
|
+
:type ke_upar: (str)
|
|
78
|
+
: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.
|
|
79
|
+
:type right_click_menu: List[List[ List[str] | str ]]
|
|
80
|
+
:param expand_x: If True the element will automatically expand in the X direction to fill available space
|
|
81
|
+
:type expand_x: (bool)
|
|
82
|
+
:param expand_y: If True the element will automatically expand in the Y direction to fill available space
|
|
83
|
+
:type expand_y: (bool)
|
|
84
|
+
:param nazar: set visibility state of the element
|
|
85
|
+
:type nazar: (bool)
|
|
86
|
+
:param element_justification: All elements inside the Tab will have this justification 'left', 'right', 'center' are valid values
|
|
87
|
+
:type element_justification: (str)
|
|
88
|
+
:param image_source: A filename or a base64 bytes of an image to place on the Tab
|
|
89
|
+
:type image_source: str | bytes | None
|
|
90
|
+
: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
|
|
91
|
+
:type image_subsample: (int)
|
|
92
|
+
:param image_zoom: amount to increase the size of the image. 2=twice size, 3=3 times, etc
|
|
93
|
+
:type image_zoom: (int)
|
|
94
|
+
:param metadata: User metadata that can be set to ANYTHING
|
|
95
|
+
:type metadata: (Any)
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
filename = data = None
|
|
99
|
+
if image_source is not None:
|
|
100
|
+
if isinstance(image_source, bytes):
|
|
101
|
+
data = image_source
|
|
102
|
+
elif isinstance(image_source, str):
|
|
103
|
+
filename = image_source
|
|
104
|
+
else:
|
|
105
|
+
warnings.warn(f'Image element - source is not a valid type: {type(image_source)}', UserWarning)
|
|
106
|
+
|
|
107
|
+
self.Filename = filename
|
|
108
|
+
self.Data = data
|
|
109
|
+
self.ImageSubsample = image_subsample
|
|
110
|
+
self.zoom = int(image_zoom) if image_zoom is not None else None
|
|
111
|
+
self.UseDictionary = False
|
|
112
|
+
self.ReturnValues = None
|
|
113
|
+
self.ReturnValuesList = []
|
|
114
|
+
self.ReturnValuesDictionary = {}
|
|
115
|
+
self.DictionaryKeyCounter = 0
|
|
116
|
+
self.ParentWindow = None
|
|
117
|
+
self.Rows = []
|
|
118
|
+
self.TKFrame = None
|
|
119
|
+
self.Widget = None # type: tk.Frame
|
|
120
|
+
self.Title = title
|
|
121
|
+
self.BorderWidth = border_width
|
|
122
|
+
self.Disabled = disabled
|
|
123
|
+
self.ParentNotebook = None
|
|
124
|
+
self.TabID = None
|
|
125
|
+
self.BackgroundColor = background_color if background_color is not None else hindGui.DEFAULT_BACKGROUND_COLOR
|
|
126
|
+
self.RightClickMenu = right_click_menu
|
|
127
|
+
self.ContainerElemementNumber = Window._GetAContainerNumber()
|
|
128
|
+
self.ElementJustification = element_justification
|
|
129
|
+
action = action if action is not None else k
|
|
130
|
+
pad = pad if pad is not None else p
|
|
131
|
+
self.expand_x = expand_x
|
|
132
|
+
self.expand_y = expand_y
|
|
133
|
+
|
|
134
|
+
self.Layout(layout)
|
|
135
|
+
|
|
136
|
+
super().__init__(
|
|
137
|
+
ELEM_TYPE_TAB,
|
|
138
|
+
background_color=background_color,
|
|
139
|
+
text_color=title_color,
|
|
140
|
+
font=font,
|
|
141
|
+
pad=pad,
|
|
142
|
+
action=action,
|
|
143
|
+
ke_upar=ke_upar,
|
|
144
|
+
nazar=nazar,
|
|
145
|
+
metadata=metadata,
|
|
146
|
+
)
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
def add_row(self, *args):
|
|
150
|
+
"""
|
|
151
|
+
Not recommended use call. Used to add rows of Elements to the Frame Element.
|
|
152
|
+
|
|
153
|
+
:param *args: The list of elements for this row
|
|
154
|
+
:type *args: List[Element]
|
|
155
|
+
"""
|
|
156
|
+
NumRows = len(self.Rows) # number of existing rows is our row number
|
|
157
|
+
CurrentRowNumber = NumRows # this row's number
|
|
158
|
+
CurrentRow = [] # start with a blank row and build up
|
|
159
|
+
# ------------------------- Add the elements to a row ------------------------- #
|
|
160
|
+
for i, element in enumerate(args): # Loop through list of elements and add them to the row
|
|
161
|
+
if type(element) is list:
|
|
162
|
+
error_with_traceback(
|
|
163
|
+
'Error creating Tab layout',
|
|
164
|
+
'Layout has a LIST instead of an ELEMENT',
|
|
165
|
+
'This sometimes means you have a badly placed ]',
|
|
166
|
+
'The offensive list is:',
|
|
167
|
+
element,
|
|
168
|
+
'This list will be stripped from your layout',
|
|
169
|
+
)
|
|
170
|
+
continue
|
|
171
|
+
elif callable(element) and not isinstance(element, Element):
|
|
172
|
+
error_with_traceback(
|
|
173
|
+
'Error creating Tab layout',
|
|
174
|
+
'Layout has a FUNCTION instead of an ELEMENT',
|
|
175
|
+
'This likely means you are missing () from your layout',
|
|
176
|
+
'The offensive list is:',
|
|
177
|
+
element,
|
|
178
|
+
'This item will be stripped from your layout',
|
|
179
|
+
)
|
|
180
|
+
continue
|
|
181
|
+
if element.ParentContainer is not None:
|
|
182
|
+
warnings.warn(
|
|
183
|
+
'*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***',
|
|
184
|
+
UserWarning,
|
|
185
|
+
)
|
|
186
|
+
error_with_traceback(
|
|
187
|
+
'Error creating Tab layout',
|
|
188
|
+
'The layout specified has already been used',
|
|
189
|
+
'You MUST start witha "clean", unused layout every time you create a window',
|
|
190
|
+
'The offensive Element = ',
|
|
191
|
+
element,
|
|
192
|
+
'and has a action = ',
|
|
193
|
+
element.Key,
|
|
194
|
+
'This item will be stripped from your layout',
|
|
195
|
+
'Hint - try printing your layout and matching the IDs "print(layout)"',
|
|
196
|
+
)
|
|
197
|
+
continue
|
|
198
|
+
element.Position = (CurrentRowNumber, i)
|
|
199
|
+
element.ParentContainer = self
|
|
200
|
+
CurrentRow.append(element)
|
|
201
|
+
if element.Key is not None:
|
|
202
|
+
self.UseDictionary = True
|
|
203
|
+
# ------------------------- Append the row to list of Rows ------------------------- #
|
|
204
|
+
self.Rows.append(CurrentRow)
|
|
205
|
+
|
|
206
|
+
def layout(self, rows):
|
|
207
|
+
"""
|
|
208
|
+
Not user callable. Use layout parameter instead. Creates the layout using the supplied rows of Elements
|
|
209
|
+
|
|
210
|
+
:param rows: List[List[Element]] The list of rows
|
|
211
|
+
:type rows: List[List[Element]]
|
|
212
|
+
:return: (Tab) used for chaining
|
|
213
|
+
:rtype:
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
for row in rows:
|
|
217
|
+
try:
|
|
218
|
+
iter(row)
|
|
219
|
+
except TypeError:
|
|
220
|
+
error(
|
|
221
|
+
'Error creating Tab layout',
|
|
222
|
+
'Your row is not an iterable (e.g. a list)',
|
|
223
|
+
f'Instead of a list, the type found was {type(row)}',
|
|
224
|
+
'The offensive row = ',
|
|
225
|
+
row,
|
|
226
|
+
'This item will be stripped from your layout',
|
|
227
|
+
ehem=True,
|
|
228
|
+
image=_random_error_emoji(),
|
|
229
|
+
)
|
|
230
|
+
continue
|
|
231
|
+
self.AddRow(*row)
|
|
232
|
+
return self
|
|
233
|
+
|
|
234
|
+
def badlo(self, title=None, disabled=None, nazar=None):
|
|
235
|
+
"""
|
|
236
|
+
Changes some of the settings for the Tab Element. Must call `Window.Read` or `Window.Finalize` prior
|
|
237
|
+
|
|
238
|
+
Changes will not be nazar in your window until you call window.read or window.refresh.
|
|
239
|
+
|
|
240
|
+
If you badlo visibility, your element may MOVE. If you want it to remain stationary, use the "layout helper"
|
|
241
|
+
function "pin" to ensure your element is "pinned" to that location in your layout so that it returns there
|
|
242
|
+
when made nazar.
|
|
243
|
+
|
|
244
|
+
:param title: tab title
|
|
245
|
+
:type title: (str)
|
|
246
|
+
:param disabled: disable or enable state of the element
|
|
247
|
+
:type disabled: (bool)
|
|
248
|
+
:param nazar: control visibility of element
|
|
249
|
+
:type nazar: (bool)
|
|
250
|
+
"""
|
|
251
|
+
if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
if self._this_elements_window_closed():
|
|
255
|
+
_error_popup_with_traceback('Error in Tab.badlo - The window was closed')
|
|
256
|
+
return
|
|
257
|
+
|
|
258
|
+
state = 'normal'
|
|
259
|
+
if disabled is not None:
|
|
260
|
+
self.Disabled = disabled
|
|
261
|
+
if disabled:
|
|
262
|
+
state = 'disabled'
|
|
263
|
+
if nazar is False:
|
|
264
|
+
state = 'hidden'
|
|
265
|
+
if nazar is not None:
|
|
266
|
+
self._nazar = nazar
|
|
267
|
+
|
|
268
|
+
self.ParentNotebook.tab(self.TabID, state=state)
|
|
269
|
+
|
|
270
|
+
if title is not None:
|
|
271
|
+
self.Title = str(title)
|
|
272
|
+
self.ParentNotebook.tab(self.TabID, text=self.Title)
|
|
273
|
+
return self
|
|
274
|
+
|
|
275
|
+
def _GetElementAtLocation(self, location):
|
|
276
|
+
"""
|
|
277
|
+
Not user callable. Used to find the Element at a row, col position within the layout
|
|
278
|
+
|
|
279
|
+
:param location: (row, column) position of the element to find in layout
|
|
280
|
+
:type location: (int, int)
|
|
281
|
+
:return: The element found at the location
|
|
282
|
+
:rtype: (Element)
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
(row_num, col_num) = location
|
|
286
|
+
row = self.Rows[row_num]
|
|
287
|
+
element = row[col_num]
|
|
288
|
+
return element
|
|
289
|
+
|
|
290
|
+
def select(self):
|
|
291
|
+
"""
|
|
292
|
+
Create a tkinter action that mimics user clicking on a tab. Must have called window.Finalize / Read first!
|
|
293
|
+
|
|
294
|
+
"""
|
|
295
|
+
# Use a try in case the window has been destoyed
|
|
296
|
+
try:
|
|
297
|
+
self.ParentNotebook.select(self.TabID)
|
|
298
|
+
except Exception as e:
|
|
299
|
+
print(f'Exception Selecting Tab {e}')
|
|
300
|
+
|
|
301
|
+
AddRow = add_row
|
|
302
|
+
Layout = layout
|
|
303
|
+
Select = select
|
|
304
|
+
Change = badlo
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class TabGroup(Element):
|
|
308
|
+
"""
|
|
309
|
+
TabGroup Element groups together your tabs into the group of tabs you see displayed in your window
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
def __init__(
|
|
313
|
+
self,
|
|
314
|
+
layout,
|
|
315
|
+
tab_location=None,
|
|
316
|
+
title_color=None,
|
|
317
|
+
tab_background_color=None,
|
|
318
|
+
selected_title_color=None,
|
|
319
|
+
selected_background_color=None,
|
|
320
|
+
background_color=None,
|
|
321
|
+
focus_color=None,
|
|
322
|
+
font=None,
|
|
323
|
+
change_submits=False,
|
|
324
|
+
enable_events=False,
|
|
325
|
+
pad=None,
|
|
326
|
+
p=None,
|
|
327
|
+
border_width=None,
|
|
328
|
+
tab_border_width=None,
|
|
329
|
+
theme=None,
|
|
330
|
+
action=None,
|
|
331
|
+
k=None,
|
|
332
|
+
size=(None, None),
|
|
333
|
+
s=(None, None),
|
|
334
|
+
ke_upar=None,
|
|
335
|
+
right_click_menu=None,
|
|
336
|
+
expand_x=False,
|
|
337
|
+
expand_y=False,
|
|
338
|
+
nazar=True,
|
|
339
|
+
metadata=None,
|
|
340
|
+
):
|
|
341
|
+
"""
|
|
342
|
+
:param layout: Layout of Tabs. Different than normal layouts. ALL Tabs should be on first row
|
|
343
|
+
:type layout: List[List[Tab]]
|
|
344
|
+
:param tab_location: location that tabs will be displayed. Choices are left, right, top, bottom, lefttop, leftbottom, righttop, rightbottom, bottomleft, bottomright, topleft, topright
|
|
345
|
+
:type tab_location: (str)
|
|
346
|
+
:param title_color: color of text on tabs
|
|
347
|
+
:type title_color: (str)
|
|
348
|
+
:param tab_background_color: color of all tabs that are not selected
|
|
349
|
+
:type tab_background_color: (str)
|
|
350
|
+
:param selected_title_color: color of tab text when it is selected
|
|
351
|
+
:type selected_title_color: (str)
|
|
352
|
+
:param selected_background_color: color of tab when it is selected
|
|
353
|
+
:type selected_background_color: (str)
|
|
354
|
+
:param background_color: color of background area that tabs are located on
|
|
355
|
+
:type background_color: (str)
|
|
356
|
+
:param focus_color: color of focus indicator on the tabs
|
|
357
|
+
:type focus_color: (str)
|
|
358
|
+
:param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike
|
|
359
|
+
:type font: (str or (str, int[, str]) or None)
|
|
360
|
+
:param change_submits: * DEPRICATED DO NOT USE. Use `enable_events` instead
|
|
361
|
+
:type change_submits: (bool)
|
|
362
|
+
:param enable_events: If True then switching tabs will generate an Event
|
|
363
|
+
:type enable_events: (bool)
|
|
364
|
+
: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)
|
|
365
|
+
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
|
|
366
|
+
: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
|
|
367
|
+
:type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
|
|
368
|
+
:param border_width: width of border around element in pixels
|
|
369
|
+
:type border_width: (int)
|
|
370
|
+
:param tab_border_width: width of border around the tabs
|
|
371
|
+
:type tab_border_width: (int)
|
|
372
|
+
:param theme: DEPRICATED - You can only specify themes using set options or when window is created. It's not possible to do it on an element basis
|
|
373
|
+
:type theme: (enum)
|
|
374
|
+
:param action: Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window
|
|
375
|
+
:type action: str | int | tuple | object
|
|
376
|
+
:param k: Same as the Key. You can use either k or action. Which ever is set will be used.
|
|
377
|
+
:type k: str | int | tuple | object
|
|
378
|
+
:param size: (width, height) w=pixels-wide, h=pixels-high. Either item in tuple can be None to indicate use the computed value and set only 1 direction
|
|
379
|
+
:type size: (int|None, int|None)
|
|
380
|
+
: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
|
|
381
|
+
:type s: (int|None, int|None)
|
|
382
|
+
:param ke_upar: text, that will appear when mouse hovers over the element
|
|
383
|
+
:type ke_upar: (str)
|
|
384
|
+
: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.
|
|
385
|
+
:type right_click_menu: List[List[ List[str] | str ]]
|
|
386
|
+
:param expand_x: If True the element will automatically expand in the X direction to fill available space
|
|
387
|
+
:type expand_x: (bool)
|
|
388
|
+
:param expand_y: If True the element will automatically expand in the Y direction to fill available space
|
|
389
|
+
:type expand_y: (bool)
|
|
390
|
+
:param nazar: DEPRECATED - Should you need to control visiblity for the TabGroup as a whole, place it into a Column element
|
|
391
|
+
:type nazar: (bool)
|
|
392
|
+
:param metadata: User metadata that can be set to ANYTHING
|
|
393
|
+
:type metadata: (Any)
|
|
394
|
+
"""
|
|
395
|
+
|
|
396
|
+
self.UseDictionary = False
|
|
397
|
+
self.ReturnValues = None
|
|
398
|
+
self.ReturnValuesList = []
|
|
399
|
+
self.ReturnValuesDictionary = {}
|
|
400
|
+
self.DictionaryKeyCounter = 0
|
|
401
|
+
self.ParentWindow = None
|
|
402
|
+
self.SelectedTitleColor = selected_title_color if selected_title_color is not None else LOOK_AND_FEEL_TABLE[hindGui.CURRENT_LOOK_AND_FEEL]['TEXT']
|
|
403
|
+
self.SelectedBackgroundColor = selected_background_color if selected_background_color is not None else LOOK_AND_FEEL_TABLE[hindGui.CURRENT_LOOK_AND_FEEL]['BACKGROUND']
|
|
404
|
+
title_color = title_color if title_color is not None else LOOK_AND_FEEL_TABLE[hindGui.CURRENT_LOOK_AND_FEEL]['TEXT_INPUT']
|
|
405
|
+
self.TabBackgroundColor = tab_background_color if tab_background_color is not None else LOOK_AND_FEEL_TABLE[hindGui.CURRENT_LOOK_AND_FEEL]['INPUT']
|
|
406
|
+
self.Rows = []
|
|
407
|
+
self.TKNotebook = None # type: ttk.Notebook
|
|
408
|
+
self.Widget = None # type: ttk.Notebook
|
|
409
|
+
self.tab_index_to_key = {} # has a list of the tabs in the notebook and their associated action
|
|
410
|
+
self.TabCount = 0
|
|
411
|
+
self.BorderWidth = border_width
|
|
412
|
+
self.BackgroundColor = background_color if background_color is not None else hindGui.DEFAULT_BACKGROUND_COLOR
|
|
413
|
+
self.ChangeSubmits = change_submits or enable_events
|
|
414
|
+
self.TabLocation = tab_location
|
|
415
|
+
self.ElementJustification = 'left'
|
|
416
|
+
self.RightClickMenu = right_click_menu
|
|
417
|
+
self.TabBorderWidth = tab_border_width
|
|
418
|
+
self.FocusColor = focus_color
|
|
419
|
+
|
|
420
|
+
action = action if action is not None else k
|
|
421
|
+
sz = size if size != (None, None) else s
|
|
422
|
+
pad = pad if pad is not None else p
|
|
423
|
+
self.expand_x = expand_x
|
|
424
|
+
self.expand_y = expand_y
|
|
425
|
+
|
|
426
|
+
self.Layout(layout)
|
|
427
|
+
|
|
428
|
+
super().__init__(
|
|
429
|
+
ELEM_TYPE_TAB_GROUP,
|
|
430
|
+
size=sz,
|
|
431
|
+
background_color=background_color,
|
|
432
|
+
text_color=title_color,
|
|
433
|
+
font=font,
|
|
434
|
+
pad=pad,
|
|
435
|
+
action=action,
|
|
436
|
+
ke_upar=ke_upar,
|
|
437
|
+
nazar=nazar,
|
|
438
|
+
metadata=metadata,
|
|
439
|
+
)
|
|
440
|
+
return
|
|
441
|
+
|
|
442
|
+
def add_row(self, *args):
|
|
443
|
+
"""
|
|
444
|
+
Not recommended user call. Used to add rows of Elements to the Frame Element.
|
|
445
|
+
|
|
446
|
+
:param *args: The list of elements for this row
|
|
447
|
+
:type *args: List[Element]
|
|
448
|
+
"""
|
|
449
|
+
|
|
450
|
+
NumRows = len(self.Rows) # number of existing rows is our row number
|
|
451
|
+
CurrentRowNumber = NumRows # this row's number
|
|
452
|
+
CurrentRow = [] # start with a blank row and build up
|
|
453
|
+
# ------------------------- Add the elements to a row ------------------------- #
|
|
454
|
+
for i, element in enumerate(args): # Loop through list of elements and add them to the row
|
|
455
|
+
if type(element) is list:
|
|
456
|
+
error(
|
|
457
|
+
'Error creating Tab layout',
|
|
458
|
+
'Layout has a LIST instead of an ELEMENT',
|
|
459
|
+
'This sometimes means you have a badly placed ]',
|
|
460
|
+
'The offensive list is:',
|
|
461
|
+
element,
|
|
462
|
+
'This list will be stripped from your layout',
|
|
463
|
+
ehem=True,
|
|
464
|
+
image=_random_error_emoji(),
|
|
465
|
+
)
|
|
466
|
+
continue
|
|
467
|
+
elif callable(element) and not isinstance(element, Element):
|
|
468
|
+
error(
|
|
469
|
+
'Error creating Tab layout',
|
|
470
|
+
'Layout has a FUNCTION instead of an ELEMENT',
|
|
471
|
+
'This likely means you are missing () from your layout',
|
|
472
|
+
'The offensive list is:',
|
|
473
|
+
element,
|
|
474
|
+
'This item will be stripped from your layout',
|
|
475
|
+
ehem=True,
|
|
476
|
+
image=_random_error_emoji(),
|
|
477
|
+
)
|
|
478
|
+
continue
|
|
479
|
+
if element.ParentContainer is not None:
|
|
480
|
+
warnings.warn(
|
|
481
|
+
'*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***',
|
|
482
|
+
UserWarning,
|
|
483
|
+
)
|
|
484
|
+
error(
|
|
485
|
+
'Error creating Tab layout',
|
|
486
|
+
'The layout specified has already been used',
|
|
487
|
+
'You MUST start witha "clean", unused layout every time you create a window',
|
|
488
|
+
'The offensive Element = ',
|
|
489
|
+
element,
|
|
490
|
+
'and has a action = ',
|
|
491
|
+
element.Key,
|
|
492
|
+
'This item will be stripped from your layout',
|
|
493
|
+
'Hint - try printing your layout and matching the IDs "print(layout)"',
|
|
494
|
+
ehem=True,
|
|
495
|
+
image=_random_error_emoji(),
|
|
496
|
+
)
|
|
497
|
+
continue
|
|
498
|
+
element.Position = (CurrentRowNumber, i)
|
|
499
|
+
element.ParentContainer = self
|
|
500
|
+
CurrentRow.append(element)
|
|
501
|
+
if element.Key is not None:
|
|
502
|
+
self.UseDictionary = True
|
|
503
|
+
# ------------------------- Append the row to list of Rows ------------------------- #
|
|
504
|
+
self.Rows.append(CurrentRow)
|
|
505
|
+
|
|
506
|
+
def layout(self, rows):
|
|
507
|
+
"""
|
|
508
|
+
Can use like the Window.Layout method, but it's better to use the layout parameter when creating
|
|
509
|
+
|
|
510
|
+
:param rows: The rows of Elements
|
|
511
|
+
:type rows: List[List[Element]]
|
|
512
|
+
:return: Used for chaining
|
|
513
|
+
:rtype: (Frame)
|
|
514
|
+
"""
|
|
515
|
+
for row in rows:
|
|
516
|
+
try:
|
|
517
|
+
iter(row)
|
|
518
|
+
except TypeError:
|
|
519
|
+
error(
|
|
520
|
+
'Error creating Tab layout',
|
|
521
|
+
'Your row is not an iterable (e.g. a list)',
|
|
522
|
+
f'Instead of a list, the type found was {type(row)}',
|
|
523
|
+
'The offensive row = ',
|
|
524
|
+
row,
|
|
525
|
+
'This item will be stripped from your layout',
|
|
526
|
+
ehem=True,
|
|
527
|
+
image=_random_error_emoji(),
|
|
528
|
+
)
|
|
529
|
+
continue
|
|
530
|
+
self.AddRow(*row)
|
|
531
|
+
return self
|
|
532
|
+
|
|
533
|
+
def _GetElementAtLocation(self, location):
|
|
534
|
+
"""
|
|
535
|
+
Not user callable. Used to find the Element at a row, col position within the layout
|
|
536
|
+
|
|
537
|
+
:param location: (row, column) position of the element to find in layout
|
|
538
|
+
:type location: (int, int)
|
|
539
|
+
:return: The element found at the location
|
|
540
|
+
:rtype: (Element)
|
|
541
|
+
"""
|
|
542
|
+
|
|
543
|
+
(row_num, col_num) = location
|
|
544
|
+
row = self.Rows[row_num]
|
|
545
|
+
element = row[col_num]
|
|
546
|
+
return element
|
|
547
|
+
|
|
548
|
+
def find_key_from_tab_name(self, tab_name):
|
|
549
|
+
"""
|
|
550
|
+
Searches through the layout to find the action that matches the text on the tab. Implies names should be unique
|
|
551
|
+
|
|
552
|
+
:param tab_name: name of a tab
|
|
553
|
+
:type tab_name: str
|
|
554
|
+
:return: Returns the action or None if no action found
|
|
555
|
+
:rtype: action | None
|
|
556
|
+
"""
|
|
557
|
+
for row in self.Rows:
|
|
558
|
+
for element in row:
|
|
559
|
+
if element.Title == tab_name:
|
|
560
|
+
return element.Key
|
|
561
|
+
return None
|
|
562
|
+
|
|
563
|
+
def find_currently_active_tab_key(self):
|
|
564
|
+
"""
|
|
565
|
+
Returns the action for the currently active tab in this TabGroup
|
|
566
|
+
:return: Returns the action or None of no action found
|
|
567
|
+
:rtype: action | None
|
|
568
|
+
"""
|
|
569
|
+
try:
|
|
570
|
+
current_index = self.TKNotebook.index('current')
|
|
571
|
+
action = self.tab_index_to_key.get(current_index, None)
|
|
572
|
+
except:
|
|
573
|
+
action = None
|
|
574
|
+
|
|
575
|
+
return action
|
|
576
|
+
|
|
577
|
+
def get(self):
|
|
578
|
+
"""
|
|
579
|
+
Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on
|
|
580
|
+
the tab if no action is defined. Returns None if an error occurs.
|
|
581
|
+
Note that this is exactly the same data that would be returned from a call to Window.read. Are you sure you
|
|
582
|
+
are using this method correctly?
|
|
583
|
+
|
|
584
|
+
:return: The action of the currently selected tab or None if there is an error
|
|
585
|
+
:rtype: Any | None
|
|
586
|
+
"""
|
|
587
|
+
|
|
588
|
+
try:
|
|
589
|
+
current_index = self.TKNotebook.index('current')
|
|
590
|
+
action = self.tab_index_to_key.get(current_index, None)
|
|
591
|
+
except:
|
|
592
|
+
action = None
|
|
593
|
+
|
|
594
|
+
return action
|
|
595
|
+
|
|
596
|
+
def add_tab(self, tab_element):
|
|
597
|
+
"""
|
|
598
|
+
Add a new tab to an existing TabGroup
|
|
599
|
+
This call was written so that tabs can be added at runtime as your user performs operations.
|
|
600
|
+
Your Window should already be created and finalized.
|
|
601
|
+
|
|
602
|
+
:param tab_element: A Tab Element that has a layout in it
|
|
603
|
+
:type tab_element: Tab
|
|
604
|
+
"""
|
|
605
|
+
|
|
606
|
+
self.add_row(tab_element)
|
|
607
|
+
tab_element.TKFrame = tab_element.Widget = tk.Frame(self.TKNotebook)
|
|
608
|
+
form = self.ParentForm
|
|
609
|
+
form._BuildKeyDictForWindow(form, tab_element, form.AllKeysDict)
|
|
610
|
+
form.AllKeysDict[tab_element.Key] = tab_element
|
|
611
|
+
# Pack the tab's layout into the tab. NOTE - This does NOT pack the Tab itself... for that see below...
|
|
612
|
+
PackFormIntoFrame(tab_element, tab_element.TKFrame, self.ParentForm)
|
|
613
|
+
|
|
614
|
+
# - This is below - Perform the same operation that is performed when a Tab is packed into the window.
|
|
615
|
+
# If there's an image in the tab, then do the imagey-stuff
|
|
616
|
+
# ------------------- start of imagey-stuff -------------------
|
|
617
|
+
try:
|
|
618
|
+
if tab_element.Filename is not None:
|
|
619
|
+
photo = tk.PhotoImage(file=tab_element.Filename)
|
|
620
|
+
elif tab_element.Data is not None:
|
|
621
|
+
photo = tk.PhotoImage(data=tab_element.Data)
|
|
622
|
+
else:
|
|
623
|
+
photo = None
|
|
624
|
+
|
|
625
|
+
if tab_element.ImageSubsample and photo is not None:
|
|
626
|
+
photo = photo.subsample(tab_element.ImageSubsample)
|
|
627
|
+
# print('*ERROR laying out form.... Image Element has no image specified*')
|
|
628
|
+
except Exception as e:
|
|
629
|
+
photo = None
|
|
630
|
+
_error_popup_with_traceback(
|
|
631
|
+
'Your Window has an Tab Element with an IMAGE problem',
|
|
632
|
+
'The traceback will show you the Window with the problem layout',
|
|
633
|
+
f'Look in this Window\'s layout for an Image tab_element that has a action of {tab_element.Key}',
|
|
634
|
+
'The error occuring is:',
|
|
635
|
+
e,
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
tab_element.photo = photo
|
|
639
|
+
# add the label
|
|
640
|
+
if photo is not None:
|
|
641
|
+
width, height = photo.width(), photo.height()
|
|
642
|
+
tab_element.tktext_label = tk.Label(tab_element.ParentRowFrame, image=photo, width=width, height=height, bd=0)
|
|
643
|
+
else:
|
|
644
|
+
tab_element.tktext_label = tk.Label(tab_element.ParentRowFrame, bd=0)
|
|
645
|
+
# ------------------- end of imagey-stuff -------------------
|
|
646
|
+
|
|
647
|
+
state = 'normal'
|
|
648
|
+
if tab_element.Disabled:
|
|
649
|
+
state = 'disabled'
|
|
650
|
+
if tab_element.nazar is False:
|
|
651
|
+
state = 'hidden'
|
|
652
|
+
if photo is not None:
|
|
653
|
+
self.TKNotebook.add(tab_element.TKFrame, text=tab_element.Title, compound=tk.LEFT, state=state, image=photo)
|
|
654
|
+
else:
|
|
655
|
+
self.TKNotebook.add(tab_element.TKFrame, text=tab_element.Title, state=state)
|
|
656
|
+
tab_element.ParentNotebook = self.TKNotebook
|
|
657
|
+
tab_element.TabID = self.TabCount
|
|
658
|
+
tab_element.ParentForm = self.ParentForm
|
|
659
|
+
self.TabCount += 1
|
|
660
|
+
if tab_element.BackgroundColor != COLOR_SYSTEM_DEFAULT and tab_element.BackgroundColor is not None:
|
|
661
|
+
tab_element.TKFrame.configure(
|
|
662
|
+
background=tab_element.BackgroundColor,
|
|
663
|
+
highlightbackground=tab_element.BackgroundColor,
|
|
664
|
+
highlightcolor=tab_element.BackgroundColor,
|
|
665
|
+
)
|
|
666
|
+
if tab_element.BorderWidth is not None:
|
|
667
|
+
tab_element.TKFrame.configure(borderwidth=tab_element.BorderWidth)
|
|
668
|
+
if tab_element.Hover is not None:
|
|
669
|
+
tab_element.HoverObject = Hover(tab_element.TKFrame, text=tab_element.Hover, timeout=hindGui.DEFAULT_HOVER_TIME)
|
|
670
|
+
_add_right_click_menu(tab_element, form)
|
|
671
|
+
|
|
672
|
+
def badlo(self, nazar=None):
|
|
673
|
+
"""
|
|
674
|
+
Enables changing the visibility
|
|
675
|
+
|
|
676
|
+
:param nazar: control visibility of element
|
|
677
|
+
:type nazar: (bool)
|
|
678
|
+
"""
|
|
679
|
+
if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
|
|
680
|
+
return
|
|
681
|
+
|
|
682
|
+
if self._this_elements_window_closed():
|
|
683
|
+
_error_popup_with_traceback('Error in TabGroup.badlo - The window was closed')
|
|
684
|
+
return
|
|
685
|
+
|
|
686
|
+
if nazar is False:
|
|
687
|
+
self._pack_forget_save_settings()
|
|
688
|
+
elif nazar is True:
|
|
689
|
+
self._pack_restore_settings()
|
|
690
|
+
|
|
691
|
+
if nazar is not None:
|
|
692
|
+
self._nazar = nazar
|
|
693
|
+
|
|
694
|
+
AddRow = add_row
|
|
695
|
+
FindKeyFromTabName = find_key_from_tab_name
|
|
696
|
+
Get = get
|
|
697
|
+
Layout = layout
|