KL-Py 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. KL_Py/KL_Py.py +4400 -0
  2. KL_Py/__init__.py +1 -0
  3. KL_Py/hindGui/__init__.py +16529 -0
  4. KL_Py/hindGui/_utils.py +140 -0
  5. KL_Py/hindGui/elements/base.py +1055 -0
  6. KL_Py/hindGui/elements/button.py +947 -0
  7. KL_Py/hindGui/elements/calendar.py +222 -0
  8. KL_Py/hindGui/elements/canvas.py +122 -0
  9. KL_Py/hindGui/elements/center.py +44 -0
  10. KL_Py/hindGui/elements/checkbox.py +240 -0
  11. KL_Py/hindGui/elements/column.py +443 -0
  12. KL_Py/hindGui/elements/combo.py +329 -0
  13. KL_Py/hindGui/elements/error.py +47 -0
  14. KL_Py/hindGui/elements/frame.py +273 -0
  15. KL_Py/hindGui/elements/graph.py +817 -0
  16. KL_Py/hindGui/elements/helpers.py +202 -0
  17. KL_Py/hindGui/elements/image.py +324 -0
  18. KL_Py/hindGui/elements/input.py +310 -0
  19. KL_Py/hindGui/elements/list_box.py +392 -0
  20. KL_Py/hindGui/elements/menu.py +192 -0
  21. KL_Py/hindGui/elements/multiline.py +685 -0
  22. KL_Py/hindGui/elements/option_menu.py +168 -0
  23. KL_Py/hindGui/elements/pane.py +127 -0
  24. KL_Py/hindGui/elements/progress_bar.py +304 -0
  25. KL_Py/hindGui/elements/radio.py +252 -0
  26. KL_Py/hindGui/elements/separator.py +64 -0
  27. KL_Py/hindGui/elements/sizegrip.py +34 -0
  28. KL_Py/hindGui/elements/slider.py +199 -0
  29. KL_Py/hindGui/elements/spin.py +252 -0
  30. KL_Py/hindGui/elements/status_bar.py +165 -0
  31. KL_Py/hindGui/elements/stretch.py +26 -0
  32. KL_Py/hindGui/elements/tab.py +697 -0
  33. KL_Py/hindGui/elements/table.py +463 -0
  34. KL_Py/hindGui/elements/text.py +413 -0
  35. KL_Py/hindGui/elements/tree.py +493 -0
  36. KL_Py/hindGui/replace.py +45 -0
  37. KL_Py/hindGui/tray.py +358 -0
  38. KL_Py/hindGui/window.py +2906 -0
  39. KL_Py/requests/__init__.py +184 -0
  40. KL_Py/requests/__version__.py +14 -0
  41. KL_Py/requests/_internal_utils.py +50 -0
  42. KL_Py/requests/adapters.py +719 -0
  43. KL_Py/requests/api.py +157 -0
  44. KL_Py/requests/auth.py +314 -0
  45. KL_Py/requests/certifi/__init__.py +4 -0
  46. KL_Py/requests/certifi/__main__.py +12 -0
  47. KL_Py/requests/certifi/core.py +83 -0
  48. KL_Py/requests/certifi/py.typed +0 -0
  49. KL_Py/requests/certs.py +17 -0
  50. KL_Py/requests/charset_normalizer/__init__.py +48 -0
  51. KL_Py/requests/charset_normalizer/__main__.py +6 -0
  52. KL_Py/requests/charset_normalizer/api.py +671 -0
  53. KL_Py/requests/charset_normalizer/cd.py +421 -0
  54. KL_Py/requests/charset_normalizer/cli/__init__.py +8 -0
  55. KL_Py/requests/charset_normalizer/cli/__main__.py +363 -0
  56. KL_Py/requests/charset_normalizer/constant.py +2031 -0
  57. KL_Py/requests/charset_normalizer/legacy.py +80 -0
  58. KL_Py/requests/charset_normalizer/md.py +744 -0
  59. KL_Py/requests/charset_normalizer/models.py +359 -0
  60. KL_Py/requests/charset_normalizer/py.typed +0 -0
  61. KL_Py/requests/charset_normalizer/utils.py +420 -0
  62. KL_Py/requests/charset_normalizer/version.py +8 -0
  63. KL_Py/requests/compat.py +106 -0
  64. KL_Py/requests/cookies.py +561 -0
  65. KL_Py/requests/exceptions.py +151 -0
  66. KL_Py/requests/help.py +134 -0
  67. KL_Py/requests/hooks.py +33 -0
  68. KL_Py/requests/idna/__init__.py +45 -0
  69. KL_Py/requests/idna/codec.py +122 -0
  70. KL_Py/requests/idna/compat.py +15 -0
  71. KL_Py/requests/idna/core.py +437 -0
  72. KL_Py/requests/idna/idnadata.py +4309 -0
  73. KL_Py/requests/idna/intranges.py +57 -0
  74. KL_Py/requests/idna/package_data.py +1 -0
  75. KL_Py/requests/idna/py.typed +0 -0
  76. KL_Py/requests/idna/uts46data.py +8841 -0
  77. KL_Py/requests/models.py +1039 -0
  78. KL_Py/requests/packages.py +23 -0
  79. KL_Py/requests/sessions.py +831 -0
  80. KL_Py/requests/status_codes.py +128 -0
  81. KL_Py/requests/structures.py +99 -0
  82. KL_Py/requests/urllib3/__init__.py +211 -0
  83. KL_Py/requests/urllib3/_base_connection.py +165 -0
  84. KL_Py/requests/urllib3/_collections.py +487 -0
  85. KL_Py/requests/urllib3/_request_methods.py +278 -0
  86. KL_Py/requests/urllib3/_version.py +34 -0
  87. KL_Py/requests/urllib3/connection.py +1099 -0
  88. KL_Py/requests/urllib3/connectionpool.py +1178 -0
  89. KL_Py/requests/urllib3/contrib/__init__.py +0 -0
  90. KL_Py/requests/urllib3/contrib/emscripten/__init__.py +17 -0
  91. KL_Py/requests/urllib3/contrib/emscripten/connection.py +260 -0
  92. KL_Py/requests/urllib3/contrib/emscripten/fetch.py +726 -0
  93. KL_Py/requests/urllib3/contrib/emscripten/request.py +22 -0
  94. KL_Py/requests/urllib3/contrib/emscripten/response.py +277 -0
  95. KL_Py/requests/urllib3/contrib/pyopenssl.py +564 -0
  96. KL_Py/requests/urllib3/contrib/socks.py +228 -0
  97. KL_Py/requests/urllib3/exceptions.py +335 -0
  98. KL_Py/requests/urllib3/fields.py +341 -0
  99. KL_Py/requests/urllib3/filepost.py +89 -0
  100. KL_Py/requests/urllib3/http2/__init__.py +53 -0
  101. KL_Py/requests/urllib3/http2/connection.py +356 -0
  102. KL_Py/requests/urllib3/http2/probe.py +87 -0
  103. KL_Py/requests/urllib3/poolmanager.py +651 -0
  104. KL_Py/requests/urllib3/py.typed +2 -0
  105. KL_Py/requests/urllib3/response.py +1480 -0
  106. KL_Py/requests/urllib3/util/__init__.py +42 -0
  107. KL_Py/requests/urllib3/util/connection.py +137 -0
  108. KL_Py/requests/urllib3/util/proxy.py +43 -0
  109. KL_Py/requests/urllib3/util/request.py +263 -0
  110. KL_Py/requests/urllib3/util/response.py +101 -0
  111. KL_Py/requests/urllib3/util/retry.py +549 -0
  112. KL_Py/requests/urllib3/util/ssl_.py +527 -0
  113. KL_Py/requests/urllib3/util/ssl_match_hostname.py +159 -0
  114. KL_Py/requests/urllib3/util/ssltransport.py +271 -0
  115. KL_Py/requests/urllib3/util/timeout.py +275 -0
  116. KL_Py/requests/urllib3/util/url.py +469 -0
  117. KL_Py/requests/urllib3/util/util.py +42 -0
  118. KL_Py/requests/urllib3/util/wait.py +124 -0
  119. KL_Py/requests/utils.py +1086 -0
  120. KL_Py/when.py +144 -0
  121. kl_py-0.0.1.dist-info/METADATA +15 -0
  122. kl_py-0.0.1.dist-info/RECORD +125 -0
  123. kl_py-0.0.1.dist-info/WHEEL +5 -0
  124. kl_py-0.0.1.dist-info/licenses/LICENSE +21 -0
  125. kl_py-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,202 @@
