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,189 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkFileExplorerbo
4
+
5
+ Pygubu Builder Object for the compound FileExplorer entry that is used by pathchooser.
6
+ """
7
+ import pygubu
8
+ from pygubu.api.v1 import (
9
+ BuilderObject,
10
+ register_widget,
11
+ register_custom_property
12
+ )
13
+
14
+ # Import the native custom class
15
+ from scustomtkinter.sctk_file_explorer import sCTkFileExplorer
16
+ from pygubu.plugins.customtkinter.widgets import CTkFrameBO
17
+
18
+ # Builder UI placement definitions
19
+ widget_namespace = "scustomtkinter.sctk_file_explorer"
20
+ widget_classname = "sCTkFileExplorer"
21
+ builder_namespace = "scustomtkinter"
22
+ section_name = "sCustomTkinter"
23
+
24
+
25
+ class sCTkFileExplorerBO(BuilderObject):
26
+ class_ = sCTkFileExplorer
27
+
28
+ # Define custom plugin properties (Note: 'title' has been completely removed)
29
+ OPTIONS_CUSTOM = (
30
+ "width", "height", "type", "initialdir", "initialfile",
31
+ "filetypes", "state", "command", "double_click_command",
32
+ "selection_color"
33
+ )
34
+
35
+ # Merge custom extensions cleanly on top of core container frame attributes
36
+ properties = CTkFrameBO.properties + OPTIONS_CUSTOM
37
+ command_properties = ("command", "double_click_command")
38
+
39
+ def _process_property_value(self, pname, value):
40
+ """Passes values directly to allow core widget validations to handle exceptions."""
41
+ return super()._process_property_value(pname, value)
42
+
43
+ def _code_define_callback_args(self, cmd_pname, cmd):
44
+ """
45
+ Declares what each callback receives, so the generated stub has
46
+ matching parameters.
47
+
48
+ FIX: without this, pygubu generated a stub with no arguments --
49
+
50
+ def single_cb(self):
51
+ pass
52
+
53
+ -- and the widget called it with the selected path:
54
+
55
+ TypeError: single_cb() takes 1 positional argument but 2 were given
56
+
57
+ The two callbacks differ. `command` receives the path alone;
58
+ `double_click_command` receives the WIDGET and the path, which is how
59
+ sCTkPathChooser drives it (it reads args[-1] to get the path).
60
+ """
61
+ if cmd_pname == "double_click_command":
62
+ return ("explorer", "selected_path")
63
+ return ("selected_path",)
64
+
65
+ def _code_set_property(self, targetid, pname, value, code_bag):
66
+ """
67
+ Emits `filetypes` as a real Python list, not a quoted string.
68
+
69
+ FIX: the bracketed form contains double quotes, and the default
70
+ handler wraps the whole value in double quotes again:
71
+
72
+ sctkfileexplorer1.configure(filetypes="[".py"]", ...)
73
+ ^^^^^^^^^
74
+ SyntaxError: invalid syntax
75
+
76
+ Emitting the literal unquoted gives valid Python and a real list, so
77
+ the widget receives one directly rather than parsing a string back
78
+ out of it. Same approach sCTkSelectorbo uses for `items`.
79
+
80
+ A bare comma-separated value -- the other accepted form -- has no
81
+ brackets and no quotes, so it is emitted as a quoted string and parsed
82
+ by the widget as usual.
83
+ """
84
+ if pname == "filetypes" and value:
85
+ text = str(value).strip()
86
+ if text.startswith("[") and text.endswith("]"):
87
+ code_bag[pname] = text
88
+ return None
89
+ return super()._code_set_property(targetid, pname, value, code_bag)
90
+
91
+ # NOTE: `type` and `filetypes` constrain each other in the WIDGET, but the
92
+ # inspector does not follow.
93
+ #
94
+ # Setting filetypes switches the widget to file mode, and choosing
95
+ # directory clears the filter -- see sCTkFileExplorer. The widget applies
96
+ # that to itself, and generated code is correct either way, because the
97
+ # widget corrects the combination at construction.
98
+ #
99
+ # The Designer keeps its own copy of the properties, so the inspector goes
100
+ # on showing the old value: adding a filter leaves `type` reading blank
101
+ # while the widget has switched to file mode. A set_property() override
102
+ # writing the companion value back into wmeta was tried and does not
103
+ # reach the live tree node, so it has been removed rather than left as
104
+ # dead code implying a behaviour that does not happen.
105
+
106
+
107
+ # Register the widget into Pygubu's layout parsing engine
108
+ builder_id = f"{builder_namespace}.{widget_classname}"
109
+ register_widget(builder_id, sCTkFileExplorerBO, 'sCTkFileExplorer', ("ttk", section_name))
110
+
111
+ # =========================================================================
112
+ # Custom Property Designer Registration Maps
113
+ # =========================================================================
114
+
115
+ register_custom_property(
116
+ builder_id,
117
+ "command",
118
+ "commandentry",
119
+ help="Method callback string triggered on single-click file item highlight"
120
+ )
121
+
122
+ register_custom_property(
123
+ builder_id,
124
+ "double_click_command",
125
+ "commandentry",
126
+ help="Method callback string triggered on double-click selection"
127
+ )
128
+
129
+ register_custom_property(
130
+ builder_id,
131
+ "width",
132
+ "naturalnumber",
133
+ help="Total horizontal pixel constraint footprint assigned to the layout canvas wrapper"
134
+ )
135
+
136
+ register_custom_property(
137
+ builder_id,
138
+ "height",
139
+ "naturalnumber",
140
+ help="Total vertical pixel constraint footprint assigned to the layout canvas wrapper"
141
+ )
142
+
143
+ register_custom_property(
144
+ builder_id,
145
+ "type",
146
+ "choice",
147
+ values=("", "file", "directory"),
148
+ state="readonly",
149
+ default_value="directory",
150
+ help="What the explorer selects. The widget's own default is 'directory'; "
151
+ "setting filetypes switches it to 'file'."
152
+ )
153
+
154
+ register_custom_property(
155
+ builder_id,
156
+ "initialdir",
157
+ "entry",
158
+ help="Default starting directory path location string"
159
+ )
160
+
161
+ register_custom_property(
162
+ builder_id,
163
+ "initialfile",
164
+ "entry",
165
+ help="Default starting highlight focus target file path string"
166
+ )
167
+
168
+ register_custom_property(
169
+ builder_id,
170
+ "filetypes",
171
+ "entry",
172
+ help='Filter by file extension. Preferred: [".py", ".txt"]. Bare comma-separated (.py, .txt) also works, but cannot contain a comma inside a value.'
173
+ )
174
+
175
+ register_custom_property(
176
+ builder_id,
177
+ "state",
178
+ "choice",
179
+ values=("", "normal", "disabled"),
180
+ state="readonly",
181
+ help="Set widget active visibility or input interaction lockdown state"
182
+ )
183
+
184
+ register_custom_property(
185
+ builder_id, "selection_color", "colorentry",
186
+ help="Colour of the highlighted row. Blank uses the theme's "
187
+ "selection_color. Separate from btn_fg, which colours the navigation "
188
+ "buttons -- changing one does not affect the other."
189
+ )
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkFrameLabeledPrimary
4
+
5
+ Similer to ttk.labelframe built on ctkscrollableframe with scrollbars hidden
6
+
7
+ UI source file: sCTkFrameLabeledPrimary.ui
8
+ """
9
+ import tkinter as tk
10
+ import tkinter.ttk as ttk
11
+ from customtkinter import CTkScrollableFrame
12
+ from pygubu.api.v1 import (
13
+ BuilderObject,
14
+ register_widget,
15
+ register_custom_property)
16
+
17
+ from pygubu.plugins.customtkinter.scrollableframe import CTkScrollableFrameBO
18
+
19
+ from scustomtkinter.sctk_frame_labeled_primary import sCTkFrameLabeledPrimary
20
+
21
+
22
+ #
23
+ # Builder definition section
24
+ #
25
+ widget_namespace = "scustomtkinter.sctk_frame_labeled_primary"
26
+ widget_classname = "sCTkFrameLabeledPrimary"
27
+ builder_namespace = "scustomtkinter"
28
+ section_name = "sCustomTkinter"
29
+
30
+
31
+ container = True
32
+ # CTkScrollableFrame does some weird things
33
+ # with layout so disabled container layout here on purpose.
34
+ container_layout = False
35
+
36
+
37
+ class sCTkFrameLabeledPrimaryBO(CTkScrollableFrameBO):
38
+ class_ = sCTkFrameLabeledPrimary
39
+
40
+ # state was never declared here, so the property did not reach the
41
+ # inspector at all -- even though the widget implements it fully, with its
42
+ # own state()/get_state() and a disabled_map that dims the border and the
43
+ # label. sCTkScrollableFramebo declares it the same way.
44
+ OPTIONS_CUSTOM = ("state",)
45
+ properties = CTkScrollableFrameBO.properties + OPTIONS_CUSTOM
46
+
47
+ OPTIONS_CUSTOM_DEFAULTS = {
48
+ "state": "normal",
49
+ }
50
+
51
+
52
+ def code_imports(self):
53
+ # should return an iterable of (module, classname/function) to import
54
+ # or None
55
+ imports = [(widget_namespace, widget_classname)]
56
+ imports.extend(self.code_extra_imports())
57
+ return imports
58
+
59
+ builder_id = f"{builder_namespace}.{widget_classname}"
60
+ register_widget(
61
+ builder_id, sCTkFrameLabeledPrimaryBO, widget_classname, ("ttk", section_name)
62
+ )
63
+
64
+ register_custom_property(
65
+ builder_id, "state", "choice", values=("normal", "disabled"),
66
+ state="readonly", default_value="normal",
67
+ help="Disabled dims the border and the label. The contents keep their own "
68
+ "state -- disabling the frame does not disable what is inside it."
69
+ )
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkFrameLabeledSecondary
4
+
5
+ Similer to ttk.labelframe built on ctkscrollableframe with scrollbars hidden
6
+
7
+ UI source file: sCTkFrameLabeledSecondary.ui
8
+ """
9
+ import tkinter as tk
10
+ import tkinter.ttk as ttk
11
+ from customtkinter import CTkScrollableFrame
12
+ from pygubu.api.v1 import (
13
+ BuilderObject,
14
+ register_widget,
15
+ register_custom_property
16
+ )
17
+
18
+ from pygubu.plugins.customtkinter import nsctk
19
+ from pygubu.plugins.customtkinter.scrollableframe import CTkScrollableFrameBO
20
+ from pygubu.api.v1 import copy_custom_property
21
+
22
+ from scustomtkinter.sctk_frame_labeled_secondary import sCTkFrameLabeledSecondary
23
+
24
+
25
+ #
26
+ # Builder definition section
27
+ #
28
+ widget_namespace = "scustomtkinter.sctk_frame_labeled_secondary"
29
+ widget_classname = "sCTkFrameLabeledSecondary"
30
+ builder_namespace = "scustomtkinter"
31
+ section_name = "sCustomTkinter"
32
+
33
+ container = True
34
+ # CTkScrollableFrame does some weird things
35
+ # with layout so disabled container layout here on purpose.
36
+ container_layout = False
37
+
38
+
39
+ class sCTkFrameLabeledSecondaryBO(CTkScrollableFrameBO):
40
+ class_ = sCTkFrameLabeledSecondary
41
+
42
+ # state was never declared here, so the property did not reach the
43
+ # inspector at all -- even though the widget implements it fully, with its
44
+ # own state()/get_state() and a disabled_map that dims the border and the
45
+ # label. sCTkScrollableFramebo declares it the same way.
46
+ OPTIONS_CUSTOM = ("state",)
47
+ properties = CTkScrollableFrameBO.properties + OPTIONS_CUSTOM
48
+
49
+ OPTIONS_CUSTOM_DEFAULTS = {
50
+ "state": "normal",
51
+ }
52
+
53
+ def code_imports(self):
54
+ # should return an iterable of (module, classname/function) to import
55
+ # or None
56
+ imports = [(widget_namespace, widget_classname)]
57
+ imports.extend(self.code_extra_imports())
58
+ return imports
59
+
60
+
61
+ builder_id = f"{builder_namespace}.{widget_classname}"
62
+ register_widget(
63
+ builder_id, sCTkFrameLabeledSecondaryBO, widget_classname, ("ttk", section_name)
64
+ )
65
+
66
+ register_custom_property(
67
+ builder_id, "state", "choice", values=("normal", "disabled"),
68
+ state="readonly", default_value="normal",
69
+ help="Disabled dims the border and the label. The contents keep their own "
70
+ "state -- disabling the frame does not disable what is inside it."
71
+ )
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkFrame
4
+
5
+ subclass of Frame tuned for this ux
6
+
7
+ UI source file: sCTkFrame.ui
8
+ """
9
+ import tkinter as tk
10
+ import tkinter.ttk as ttk
11
+ from customtkinter import CTkFrame
12
+ from pygubu.api.v1 import (
13
+ BuilderObject,
14
+ register_widget,
15
+ register_custom_property
16
+ )
17
+
18
+ from pygubu.plugins.customtkinter import nsctk
19
+ from pygubu.plugins.customtkinter.widgets import CTkFrameBO
20
+ from pygubu.api.v1 import copy_custom_property
21
+
22
+ from scustomtkinter.sctk_frame import sCTkFrame
23
+
24
+
25
+ #
26
+ # Builder definition section
27
+ #
28
+ widget_namespace = "scustomtkinter.sctk_frame"
29
+ widget_classname = "sCTkFrame"
30
+ builder_namespace = "scustomtkinter"
31
+ section_name = "sCustomTkinter"
32
+
33
+
34
+ class sCTkFrameBO(CTkFrameBO):
35
+ class_ = sCTkFrame
36
+
37
+ def code_imports(self):
38
+ # should return an iterable of (module, classname/function) to import
39
+ # or None
40
+ return [(widget_namespace, widget_classname)]
41
+
42
+
43
+ builder_id = f"{builder_namespace}.{widget_classname}"
44
+ register_widget(
45
+ builder_id, sCTkFrameBO, widget_classname, ("ttk", section_name)
46
+ )
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkFrequencyDisplay
4
+
5
+ Pygubu builder object for the grouped numeric readout.
6
+ """
7
+ from pygubu.api.v1 import (
8
+ register_widget,
9
+ register_custom_property,
10
+ )
11
+ from pygubu.plugins.customtkinter.widgets import CTkFrameBO
12
+
13
+ from scustomtkinter.sctk_frequency_display import sCTkFrequencyDisplay
14
+
15
+ widget_namespace = "scustomtkinter.sctk_frequency_display"
16
+ widget_classname = "sCTkFrequencyDisplay"
17
+ builder_namespace = "scustomtkinter"
18
+ section_name = "sCustomTkinter"
19
+
20
+
21
+ class sCTkFrequencyDisplayBO(CTkFrameBO):
22
+ class_ = sCTkFrequencyDisplay
23
+
24
+ OPTIONS_CUSTOM = (
25
+ "digits", "signed", "value", "delimiter", "font_size",
26
+ "selectable", "min_digit", "state",
27
+ )
28
+ properties = CTkFrameBO.properties + OPTIONS_CUSTOM
29
+ command_properties = ("command",)
30
+
31
+ OPTIONS_CUSTOM_DEFAULTS = {
32
+ "digits": "10",
33
+ "signed": "False",
34
+ "value": "0",
35
+ "delimiter": ".",
36
+ "font_size": "34",
37
+ "selectable": "True",
38
+ "min_digit": "1",
39
+ "state": "normal",
40
+ }
41
+
42
+ container = False
43
+
44
+ def realize(self, parent, extra_init_args: dict = None):
45
+ """
46
+ Builds the readout with its properties as constructor arguments.
47
+
48
+ digits and signed change the LAYOUT, so they have to arrive as real
49
+ values rather than being set afterwards -- a readout that builds at
50
+ ten digits and shrinks to four flickers through the wrong size on
51
+ every Designer repaint.
52
+ """
53
+ if extra_init_args is None:
54
+ extra_init_args = {}
55
+
56
+ props = self.wmeta.properties
57
+ init_args = {
58
+ "digits": int(props.get("digits", 10) or 10),
59
+ "signed": self._as_bool(props.get("signed", "False")),
60
+ "value": int(props.get("value", 0) or 0),
61
+ "delimiter": props.get("delimiter", "."),
62
+ "font_size": int(props.get("font_size", 34) or 34),
63
+ "selectable": self._as_bool(props.get("selectable", "True")),
64
+ "min_digit": int(props.get("min_digit", 1) or 0),
65
+ "state": props.get("state", "normal"),
66
+ }
67
+
68
+ for prop in self.OPTIONS_CUSTOM:
69
+ extra_init_args.pop(prop, None)
70
+ init_args.update(extra_init_args)
71
+
72
+ real_master = parent.widget if hasattr(parent, "widget") else parent
73
+ self.widget = self.class_(real_master, **init_args)
74
+ return self.widget
75
+
76
+ @staticmethod
77
+ def _as_bool(value):
78
+ """bool("False") is True, and the Designer sends strings."""
79
+ if isinstance(value, str):
80
+ return value.strip().lower() in ("true", "1", "yes", "on")
81
+ return bool(value)
82
+
83
+ def _process_property_value(self, pname, value):
84
+ if pname in ("digits", "value", "font_size", "min_digit"):
85
+ return int(value)
86
+ if pname in ("signed", "selectable"):
87
+ return self._as_bool(value)
88
+ return super()._process_property_value(pname, value)
89
+
90
+ def _code_set_property(self, targetid, pname, value, code_bag):
91
+ """Numbers and booleans emit as tokens; the rest keep their quotes."""
92
+ if pname in ("digits", "value", "font_size", "min_digit",
93
+ "signed", "selectable"):
94
+ code_bag[pname] = str(value).strip("'\"")
95
+ elif pname in ("delimiter", "state"):
96
+ code_bag[pname] = f"'{str(value).strip(chr(39) + chr(34))}'"
97
+ else:
98
+ super()._code_set_property(targetid, pname, value, code_bag)
99
+
100
+ def _code_define_callback_args(self, cmd_pname, cmd):
101
+ """
102
+ Declares that `command` receives the step, so the generated stub has
103
+ a matching parameter.
104
+
105
+ Without this a user writing a handler has no indication that the
106
+ selected digit's place value is being handed to them -- which is the
107
+ entire point of the callback.
108
+ """
109
+ return ("step",)
110
+
111
+ def code_imports(self):
112
+ imports = [(widget_namespace, widget_classname)]
113
+ imports.extend(self.code_extra_imports())
114
+ return imports
115
+
116
+
117
+ builder_id = f"{builder_namespace}.{widget_classname}"
118
+ register_widget(builder_id, sCTkFrequencyDisplayBO, widget_classname,
119
+ ("ttk", section_name))
120
+
121
+
122
+ # ---------------------------------------------------------------------------
123
+ # Inspector properties
124
+ # ---------------------------------------------------------------------------
125
+ register_custom_property(
126
+ builder_id, "digits", "naturalnumber", default_value="10",
127
+ help="How many digit positions. Ten reaches into the GHz as "
128
+ "x.xxx.xxx.xxx; four suits a signed offset. Leading groups are "
129
+ "hidden until they hold something, and the layout does not move "
130
+ "when one appears.")
131
+
132
+ register_custom_property(
133
+ builder_id, "signed", "choice", values=("True", "False"),
134
+ state="readonly", default_value="False",
135
+ help="Shows a leading + or -, for an offset rather than a frequency. "
136
+ "The sign is always drawn, even when the leading digits are not.")
137
+
138
+ register_custom_property(
139
+ builder_id, "value", "entry", default_value="0",
140
+ help="The value shown, as an integer -- Hz for a frequency.")
141
+
142
+ register_custom_property(
143
+ builder_id, "delimiter", "entry", default_value=".",
144
+ help="What separates the groups of three. Changeable at any time, "
145
+ "because it is a display preference the whole interface shares.")
146
+
147
+ register_custom_property(
148
+ builder_id, "font_size", "naturalnumber", default_value="34",
149
+ help="Point size of the digits. The FAMILY comes from the theme and "
150
+ "should stay fixed-width -- a proportional font makes 1 and 8 "
151
+ "different widths, so the digits shift as the numbers change.")
152
+
153
+ register_custom_property(
154
+ builder_id, "selectable", "choice", values=("True", "False"),
155
+ state="readonly", default_value="True",
156
+ help="Whether clicking a digit selects it. The selection IS the tuning "
157
+ "step, so a readout that is only a readout should set this False.")
158
+
159
+ register_custom_property(
160
+ builder_id, "min_digit", "naturalnumber", default_value="1",
161
+ help="The smallest selectable digit, as a power of ten. 1 means the "
162
+ "units digit is shown but cannot be tuned -- right for a rig that "
163
+ "steps in whole 10 Hz.")
164
+
165
+ register_custom_property(
166
+ builder_id, "state", "choice", values=("normal", "disabled"),
167
+ state="readonly", default_value="normal",
168
+ help="Disabled dims the digits and stops selection. The value keeps "
169
+ "updating: a display that froze while greyed would look like one "
170
+ "showing a current reading.")
171
+
172
+ register_custom_property(
173
+ builder_id, "command", "commandentry",
174
+ help="Called with the new step, in units, when the selected digit "
175
+ "changes. 100 means the hundreds digit -- 100 Hz per detent.")
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkLabelPrimary
4
+
5
+ The primary label used for headers etc.
6
+
7
+ UI source file: sCTkLabelPrimary.ui
8
+ """
9
+ import tkinter as tk
10
+ import tkinter.ttk as ttk
11
+ from customtkinter import CTkLabel
12
+ from pygubu.api.v1 import (
13
+ BuilderObject,
14
+ register_widget,
15
+ )
16
+
17
+ from scustomtkinter.sctk_label_primary import sCTkLabelPrimary
18
+ from pygubu.plugins.customtkinter.widgets import CTkLabelBO
19
+
20
+
21
+ #
22
+ # Builder definition section
23
+ #
24
+ widget_namespace = "scustomtkinter.sctk_label_primary"
25
+ widget_classname = "sCTkLabelPrimary"
26
+ builder_namespace = "scustomtkinter"
27
+ section_name = "sCustomTkinter"
28
+
29
+
30
+ class sCTkLabelPrimaryBO(CTkLabelBO):
31
+ class_ = sCTkLabelPrimary
32
+
33
+ def code_imports(self):
34
+ # should return an iterable of (module, classname/function) to import
35
+ # or None
36
+ imports = [(widget_namespace, widget_classname)]
37
+ imports.extend(self.code_extra_imports())
38
+ return imports
39
+
40
+
41
+ builder_id = f"{builder_namespace}.{widget_classname}"
42
+ register_widget(
43
+ builder_id, sCTkLabelPrimaryBO, widget_classname, ("ttk", section_name)
44
+ )
45
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkLabelSecondary
4
+
5
+ The secondary label used for general use.
6
+
7
+ UI source file: sCTkLabelSecondary.ui
8
+ """
9
+ import tkinter as tk
10
+ import tkinter.ttk as ttk
11
+ from customtkinter import CTkLabel
12
+ from pygubu.api.v1 import (
13
+ BuilderObject,
14
+ register_widget,
15
+ )
16
+
17
+ from pygubu.plugins.customtkinter.widgets import CTkLabelBO
18
+ from scustomtkinter.sctk_label_secondary import sCTkLabelSecondary
19
+
20
+
21
+ #
22
+ # Builder definition section
23
+ #
24
+ widget_namespace = "scustomtkinter.sctk_label_secondary"
25
+ widget_classname = "sCTkLabelSecondary"
26
+ builder_namespace = "scustomtkinter"
27
+ section_name = "sCustomTkinter"
28
+
29
+
30
+ class sCTkLabelSecondaryBO(CTkLabelBO):
31
+ class_ = sCTkLabelSecondary
32
+
33
+ def code_imports(self):
34
+ # should return an iterable of (module, classname/function) to import
35
+ # or None
36
+ imports = [(widget_namespace, widget_classname)]
37
+ imports.extend(self.code_extra_imports())
38
+ return imports
39
+
40
+
41
+ builder_id = f"{builder_namespace}.{widget_classname}"
42
+ register_widget(
43
+ builder_id, sCTkLabelSecondaryBO, widget_classname, ("ttk", section_name)
44
+ )
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/python3
2
+ """
3
+ sCTkLabelTertiary
4
+
5
+ 3rd level Label used for notes
6
+
7
+ UI source file: sCTkLabelTertiary.ui
8
+ """
9
+ import tkinter as tk
10
+ import tkinter.ttk as ttk
11
+ from customtkinter import CTkLabel
12
+ from pygubu.api.v1 import (
13
+ BuilderObject,
14
+ register_widget,
15
+ )
16
+
17
+ from pygubu.plugins.customtkinter.widgets import CTkLabelBO
18
+ from scustomtkinter.sctk_label_tertiary import sCTkLabelTertiary
19
+
20
+
21
+ #
22
+ # Builder definition section
23
+ #
24
+ widget_namespace = "scustomtkinter.sctk_label_tertiary"
25
+ widget_classname = "sCTkLabelTertiary"
26
+ builder_namespace = "scustomtkinter"
27
+ section_name = "sCustomTkinter"
28
+
29
+
30
+ class sCTkLabelTertiaryBO(CTkLabelBO):
31
+ class_ = sCTkLabelTertiary
32
+
33
+ def code_imports(self):
34
+ # should return an iterable of (module, classname/function) to import
35
+ # or None
36
+ imports = [(widget_namespace, widget_classname)]
37
+ imports.extend(self.code_extra_imports())
38
+ return imports
39
+
40
+
41
+ builder_id = f"{builder_namespace}.{widget_classname}"
42
+ register_widget(
43
+ builder_id, sCTkLabelTertiaryBO, widget_classname, ("ttk", section_name)
44
+ )
45
+