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.
Files changed (101) hide show
  1. scustomtkinter/__init__.py +81 -0
  2. scustomtkinter/assets/images/error.png +0 -0
  3. scustomtkinter/assets/images/info.png +0 -0
  4. scustomtkinter/assets/images/warning.png +0 -0
  5. scustomtkinter/assets/sCTkThemes.json +1963 -0
  6. scustomtkinter/license_morecustomtkinterwidgets.txt +22 -0
  7. scustomtkinter/sctk_button_primary.py +366 -0
  8. scustomtkinter/sctk_button_secondary.py +354 -0
  9. scustomtkinter/sctk_button_tertiary.py +375 -0
  10. scustomtkinter/sctk_checkbox.py +270 -0
  11. scustomtkinter/sctk_combobox.py +155 -0
  12. scustomtkinter/sctk_core.py +15 -0
  13. scustomtkinter/sctk_dial.py +1472 -0
  14. scustomtkinter/sctk_dialog.py +701 -0
  15. scustomtkinter/sctk_dialog_toplevel.py +268 -0
  16. scustomtkinter/sctk_entry_primary.py +400 -0
  17. scustomtkinter/sctk_entry_secondary.py +342 -0
  18. scustomtkinter/sctk_file_explorer.py +879 -0
  19. scustomtkinter/sctk_frame.py +210 -0
  20. scustomtkinter/sctk_frame_labeled_primary.py +667 -0
  21. scustomtkinter/sctk_frame_labeled_secondary.py +598 -0
  22. scustomtkinter/sctk_frequency_display.py +636 -0
  23. scustomtkinter/sctk_label_primary.py +283 -0
  24. scustomtkinter/sctk_label_secondary.py +275 -0
  25. scustomtkinter/sctk_label_tertiary.py +278 -0
  26. scustomtkinter/sctk_messagebox.py +275 -0
  27. scustomtkinter/sctk_notebook.py +1103 -0
  28. scustomtkinter/sctk_optionmenu_border_mixin.py +203 -0
  29. scustomtkinter/sctk_optionmenu_primary.py +378 -0
  30. scustomtkinter/sctk_optionmenu_secondary.py +346 -0
  31. scustomtkinter/sctk_path_chooser.py +516 -0
  32. scustomtkinter/sctk_progress_bar.py +274 -0
  33. scustomtkinter/sctk_radiobutton.py +360 -0
  34. scustomtkinter/sctk_scroll_mixin.py +546 -0
  35. scustomtkinter/sctk_scrollable_frame.py +795 -0
  36. scustomtkinter/sctk_scrollbar.py +313 -0
  37. scustomtkinter/sctk_segmentedbutton.py +424 -0
  38. scustomtkinter/sctk_selector.py +581 -0
  39. scustomtkinter/sctk_separator.py +308 -0
  40. scustomtkinter/sctk_slider.py +264 -0
  41. scustomtkinter/sctk_smeter.py +405 -0
  42. scustomtkinter/sctk_smeter_bar.py +557 -0
  43. scustomtkinter/sctk_spinbox.py +664 -0
  44. scustomtkinter/sctk_switch.py +463 -0
  45. scustomtkinter/sctk_tableview.py +869 -0
  46. scustomtkinter/sctk_tabview.py +409 -0
  47. scustomtkinter/sctk_textbox_primary.py +291 -0
  48. scustomtkinter/sctk_textbox_secondary.py +225 -0
  49. scustomtkinter/sctk_toplevel.py +153 -0
  50. scustomtkinter/themeable_widget.py +938 -0
  51. scustomtkinter-0.2.1.dist-info/METADATA +336 -0
  52. scustomtkinter-0.2.1.dist-info/RECORD +101 -0
  53. scustomtkinter-0.2.1.dist-info/WHEEL +5 -0
  54. scustomtkinter-0.2.1.dist-info/entry_points.txt +2 -0
  55. scustomtkinter-0.2.1.dist-info/licenses/LICENSE +21 -0
  56. scustomtkinter-0.2.1.dist-info/licenses/scustomtkinter/license_morecustomtkinterwidgets.txt +22 -0
  57. scustomtkinter-0.2.1.dist-info/top_level.txt +2 -0
  58. scustomtkinter_pygubu/__init__.py +1 -0
  59. scustomtkinter_pygubu/designer/__init__.py +0 -0
  60. scustomtkinter_pygubu/designer/plugin.py +1854 -0
  61. scustomtkinter_pygubu/designer/properties.py +247 -0
  62. scustomtkinter_pygubu/sCTkButtonPrimarybo.py +46 -0
  63. scustomtkinter_pygubu/sCTkButtonSecondarybo.py +45 -0
  64. scustomtkinter_pygubu/sCTkButtonTertiarybo.py +44 -0
  65. scustomtkinter_pygubu/sCTkCheckBoxbo.py +45 -0
  66. scustomtkinter_pygubu/sCTkComboBoxbo.py +45 -0
  67. scustomtkinter_pygubu/sCTkCorebo.py +120 -0
  68. scustomtkinter_pygubu/sCTkDialbo.py +371 -0
  69. scustomtkinter_pygubu/sCTkDialogbo.py +397 -0
  70. scustomtkinter_pygubu/sCTkEntryPrimarybo.py +100 -0
  71. scustomtkinter_pygubu/sCTkEntrySecondarybo.py +98 -0
  72. scustomtkinter_pygubu/sCTkFileExplorerbo.py +189 -0
  73. scustomtkinter_pygubu/sCTkFrameLabeledPrimarybo.py +69 -0
  74. scustomtkinter_pygubu/sCTkFrameLabeledSecondarybo.py +71 -0
  75. scustomtkinter_pygubu/sCTkFramebo.py +46 -0
  76. scustomtkinter_pygubu/sCTkFrequencyDisplaybo.py +175 -0
  77. scustomtkinter_pygubu/sCTkLabelPrimarybo.py +45 -0
  78. scustomtkinter_pygubu/sCTkLabelSecondarybo.py +44 -0
  79. scustomtkinter_pygubu/sCTkLabelTertiarybo.py +45 -0
  80. scustomtkinter_pygubu/sCTkNotebookbo.py +392 -0
  81. scustomtkinter_pygubu/sCTkOptionMenuPrimarybo.py +45 -0
  82. scustomtkinter_pygubu/sCTkOptionMenuSecondarybo.py +39 -0
  83. scustomtkinter_pygubu/sCTkPathChooserbo.py +204 -0
  84. scustomtkinter_pygubu/sCTkProgressBarbo.py +45 -0
  85. scustomtkinter_pygubu/sCTkRadioButtonbo.py +45 -0
  86. scustomtkinter_pygubu/sCTkSMeterBarbo.py +153 -0
  87. scustomtkinter_pygubu/sCTkSMeterbo.py +101 -0
  88. scustomtkinter_pygubu/sCTkScrollableFramebo.py +66 -0
  89. scustomtkinter_pygubu/sCTkScrollbarbo.py +48 -0
  90. scustomtkinter_pygubu/sCTkSegmentedButtonbo.py +47 -0
  91. scustomtkinter_pygubu/sCTkSelectorbo.py +167 -0
  92. scustomtkinter_pygubu/sCTkSeparatorbo.py +141 -0
  93. scustomtkinter_pygubu/sCTkSliderbo.py +45 -0
  94. scustomtkinter_pygubu/sCTkSpinboxbo.py +200 -0
  95. scustomtkinter_pygubu/sCTkSwitchbo.py +45 -0
  96. scustomtkinter_pygubu/sCTkTableviewbo.py +188 -0
  97. scustomtkinter_pygubu/sCTkTabviewbo.py +226 -0
  98. scustomtkinter_pygubu/sCTkTextboxPrimarybo.py +45 -0
  99. scustomtkinter_pygubu/sCTkTextboxSecondarybo.py +45 -0
  100. scustomtkinter_pygubu/sCTkToplevelbo.py +55 -0
  101. 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"