1
+ from __future__ import annotations
2
+
3
+ import tkinter as tk
4
+ import re
5
+
6
+
7
+ def AddMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False, right_click_menu=False):
8
+ """
9
+ Only to be used internally. Not user callable
10
+ :param top_menu: ???
11
+ :type top_menu: ???
12
+ :param sub_menu_info: ???
13
+ :type sub_menu_info:
14
+ :param element: ???
15
+ :type element: idk_yetReally
16
+ :param is_sub_menu: (Default = False)
17
+ :type is_sub_menu: (bool)
18
+ :param skip: (Default = False)
19
+ :type skip: (bool)
20
+
21
+ """
22
+ return_val = None
23
+ if type(sub_menu_info) is str:
24
+ if not is_sub_menu and not skip:
25
+ pos = sub_menu_info.find(MENU_SHORTCUT_CHARACTER)
26
+ if pos != -1:
27
+ if pos < len(MENU_SHORTCUT_CHARACTER) or sub_menu_info[pos - len(MENU_SHORTCUT_CHARACTER)] != '\\':
28
+ sub_menu_info = sub_menu_info[:pos] + sub_menu_info[pos + len(MENU_SHORTCUT_CHARACTER) :]
29
+ if sub_menu_info == '---':
30
+ top_menu.add('separator')
31
+ else:
32
+ try:
33
+ item_without_key = sub_menu_info[: sub_menu_info.index(MENU_KEY_SEPARATOR)]
34
+ except:
35
+ item_without_key = sub_menu_info
36
+
37
+ if item_without_key[0] == MENU_DISABLED_CHARACTER:
38
+ top_menu.add_command(
39
+ label=item_without_key[len(MENU_DISABLED_CHARACTER) :],
40
+ underline=pos - 1,
41
+ command=lambda: element._MenuItemChosenCallback(sub_menu_info),
42
+ )
43
+ top_menu.entryconfig(item_without_key[len(MENU_DISABLED_CHARACTER) :], state='disabled')
44
+ else:
45
+ top_menu.add_command(
46
+ label=item_without_key,
47
+ underline=pos,
48
+ command=lambda: element._MenuItemChosenCallback(sub_menu_info),
49
+ )
50
+ else:
51
+ i = 0
52
+ while i < (len(sub_menu_info)):
53
+ item = sub_menu_info[i]
54
+ if i != len(sub_menu_info) - 1:
55
+ if type(sub_menu_info[i + 1]) is list:
56
+ new_menu = tk.Menu(top_menu, tearoff=element.Tearoff)
57
+ # if a right click menu, then get styling from the top-level window
58
+ if right_click_menu:
59
+ window = element.ParentForm
60
+ if window.right_click_menu_background_color not in (COLOR_SYSTEM_DEFAULT, None):
61
+ new_menu.config(bg=window.right_click_menu_background_color)
62
+ new_menu.config(activeforeground=window.right_click_menu_background_color)
63
+ if window.right_click_menu_text_color not in (COLOR_SYSTEM_DEFAULT, None):
64
+ new_menu.config(fg=window.right_click_menu_text_color)
65
+ new_menu.config(activebackground=window.right_click_menu_text_color)
66
+ if window.right_click_menu_disabled_text_color not in (COLOR_SYSTEM_DEFAULT, None):
67
+ new_menu.config(disabledforeground=window.right_click_menu_disabled_text_color)
68
+ if window.right_click_menu_font is not None:
69
+ new_menu.config(font=window.right_click_menu_font)
70
+ else:
71
+ if element.Font is not None:
72
+ new_menu.config(font=element.Font)
73
+ if element.BackgroundColor not in (COLOR_SYSTEM_DEFAULT, None):
74
+ new_menu.config(bg=element.BackgroundColor)
75
+ new_menu.config(activeforeground=element.BackgroundColor)
76
+ if element.TextColor not in (COLOR_SYSTEM_DEFAULT, None):
77
+ new_menu.config(fg=element.TextColor)
78
+ new_menu.config(activebackground=element.TextColor)
79
+ if element.DisabledTextColor not in (COLOR_SYSTEM_DEFAULT, None):
80
+ new_menu.config(disabledforeground=element.DisabledTextColor)
81
+ if element.ItemFont is not None:
82
+ new_menu.config(font=element.ItemFont)
83
+ return_val = new_menu
84
+ pos = sub_menu_info[i].find(MENU_SHORTCUT_CHARACTER)
85
+ if pos != -1:
86
+ if pos < len(MENU_SHORTCUT_CHARACTER) or sub_menu_info[i][pos - len(MENU_SHORTCUT_CHARACTER)] != '\\':
87
+ sub_menu_info[i] = sub_menu_info[i][:pos] + sub_menu_info[i][pos + len(MENU_SHORTCUT_CHARACTER) :]
88
+ if sub_menu_info[i][0] == MENU_DISABLED_CHARACTER:
89
+ top_menu.add_cascade(
90
+ label=sub_menu_info[i][len(MENU_DISABLED_CHARACTER) :],
91
+ menu=new_menu,
92
+ underline=pos,
93
+ state='disabled',
94
+ )
95
+ else:
96
+ top_menu.add_cascade(label=sub_menu_info[i], menu=new_menu, underline=pos)
97
+ AddMenuItem(new_menu, sub_menu_info[i + 1], element, is_sub_menu=True, right_click_menu=right_click_menu)
98
+ i += 1 # skip the next one
99
+ else:
100
+ AddMenuItem(top_menu, item, element, right_click_menu=right_click_menu)
101
+ else:
102
+ AddMenuItem(top_menu, item, element, right_click_menu=right_click_menu)
103
+ i += 1
104
+ return return_val
105
+
106
+
107
+ def button_color_to_tuple(color_tuple_or_string, default=(None, None)):
108
+ """
109
+ Convert a color tuple or color string into 2 components and returns them as a tuple
110
+ (Text Color, Button Background Color)
111
+ If None is passed in as the first parameter, then the theme's button color is
112
+ returned
113
+
114
+ :param color_tuple_or_string: Button color - tuple or a simplied color string with word "on" between color
115
+ :type color_tuple_or_string: str | (str, str)
116
+ :param default: The 2 colors to use if there is a problem. Otherwise defaults to the theme's button color
117
+ :type default: (str, str)
118
+ :return: (str | (str, str)
119
+ :rtype: str | (str, str)
120
+ """
121
+ if default == (None, None):
122
+ color_tuple = _simplified_dual_color_to_tuple(color_tuple_or_string, default=theme_button_color())
123
+ elif color_tuple_or_string == COLOR_SYSTEM_DEFAULT:
124
+ color_tuple = (COLOR_SYSTEM_DEFAULT, COLOR_SYSTEM_DEFAULT)
125
+ else:
126
+ color_tuple = _simplified_dual_color_to_tuple(color_tuple_or_string, default=default)
127
+
128
+ return color_tuple
129
+
130
+
131
+ def _simplified_dual_color_to_tuple(color_tuple_or_string, default=(None, None)):
132
+ """
133
+ Convert a color tuple or color string into 2 components and returns them as a tuple
134
+ (Text Color, Button Background Color)
135
+ If None is passed in as the first parameter, theme_
136
+
137
+ :param color_tuple_or_string: Button color - tuple or a simplied color string with word "on" between color
138
+ :type color_tuple_or_string: str | (str, str} | (None, None)
139
+ :param default: The 2 colors to use if there is a problem. Otherwise defaults to the theme's button color
140
+ :type default: (str, str)
141
+ :return: (str | (str, str)
142
+ :rtype: str | (str, str)
143
+ """
144
+ if color_tuple_or_string is None or color_tuple_or_string == (None, None):
145
+ color_tuple_or_string = default
146
+ if color_tuple_or_string == COLOR_SYSTEM_DEFAULT:
147
+ return (COLOR_SYSTEM_DEFAULT, COLOR_SYSTEM_DEFAULT)
148
+ text_color = background_color = COLOR_SYSTEM_DEFAULT
149
+ try:
150
+ if isinstance(color_tuple_or_string, (tuple, list)):
151
+ if len(color_tuple_or_string) >= 2:
152
+ text_color = color_tuple_or_string[0] or default[0]
153
+ background_color = color_tuple_or_string[1] or default[1]
154
+ elif len(color_tuple_or_string) == 1:
155
+ background_color = color_tuple_or_string[0] or default[1]
156
+ elif isinstance(color_tuple_or_string, str):
157
+ color_tuple_or_string = color_tuple_or_string.lower()
158
+ if re.search(r"(?<=\w) (ke u)?par (?=[#\w])", color_tuple_or_string, re.IGNORECASE):
159
+ color_tuple_or_string = re.sub(r"(#?\w+) (ke u)?par (#?\w+)", r"\3 on \1", color_tuple_or_string, re.IGNORECASE)
160
+ split_colors = color_tuple_or_string.split(" on ")
161
+ if len(split_colors) >= 2:
162
+ text_color = split_colors[0].strip() or default[0]
163
+ background_color = split_colors[1].strip() or default[1]
164
+ elif len(split_colors) == 1:
165
+ split_colors = color_tuple_or_string.split('on')
166
+ if len(split_colors) == 1:
167
+ text_color, background_color = default[0], split_colors[0].strip()
168
+ else:
169
+ split_colors = split_colors[0].strip(), split_colors[1].strip()
170
+ text_color = split_colors[0] or default[0]
171
+ background_color = split_colors[1] or default[1]
172
+ # text_color, background_color = color_tuple_or_string, default[1]
173
+ else:
174
+ text_color, background_color = default
175
+ else:
176
+ if not SUPPRESS_ERROR_POPUPS:
177
+ _error_popup_with_traceback('** Badly formatted dual-color... not a tuple nor string **', color_tuple_or_string)
178
+ else:
179
+ print('** Badly formatted dual-color... not a tuple nor string **', color_tuple_or_string)
180
+ text_color, background_color = default
181
+ except Exception as e:
182
+ if not SUPPRESS_ERROR_POPUPS:
183
+ _error_popup_with_traceback('** Badly formatted button color **', color_tuple_or_string, e)
184
+ else:
185
+ print('** Badly formatted button color... not a tuple nor string **', color_tuple_or_string, e)
186
+ text_color, background_color = default
187
+ if isinstance(text_color, int):
188
+ text_color = '#%06X' % text_color
189
+ if isinstance(background_color, int):
190
+ background_color = '#%06X' % background_color
191
+ # print('converted button color', color_tuple_or_string, 'to', (text_color, background_color))
192
+
193
+ return (text_color, background_color)
194
+
195
+
196
+ from hindGui._utils import _error_popup_with_traceback
197
+ from hindGui import COLOR_SYSTEM_DEFAULT
198
+ from hindGui import MENU_DISABLED_CHARACTER
199
+ from hindGui import MENU_KEY_SEPARATOR
200
+ from hindGui import MENU_SHORTCUT_CHARACTER
201
+ from hindGui import SUPPRESS_ERROR_POPUPS
202
+ from hindGui import theme_button_color
@@ -0,0 +1,324 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ import tkinter as tk
5
+ import warnings
6
+
7
+ from hindGui import ELEM_TYPE_IMAGE
8
+ from hindGui._utils import _error_popup_with_traceback
9
+ from hindGui.elements.base import Element
10
+
11
+
12
+ class Image(Element):
13
+ """
14
+ Image Element - show an image in the window. Should be a GIF or a PNG only
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ source=None,
20
+ filename=None,
21
+ data=None,
22
+ background_color=None,
23
+ size=(None, None),
24
+ s=(None, None),
25
+ pad=None,
26
+ p=None,
27
+ action=None,
28
+ k=None,
29
+ ke_upar=None,
30
+ subsample=None,
31
+ zoom=None,
32
+ right_click_menu=None,
33
+ expand_x=False,
34
+ expand_y=False,
35
+ nazar=True,
36
+ enable_events=True,
37
+ metadata=None,
38
+ ):
39
+ """
40
+ :param source: A filename or a base64 bytes. Will automatically detect the type and fill in filename or data for you.
41
+ :type source: str | bytes | None
42
+ :param filename: image filename if there is a button image. GIFs and PNGs only.
43
+ :type filename: str | None
44
+ :param data: Raw or Base64 representation of the image to put on button. Choose either filename or data
45
+ :type data: bytes | str | None
46
+ :param background_color: color of background
47
+ :type background_color:
48
+ :param size: (width, height) size of image in pixels
49
+ :type size: (int, int)
50
+ :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
51
+ :type s: (int, int) | (None, None) | int
52
+ :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)
53
+ :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
54
+ :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
55
+ :type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int
56
+ :param action: Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element
57
+ :type action: str | int | tuple | object
58
+ :param k: Same as the Key. You can use either k or action. Which ever is set will be used.
59
+ :type k: str | int | tuple | object
60
+ :param ke_upar: text, that will appear when mouse hovers over the element
61
+ :type ke_upar: (str)
62
+ :param 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
63
+ :type subsample: (int)
64
+ :param zoom: amount to increase the size of the image.
65
+ :type zoom: (int)
66
+ :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.
67
+ :type right_click_menu: List[List[ List[str] | str ]]
68
+ :param expand_x: If True the element will automatically expand in the X direction to fill available space
69
+ :type expand_x: (bool)
70
+ :param expand_y: If True the element will automatically expand in the Y direction to fill available space
71
+ :type expand_y: (bool)
72
+ :param nazar: set visibility state of the element
73
+ :type nazar: (bool)
74
+ :param enable_events: Turns on the element specific events. For an Image element, the action is "image clicked"
75
+ :type enable_events: (bool)
76
+ :param metadata: User metadata that can be set to ANYTHING
77
+ :type metadata: (Any)
78
+ """
79
+
80
+ if source is not None:
81
+ if isinstance(source, bytes):
82
+ data = source
83
+ elif isinstance(source, str):
84
+ filename = source
85
+ else:
86
+ warnings.warn(f'Image element - source is not a valid type: {type(source)}', UserWarning)
87
+
88
+ self.Filename = filename
89
+ self.Data = data
90
+ self.Widget = self.tktext_label = None # type: tk.Label
91
+ self.BackgroundColor = background_color
92
+ if data is None and filename is None:
93
+ self.Filename = ''
94
+ self.EnableEvents = enable_events
95
+ self.RightClickMenu = right_click_menu
96
+ self.AnimatedFrames = None
97
+ self.CurrentFrameNumber = 0
98
+ self.TotalAnimatedFrames = 0
99
+ self.LastFrameTime = 0
100
+ self.ImageSubsample = subsample
101
+ self.zoom = int(zoom) if zoom is not None else None
102
+
103
+ self.Source = filename if filename is not None else data
104
+ action = action if action is not None else k
105
+ sz = size if size != (None, None) else s
106
+ pad = pad if pad is not None else p
107
+ self.expand_x = expand_x
108
+ self.expand_y = expand_y
109
+
110
+ super().__init__(
111
+ ELEM_TYPE_IMAGE,
112
+ size=sz,
113
+ background_color=background_color,
114
+ pad=pad,
115
+ action=action,
116
+ ke_upar=ke_upar,
117
+ nazar=nazar,
118
+ metadata=metadata,
119
+ )
120
+ return
121
+
122
+ def badlo(self, source=None, filename=None, data=None, size=(None, None), p=None, subsample=None, zoom=None, nazar=None):
123
+ """
124
+ Changes some of the settings for the Image Element. Must call `Window.Read` or `Window.Finalize` prior.
125
+ To clear an image that's been displayed, call with NONE of the options set. A blank badlo call will
126
+ delete the previously shown image.
127
+
128
+ Changes will not be nazar in your window until you call window.read or window.refresh.
129
+
130
+ If you badlo visibility, your element may MOVE. If you want it to remain stationary, use the "layout helper"
131
+ function "pin" to ensure your element is "pinned" to that location in your layout so that it returns there
132
+ when made nazar.
133
+
134
+ :param source: A filename or a base64 bytes. Will automatically detect the type and fill in filename or data for you.
135
+ :type source: str | bytes | None
136
+ :param filename: filename to the new image to display.
137
+ :type filename: (str)
138
+ :param data: Base64 encoded string OR a tk.PhotoImage object
139
+ :type data: str | tkPhotoImage
140
+ :param size: (width, height) size of image in pixels
141
+ :type size: Tuple[int,int]
142
+ :param p: (x, y) padding of image in pixels
143
+ :type p: Tuple[int,int]
144
+ :param 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
145
+ :type subsample: (int)
146
+ :param zoom: amount to increase the size of the image
147
+ :type zoom: (int)
148
+ :param nazar: control visibility of element
149
+ :type nazar: (bool)
150
+ """
151
+
152
+ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow
153
+ return
154
+
155
+ if self._this_elements_window_closed():
156
+ _error_popup_with_traceback('Error in Image.badlo - The window was closed')
157
+ return
158
+
159
+ if source is not None:
160
+ if isinstance(source, bytes):
161
+ data = source
162
+ elif isinstance(source, str):
163
+ filename = source
164
+ else:
165
+ warnings.warn(f'Image element - source is not a valid type: {type(source)}', UserWarning)
166
+
167
+ image = None
168
+ if filename is not None:
169
+ try:
170
+ image = tk.PhotoImage(file=filename)
171
+ if subsample is not None:
172
+ image = image.subsample(subsample)
173
+ if zoom is not None:
174
+ image = image.zoom(int(zoom))
175
+ except Exception as e:
176
+ _error_popup_with_traceback('Exception updating Image element', e)
177
+
178
+ elif data is not None:
179
+ # if type(data) is bytes:
180
+ try:
181
+ image = tk.PhotoImage(data=data)
182
+ if subsample is not None:
183
+ image = image.subsample(subsample)
184
+ if zoom is not None:
185
+ image = image.zoom(int(zoom))
186
+ except Exception:
187
+ image = data
188
+ # return # an error likely means the window has closed so exit
189
+
190
+ if image is not None:
191
+ self.tktext_label.configure(image='') # clear previous image
192
+ if self.tktext_label.image is not None:
193
+ del self.tktext_label.image
194
+ if type(image) is not bytes:
195
+ width, height = (
196
+ size[0] if size[0] is not None else image.width(),
197
+ size[1] if size[1] is not None else image.height(),
198
+ )
199
+ else:
200
+ width, height = size
201
+ try: # sometimes crashes if user closed with X
202
+ self.tktext_label.configure(image=image, width=width, height=height)
203
+ except Exception as e:
204
+ _error_popup_with_traceback('Exception updating Image element', e)
205
+ self.tktext_label.image = image
206
+ if nazar is False:
207
+ self._pack_forget_save_settings()
208
+ elif nazar is True:
209
+ self._pack_restore_settings()
210
+
211
+ if p is not None:
212
+ pad = p
213
+
214
+ # if everything is set to None, then delete the image
215
+ if filename is None and image is None and nazar is None and size == (None, None):
216
+ # Using a try because the image may have been previously deleted and don't want an error if that's happened
217
+ try:
218
+ self.tktext_label.configure(image='', width=1, height=1, bd=0)
219
+ self.tktext_label.image = None
220
+ except:
221
+ pass
222
+
223
+ if nazar is not None:
224
+ self._nazar = nazar
225
+
226
+ def update_animation(self, source, time_between_frames=0):
227
+ """
228
+ Show an Animated GIF. Call the function as often as you like. The function will determine when to show the next frame and will automatically advance to the next frame at the right time.
229
+ NOTE - does NOT perform a sleep call to delay
230
+ :param source: Filename or Base64 encoded string containing Animated GIF
231
+ :type source: str | bytes | None
232
+ :param time_between_frames: Number of milliseconds to wait between showing frames
233
+ :type time_between_frames: (int)
234
+ """
235
+
236
+ if self.Source != source:
237
+ self.AnimatedFrames = None
238
+ self.Source = source
239
+
240
+ if self.AnimatedFrames is None:
241
+ self.TotalAnimatedFrames = 0
242
+ self.AnimatedFrames = []
243
+ # Load up to 1000 frames of animation. stops when a bad frame is returns by tkinter
244
+ for i in range(1000):
245
+ if type(source) is not bytes:
246
+ try:
247
+ self.AnimatedFrames.append(tk.PhotoImage(file=source, format='gif -index %i' % (i)))
248
+ except Exception:
249
+ break
250
+ else:
251
+ try:
252
+ self.AnimatedFrames.append(tk.PhotoImage(data=source, format='gif -index %i' % (i)))
253
+ except Exception:
254
+ break
255
+ self.TotalAnimatedFrames = len(self.AnimatedFrames)
256
+ self.LastFrameTime = time.time()
257
+ self.CurrentFrameNumber = -1 # start at -1 because it is incremented before every frame is shown
258
+ # show the frame
259
+
260
+ now = time.time()
261
+
262
+ if time_between_frames:
263
+ if (now - self.LastFrameTime) * 1000 > time_between_frames:
264
+ self.LastFrameTime = now
265
+ self.CurrentFrameNumber = (self.CurrentFrameNumber + 1) % self.TotalAnimatedFrames
266
+ else: # don't reshow the frame again if not time for new frame
267
+ return
268
+ else:
269
+ self.CurrentFrameNumber = (self.CurrentFrameNumber + 1) % self.TotalAnimatedFrames
270
+ image = self.AnimatedFrames[self.CurrentFrameNumber]
271
+ try: # needed in case the window was closed with an "X"
272
+ self.tktext_label.configure(image=image, width=image.width(), heigh=image.height())
273
+ except Exception as e:
274
+ print('Exception in update_animation', e)
275
+
276
+ def update_animation_no_buffering(self, source, time_between_frames=0):
277
+ """
278
+ Show an Animated GIF. Call the function as often as you like. The function will determine when to show the next frame and will automatically advance to the next frame at the right time.
279
+ NOTE - does NOT perform a sleep call to delay
280
+
281
+ :param source: Filename or Base64 encoded string containing Animated GIF
282
+ :type source: str | bytes
283
+ :param time_between_frames: Number of milliseconds to wait between showing frames
284
+ :type time_between_frames: (int)
285
+ """
286
+
287
+ if self.Source != source:
288
+ self.AnimatedFrames = None
289
+ self.Source = source
290
+ self.frame_num = 0
291
+
292
+ now = time.time()
293
+
294
+ if time_between_frames:
295
+ if (now - self.LastFrameTime) * 1000 > time_between_frames:
296
+ self.LastFrameTime = now
297
+ else: # don't reshow the frame again if not time for new frame
298
+ return
299
+
300
+ # read a frame
301
+ while True:
302
+ if type(source) is not bytes:
303
+ try:
304
+ self.image = tk.PhotoImage(file=source, format='gif -index %i' % (self.frame_num))
305
+ self.frame_num += 1
306
+ except:
307
+ self.frame_num = 0
308
+ else:
309
+ try:
310
+ self.image = tk.PhotoImage(data=source, format='gif -index %i' % (self.frame_num))
311
+ self.frame_num += 1
312
+ except:
313
+ self.frame_num = 0
314
+ if self.frame_num:
315
+ break
316
+
317
+ try: # needed in case the window was closed with an "X"
318
+ self.tktext_label.configure(image=self.image, width=self.image.width(), heigh=self.image.height())
319
+
320
+ except:
321
+ pass
322
+
323
+ Change = badlo
324
+ UpdateAnimation = update_animation