scustomtkinter 0.2.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.
- scustomtkinter/__init__.py +81 -0
- scustomtkinter/assets/images/error.png +0 -0
- scustomtkinter/assets/images/info.png +0 -0
- scustomtkinter/assets/images/warning.png +0 -0
- scustomtkinter/assets/sCTkThemes.json +1963 -0
- scustomtkinter/license_morecustomtkinterwidgets.txt +22 -0
- scustomtkinter/sctk_button_primary.py +366 -0
- scustomtkinter/sctk_button_secondary.py +354 -0
- scustomtkinter/sctk_button_tertiary.py +375 -0
- scustomtkinter/sctk_checkbox.py +270 -0
- scustomtkinter/sctk_combobox.py +155 -0
- scustomtkinter/sctk_core.py +15 -0
- scustomtkinter/sctk_dial.py +1472 -0
- scustomtkinter/sctk_dialog.py +701 -0
- scustomtkinter/sctk_dialog_toplevel.py +268 -0
- scustomtkinter/sctk_entry_primary.py +400 -0
- scustomtkinter/sctk_entry_secondary.py +342 -0
- scustomtkinter/sctk_file_explorer.py +879 -0
- scustomtkinter/sctk_frame.py +210 -0
- scustomtkinter/sctk_frame_labeled_primary.py +667 -0
- scustomtkinter/sctk_frame_labeled_secondary.py +598 -0
- scustomtkinter/sctk_frequency_display.py +636 -0
- scustomtkinter/sctk_label_primary.py +283 -0
- scustomtkinter/sctk_label_secondary.py +275 -0
- scustomtkinter/sctk_label_tertiary.py +278 -0
- scustomtkinter/sctk_messagebox.py +275 -0
- scustomtkinter/sctk_notebook.py +1103 -0
- scustomtkinter/sctk_optionmenu_border_mixin.py +203 -0
- scustomtkinter/sctk_optionmenu_primary.py +378 -0
- scustomtkinter/sctk_optionmenu_secondary.py +346 -0
- scustomtkinter/sctk_path_chooser.py +516 -0
- scustomtkinter/sctk_progress_bar.py +274 -0
- scustomtkinter/sctk_radiobutton.py +360 -0
- scustomtkinter/sctk_scroll_mixin.py +546 -0
- scustomtkinter/sctk_scrollable_frame.py +795 -0
- scustomtkinter/sctk_scrollbar.py +313 -0
- scustomtkinter/sctk_segmentedbutton.py +424 -0
- scustomtkinter/sctk_selector.py +581 -0
- scustomtkinter/sctk_separator.py +308 -0
- scustomtkinter/sctk_slider.py +264 -0
- scustomtkinter/sctk_smeter.py +405 -0
- scustomtkinter/sctk_smeter_bar.py +557 -0
- scustomtkinter/sctk_spinbox.py +664 -0
- scustomtkinter/sctk_switch.py +463 -0
- scustomtkinter/sctk_tableview.py +869 -0
- scustomtkinter/sctk_tabview.py +409 -0
- scustomtkinter/sctk_textbox_primary.py +291 -0
- scustomtkinter/sctk_textbox_secondary.py +225 -0
- scustomtkinter/sctk_toplevel.py +153 -0
- scustomtkinter/themeable_widget.py +938 -0
- scustomtkinter-0.2.1.dist-info/METADATA +336 -0
- scustomtkinter-0.2.1.dist-info/RECORD +101 -0
- scustomtkinter-0.2.1.dist-info/WHEEL +5 -0
- scustomtkinter-0.2.1.dist-info/entry_points.txt +2 -0
- scustomtkinter-0.2.1.dist-info/licenses/LICENSE +21 -0
- scustomtkinter-0.2.1.dist-info/licenses/scustomtkinter/license_morecustomtkinterwidgets.txt +22 -0
- scustomtkinter-0.2.1.dist-info/top_level.txt +2 -0
- scustomtkinter_pygubu/__init__.py +1 -0
- scustomtkinter_pygubu/designer/__init__.py +0 -0
- scustomtkinter_pygubu/designer/plugin.py +1854 -0
- scustomtkinter_pygubu/designer/properties.py +247 -0
- scustomtkinter_pygubu/sCTkButtonPrimarybo.py +46 -0
- scustomtkinter_pygubu/sCTkButtonSecondarybo.py +45 -0
- scustomtkinter_pygubu/sCTkButtonTertiarybo.py +44 -0
- scustomtkinter_pygubu/sCTkCheckBoxbo.py +45 -0
- scustomtkinter_pygubu/sCTkComboBoxbo.py +45 -0
- scustomtkinter_pygubu/sCTkCorebo.py +120 -0
- scustomtkinter_pygubu/sCTkDialbo.py +371 -0
- scustomtkinter_pygubu/sCTkDialogbo.py +397 -0
- scustomtkinter_pygubu/sCTkEntryPrimarybo.py +100 -0
- scustomtkinter_pygubu/sCTkEntrySecondarybo.py +98 -0
- scustomtkinter_pygubu/sCTkFileExplorerbo.py +189 -0
- scustomtkinter_pygubu/sCTkFrameLabeledPrimarybo.py +69 -0
- scustomtkinter_pygubu/sCTkFrameLabeledSecondarybo.py +71 -0
- scustomtkinter_pygubu/sCTkFramebo.py +46 -0
- scustomtkinter_pygubu/sCTkFrequencyDisplaybo.py +175 -0
- scustomtkinter_pygubu/sCTkLabelPrimarybo.py +45 -0
- scustomtkinter_pygubu/sCTkLabelSecondarybo.py +44 -0
- scustomtkinter_pygubu/sCTkLabelTertiarybo.py +45 -0
- scustomtkinter_pygubu/sCTkNotebookbo.py +392 -0
- scustomtkinter_pygubu/sCTkOptionMenuPrimarybo.py +45 -0
- scustomtkinter_pygubu/sCTkOptionMenuSecondarybo.py +39 -0
- scustomtkinter_pygubu/sCTkPathChooserbo.py +204 -0
- scustomtkinter_pygubu/sCTkProgressBarbo.py +45 -0
- scustomtkinter_pygubu/sCTkRadioButtonbo.py +45 -0
- scustomtkinter_pygubu/sCTkSMeterBarbo.py +153 -0
- scustomtkinter_pygubu/sCTkSMeterbo.py +101 -0
- scustomtkinter_pygubu/sCTkScrollableFramebo.py +66 -0
- scustomtkinter_pygubu/sCTkScrollbarbo.py +48 -0
- scustomtkinter_pygubu/sCTkSegmentedButtonbo.py +47 -0
- scustomtkinter_pygubu/sCTkSelectorbo.py +167 -0
- scustomtkinter_pygubu/sCTkSeparatorbo.py +141 -0
- scustomtkinter_pygubu/sCTkSliderbo.py +45 -0
- scustomtkinter_pygubu/sCTkSpinboxbo.py +200 -0
- scustomtkinter_pygubu/sCTkSwitchbo.py +45 -0
- scustomtkinter_pygubu/sCTkTableviewbo.py +188 -0
- scustomtkinter_pygubu/sCTkTabviewbo.py +226 -0
- scustomtkinter_pygubu/sCTkTextboxPrimarybo.py +45 -0
- scustomtkinter_pygubu/sCTkTextboxSecondarybo.py +45 -0
- scustomtkinter_pygubu/sCTkToplevelbo.py +55 -0
- scustomtkinter_pygubu/sCTkWidgetSetForPygubuDesigner.py +141 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
"""
|
|
3
|
+
sCTkOptionMenuSecondary
|
|
4
|
+
|
|
5
|
+
The quiet variant of the dropdown option-selection menu (see also
|
|
6
|
+
sCTkOptionMenuPrimary, the emphasised one). Inherits directly from
|
|
7
|
+
ctk.CTkOptionMenu so CustomTkinter handles native rendering and dropdown
|
|
8
|
+
behaviour; this class layers theme resolution, a disabled state, and a border
|
|
9
|
+
on top.
|
|
10
|
+
|
|
11
|
+
FORMERLY A COMPOSITE. This widget used to be a ctk.CTkFrame wrapping an inner
|
|
12
|
+
ctk.CTkOptionMenu, because native CTkOptionMenu has no border option and this
|
|
13
|
+
variant needs one -- its fill is deliberately close to the background it sits
|
|
14
|
+
on, so without an outline the control is hard to see at rest.
|
|
15
|
+
|
|
16
|
+
That structure cost more than it bought:
|
|
17
|
+
|
|
18
|
+
- values, command and variable lived on the inner menu, so cget("values")
|
|
19
|
+
returned None here while returning a list on Primary. Two widgets meant to
|
|
20
|
+
be interchangeable, disagreeing.
|
|
21
|
+
- Every option CustomTkinter adds to CTkOptionMenu had to be forwarded by
|
|
22
|
+
hand, forever.
|
|
23
|
+
- The outline did not line up. A frame draws its own rounded rectangle
|
|
24
|
+
around a widget that draws another, and at the corners the two diverged
|
|
25
|
+
visibly.
|
|
26
|
+
- The widget's SHAPE was dictated by one theme's colour choices. Swap the
|
|
27
|
+
Primary and Secondary palettes and the structure is wrong.
|
|
28
|
+
|
|
29
|
+
sCTkOptionMenuBorderMixin now supplies the border, so this is a plain subclass
|
|
30
|
+
like Primary. get(), set(), values, command and variable are all native again.
|
|
31
|
+
|
|
32
|
+
Base class order matters. The mixin comes FIRST so its _draw() replaces the
|
|
33
|
+
native one; ctk.CTkOptionMenu comes next, so every other super() call in this
|
|
34
|
+
file resolves to it -- never to ThemeableWidget, whose own
|
|
35
|
+
configure()/cget()/_set_appearance_mode() overrides were removed for this
|
|
36
|
+
reason (see themeable_widget.py).
|
|
37
|
+
"""
|
|
38
|
+
from typing import Any, Optional
|
|
39
|
+
import customtkinter as ctk
|
|
40
|
+
from .themeable_widget import ThemeableWidget
|
|
41
|
+
from .sctk_optionmenu_border_mixin import sCTkOptionMenuBorderMixin
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class sCTkOptionMenuSecondary(sCTkOptionMenuBorderMixin, ctk.CTkOptionMenu,
|
|
45
|
+
ThemeableWidget):
|
|
46
|
+
"""Themeable dropdown option-selection menu, quiet variant.
|
|
47
|
+
|
|
48
|
+
Differs from sCTkOptionMenuPrimary in two ways, both from the theme file
|
|
49
|
+
rather than from anything structural:
|
|
50
|
+
|
|
51
|
+
- A border. border_width and border_color come from this widget's theme
|
|
52
|
+
block via sCTkOptionMenuBorderMixin. Primary supports the same keys and
|
|
53
|
+
simply sets border_width to 0.
|
|
54
|
+
- No distinct arrow button. button_color is set from fg_color, so the
|
|
55
|
+
arrow blends into the control rather than standing out as a separate
|
|
56
|
+
block of colour. Primary gives it its own colour.
|
|
57
|
+
|
|
58
|
+
fg_color and text_color are REQUIRED in whichever map is active -- top
|
|
59
|
+
level for the normal state, disabled_map when disabled. Missing either
|
|
60
|
+
raises rather than substituting a guess, following the library-wide
|
|
61
|
+
fail-loud rule.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(self, master: Optional[Any] = None, width: int = 160,
|
|
65
|
+
height: int = 28, **kw: Any) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Args:
|
|
68
|
+
master: Parent container.
|
|
69
|
+
width / height: Widget dimensions in pixels.
|
|
70
|
+
**kw: `values` (list[str]), `command` (callable) and `variable`
|
|
71
|
+
(tkinter.StringVar) are pulled out and applied after the native
|
|
72
|
+
widget exists. Everything else is either a native
|
|
73
|
+
CTkOptionMenu argument or a theme-key override (see the
|
|
74
|
+
"sCTkOptionMenuSecondary" block in sCTkThemes.json).
|
|
75
|
+
"""
|
|
76
|
+
# 1. Capture widget-specific attributes before the theme pass, so they
|
|
77
|
+
# are not merged into final_kw and treated as theme properties.
|
|
78
|
+
values = kw.pop("values", None)
|
|
79
|
+
command = kw.pop("command", None)
|
|
80
|
+
variable = kw.pop("variable", None)
|
|
81
|
+
|
|
82
|
+
kw.setdefault("width", width)
|
|
83
|
+
kw.setdefault("height", height)
|
|
84
|
+
|
|
85
|
+
# 2. Shared theme logic: resolves final_kw and the disabled map.
|
|
86
|
+
ThemeableWidget.__init__(self, kw)
|
|
87
|
+
|
|
88
|
+
# 3. Deep-copy onto this instance, so later changes never leak back
|
|
89
|
+
# into the shared theme registry.
|
|
90
|
+
self._local_defaults = dict(self.final_kw)
|
|
91
|
+
self._custom_disabled_map = dict(self._widget_disabled_map)
|
|
92
|
+
|
|
93
|
+
# 4. Initialize CustomTkinter natively.
|
|
94
|
+
#
|
|
95
|
+
# border_width and border_color are REMOVED first. They are this
|
|
96
|
+
# library's own additions -- native CTkOptionMenu has no border option
|
|
97
|
+
# and rejects any keyword it does not recognise, so leaving them in
|
|
98
|
+
# final_kw would raise at construction. _local_defaults above already
|
|
99
|
+
# holds copies for _init_border() to read.
|
|
100
|
+
native_kw = {k: v for k, v in self.final_kw.items()
|
|
101
|
+
if k not in ("border_width", "border_color")}
|
|
102
|
+
super().__init__(master, **native_kw)
|
|
103
|
+
|
|
104
|
+
# 5. Apply the extracted attributes now the native widget exists.
|
|
105
|
+
if values is not None:
|
|
106
|
+
super().configure(values=values)
|
|
107
|
+
if command is not None:
|
|
108
|
+
super().configure(command=command)
|
|
109
|
+
if variable is not None:
|
|
110
|
+
super().configure(variable=variable)
|
|
111
|
+
|
|
112
|
+
# 6. Border, after the native widget exists: the first redraw needs a
|
|
113
|
+
# canvas.
|
|
114
|
+
self._init_border(
|
|
115
|
+
border_width=self._local_defaults.get("border_width", 0),
|
|
116
|
+
border_color=self._local_defaults.get("border_color"),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
self._custom_current_state = "normal"
|
|
120
|
+
self._update_current_visual_state()
|
|
121
|
+
|
|
122
|
+
# 7. Lifecycle handshake, notifying Pygubu-style consumers that
|
|
123
|
+
# construction is complete.
|
|
124
|
+
self._finalize_themeable_lifecycle()
|
|
125
|
+
|
|
126
|
+
def configure(self, *args: Any, **kwargs: Any) -> Any:
|
|
127
|
+
"""
|
|
128
|
+
Standard widget configuration, with Pygubu/positional-argument handling.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
*args: At most one positional argument is meaningful:
|
|
132
|
+
- a dict: merged into kwargs and processed normally below.
|
|
133
|
+
- "state": returns a Tkinter-style
|
|
134
|
+
(name, name, name, default, current) tuple.
|
|
135
|
+
- "border_width" or "border_color": the same, from the mixin.
|
|
136
|
+
- "fg_color"/"button_color"/"button_hover_color"/"text_color":
|
|
137
|
+
the same, with `current` reflecting the disabled or normal
|
|
138
|
+
value as appropriate.
|
|
139
|
+
- anything else: handed to _configure_query(), which builds a
|
|
140
|
+
proper tuple rather than forwarding the name to the native
|
|
141
|
+
configure() -- see themeable_widget.py.
|
|
142
|
+
**kwargs: Standard CTkOptionMenu options, plus `border_width` and
|
|
143
|
+
`border_color`; `values`/`command`/`variable` are routed
|
|
144
|
+
through super().configure() individually, and `state=...` goes
|
|
145
|
+
through self.state().
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
The query tuple for the single-argument case, otherwise whatever
|
|
149
|
+
super().configure() returns.
|
|
150
|
+
"""
|
|
151
|
+
if len(args) == 1:
|
|
152
|
+
if isinstance(args[0], dict):
|
|
153
|
+
kwargs = {**args[0], **kwargs}
|
|
154
|
+
else:
|
|
155
|
+
pname = args[0]
|
|
156
|
+
if pname == "state":
|
|
157
|
+
return ("state", "state", "state", "normal", str(self.state()))
|
|
158
|
+
|
|
159
|
+
border_value = self._cget_border(pname)
|
|
160
|
+
if border_value is not self._NOT_A_BORDER_PROPERTY:
|
|
161
|
+
return (pname, pname, pname,
|
|
162
|
+
self._query_value(self._theme_default(pname)),
|
|
163
|
+
self._query_value(border_value))
|
|
164
|
+
|
|
165
|
+
if pname in ["fg_color", "button_color", "button_hover_color",
|
|
166
|
+
"text_color"]:
|
|
167
|
+
is_disabled = str(self.state()).lower() == "disabled"
|
|
168
|
+
source = (self._custom_disabled_map if is_disabled
|
|
169
|
+
else self._local_defaults)
|
|
170
|
+
return (pname, pname, pname,
|
|
171
|
+
self._query_value(self._theme_default(pname)),
|
|
172
|
+
self._query_value(source.get(pname)))
|
|
173
|
+
|
|
174
|
+
return self._configure_query(pname)
|
|
175
|
+
|
|
176
|
+
# Consumed before the native call below, which rejects both as unknown
|
|
177
|
+
# options.
|
|
178
|
+
self._configure_border(kwargs)
|
|
179
|
+
|
|
180
|
+
if "values" in kwargs:
|
|
181
|
+
super().configure(values=kwargs.pop("values"))
|
|
182
|
+
if "command" in kwargs:
|
|
183
|
+
super().configure(command=kwargs.pop("command"))
|
|
184
|
+
if "variable" in kwargs:
|
|
185
|
+
super().configure(variable=kwargs.pop("variable"))
|
|
186
|
+
|
|
187
|
+
# Runtime overrides have to reach the map a repaint reads, or the
|
|
188
|
+
# repaint puts the theme value straight back -- see
|
|
189
|
+
# ThemeableWidget._record_theme_overrides().
|
|
190
|
+
self._record_theme_overrides(kwargs)
|
|
191
|
+
|
|
192
|
+
if "state" in kwargs:
|
|
193
|
+
self.state(str(kwargs.pop("state")).lower())
|
|
194
|
+
|
|
195
|
+
self._drop_cleared(kwargs)
|
|
196
|
+
|
|
197
|
+
if kwargs:
|
|
198
|
+
return super().configure(**kwargs)
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
# Tkinter/CTk convention binds .config to .configure as a SEPARATE class
|
|
202
|
+
# attribute -- it does not track whichever configure() a subclass defines.
|
|
203
|
+
# Without this line, .config(...) would skip this override entirely and
|
|
204
|
+
# land on the native widget, bypassing theming and state handling.
|
|
205
|
+
config = configure
|
|
206
|
+
|
|
207
|
+
def cget(self, attribute_name: str) -> Any:
|
|
208
|
+
"""
|
|
209
|
+
Standard cget(), extended to this widget's own border properties.
|
|
210
|
+
|
|
211
|
+
border_width and border_color are not native CTkOptionMenu options, so
|
|
212
|
+
without this they reach CTkBaseClass.cget() and raise.
|
|
213
|
+
"""
|
|
214
|
+
border_value = self._cget_border(attribute_name)
|
|
215
|
+
if border_value is not self._NOT_A_BORDER_PROPERTY:
|
|
216
|
+
return border_value
|
|
217
|
+
return super().cget(attribute_name)
|
|
218
|
+
|
|
219
|
+
def _set_appearance_mode(self, mode_string: str) -> None:
|
|
220
|
+
"""
|
|
221
|
+
Forwards CustomTkinter's light/dark change to the native widget.
|
|
222
|
+
|
|
223
|
+
No manual re-application is needed: colours are passed through as raw
|
|
224
|
+
(light, dark) tuples, so CTk's own appearance tracking repaints them.
|
|
225
|
+
The border follows because _draw() re-resolves it on every redraw.
|
|
226
|
+
"""
|
|
227
|
+
if hasattr(super(), "_set_appearance_mode"):
|
|
228
|
+
try:
|
|
229
|
+
super()._set_appearance_mode(mode_string)
|
|
230
|
+
except Exception:
|
|
231
|
+
pass
|
|
232
|
+
|
|
233
|
+
def get_state(self) -> str:
|
|
234
|
+
"""Equivalent to calling state() with no argument."""
|
|
235
|
+
return self.state()
|
|
236
|
+
|
|
237
|
+
def state(self, mode: Optional[str] = None) -> str:
|
|
238
|
+
"""
|
|
239
|
+
Gets or sets the widget's enabled/disabled visual state.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
mode: None returns the current state unchanged. Otherwise only
|
|
243
|
+
"disabled" (case-insensitive) disables; anything in
|
|
244
|
+
("normal", "enabled", "active") enables. Any other value
|
|
245
|
+
matches neither branch, though the repaint still runs.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
The resulting state, lowercase.
|
|
249
|
+
"""
|
|
250
|
+
if mode is None:
|
|
251
|
+
return str(getattr(self, "_custom_current_state", "normal")).lower()
|
|
252
|
+
|
|
253
|
+
mode = mode.lower()
|
|
254
|
+
if mode in ("normal", "enabled", "active"):
|
|
255
|
+
self._custom_current_state = "normal"
|
|
256
|
+
elif mode == "disabled":
|
|
257
|
+
self._custom_current_state = "disabled"
|
|
258
|
+
|
|
259
|
+
self._update_current_visual_state()
|
|
260
|
+
return self._custom_current_state
|
|
261
|
+
|
|
262
|
+
def _update_current_visual_state(self) -> None:
|
|
263
|
+
"""
|
|
264
|
+
Recomputes and applies this widget's colours from the theme, based on
|
|
265
|
+
the current state, then sets the native interactive lock.
|
|
266
|
+
|
|
267
|
+
Colours are passed through as raw (light, dark) tuples so CTk's own
|
|
268
|
+
appearance tracking handles light/dark repaints.
|
|
269
|
+
|
|
270
|
+
button_color is set FROM fg_color rather than read as its own key.
|
|
271
|
+
That is what makes this the quiet variant: the arrow blends into the
|
|
272
|
+
control instead of standing out as a separate block, and the theme
|
|
273
|
+
block accordingly has no button_color of its own. Primary gives the
|
|
274
|
+
arrow its own colour.
|
|
275
|
+
"""
|
|
276
|
+
is_disabled = getattr(self, "_custom_current_state", "normal") == "disabled"
|
|
277
|
+
target_map = self._custom_disabled_map if is_disabled else self._local_defaults
|
|
278
|
+
|
|
279
|
+
# fg_color and text_color are required in whichever map is active.
|
|
280
|
+
# Substituting a guess would leave a broken theme block looking merely
|
|
281
|
+
# slightly wrong -- see the library-wide fail-loud rule.
|
|
282
|
+
section = "disabled_map" if is_disabled else "top-level"
|
|
283
|
+
for required_key in ("fg_color", "text_color"):
|
|
284
|
+
if target_map.get(required_key) is None:
|
|
285
|
+
name = (getattr(self, "_THEME_BLOCK_NAME", None)
|
|
286
|
+
or self.__class__.__name__)
|
|
287
|
+
raise KeyError(
|
|
288
|
+
f"'{name}' theme block is missing '{required_key}' in its "
|
|
289
|
+
f"{section} section of sCTkThemes.json."
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
payload = {}
|
|
293
|
+
for key in ("font", "dropdown_font", "dropdown_fg_color",
|
|
294
|
+
"dropdown_text_color", "dropdown_hover_color",
|
|
295
|
+
"button_hover_color"):
|
|
296
|
+
val = self._local_defaults.get(key)
|
|
297
|
+
if val is not None:
|
|
298
|
+
payload[key] = val
|
|
299
|
+
|
|
300
|
+
fill = target_map.get("fg_color")
|
|
301
|
+
payload.update({
|
|
302
|
+
"fg_color": fill,
|
|
303
|
+
"button_color": fill,
|
|
304
|
+
# text_color stays the NORMAL value and the disabled one goes to
|
|
305
|
+
# CTk's native text_color_disabled, because the state below puts
|
|
306
|
+
# the widget into CTk's own disabled mode -- where its draw code
|
|
307
|
+
# uses that option and ignores text_color entirely. Assigning the
|
|
308
|
+
# disabled colour here was discarded at draw time, so the theme key
|
|
309
|
+
# had no visible effect.
|
|
310
|
+
"text_color": self._local_defaults.get("text_color"),
|
|
311
|
+
"text_color_disabled": self._custom_disabled_map.get("text_color"),
|
|
312
|
+
"state": "disabled" if is_disabled else "normal",
|
|
313
|
+
})
|
|
314
|
+
super().configure(**payload)
|
|
315
|
+
|
|
316
|
+
# The border is not a native option, so it cannot ride along above.
|
|
317
|
+
# Its disabled colour comes from disabled_map like any other, falling
|
|
318
|
+
# back to the normal one when unspecified.
|
|
319
|
+
border_colour = target_map.get("border_color")
|
|
320
|
+
if border_colour is None:
|
|
321
|
+
border_colour = self._local_defaults.get("border_color")
|
|
322
|
+
if border_colour is not None:
|
|
323
|
+
self._border_color = border_colour
|
|
324
|
+
self._redraw_border()
|
|
325
|
+
|
|
326
|
+
def update_list(self, new_values: list, default_index: int = 0) -> None:
|
|
327
|
+
"""
|
|
328
|
+
Replaces the dropdown's options and resets the visible selection.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
new_values: The new options. An empty list sets a single blank
|
|
332
|
+
option and clears the display.
|
|
333
|
+
default_index: Which option to select afterwards. Out of range
|
|
334
|
+
falls back to index 0 rather than raising.
|
|
335
|
+
"""
|
|
336
|
+
if not new_values:
|
|
337
|
+
self.configure(values=[""])
|
|
338
|
+
self.set("")
|
|
339
|
+
return
|
|
340
|
+
|
|
341
|
+
self.configure(values=new_values)
|
|
342
|
+
|
|
343
|
+
if default_index < len(new_values):
|
|
344
|
+
self.set(new_values[default_index])
|
|
345
|
+
else:
|
|
346
|
+
self.set(new_values[0])
|