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,210 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
"""
|
|
3
|
+
sCTkFrame
|
|
4
|
+
|
|
5
|
+
A theme-compliant container frame widget. Inherits directly from ctk.CTkFrame
|
|
6
|
+
so CustomTkinter handles native rendering and layout; this class layers
|
|
7
|
+
automatic light/dark theme resolution on top.
|
|
8
|
+
|
|
9
|
+
Base class order matters here: `class sCTkFrame(ctk.CTkFrame,
|
|
10
|
+
ThemeableWidget)` puts the native CTk class first, so every `super()` call in
|
|
11
|
+
this file's own methods resolves to ctk.CTkFrame -- and, beneath it,
|
|
12
|
+
tkinter.Misc -- never to ThemeableWidget. ThemeableWidget's own
|
|
13
|
+
configure()/cget()/_set_appearance_mode() overrides have been removed entirely
|
|
14
|
+
for this reason (see themeable_widget.py's docstring).
|
|
15
|
+
|
|
16
|
+
Unlike every other widget in this library, sCTkFrame has no disabled state and
|
|
17
|
+
no _update_current_visual_state() at all -- frames are containers, not
|
|
18
|
+
interactive controls, so there's nothing to dim or lock. Colors are set once
|
|
19
|
+
at construction (as raw (light, dark) tuples, via final_kw) and never touched
|
|
20
|
+
again; CustomTkinter's own native appearance-mode tracking handles light/dark
|
|
21
|
+
repaints on its own, the same underlying mechanism validated more deliberately
|
|
22
|
+
on sCTkComboBox, sCTkSegmentedButton, and the button family. There's also no
|
|
23
|
+
_set_appearance_mode() override here, for the same reason -- there's nothing
|
|
24
|
+
for it to re-trigger.
|
|
25
|
+
"""
|
|
26
|
+
from typing import Any, Optional
|
|
27
|
+
import customtkinter as ctk
|
|
28
|
+
from .themeable_widget import ThemeableWidget
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class sCTkFrame(ctk.CTkFrame, ThemeableWidget):
|
|
32
|
+
"""Themeable container frame.
|
|
33
|
+
|
|
34
|
+
Adds to native ctk.CTkFrame:
|
|
35
|
+
- Automatic light/dark theme resolution from sCTkThemes.json (via
|
|
36
|
+
ThemeableWidget.__init__ -- see that class's docstring for what it does,
|
|
37
|
+
and just as importantly, what it no longer does).
|
|
38
|
+
- Pygubu Designer property introspection for `state`, `fg_color`, and
|
|
39
|
+
`border_color` via a single-argument configure() call.
|
|
40
|
+
- A no-op state()/get_state() pair, so generic test harnesses that call
|
|
41
|
+
.state() uniformly across every widget type don't crash when handed a
|
|
42
|
+
Frame. This is deliberate, not a bug -- see state()'s docstring.
|
|
43
|
+
|
|
44
|
+
WHITELIST GUARD: if a composite widget inherits sCTkFrame as its own base
|
|
45
|
+
class (e.g. sCTkSelector(sCTkFrame, ThemeableWidget)) and explicitly calls
|
|
46
|
+
ThemeableWidget.__init__ itself before calling super().__init__(), that
|
|
47
|
+
composite's own final_kw -- built from ITS theme block, which may contain
|
|
48
|
+
keys native ctk.CTkFrame knows nothing about -- would otherwise flow
|
|
49
|
+
straight through to super().__init__(master, **self.final_kw) here and
|
|
50
|
+
crash. _NATIVE_CTKFRAME_KWARGS filters final_kw down to only the keys the
|
|
51
|
+
real native CTkFrame.__init__ actually accepts (confirmed directly against
|
|
52
|
+
CustomTkinter's own source) before that call, discarding anything foreign.
|
|
53
|
+
This only matters for the Pattern-B composition scenario described above;
|
|
54
|
+
for direct construction of a plain sCTkFrame, final_kw already only
|
|
55
|
+
contains this widget's own theme keys, so the filter is a no-op. Note this
|
|
56
|
+
is independent of ThemeableWidget's run-once guard: that guard stops
|
|
57
|
+
final_kw from being silently overwritten by a second init call; this
|
|
58
|
+
whitelist stops whatever final_kw a widget legitimately has from being
|
|
59
|
+
blindly forwarded to a native constructor that can't handle all of it.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
# Confirmed directly against CustomTkinter's own ctk_frame.py source:
|
|
63
|
+
# def __init__(self, master, width=200, height=200, corner_radius=None,
|
|
64
|
+
# border_width=None, bg_color="transparent", fg_color=None,
|
|
65
|
+
# border_color=None, background_corner_colors=None,
|
|
66
|
+
# overwrite_preferred_drawing_method=None, **kwargs)
|
|
67
|
+
# "master" is excluded here since it's always passed positionally, never
|
|
68
|
+
# part of the filtered kwargs dict.
|
|
69
|
+
# Native CTkFrame's own constructor defaults, for the single-argument
|
|
70
|
+
# query below. Taken from the signature quoted above: anything not listed
|
|
71
|
+
# reports its current value as its default, which makes blanking that
|
|
72
|
+
# field in a designer a no-op rather than a change to a guessed value.
|
|
73
|
+
_NATIVE_DEFAULTS = {"width": 200, "height": 200}
|
|
74
|
+
|
|
75
|
+
_NATIVE_CTKFRAME_KWARGS = frozenset({
|
|
76
|
+
"width", "height", "corner_radius", "border_width", "bg_color",
|
|
77
|
+
"fg_color", "border_color", "background_corner_colors",
|
|
78
|
+
"overwrite_preferred_drawing_method",
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
def __init__(self, master: Optional[Any] = None, **kwargs: Any) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Args:
|
|
84
|
+
master: Parent container.
|
|
85
|
+
**kwargs: Any native CTkFrame argument, or a theme-key override
|
|
86
|
+
(see the "sCTkFrame" block in sCTkThemes.json). There is no
|
|
87
|
+
disabled_map for this widget -- frames have no disabled state.
|
|
88
|
+
"""
|
|
89
|
+
# 1. Fire our shared theme logic first. This resolves final_kw
|
|
90
|
+
# (construction-time properties). See ThemeableWidget.__init__ for
|
|
91
|
+
# what actually happens here.
|
|
92
|
+
ThemeableWidget.__init__(self, kwargs)
|
|
93
|
+
|
|
94
|
+
# 2. Deep-copy the resolved kwargs onto this instance, so later
|
|
95
|
+
# changes here never leak back into the shared theme registry.
|
|
96
|
+
self._local_defaults = dict(self.final_kw)
|
|
97
|
+
|
|
98
|
+
# 3. Initialize CustomTkinter natively. Only forwards the subset of
|
|
99
|
+
# final_kw that native CTkFrame actually accepts -- see this class's
|
|
100
|
+
# docstring ("WHITELIST GUARD") for why this filtering exists.
|
|
101
|
+
native_kwargs = {k: v for k, v in self.final_kw.items() if k in self._NATIVE_CTKFRAME_KWARGS}
|
|
102
|
+
super().__init__(master, **native_kwargs)
|
|
103
|
+
|
|
104
|
+
# 4. Register lifecycle handshake hook, notifying Pygubu-style consumers
|
|
105
|
+
# that construction is complete.
|
|
106
|
+
self._finalize_themeable_lifecycle()
|
|
107
|
+
|
|
108
|
+
def configure(self, *args: Any, **kwargs: Any) -> Any:
|
|
109
|
+
"""
|
|
110
|
+
Standard widget configuration, with Pygubu/positional-argument handling.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
*args: At most one positional argument is meaningful:
|
|
114
|
+
- a dict: merged into kwargs and processed normally below.
|
|
115
|
+
- the literal string "state": returns a Tkinter-style
|
|
116
|
+
(name, name, name, default, current) tuple. Since frames
|
|
117
|
+
have no real state, `default` and `current` are always the
|
|
118
|
+
same value: "normal".
|
|
119
|
+
- "fg_color" or "border_color": returns the same style of
|
|
120
|
+
tuple. Since these never vary by state for a frame,
|
|
121
|
+
`default` and `current` are always identical here too.
|
|
122
|
+
- anything else: forwarded directly to the native widget's
|
|
123
|
+
configure(), which does not support single-argument property
|
|
124
|
+
queries for arbitrary properties -- a known limitation
|
|
125
|
+
shared with the wider Pygubu-query investigation set aside
|
|
126
|
+
elsewhere in this project.
|
|
127
|
+
**kwargs: Standard CTkFrame configuration options, plus: passing
|
|
128
|
+
`state=...` is silently absorbed via self.state() (a no-op)
|
|
129
|
+
rather than forwarded to the native widget, which has no real
|
|
130
|
+
concept of "state" to configure in the first place.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
The query tuple described above for the single-argument case, or
|
|
134
|
+
whatever super().configure() returns for the keyword-argument case
|
|
135
|
+
(typically None).
|
|
136
|
+
"""
|
|
137
|
+
if len(args) == 1:
|
|
138
|
+
if isinstance(args[0], dict):
|
|
139
|
+
kwargs = {**args[0], **kwargs}
|
|
140
|
+
else:
|
|
141
|
+
pname = args[0]
|
|
142
|
+
if pname == "state":
|
|
143
|
+
return ("state", "state", "state", "normal", str(self.state()))
|
|
144
|
+
if pname in ["fg_color", "border_color"]:
|
|
145
|
+
val = self._local_defaults.get(pname)
|
|
146
|
+
return (pname, pname, pname, self._query_value(val), self._query_value(val))
|
|
147
|
+
|
|
148
|
+
# FIX: this used to be `return super().configure(pname)`.
|
|
149
|
+
#
|
|
150
|
+
# Native CTkFrame.configure() is declared
|
|
151
|
+
# configure(self, require_redraw=False, **kwargs) -- so the
|
|
152
|
+
# property NAME was passed as require_redraw and the call
|
|
153
|
+
# returned None. Pygubu's _get_default_value() expects a
|
|
154
|
+
# five-element tuple, found None, and handed that None straight
|
|
155
|
+
# back to _set_property(), where CustomTkinter did float(None):
|
|
156
|
+
#
|
|
157
|
+
# Failed to set property 'height' ... float() argument must
|
|
158
|
+
# be a string or a real number, not 'NoneType'
|
|
159
|
+
#
|
|
160
|
+
# Reached whenever a field is blanked in the Designer
|
|
161
|
+
# inspector, which calls configure(name) to discover the
|
|
162
|
+
# property's default.
|
|
163
|
+
#
|
|
164
|
+
# A proper Tkinter-style tuple is returned instead, built from
|
|
165
|
+
# cget() so the reported current value is real.
|
|
166
|
+
try:
|
|
167
|
+
current = self.cget(pname)
|
|
168
|
+
except Exception:
|
|
169
|
+
current = None
|
|
170
|
+
default = self._NATIVE_DEFAULTS.get(pname, current)
|
|
171
|
+
return (pname, pname, pname, default, current)
|
|
172
|
+
|
|
173
|
+
# Absorbs "state" so generic test harnesses that call
|
|
174
|
+
# configure(state=...) uniformly across widget types don't raise on a
|
|
175
|
+
# Frame, which has no native "state" option.
|
|
176
|
+
if "state" in kwargs:
|
|
177
|
+
target_state = kwargs.pop("state")
|
|
178
|
+
self.state(target_state)
|
|
179
|
+
|
|
180
|
+
self._drop_cleared(kwargs)
|
|
181
|
+
|
|
182
|
+
if kwargs:
|
|
183
|
+
return super().configure(**kwargs)
|
|
184
|
+
return None
|
|
185
|
+
|
|
186
|
+
# Tkinter/CTk convention binds .config to .configure as a SEPARATE class
|
|
187
|
+
# attribute -- it does not automatically track whichever configure() a
|
|
188
|
+
# subclass defines. Without this line, calling .config(...) on an instance
|
|
189
|
+
# would silently skip this entire override and land on the native widget's
|
|
190
|
+
# configure() directly.
|
|
191
|
+
config = configure
|
|
192
|
+
|
|
193
|
+
def get_state(self) -> str:
|
|
194
|
+
"""Equivalent to calling state() with no argument. Always returns "normal"."""
|
|
195
|
+
return self.state()
|
|
196
|
+
|
|
197
|
+
def state(self, mode: Optional[str] = None) -> str:
|
|
198
|
+
"""
|
|
199
|
+
No-op state controller. Frames have no disabled concept -- this exists
|
|
200
|
+
purely so code written generically against every widget's state()/
|
|
201
|
+
get_state()/configure(state=...) API doesn't need a special case for
|
|
202
|
+
Frame. Whatever `mode` is passed, it's ignored and never stored.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
mode: Ignored entirely.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Always "normal".
|
|
209
|
+
"""
|
|
210
|
+
return "normal"
|