bootstack 0.1.0a1__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.
- bootstack/__init__.py +249 -0
- bootstack/__main__.py +5 -0
- bootstack/api/__init__.py +127 -0
- bootstack/api/app.py +30 -0
- bootstack/api/constants.py +3 -0
- bootstack/api/data.py +23 -0
- bootstack/api/dialogs.py +44 -0
- bootstack/api/i18n.py +17 -0
- bootstack/api/localization.py +16 -0
- bootstack/api/menu.py +7 -0
- bootstack/api/style.py +23 -0
- bootstack/api/utils.py +24 -0
- bootstack/api/widgets.py +137 -0
- bootstack/assets/__init__.py +24 -0
- bootstack/assets/bootstack-transparent.png +0 -0
- bootstack/assets/bootstack.ico +0 -0
- bootstack/assets/bootstack.png +0 -0
- bootstack/assets/elements/__init__.py +0 -0
- bootstack/assets/elements/badge-pill.png +0 -0
- bootstack/assets/elements/badge-square.png +0 -0
- bootstack/assets/elements/border.png +0 -0
- bootstack/assets/elements/button-compact.png +0 -0
- bootstack/assets/elements/button-default.png +0 -0
- bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
- bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
- bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
- bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
- bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
- bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
- bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
- bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
- bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
- bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
- bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
- bootstack/assets/elements/button-group-vertical-center-default.png +0 -0
- bootstack/assets/elements/checkbox-checked.png +0 -0
- bootstack/assets/elements/checkbox-indeterminate.png +0 -0
- bootstack/assets/elements/checkbox-unchecked.png +0 -0
- bootstack/assets/elements/field.png +0 -0
- bootstack/assets/elements/input-after-compact.png +0 -0
- bootstack/assets/elements/input-after-default.png +0 -0
- bootstack/assets/elements/input-before-compact.png +0 -0
- bootstack/assets/elements/input-before-default.png +0 -0
- bootstack/assets/elements/input-compact.png +0 -0
- bootstack/assets/elements/input-default.png +0 -0
- bootstack/assets/elements/list-item-separated.png +0 -0
- bootstack/assets/elements/list-item.png +0 -0
- bootstack/assets/elements/manifest.toml +480 -0
- bootstack/assets/elements/menu-item.png +0 -0
- bootstack/assets/elements/nav-button-compact.png +0 -0
- bootstack/assets/elements/nav-button-default.png +0 -0
- bootstack/assets/elements/nav-icon-button-compact.png +0 -0
- bootstack/assets/elements/nav-icon-button-default.png +0 -0
- bootstack/assets/elements/notebook-client-border.png +0 -0
- bootstack/assets/elements/notebook-tab-active.png +0 -0
- bootstack/assets/elements/notebook-tab-bar.png +0 -0
- bootstack/assets/elements/notebook-tab-normal.png +0 -0
- bootstack/assets/elements/notebook-tab-pill.png +0 -0
- bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
- bootstack/assets/elements/progress-bar-solid.png +0 -0
- bootstack/assets/elements/progress-bar-thin.png +0 -0
- bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
- bootstack/assets/elements/radio-selected.png +0 -0
- bootstack/assets/elements/radio-unselected.png +0 -0
- bootstack/assets/elements/scrollbar-horizontal.png +0 -0
- bootstack/assets/elements/scrollbar-vertical.png +0 -0
- bootstack/assets/elements/slider-handle-focus.png +0 -0
- bootstack/assets/elements/slider-handle.png +0 -0
- bootstack/assets/elements/slider-track-horizontal.png +0 -0
- bootstack/assets/elements/slider-track-vertical.png +0 -0
- bootstack/assets/elements/switch-off.png +0 -0
- bootstack/assets/elements/switch-on.png +0 -0
- bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
- bootstack/assets/elements/tabs-bar-vertical.png +0 -0
- bootstack/assets/elements/tabs-pill.png +0 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/themes/__init__.py +0 -0
- bootstack/assets/themes/amber-dark.json +32 -0
- bootstack/assets/themes/amber-light.json +32 -0
- bootstack/assets/themes/aurora-dark.json +32 -0
- bootstack/assets/themes/aurora-light.json +32 -0
- bootstack/assets/themes/bootstrap-dark.json +32 -0
- bootstack/assets/themes/bootstrap-light.json +32 -0
- bootstack/assets/themes/classic-dark.json +32 -0
- bootstack/assets/themes/classic-light.json +32 -0
- bootstack/assets/themes/docs-dark.json +32 -0
- bootstack/assets/themes/docs-light.json +32 -0
- bootstack/assets/themes/forest-dark.json +32 -0
- bootstack/assets/themes/forest-light.json +32 -0
- bootstack/assets/themes/ocean-dark.json +32 -0
- bootstack/assets/themes/ocean-light.json +32 -0
- bootstack/assets/themes/rose-dark.json +32 -0
- bootstack/assets/themes/rose-light.json +32 -0
- bootstack/assets/widgets/__init__.py +0 -0
- bootstack/assets/widgets/badge-default.png +0 -0
- bootstack/assets/widgets/badge-pill.png +0 -0
- bootstack/assets/widgets/border.png +0 -0
- bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
- bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
- bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
- bootstack/assets/widgets/button-group-vertical-after.png +0 -0
- bootstack/assets/widgets/button-group-vertical-before.png +0 -0
- bootstack/assets/widgets/button-group-vertical-center.png +0 -0
- bootstack/assets/widgets/button.png +0 -0
- bootstack/assets/widgets/checkbox-checked.png +0 -0
- bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
- bootstack/assets/widgets/checkbox-unchecked.png +0 -0
- bootstack/assets/widgets/field.png +0 -0
- bootstack/assets/widgets/icon-button.png +0 -0
- bootstack/assets/widgets/input-inner.png +0 -0
- bootstack/assets/widgets/input-prefix.png +0 -0
- bootstack/assets/widgets/input-suffix.png +0 -0
- bootstack/assets/widgets/input.png +0 -0
- bootstack/assets/widgets/list-item-focus.png +0 -0
- bootstack/assets/widgets/list-item-separated.png +0 -0
- bootstack/assets/widgets/menu-item-separated.png +0 -0
- bootstack/assets/widgets/notebook-client-border.png +0 -0
- bootstack/assets/widgets/notebook-pill-active.png +0 -0
- bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
- bootstack/assets/widgets/notebook-tab-active.png +0 -0
- bootstack/assets/widgets/notebook-tab-border.png +0 -0
- bootstack/assets/widgets/notebook-tab-normal.png +0 -0
- bootstack/assets/widgets/notebook-underline.png +0 -0
- bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
- bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
- bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
- bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
- bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
- bootstack/assets/widgets/progress-trough-vertical.png +0 -0
- bootstack/assets/widgets/radio-selected.png +0 -0
- bootstack/assets/widgets/radio-unselected.png +0 -0
- bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
- bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
- bootstack/assets/widgets/separator-horizontal.png +0 -0
- bootstack/assets/widgets/separator-vertical.png +0 -0
- bootstack/assets/widgets/slider-handle-focus.png +0 -0
- bootstack/assets/widgets/slider-handle.png +0 -0
- bootstack/assets/widgets/slider-track-horizontal.png +0 -0
- bootstack/assets/widgets/slider-track-vertical.png +0 -0
- bootstack/assets/widgets/switch-off.png +0 -0
- bootstack/assets/widgets/switch-on.png +0 -0
- bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
- bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
- bootstack/assets/widgets/tabs-pill.png +0 -0
- bootstack/cli/__init__.py +124 -0
- bootstack/cli/__main__.py +6 -0
- bootstack/cli/add.py +439 -0
- bootstack/cli/build.py +115 -0
- bootstack/cli/config.py +287 -0
- bootstack/cli/demo.py +1267 -0
- bootstack/cli/doctor.py +195 -0
- bootstack/cli/list_cmd.py +71 -0
- bootstack/cli/promote.py +120 -0
- bootstack/cli/pyinstaller.py +246 -0
- bootstack/cli/run.py +99 -0
- bootstack/cli/start.py +105 -0
- bootstack/cli/templates/__init__.py +861 -0
- bootstack/constants.py +325 -0
- bootstack/core/__init__.py +34 -0
- bootstack/core/capabilities/__init__.py +45 -0
- bootstack/core/capabilities/after.py +103 -0
- bootstack/core/capabilities/bind.py +154 -0
- bootstack/core/capabilities/bindtags.py +112 -0
- bootstack/core/capabilities/busy.py +61 -0
- bootstack/core/capabilities/clipboard.py +88 -0
- bootstack/core/capabilities/focus.py +118 -0
- bootstack/core/capabilities/grab.py +65 -0
- bootstack/core/capabilities/grid.py +188 -0
- bootstack/core/capabilities/localization.py +231 -0
- bootstack/core/capabilities/pack.py +119 -0
- bootstack/core/capabilities/place.py +92 -0
- bootstack/core/capabilities/selection.py +136 -0
- bootstack/core/capabilities/signals.py +242 -0
- bootstack/core/capabilities/winfo.py +315 -0
- bootstack/core/colorutils.py +234 -0
- bootstack/core/exceptions.py +95 -0
- bootstack/core/images.py +283 -0
- bootstack/core/localization/README.md +90 -0
- bootstack/core/localization/__init__.py +13 -0
- bootstack/core/localization/intl_format.py +580 -0
- bootstack/core/localization/msgcat.py +425 -0
- bootstack/core/localization/specs.py +143 -0
- bootstack/core/mixins/__init__.py +1 -0
- bootstack/core/mixins/ttk_state.py +35 -0
- bootstack/core/mixins/widget.py +132 -0
- bootstack/core/publisher.py +147 -0
- bootstack/core/signals/README.md +112 -0
- bootstack/core/signals/__init__.py +8 -0
- bootstack/core/signals/integration.py +100 -0
- bootstack/core/signals/signal.py +317 -0
- bootstack/core/signals/types.py +4 -0
- bootstack/core/validation/__init__.py +5 -0
- bootstack/core/validation/types.py +13 -0
- bootstack/core/validation/validation_result.py +17 -0
- bootstack/core/validation/validation_rules.py +112 -0
- bootstack/core/variables.py +62 -0
- bootstack/datasource/README.md +607 -0
- bootstack/datasource/__init__.py +51 -0
- bootstack/datasource/base.py +474 -0
- bootstack/datasource/file_source.py +541 -0
- bootstack/datasource/memory_source.py +482 -0
- bootstack/datasource/sqlite_source.py +453 -0
- bootstack/datasource/types.py +259 -0
- bootstack/dialogs/__init__.py +56 -0
- bootstack/dialogs/colorchooser.py +674 -0
- bootstack/dialogs/colordropper.py +257 -0
- bootstack/dialogs/datedialog.py +404 -0
- bootstack/dialogs/dialog.py +514 -0
- bootstack/dialogs/filterdialog.py +358 -0
- bootstack/dialogs/fontdialog.py +339 -0
- bootstack/dialogs/formdialog.py +541 -0
- bootstack/dialogs/message.py +489 -0
- bootstack/dialogs/query.py +561 -0
- bootstack/py.typed +1 -0
- bootstack/runtime/__init__.py +3 -0
- bootstack/runtime/app.py +879 -0
- bootstack/runtime/base_window.py +786 -0
- bootstack/runtime/events.py +399 -0
- bootstack/runtime/menu.py +510 -0
- bootstack/runtime/shortcuts.py +423 -0
- bootstack/runtime/tk_patch.py +31 -0
- bootstack/runtime/toplevel.py +131 -0
- bootstack/runtime/utility.py +371 -0
- bootstack/runtime/visual_focus.py +228 -0
- bootstack/runtime/window_utilities.py +1043 -0
- bootstack/style/__init__.py +5498 -0
- bootstack/style/bootstyle.py +507 -0
- bootstack/style/bootstyle_builder_base.py +752 -0
- bootstack/style/bootstyle_builder_mixed.py +93 -0
- bootstack/style/bootstyle_builder_tk.py +109 -0
- bootstack/style/bootstyle_builder_ttk.py +354 -0
- bootstack/style/builders/__init__.py +51 -0
- bootstack/style/builders/badge.py +44 -0
- bootstack/style/builders/button.py +453 -0
- bootstack/style/builders/buttongroup.py +344 -0
- bootstack/style/builders/calendar.py +271 -0
- bootstack/style/builders/checkbutton.py +95 -0
- bootstack/style/builders/combobox.py +112 -0
- bootstack/style/builders/contextmenu.py +268 -0
- bootstack/style/builders/entry.py +83 -0
- bootstack/style/builders/expander.py +171 -0
- bootstack/style/builders/field.py +312 -0
- bootstack/style/builders/frame.py +27 -0
- bootstack/style/builders/label.py +28 -0
- bootstack/style/builders/labelframe.py +41 -0
- bootstack/style/builders/listview.py +267 -0
- bootstack/style/builders/menubar.py +74 -0
- bootstack/style/builders/menubutton.py +408 -0
- bootstack/style/builders/notebook.py +316 -0
- bootstack/style/builders/panedwindow.py +25 -0
- bootstack/style/builders/progressbar.py +71 -0
- bootstack/style/builders/radiobutton.py +68 -0
- bootstack/style/builders/scale.py +66 -0
- bootstack/style/builders/scrollbar.py +360 -0
- bootstack/style/builders/separator.py +45 -0
- bootstack/style/builders/sidenav.py +313 -0
- bootstack/style/builders/sizegrip.py +15 -0
- bootstack/style/builders/spinbox.py +119 -0
- bootstack/style/builders/switch.py +67 -0
- bootstack/style/builders/tabitem.py +205 -0
- bootstack/style/builders/toolbutton.py +260 -0
- bootstack/style/builders/tooltip.py +26 -0
- bootstack/style/builders/treeview.py +269 -0
- bootstack/style/builders/utils.py +404 -0
- bootstack/style/builders_tk/__init__.py +16 -0
- bootstack/style/builders_tk/defaults.py +229 -0
- bootstack/style/element.py +173 -0
- bootstack/style/style.py +499 -0
- bootstack/style/theme_provider.py +449 -0
- bootstack/style/tk_patch.py +5 -0
- bootstack/style/token_maps.py +42 -0
- bootstack/style/types.py +32 -0
- bootstack/style/typography.py +527 -0
- bootstack/style/utility.py +696 -0
- bootstack/themes/__init__.py +12 -0
- bootstack/themes/standard.py +415 -0
- bootstack/themes/user.py +45 -0
- bootstack/widgets/__init__.py +53 -0
- bootstack/widgets/composites/__init__.py +38 -0
- bootstack/widgets/composites/accordion.py +385 -0
- bootstack/widgets/composites/appshell.py +445 -0
- bootstack/widgets/composites/buttongroup.py +391 -0
- bootstack/widgets/composites/calendar.py +914 -0
- bootstack/widgets/composites/compositeframe.py +282 -0
- bootstack/widgets/composites/contextmenu.py +1754 -0
- bootstack/widgets/composites/dateentry.py +261 -0
- bootstack/widgets/composites/dropdownbutton.py +190 -0
- bootstack/widgets/composites/expander.py +508 -0
- bootstack/widgets/composites/field.py +448 -0
- bootstack/widgets/composites/floodgauge.py +434 -0
- bootstack/widgets/composites/form.py +983 -0
- bootstack/widgets/composites/labeledscale.py +209 -0
- bootstack/widgets/composites/list/__init__.py +15 -0
- bootstack/widgets/composites/list/listitem.py +733 -0
- bootstack/widgets/composites/list/listview.py +1507 -0
- bootstack/widgets/composites/menubar.py +303 -0
- bootstack/widgets/composites/meter.py +882 -0
- bootstack/widgets/composites/numericentry.py +183 -0
- bootstack/widgets/composites/pagestack.py +330 -0
- bootstack/widgets/composites/passwordentry.py +149 -0
- bootstack/widgets/composites/pathentry.py +223 -0
- bootstack/widgets/composites/radiogroup.py +466 -0
- bootstack/widgets/composites/scrolledtext.py +388 -0
- bootstack/widgets/composites/scrolledtext.pyi +186 -0
- bootstack/widgets/composites/scrollview.py +675 -0
- bootstack/widgets/composites/selectbox.py +544 -0
- bootstack/widgets/composites/sidenav/__init__.py +24 -0
- bootstack/widgets/composites/sidenav/group.py +485 -0
- bootstack/widgets/composites/sidenav/header.py +83 -0
- bootstack/widgets/composites/sidenav/item.py +413 -0
- bootstack/widgets/composites/sidenav/separator.py +51 -0
- bootstack/widgets/composites/sidenav/view.py +919 -0
- bootstack/widgets/composites/spinnerentry.py +232 -0
- bootstack/widgets/composites/tableview/__init__.py +5 -0
- bootstack/widgets/composites/tableview/tableview.py +2254 -0
- bootstack/widgets/composites/tableview/types.py +169 -0
- bootstack/widgets/composites/tabs/__init__.py +6 -0
- bootstack/widgets/composites/tabs/tabitem.py +372 -0
- bootstack/widgets/composites/tabs/tabs.py +478 -0
- bootstack/widgets/composites/tabs/tabview.py +352 -0
- bootstack/widgets/composites/textentry.py +90 -0
- bootstack/widgets/composites/timeentry.py +189 -0
- bootstack/widgets/composites/toast.py +364 -0
- bootstack/widgets/composites/togglegroup.py +382 -0
- bootstack/widgets/composites/toolbar.py +393 -0
- bootstack/widgets/composites/tooltip.py +404 -0
- bootstack/widgets/internal/__init__.py +0 -0
- bootstack/widgets/internal/wrapper_base.py +304 -0
- bootstack/widgets/mixins/__init__.py +25 -0
- bootstack/widgets/mixins/configure_mixin.py +186 -0
- bootstack/widgets/mixins/entry_mixin.py +70 -0
- bootstack/widgets/mixins/font_mixin.py +346 -0
- bootstack/widgets/mixins/icon_mixin.py +38 -0
- bootstack/widgets/mixins/localization_mixin.py +255 -0
- bootstack/widgets/mixins/signal_mixin.py +272 -0
- bootstack/widgets/mixins/validation_mixin.py +204 -0
- bootstack/widgets/parts/__init__.py +11 -0
- bootstack/widgets/parts/numberentry_part.py +345 -0
- bootstack/widgets/parts/spinnerentry_part.py +394 -0
- bootstack/widgets/parts/textentry_part.py +344 -0
- bootstack/widgets/primitives/__init__.py +55 -0
- bootstack/widgets/primitives/badge.py +44 -0
- bootstack/widgets/primitives/button.py +89 -0
- bootstack/widgets/primitives/card.py +66 -0
- bootstack/widgets/primitives/checkbutton.py +124 -0
- bootstack/widgets/primitives/checktoggle.py +53 -0
- bootstack/widgets/primitives/combobox.py +165 -0
- bootstack/widgets/primitives/entry.py +98 -0
- bootstack/widgets/primitives/frame.py +206 -0
- bootstack/widgets/primitives/gridframe.py +479 -0
- bootstack/widgets/primitives/label.py +95 -0
- bootstack/widgets/primitives/labelframe.py +63 -0
- bootstack/widgets/primitives/menubutton.py +118 -0
- bootstack/widgets/primitives/notebook.py +551 -0
- bootstack/widgets/primitives/optionmenu.py +248 -0
- bootstack/widgets/primitives/packframe.py +228 -0
- bootstack/widgets/primitives/panedwindow.py +58 -0
- bootstack/widgets/primitives/progressbar.py +95 -0
- bootstack/widgets/primitives/radiobutton.py +115 -0
- bootstack/widgets/primitives/radiotoggle.py +50 -0
- bootstack/widgets/primitives/scale.py +85 -0
- bootstack/widgets/primitives/scrollbar.py +56 -0
- bootstack/widgets/primitives/separator.py +56 -0
- bootstack/widgets/primitives/sizegrip.py +47 -0
- bootstack/widgets/primitives/spinbox.py +91 -0
- bootstack/widgets/primitives/switch.py +41 -0
- bootstack/widgets/primitives/treeview.py +77 -0
- bootstack/widgets/types.py +20 -0
- bootstack-0.1.0a1.dist-info/METADATA +196 -0
- bootstack-0.1.0a1.dist-info/RECORD +419 -0
- bootstack-0.1.0a1.dist-info/WHEEL +5 -0
- bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
- bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
- bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
- bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Builder utilities for TTK widgets with embedded Tk components.
|
|
2
|
+
|
|
3
|
+
This module handles styling for TTK widgets that contain legacy Tk components
|
|
4
|
+
that aren't styled by the TTK theme engine, such as:
|
|
5
|
+
- ttk.Combobox (contains Tk listbox and scrollbar in popdown)
|
|
6
|
+
- Other hybrid widgets as needed
|
|
7
|
+
|
|
8
|
+
These widgets require manual Tcl/Tk calls to style their embedded components.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any, Optional
|
|
14
|
+
|
|
15
|
+
from bootstack.style.bootstyle_builder_base import BootstyleBuilderBase
|
|
16
|
+
from bootstack.style.theme_provider import ThemeProvider
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BootstyleBuilderMixed(BootstyleBuilderBase):
|
|
20
|
+
"""Builder for TTK widgets containing legacy Tk components.
|
|
21
|
+
|
|
22
|
+
This class provides methods to style embedded Tk components within
|
|
23
|
+
TTK widgets that aren't handled by the standard TTK theme engine.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
theme_provider: Optional[ThemeProvider] = None,
|
|
29
|
+
style_instance: Optional[Any] = None
|
|
30
|
+
):
|
|
31
|
+
"""Initialize the mixed builder.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
theme_provider: Optional ThemeProvider instance
|
|
35
|
+
style_instance: Optional Style instance
|
|
36
|
+
"""
|
|
37
|
+
super().__init__(theme_provider, style_instance)
|
|
38
|
+
|
|
39
|
+
def update_combobox_popdown_style(self, widget: Any) -> None:
|
|
40
|
+
"""Update styling for legacy Tk components in ttk.Combobox.
|
|
41
|
+
|
|
42
|
+
The ttk.Combobox contains embedded Tk components (popdown listbox
|
|
43
|
+
and scrollbar) that aren't styled by the TTK theme engine and must
|
|
44
|
+
be configured manually via Tcl/Tk calls.
|
|
45
|
+
|
|
46
|
+
This method configures:
|
|
47
|
+
- The popdown listbox window (colors, borders, selection)
|
|
48
|
+
- The scrollbar within the popdown
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
widget: ttk.Combobox widget to update
|
|
52
|
+
"""
|
|
53
|
+
# Match the entry field: surface = 'content', selection = primary
|
|
54
|
+
surface = self.color('content')
|
|
55
|
+
on_surface = self.on_color(surface)
|
|
56
|
+
select = self.color('primary')
|
|
57
|
+
on_select = self.on_color(select)
|
|
58
|
+
|
|
59
|
+
# Listbox has no border of its own — the popdown frame already draws
|
|
60
|
+
# the outer border, and stacking a listbox highlight on top creates a
|
|
61
|
+
# visible double-border effect.
|
|
62
|
+
tk_settings = [
|
|
63
|
+
"-borderwidth", 0,
|
|
64
|
+
"-highlightthickness", 0,
|
|
65
|
+
"-background", surface,
|
|
66
|
+
"-foreground", on_surface,
|
|
67
|
+
"-selectbackground", select,
|
|
68
|
+
"-selectforeground", on_select,
|
|
69
|
+
"-activestyle", "none",
|
|
70
|
+
"-relief", "flat",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
# Skip if the popdown hasn't been created yet (lazy construction).
|
|
75
|
+
# The postcommand handler will style it on first open.
|
|
76
|
+
popdown_path = f"{widget}.popdown"
|
|
77
|
+
if not int(widget.tk.eval(f"winfo exists {popdown_path}")):
|
|
78
|
+
return
|
|
79
|
+
widget.tk.call(f"{popdown_path}.f.l", "configure", *tk_settings)
|
|
80
|
+
|
|
81
|
+
# Build a themed scrollbar style and apply it to the popdown
|
|
82
|
+
# scrollbar. Bootstyle.create_ttk_style returns a hashed style
|
|
83
|
+
# name (e.g. bs[xxx].Default.Vertical.TScrollbar) that is rebuilt
|
|
84
|
+
# automatically on theme change.
|
|
85
|
+
from bootstack.style.bootstyle import Bootstyle
|
|
86
|
+
sb_style = Bootstyle.create_ttk_style(
|
|
87
|
+
'TScrollbar', variant='default',
|
|
88
|
+
style_options={'orient': 'vertical', 'show_arrows': False},
|
|
89
|
+
)
|
|
90
|
+
widget.tk.call(f"{popdown_path}.f.sb", "configure", "-style", sb_style)
|
|
91
|
+
except Exception:
|
|
92
|
+
# Silently fail if widget isn't fully initialized or mapped yet
|
|
93
|
+
pass
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
from typing import Callable, Dict, Optional
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
7
|
+
from typing_extensions import Any, Protocol
|
|
8
|
+
|
|
9
|
+
from bootstack.style.bootstyle_builder_base import BootstyleBuilderBase, IconSpec
|
|
10
|
+
from bootstack.style.theme_provider import ThemeProvider
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TkBuilderCallable(Protocol):
|
|
14
|
+
def __call__(self, builder: "BootstyleBuilderBuilderTk", widget: Any, **options: Any) -> None: # noqa: ANN401
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BootstyleBuilderBuilderTk(BootstyleBuilderBase):
|
|
19
|
+
"""Builder registry for legacy Tk widgets.
|
|
20
|
+
|
|
21
|
+
Mirrors the TTK BootstyleBuilder API, but targets Tk widgets and passes
|
|
22
|
+
the actual widget instance to builder functions.
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
>>> @BootstyleBuilderBuilderTk.register_builder('Button')
|
|
26
|
+
... def build_tk_button(builder, widget, **opts):
|
|
27
|
+
... bg = builder.color(opts.get('surface', 'content'))
|
|
28
|
+
... widget.configure(background=bg, foreground=builder.colors.get('foreground'))
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
_registry: Dict[str, TkBuilderCallable] = {}
|
|
32
|
+
_lock = threading.Lock()
|
|
33
|
+
_builders_loaded = False
|
|
34
|
+
|
|
35
|
+
def __init__(self, theme_provider: Optional[ThemeProvider] = None, style_instance: Optional[Any] = None):
|
|
36
|
+
super().__init__(theme_provider, style_instance)
|
|
37
|
+
|
|
38
|
+
# Color utilities and provider/colors properties are inherited from BootstyleBase
|
|
39
|
+
|
|
40
|
+
# ----- Registry API -----
|
|
41
|
+
@classmethod
|
|
42
|
+
def register_builder(cls, widget_name: str):
|
|
43
|
+
"""Register a Tk widget builder by Tk class name (e.g., 'Button')."""
|
|
44
|
+
|
|
45
|
+
if not isinstance(widget_name, str) or not widget_name:
|
|
46
|
+
raise ValueError("`widget_name` must be a non-empty string")
|
|
47
|
+
|
|
48
|
+
def deco(func: TkBuilderCallable) -> TkBuilderCallable:
|
|
49
|
+
with cls._lock:
|
|
50
|
+
cls._registry[widget_name] = func
|
|
51
|
+
return func
|
|
52
|
+
|
|
53
|
+
return deco
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def has_builder(cls, widget_name: str) -> bool:
|
|
57
|
+
cls._ensure_builders_loaded()
|
|
58
|
+
with cls._lock:
|
|
59
|
+
return widget_name in cls._registry
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def get_registered_widgets(cls) -> list[str]:
|
|
63
|
+
cls._ensure_builders_loaded()
|
|
64
|
+
with cls._lock:
|
|
65
|
+
return list(cls._registry.keys())
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def _ensure_builders_loaded(cls) -> None:
|
|
69
|
+
# Fast path
|
|
70
|
+
if cls._builders_loaded:
|
|
71
|
+
return
|
|
72
|
+
try:
|
|
73
|
+
import bootstack.style.builders_tk # noqa: F401
|
|
74
|
+
except Exception:
|
|
75
|
+
# If not present, that's fine; avoid repeated import attempts
|
|
76
|
+
pass
|
|
77
|
+
finally:
|
|
78
|
+
cls._builders_loaded = True
|
|
79
|
+
|
|
80
|
+
def call_builder(self, widget: Any, **options: Any) -> None: # noqa: ANN401
|
|
81
|
+
"""Call a registered builder for this Tk widget instance."""
|
|
82
|
+
# Prefer Tk's class name; fallback to Python class name
|
|
83
|
+
try:
|
|
84
|
+
widget_name = widget.winfo_class()
|
|
85
|
+
except Exception:
|
|
86
|
+
widget_name = widget.__class__.__name__
|
|
87
|
+
|
|
88
|
+
# Ensure builder modules are imported
|
|
89
|
+
self._ensure_builders_loaded()
|
|
90
|
+
|
|
91
|
+
with self._lock:
|
|
92
|
+
builder_func = self._registry.get(widget_name)
|
|
93
|
+
|
|
94
|
+
if builder_func is None:
|
|
95
|
+
# Nothing to do for this Tk widget
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
builder_func(self, widget, **options)
|
|
99
|
+
|
|
100
|
+
# --- Icons ---
|
|
101
|
+
def map_stateful_icons(self, icon: IconSpec, foreground_spec: Sequence[tuple]):
|
|
102
|
+
"""Stateful icon mapping is not supported for Tk builders.
|
|
103
|
+
|
|
104
|
+
This API is intended for TTK style building only. Raise a clear
|
|
105
|
+
error if accidentally invoked from the Tk builder.
|
|
106
|
+
"""
|
|
107
|
+
raise NotImplementedError(
|
|
108
|
+
"map_stateful_icons is only supported for TTK styles via BootstyleBuilderBuilderTTk."
|
|
109
|
+
)
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
from typing import Callable, Dict, Optional
|
|
5
|
+
|
|
6
|
+
from typing_extensions import Any, ParamSpec, Protocol, TypeVar
|
|
7
|
+
|
|
8
|
+
from bootstack.core.exceptions import BootstyleBuilderError
|
|
9
|
+
from bootstack.style.bootstyle_builder_base import BootstyleBuilderBase
|
|
10
|
+
from bootstack.style.element import Element, ElementImage
|
|
11
|
+
from bootstack.style.theme_provider import ThemeProvider
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BuilderCallable(Protocol):
|
|
15
|
+
def __call__(self, builder: BootstyleBuilderTTk, ttk_style: str, **options: Any) -> None:
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
F = TypeVar("F", bound=BuilderCallable)
|
|
20
|
+
P = ParamSpec("P")
|
|
21
|
+
R = TypeVar("R")
|
|
22
|
+
|
|
23
|
+
from bootstack.style.token_maps import WIDGET_CLASS_MAP, WIDGET_NAME_MAP
|
|
24
|
+
|
|
25
|
+
# Default variant name used when no variant is specified
|
|
26
|
+
# Builders should register under both their specific name AND 'default'
|
|
27
|
+
# Example:
|
|
28
|
+
# @BootstyleBuilder.register_builder('solid', 'TButton')
|
|
29
|
+
# @BootstyleBuilder.register_builder('default', 'TButton')
|
|
30
|
+
# def build_button_solid(builder, ttk_style, **options):
|
|
31
|
+
# ...
|
|
32
|
+
DEFAULT_VARIANT = 'default'
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BootstyleBuilderTTk(BootstyleBuilderBase):
|
|
36
|
+
"""Builder manager with widget-specific style builder registry.
|
|
37
|
+
|
|
38
|
+
This class manages registration and invocation of style builder functions.
|
|
39
|
+
Builders are registered per-widget-class and variant.
|
|
40
|
+
|
|
41
|
+
Registry structure:
|
|
42
|
+
{
|
|
43
|
+
'TButton': {
|
|
44
|
+
'solid': builder_func,
|
|
45
|
+
'outline': builder_func,
|
|
46
|
+
...
|
|
47
|
+
},
|
|
48
|
+
'TLabel': {
|
|
49
|
+
'solid': builder_func,
|
|
50
|
+
'inverse': builder_func,
|
|
51
|
+
...
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# Widget-specific builder registry: {widget_class: {variant: builder_func}}
|
|
57
|
+
_builder_registry: Dict[str, Dict[str, Callable]] = {}
|
|
58
|
+
_builder_lock = threading.Lock()
|
|
59
|
+
_builders_loaded = False # Track if builders have been auto-imported
|
|
60
|
+
|
|
61
|
+
def __init__(
|
|
62
|
+
self, theme_provider: Optional[ThemeProvider] = None,
|
|
63
|
+
style_instance: Optional[Any] = None):
|
|
64
|
+
"""Initialize the BootstyleBuilder.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
theme_provider: Optional ThemeProvider instance (creates one if None)
|
|
68
|
+
style_instance: Optional Style instance (set later to avoid circular import)
|
|
69
|
+
"""
|
|
70
|
+
super().__init__(theme_provider, style_instance)
|
|
71
|
+
|
|
72
|
+
def set_style_instance(self, style_instance: Any):
|
|
73
|
+
"""Set the Style instance (avoids circular import in __init__).
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
style_instance: Style instance to use for configuration
|
|
77
|
+
"""
|
|
78
|
+
self._style = style_instance
|
|
79
|
+
|
|
80
|
+
# provider, style, colors inherited from BootstyleBase
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def register_builder(cls, variant: str, widget_class: str):
|
|
84
|
+
"""Register a builder for a specific widget variant.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
variant: Variant name (e.g., 'solid', 'outline', 'link')
|
|
88
|
+
widget_class: TTK widget class (e.g., 'TButton', 'TLabel')
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Decorator function
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
BootstyleBuilderError: If variant or widget_class invalid
|
|
95
|
+
|
|
96
|
+
Examples:
|
|
97
|
+
>>> @BootstyleBuilderTTk.register_builder('outline', 'TButton')
|
|
98
|
+
... def build_button_outline(builder, ttk_style, **options):
|
|
99
|
+
... # Builder implementation
|
|
100
|
+
... pass
|
|
101
|
+
"""
|
|
102
|
+
if not isinstance(variant, str) or not variant:
|
|
103
|
+
raise BootstyleBuilderError("`variant` must be a non-empty string")
|
|
104
|
+
|
|
105
|
+
if not isinstance(widget_class, str) or not widget_class:
|
|
106
|
+
raise BootstyleBuilderError("`widget_class` must be a non-empty string")
|
|
107
|
+
|
|
108
|
+
def deco(func: F) -> F:
|
|
109
|
+
with cls._builder_lock:
|
|
110
|
+
if widget_class not in cls._builder_registry:
|
|
111
|
+
cls._builder_registry[widget_class] = {}
|
|
112
|
+
|
|
113
|
+
if variant not in cls._builder_registry[widget_class]:
|
|
114
|
+
cls._builder_registry[widget_class][variant] = func
|
|
115
|
+
else:
|
|
116
|
+
# Warn about overwriting?
|
|
117
|
+
cls._builder_registry[widget_class][variant] = func
|
|
118
|
+
|
|
119
|
+
return func
|
|
120
|
+
|
|
121
|
+
return deco
|
|
122
|
+
|
|
123
|
+
def call_builder(
|
|
124
|
+
self, widget_class: str, variant: str, ttk_style: str,
|
|
125
|
+
accent: Optional[str] = None, **options):
|
|
126
|
+
"""Call a registered builder for a specific widget variant.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
widget_class: TTK widget class (e.g., 'TButton')
|
|
130
|
+
variant: Variant name (e.g., 'outline')
|
|
131
|
+
ttk_style: Full TTK style name
|
|
132
|
+
accent: Optional accent token (passed directly to builder)
|
|
133
|
+
**options: Custom style options
|
|
134
|
+
|
|
135
|
+
Raises:
|
|
136
|
+
BootstyleBuilderError: If builder not found
|
|
137
|
+
"""
|
|
138
|
+
# Ensure builders are loaded before accessing registry
|
|
139
|
+
BootstyleBuilderTTk._ensure_builders_loaded()
|
|
140
|
+
|
|
141
|
+
with BootstyleBuilderTTk._builder_lock:
|
|
142
|
+
widget_registry = BootstyleBuilderTTk._builder_registry.get(widget_class)
|
|
143
|
+
|
|
144
|
+
if not widget_registry:
|
|
145
|
+
raise BootstyleBuilderError(
|
|
146
|
+
f"No builders registered for widget class '{widget_class}'"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
builder_func = widget_registry.get(variant)
|
|
150
|
+
|
|
151
|
+
if not builder_func:
|
|
152
|
+
available = ', '.join(widget_registry.keys())
|
|
153
|
+
raise BootstyleBuilderError(
|
|
154
|
+
f"Builder '{variant}' not found for widget class '{widget_class}'. "
|
|
155
|
+
f"Available variants: {available}"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Pass parsed accent directly to builder
|
|
159
|
+
# No need to pass variant - the builder itself is variant-specific
|
|
160
|
+
builder_func(self, ttk_style, accent=accent, **options)
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def get_widget_class(cls, widget_name: str) -> str:
|
|
164
|
+
"""Convert widget common name to TTK class name.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
widget_name: Common widget name (e.g., 'button')
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
TTK class name (e.g., 'TButton')
|
|
171
|
+
|
|
172
|
+
Raises:
|
|
173
|
+
ValueError: If widget name not recognized
|
|
174
|
+
"""
|
|
175
|
+
if widget_name not in WIDGET_CLASS_MAP:
|
|
176
|
+
raise ValueError(
|
|
177
|
+
f"Unknown widget name: '{widget_name}'. "
|
|
178
|
+
f"Known names: {', '.join(WIDGET_CLASS_MAP.keys())}"
|
|
179
|
+
)
|
|
180
|
+
return WIDGET_CLASS_MAP[widget_name]
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def get_widget_name(cls, widget_class: str) -> str:
|
|
184
|
+
"""Convert TTK class name to common widget name.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
widget_class: TTK class name (e.g., 'TButton')
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Common widget name (e.g., 'button')
|
|
191
|
+
|
|
192
|
+
Raises:
|
|
193
|
+
ValueError: If widget class not recognized
|
|
194
|
+
"""
|
|
195
|
+
if widget_class not in WIDGET_NAME_MAP:
|
|
196
|
+
raise ValueError(
|
|
197
|
+
f"Unknown widget class: '{widget_class}'. "
|
|
198
|
+
f"Known classes: {', '.join(WIDGET_NAME_MAP.keys())}"
|
|
199
|
+
)
|
|
200
|
+
return WIDGET_NAME_MAP[widget_class]
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def get_default_variant(cls, widget_class: str = None) -> str:
|
|
204
|
+
"""Get the default variant name.
|
|
205
|
+
|
|
206
|
+
The default variant is 'default'. Builders should register under
|
|
207
|
+
both their specific variant name and 'default' to be used as the
|
|
208
|
+
default for their widget class.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
widget_class: TTK widget class (unused, kept for compatibility)
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Default variant name ('default')
|
|
215
|
+
|
|
216
|
+
Examples:
|
|
217
|
+
>>> @BootstyleBuilderTTk.register_builder('solid', 'TButton')
|
|
218
|
+
... @BootstyleBuilderTTk.register_builder('default', 'TButton')
|
|
219
|
+
... def build_button_solid(builder, ttk_style, **options):
|
|
220
|
+
... pass
|
|
221
|
+
"""
|
|
222
|
+
return DEFAULT_VARIANT
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def get_registered_builders(cls, widget_class: str) -> list:
|
|
226
|
+
"""Get list of registered builders for a widget class.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
widget_class: TTK widget class
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
List of variant names
|
|
233
|
+
"""
|
|
234
|
+
cls._ensure_builders_loaded()
|
|
235
|
+
registry = cls._builder_registry.get(widget_class, {})
|
|
236
|
+
return list(registry.keys())
|
|
237
|
+
|
|
238
|
+
@classmethod
|
|
239
|
+
def get_all_registered_widgets(cls) -> list:
|
|
240
|
+
"""Get list of all widget classes with registered builders.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
List of TTK widget class names
|
|
244
|
+
"""
|
|
245
|
+
cls._ensure_builders_loaded()
|
|
246
|
+
return list(cls._builder_registry.keys())
|
|
247
|
+
|
|
248
|
+
@classmethod
|
|
249
|
+
def _ensure_builders_loaded(cls):
|
|
250
|
+
"""Ensure builders module is loaded (lazy import).
|
|
251
|
+
|
|
252
|
+
This is called automatically when registry is accessed to ensure
|
|
253
|
+
all builder functions are registered before use.
|
|
254
|
+
"""
|
|
255
|
+
# Fast path - no lock needed if already loaded
|
|
256
|
+
if cls._builders_loaded:
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
# Use a simple flag to prevent multiple imports
|
|
260
|
+
# We check WITHOUT holding the lock to avoid deadlock
|
|
261
|
+
if not cls._builders_loaded:
|
|
262
|
+
try:
|
|
263
|
+
# Import builders module WITHOUT holding the lock
|
|
264
|
+
# This allows the builders to register themselves (which needs the lock)
|
|
265
|
+
import bootstack.style.builders # noqa: F401
|
|
266
|
+
cls._builders_loaded = True
|
|
267
|
+
except ImportError:
|
|
268
|
+
# Builders module doesn't exist yet, that's ok
|
|
269
|
+
cls._builders_loaded = True # Set to avoid retrying
|
|
270
|
+
except Exception:
|
|
271
|
+
# Unexpected error, but set flag to avoid infinite retries
|
|
272
|
+
cls._builders_loaded = True
|
|
273
|
+
|
|
274
|
+
@classmethod
|
|
275
|
+
def has_builder(cls, widget_class: str, variant: str) -> bool:
|
|
276
|
+
"""Check if a builder exists for widget class and variant.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
widget_class: TTK widget class (e.g., 'TButton')
|
|
280
|
+
variant: Variant name (e.g., 'solid', 'outline')
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
True if builder exists, False otherwise
|
|
284
|
+
|
|
285
|
+
Examples:
|
|
286
|
+
>>> BootstyleBuilderTTk.has_builder('TButton', 'solid')
|
|
287
|
+
True
|
|
288
|
+
>>> BootstyleBuilderTTk.has_builder('TButton', 'nonexistent')
|
|
289
|
+
False
|
|
290
|
+
"""
|
|
291
|
+
cls._ensure_builders_loaded()
|
|
292
|
+
return variant in cls._builder_registry.get(widget_class, {})
|
|
293
|
+
|
|
294
|
+
def initialize_all_default_styles(self):
|
|
295
|
+
"""Initialize all default widget styles.
|
|
296
|
+
|
|
297
|
+
This method should be called when a theme is loaded to ensure
|
|
298
|
+
all base widget styles are properly configured before any
|
|
299
|
+
bootstyle variants are created.
|
|
300
|
+
|
|
301
|
+
It iterates through all registered widget classes and calls
|
|
302
|
+
their 'default' builder (if registered) with no accent specified,
|
|
303
|
+
which creates the base widget style.
|
|
304
|
+
"""
|
|
305
|
+
BootstyleBuilderTTk._ensure_builders_loaded()
|
|
306
|
+
|
|
307
|
+
from bootstack.style.bootstyle import generate_ttk_style_name
|
|
308
|
+
|
|
309
|
+
for widget_class in BootstyleBuilderTTk.get_all_registered_widgets():
|
|
310
|
+
# Check if widget has a default builder
|
|
311
|
+
if BootstyleBuilderTTk.has_builder(widget_class, DEFAULT_VARIANT):
|
|
312
|
+
try:
|
|
313
|
+
# Generate the proper style name (e.g., 'Default.TFrame')
|
|
314
|
+
ttk_style = generate_ttk_style_name(
|
|
315
|
+
accent=None,
|
|
316
|
+
variant=DEFAULT_VARIANT,
|
|
317
|
+
widget_class=widget_class
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
# Call the default builder with the generated style name
|
|
321
|
+
# and no accent (None), which creates the default style
|
|
322
|
+
self.call_builder(
|
|
323
|
+
widget_class=widget_class,
|
|
324
|
+
variant=DEFAULT_VARIANT,
|
|
325
|
+
ttk_style=ttk_style,
|
|
326
|
+
accent=None
|
|
327
|
+
)
|
|
328
|
+
except Exception:
|
|
329
|
+
# Silently ignore errors to avoid breaking theme initialization
|
|
330
|
+
# Individual builder errors shouldn't prevent other builders from running
|
|
331
|
+
pass
|
|
332
|
+
|
|
333
|
+
def map_style(self, ttk_style: str, **options):
|
|
334
|
+
self.style.map(ttk_style, **options)
|
|
335
|
+
|
|
336
|
+
def configure_style(self, ttk_style, **kwargs):
|
|
337
|
+
self.style.configure(ttk_style, **kwargs)
|
|
338
|
+
|
|
339
|
+
def create_style_element_image(self, element: ElementImage):
|
|
340
|
+
name, args, kwargs = element.build()
|
|
341
|
+
try:
|
|
342
|
+
existing = set(self.style.element_names())
|
|
343
|
+
except Exception:
|
|
344
|
+
existing = set()
|
|
345
|
+
if name in existing:
|
|
346
|
+
# Element already exists; avoid duplicate creation error on theme rebuilds
|
|
347
|
+
return
|
|
348
|
+
self.style.element_create(name, "image", *args, **kwargs)
|
|
349
|
+
|
|
350
|
+
def create_style_layout(self, ttk_style: str, element: Element | list[Element]):
|
|
351
|
+
if isinstance(element, list):
|
|
352
|
+
self.style.layout(ttk_style, [e.spec() for e in element])
|
|
353
|
+
else:
|
|
354
|
+
self.style.layout(ttk_style, [element.spec()])
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Style builder functions for bootstack widgets.
|
|
2
|
+
|
|
3
|
+
This package contains individual builder functions organized by widget type.
|
|
4
|
+
Each builder is registered with the BootstyleBuilder registry using decorators.
|
|
5
|
+
|
|
6
|
+
Builder modules are automatically imported to trigger registration.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from . import (
|
|
12
|
+
badge, button, checkbutton, combobox, entry, expander, frame, label, labelframe, menubutton, sidenav,
|
|
13
|
+
notebook, panedwindow, progressbar, radiobutton, scale, scrollbar, separator, sizegrip, spinbox, switch,
|
|
14
|
+
treeview, toolbutton, tooltip, field, buttongroup, listview, calendar, contextmenu, tabitem, menubar
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Import all builder modules to trigger registration
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
'badge',
|
|
21
|
+
'button',
|
|
22
|
+
'expander',
|
|
23
|
+
'frame',
|
|
24
|
+
'label',
|
|
25
|
+
'sidenav',
|
|
26
|
+
'radiobutton',
|
|
27
|
+
'checkbutton',
|
|
28
|
+
'switch',
|
|
29
|
+
'progressbar',
|
|
30
|
+
'scale',
|
|
31
|
+
'scrollbar',
|
|
32
|
+
'menubutton',
|
|
33
|
+
'entry',
|
|
34
|
+
'field',
|
|
35
|
+
'separator',
|
|
36
|
+
'combobox',
|
|
37
|
+
'labelframe',
|
|
38
|
+
'notebook',
|
|
39
|
+
'panedwindow',
|
|
40
|
+
'sizegrip',
|
|
41
|
+
'spinbox',
|
|
42
|
+
'treeview',
|
|
43
|
+
'toolbutton',
|
|
44
|
+
'tooltip',
|
|
45
|
+
'buttongroup',
|
|
46
|
+
'listview',
|
|
47
|
+
'calendar',
|
|
48
|
+
'contextmenu',
|
|
49
|
+
'menubar',
|
|
50
|
+
'tabitem'
|
|
51
|
+
]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Badge style builders.
|
|
2
|
+
|
|
3
|
+
This module contains style builders for ttk.Label widget badge variants.
|
|
4
|
+
"""
|
|
5
|
+
from bootstack.style.bootstyle_builder_ttk import BootstyleBuilderTTk
|
|
6
|
+
from bootstack.style.element import Element, ElementImage
|
|
7
|
+
from bootstack.style.utility import recolor_element_image
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@BootstyleBuilderTTk.register_builder('square', 'TBadge')
|
|
11
|
+
def build_default_badge_style(b: BootstyleBuilderTTk, ttk_style: str, accent: str = None, **options):
|
|
12
|
+
build_badge(b, ttk_style, accent, 'square', **options)
|
|
13
|
+
|
|
14
|
+
@BootstyleBuilderTTk.register_builder('pill', 'TBadge')
|
|
15
|
+
def build_pill_badge_style(b: BootstyleBuilderTTk, ttk_style: str, accent: str = None, **options):
|
|
16
|
+
build_badge(b, ttk_style, accent, 'pill', **options)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def build_badge(b: BootstyleBuilderTTk, ttk_style: str, accent: str = None, variant: str = 'square', **options):
|
|
20
|
+
"""Create a badge style for the variant specified"""
|
|
21
|
+
|
|
22
|
+
surface_token = options.get('surface', 'content')
|
|
23
|
+
surface = b.color(surface_token)
|
|
24
|
+
normal = b.color(accent or 'primary')
|
|
25
|
+
foreground = b.on_color(normal)
|
|
26
|
+
|
|
27
|
+
badge_img = recolor_element_image(f'badge_{variant}', normal, surface, surface, surface)
|
|
28
|
+
|
|
29
|
+
b.create_style_element_image(ElementImage(f'{ttk_style}.border', badge_img.image,
|
|
30
|
+
border=badge_img.meta.border,
|
|
31
|
+
padding=badge_img.meta.padding,
|
|
32
|
+
height=badge_img.meta.height,
|
|
33
|
+
sticky='nsew'))
|
|
34
|
+
|
|
35
|
+
b.create_style_layout(
|
|
36
|
+
ttk_style, Element(f"{ttk_style}.border", sticky="nsew").children(
|
|
37
|
+
[
|
|
38
|
+
Element("Label.padding", sticky="nsew").children(
|
|
39
|
+
[
|
|
40
|
+
Element("Label.label", sticky="ew")
|
|
41
|
+
])
|
|
42
|
+
]))
|
|
43
|
+
|
|
44
|
+
b.configure_style(ttk_style, background=surface, foreground=foreground, padding=(6, 0))
|