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,269 @@
|
|
|
1
|
+
"""Treeview widget style builders.
|
|
2
|
+
|
|
3
|
+
This module contains style builders for ttk.Treeview widget and variants.
|
|
4
|
+
|
|
5
|
+
TODO there is a strange bug that causes the treeview to request more size when the custom border element is used.
|
|
6
|
+
"""
|
|
7
|
+
import tkinter as tk
|
|
8
|
+
from tkinter import font
|
|
9
|
+
|
|
10
|
+
from ttkbootstrap_icons_bs import BootstrapIcon
|
|
11
|
+
from bootstack.style.bootstyle_builder_ttk import BootstyleBuilderTTk
|
|
12
|
+
from bootstack.style.element import Element, ElementImage
|
|
13
|
+
from bootstack.style.utility import create_transparent_image, recolor_element_image
|
|
14
|
+
from bootstack.style.builders.utils import normalize_button_density
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _tk_version_at_least(major: int, minor: int, patch: int) -> bool:
|
|
18
|
+
"""Check if the current Tk version is at least the specified version.
|
|
19
|
+
|
|
20
|
+
This is used to work around a regression in Tk 8.6.13+ where user1/user2
|
|
21
|
+
states don't work properly with custom image elements for treeview indicators.
|
|
22
|
+
See: https://core.tcl-lang.org/tk/timeline?r=rfe-d632d28ba4
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
version_str = tk._default_root.tk.call('info', 'patchlevel')
|
|
26
|
+
parts = version_str.split('.')
|
|
27
|
+
current = (int(parts[0]), int(parts[1]), int(parts[2]))
|
|
28
|
+
return current >= (major, minor, patch)
|
|
29
|
+
except Exception:
|
|
30
|
+
# If we can't determine version, assume newer Tk (safer fallback)
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _treeview_font(density: str) -> str:
|
|
35
|
+
"""Get font token based on density."""
|
|
36
|
+
return 'caption' if density == 'compact' else 'body'
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _treeview_row_height(density: str) -> float:
|
|
40
|
+
"""Get row height multiplier based on density."""
|
|
41
|
+
return 1.6 if density == 'compact' else 1.75
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _treeview_indicator_size(density: str) -> int:
|
|
45
|
+
"""Get indicator size based on density."""
|
|
46
|
+
return 10 if density == 'compact' else 12
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _treeview_icon_size(density: str) -> int:
|
|
50
|
+
"""Get custom icon size based on density."""
|
|
51
|
+
return 12 if density == 'compact' else 16
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _treeview_item_padding(density: str) -> tuple[int, int]:
|
|
55
|
+
"""Get item padding based on density."""
|
|
56
|
+
return (4, 0) if density == 'compact' else (6, 0)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _treeview_heading_padding(density: str) -> tuple[int, int]:
|
|
60
|
+
"""Get heading padding based on density."""
|
|
61
|
+
return (4, 4) if density == 'compact' else (8, 10)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _treeview_cell_padding(density: str) -> tuple[int, int]:
|
|
65
|
+
"""Get cell padding based on density."""
|
|
66
|
+
return (2, 0) if density == 'compact' else (6, 0)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@BootstyleBuilderTTk.register_builder('default', 'Treeview')
|
|
70
|
+
@BootstyleBuilderTTk.register_builder('tree', 'Treeview')
|
|
71
|
+
def build_tree_style(b: BootstyleBuilderTTk, ttk_style: str, **options):
|
|
72
|
+
"""
|
|
73
|
+
Create treeview style.
|
|
74
|
+
|
|
75
|
+
Available options via `style_options`:
|
|
76
|
+
* border_color
|
|
77
|
+
* show_border
|
|
78
|
+
* open_icon
|
|
79
|
+
* close_icon
|
|
80
|
+
* select_background
|
|
81
|
+
* header_background
|
|
82
|
+
* density ('default' or 'compact')
|
|
83
|
+
"""
|
|
84
|
+
surface_token = options.get('surface', 'content')
|
|
85
|
+
density = normalize_button_density(options.get('density', 'default'))
|
|
86
|
+
surface = b.color(surface_token)
|
|
87
|
+
|
|
88
|
+
if options.get('show_border', True):
|
|
89
|
+
if options.get('border_color'):
|
|
90
|
+
border_color = b.color(options.get('border_color'))
|
|
91
|
+
else:
|
|
92
|
+
border_color = b.border(surface)
|
|
93
|
+
else:
|
|
94
|
+
border_color = surface
|
|
95
|
+
|
|
96
|
+
if options.get('header_background'):
|
|
97
|
+
heading_color = b.color(options.get('header_background'))
|
|
98
|
+
heading_hover = b.active(heading_color)
|
|
99
|
+
else:
|
|
100
|
+
heading_color = b.elevate(surface, 3)
|
|
101
|
+
heading_hover = b.active(heading_color)
|
|
102
|
+
|
|
103
|
+
on_heading = b.on_color(heading_color)
|
|
104
|
+
on_surface = b.on_color(surface)
|
|
105
|
+
on_surface_disabled = b.disabled('text', surface)
|
|
106
|
+
hover = b.active(surface)
|
|
107
|
+
|
|
108
|
+
select_background_token = options.get('select_background', 'primary')
|
|
109
|
+
select_background = b.color(select_background_token)
|
|
110
|
+
select_hover = b.active(select_background)
|
|
111
|
+
on_select = b.on_color(select_background)
|
|
112
|
+
|
|
113
|
+
# Density-based sizing
|
|
114
|
+
body_font = _treeview_font(density)
|
|
115
|
+
row_multiplier = _treeview_row_height(density)
|
|
116
|
+
indicator_size = _treeview_indicator_size(density)
|
|
117
|
+
item_padding = _treeview_item_padding(density)
|
|
118
|
+
heading_padding = _treeview_heading_padding(density)
|
|
119
|
+
cell_padding = _treeview_cell_padding(density)
|
|
120
|
+
|
|
121
|
+
# Calculate row height - use TkDefaultFont for metrics when using font spec
|
|
122
|
+
metrics_font = 'TkDefaultFont' if body_font.startswith('-') else body_font
|
|
123
|
+
f = font.nametofont(metrics_font)
|
|
124
|
+
row_height = int(f.metrics()['linespace'] * row_multiplier)
|
|
125
|
+
|
|
126
|
+
# Tk 8.6.13+ has a regression where user1/user2 states don't work with
|
|
127
|
+
# custom image elements for treeview indicators. Use native indicator on
|
|
128
|
+
# newer Tk versions until TIP #719 lands with proper open/leaf states.
|
|
129
|
+
# See: https://core.tcl-lang.org/tk/timeline?r=rfe-d632d28ba4
|
|
130
|
+
use_native_indicator = _tk_version_at_least(8, 6, 13)
|
|
131
|
+
|
|
132
|
+
if use_native_indicator:
|
|
133
|
+
# Use native Treeitem.indicator with custom foreground colors
|
|
134
|
+
# The native indicator uses triangles that rotate based on open/closed state
|
|
135
|
+
# Create a spacer element to add space between indicator and text
|
|
136
|
+
spacer_width = 8 if density == 'compact' else 8
|
|
137
|
+
spacer = create_transparent_image(b.scale(spacer_width), 1)
|
|
138
|
+
b.create_style_element_image(
|
|
139
|
+
ElementImage(f'{ttk_style}.spacer', spacer, sticky='', width=b.scale(spacer_width))
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
b.create_style_layout(
|
|
143
|
+
f'{ttk_style}.Item',
|
|
144
|
+
Element('Treeitem.padding').children(
|
|
145
|
+
[
|
|
146
|
+
Element('Treeitem.indicator', side='left', sticky=''),
|
|
147
|
+
Element(f'{ttk_style}.spacer', side='left', sticky=''),
|
|
148
|
+
Element('Treeitem.image', side='left', sticky=''),
|
|
149
|
+
Element('Treeitem.text', side='left', sticky='w')
|
|
150
|
+
])
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
indicator_margins = (0, 0, 0, 2) if density == 'compact' else (0, 0, 0, 2)
|
|
154
|
+
b.configure_style(
|
|
155
|
+
f'{ttk_style}.Item',
|
|
156
|
+
padding=b.scale(item_padding),
|
|
157
|
+
foreground=on_surface,
|
|
158
|
+
indicatorsize=b.scale(indicator_size),
|
|
159
|
+
indicatormargins=b.scale(indicator_margins)
|
|
160
|
+
)
|
|
161
|
+
b.map_style(
|
|
162
|
+
f'{ttk_style}.Item',
|
|
163
|
+
foreground=[
|
|
164
|
+
('selected', on_select),
|
|
165
|
+
('', on_surface)
|
|
166
|
+
]
|
|
167
|
+
)
|
|
168
|
+
else:
|
|
169
|
+
# Use custom image indicator with user1/user2 states (works on Tk < 8.6.13)
|
|
170
|
+
open_icon = options.get('open_icon', 'chevron-right')
|
|
171
|
+
closed_icon = options.get('close_icon', 'chevron-down')
|
|
172
|
+
icon_size = b.scale(_treeview_icon_size(density))
|
|
173
|
+
|
|
174
|
+
expand_icon_normal = BootstrapIcon(open_icon, icon_size, on_surface).image
|
|
175
|
+
expand_icon_selected = BootstrapIcon(open_icon, icon_size, on_select).image
|
|
176
|
+
collapse_icon_normal = BootstrapIcon(closed_icon, icon_size, on_surface).image
|
|
177
|
+
collapse_icon_selected = BootstrapIcon(closed_icon, icon_size, on_select).image
|
|
178
|
+
leaf = create_transparent_image(icon_size, icon_size)
|
|
179
|
+
|
|
180
|
+
indicator_height = 12 if density == 'compact' else 14
|
|
181
|
+
b.create_style_element_image(
|
|
182
|
+
ElementImage(
|
|
183
|
+
f'{ttk_style}.indicator', expand_icon_normal,
|
|
184
|
+
sticky='w', height=b.scale(indicator_height), width=b.scale(icon_size + 10)).state_specs(
|
|
185
|
+
[
|
|
186
|
+
('user2', leaf),
|
|
187
|
+
('user1 selected', collapse_icon_selected),
|
|
188
|
+
('user1', collapse_icon_normal),
|
|
189
|
+
('!user1 selected', expand_icon_selected),
|
|
190
|
+
])
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
b.create_style_layout(
|
|
194
|
+
f'{ttk_style}.Item',
|
|
195
|
+
Element('Treeitem.padding').children(
|
|
196
|
+
[
|
|
197
|
+
Element(f'{ttk_style}.indicator', side='left', sticky=''),
|
|
198
|
+
Element('Treeitem.image', side='left', sticky=''),
|
|
199
|
+
Element('Treeitem.text', side='left', sticky='w')
|
|
200
|
+
])
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
b.configure_style(f'{ttk_style}.Item', padding=b.scale(item_padding))
|
|
204
|
+
|
|
205
|
+
# customize the tree field
|
|
206
|
+
border_img = recolor_element_image('border', surface, border_color, surface, surface)
|
|
207
|
+
|
|
208
|
+
b.create_style_element_image(
|
|
209
|
+
ElementImage(
|
|
210
|
+
f'{ttk_style}.field', border_img.image, sticky='nsew',
|
|
211
|
+
border=border_img.meta.border, padding=border_img.meta.border,
|
|
212
|
+
width=0, height=0
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
b.create_style_layout(
|
|
217
|
+
ttk_style, Element(f'{ttk_style}.field', sticky="nsew").children(
|
|
218
|
+
[
|
|
219
|
+
Element('Treeview.padding', sticky="nsew").children(
|
|
220
|
+
[
|
|
221
|
+
Element('Treeview.treearea', sticky="nsew")
|
|
222
|
+
]),
|
|
223
|
+
]))
|
|
224
|
+
|
|
225
|
+
# configure header
|
|
226
|
+
heading_font = 'caption' if density == 'compact' else 'label'
|
|
227
|
+
b.configure_style(
|
|
228
|
+
f'{ttk_style}.Heading',
|
|
229
|
+
font=heading_font,
|
|
230
|
+
background=heading_color,
|
|
231
|
+
foreground=on_heading,
|
|
232
|
+
padding=b.scale(heading_padding)
|
|
233
|
+
)
|
|
234
|
+
b.map_style(
|
|
235
|
+
f'{ttk_style}.Heading',
|
|
236
|
+
foreground=[('disabled', on_surface_disabled), ('', on_heading)],
|
|
237
|
+
background=[('active !disabled', heading_hover), ('', heading_color)]
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# configure tree body
|
|
241
|
+
b.configure_style(
|
|
242
|
+
ttk_style,
|
|
243
|
+
font=body_font,
|
|
244
|
+
background=surface,
|
|
245
|
+
fieldbackground=surface,
|
|
246
|
+
foreground=on_surface,
|
|
247
|
+
borderwidth=0,
|
|
248
|
+
padding=0,
|
|
249
|
+
rowheight=row_height,
|
|
250
|
+
relief='flat'
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
b.map_style(
|
|
254
|
+
ttk_style,
|
|
255
|
+
background=[
|
|
256
|
+
('active !disabled', hover),
|
|
257
|
+
('selected active !disabled', select_hover),
|
|
258
|
+
('selected !disabled', select_background)
|
|
259
|
+
# do not set fallback or it will override tag formats
|
|
260
|
+
],
|
|
261
|
+
foreground=[
|
|
262
|
+
('disabled', on_surface_disabled),
|
|
263
|
+
('selected !disabled', on_select)
|
|
264
|
+
# do not set fallback or it will override tag formats
|
|
265
|
+
]
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# configure cell
|
|
269
|
+
b.configure_style(f"{ttk_style}.Cell", font=body_font, padding=b.scale(cell_padding))
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
"""Utility functions for style builders.
|
|
2
|
+
|
|
3
|
+
This module provides common utilities used across builder functions,
|
|
4
|
+
including accent extraction, variant parsing, and style name manipulation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
10
|
+
|
|
11
|
+
from bootstack.style.element import Element
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from bootstack.style.bootstyle_builder_ttk import BootstyleBuilderTTk
|
|
15
|
+
|
|
16
|
+
# Standard bootstack color tokens
|
|
17
|
+
COLORS = {
|
|
18
|
+
'primary', 'secondary', 'success', 'info',
|
|
19
|
+
'warning', 'danger', 'light', 'dark', 'blue'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def extract_accent_from_style(ttk_style: str, default: str = 'primary') -> str:
|
|
24
|
+
"""Extract accent token from TTK style name.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
ttk_style: Full TTK style name (e.g., "custom_abc.success.Outline.TButton")
|
|
28
|
+
default: Default accent if none found
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Accent token name (e.g., "success")
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
>>> extract_accent_from_style("success.Outline.TButton")
|
|
35
|
+
'success'
|
|
36
|
+
>>> extract_accent_from_style("custom_abc.danger.TLabel")
|
|
37
|
+
'danger'
|
|
38
|
+
>>> extract_accent_from_style("TButton")
|
|
39
|
+
'primary'
|
|
40
|
+
"""
|
|
41
|
+
# Remove custom prefix if present
|
|
42
|
+
parts = ttk_style.split('.')
|
|
43
|
+
if parts and parts[0].startswith('custom_'):
|
|
44
|
+
parts = parts[1:]
|
|
45
|
+
|
|
46
|
+
# Find accent in parts
|
|
47
|
+
for part in parts:
|
|
48
|
+
if part.lower() in COLORS:
|
|
49
|
+
return part.lower()
|
|
50
|
+
|
|
51
|
+
return default
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def extract_variant_from_style(ttk_style: str) -> Optional[str]:
|
|
55
|
+
"""Extract variant name from TTK style name.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
ttk_style: Full TTK style name (e.g., "success.Outline.TButton")
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Variant name (lowercase) or None
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
>>> extract_variant_from_style("success.Outline.TButton")
|
|
65
|
+
'outline'
|
|
66
|
+
>>> extract_variant_from_style("primary.TLabel") is None
|
|
67
|
+
True
|
|
68
|
+
"""
|
|
69
|
+
parts = ttk_style.split('.')
|
|
70
|
+
|
|
71
|
+
# Remove custom prefix if present
|
|
72
|
+
if parts and parts[0].startswith('custom_'):
|
|
73
|
+
parts = parts[1:]
|
|
74
|
+
|
|
75
|
+
# Find variant (not accent, not widget class)
|
|
76
|
+
for part in parts:
|
|
77
|
+
part_lower = part.lower()
|
|
78
|
+
if part_lower not in COLORS and not part.startswith('T'):
|
|
79
|
+
return part_lower
|
|
80
|
+
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def extract_widget_class_from_style(ttk_style: str) -> Optional[str]:
|
|
85
|
+
"""Extract widget class from TTK style name.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
ttk_style: Full TTK style name (e.g., "success.Outline.TButton")
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Widget class name or None
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
>>> extract_widget_class_from_style("success.Outline.TButton")
|
|
95
|
+
'TButton'
|
|
96
|
+
>>> extract_widget_class_from_style("primary.TLabel")
|
|
97
|
+
'TLabel'
|
|
98
|
+
"""
|
|
99
|
+
parts = ttk_style.split('.')
|
|
100
|
+
|
|
101
|
+
# Find widget class (starts with 'T')
|
|
102
|
+
for part in parts:
|
|
103
|
+
if part.startswith('T'):
|
|
104
|
+
return part
|
|
105
|
+
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def parse_style_components(ttk_style: str) -> dict:
|
|
110
|
+
"""Parse TTK style name into all components.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
ttk_style: Full TTK style name
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Dictionary with parsed components:
|
|
117
|
+
{
|
|
118
|
+
'custom_prefix': 'custom_abc123' or None,
|
|
119
|
+
'accent': 'success' or default,
|
|
120
|
+
'variant': 'outline' or None,
|
|
121
|
+
'widget_class': 'TButton'
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
Examples:
|
|
125
|
+
>>> parse_style_components("custom_abc.success.Outline.TButton")
|
|
126
|
+
{'custom_prefix': 'custom_abc', 'accent': 'success', 'variant': 'outline', 'widget_class': 'TButton'}
|
|
127
|
+
>>> parse_style_components("danger.TLabel")
|
|
128
|
+
{'custom_prefix': None, 'accent': 'danger', 'variant': None, 'widget_class': 'TLabel'}
|
|
129
|
+
"""
|
|
130
|
+
parts = ttk_style.split('.')
|
|
131
|
+
|
|
132
|
+
# Check for custom prefix
|
|
133
|
+
custom_prefix = None
|
|
134
|
+
if parts and parts[0].startswith('custom_'):
|
|
135
|
+
custom_prefix = parts[0]
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
'custom_prefix': custom_prefix,
|
|
139
|
+
'accent': extract_accent_from_style(ttk_style),
|
|
140
|
+
'variant': extract_variant_from_style(ttk_style),
|
|
141
|
+
'widget_class': extract_widget_class_from_style(ttk_style),
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Button utilities
|
|
146
|
+
# These utilities are used by button style builders and can be reused by other widgets.
|
|
147
|
+
|
|
148
|
+
# Valid button densities: 'default' (normal) and 'compact' (smaller/tighter)
|
|
149
|
+
BUTTON_DENSITIES = {'default', 'compact'}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def normalize_button_density(density: str) -> str:
|
|
153
|
+
"""Normalize button density to valid values ('default' or 'compact').
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
density: The requested button density.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
'compact' for compact buttons, 'default' for all other densities.
|
|
160
|
+
"""
|
|
161
|
+
return 'compact' if density == 'compact' else 'default'
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def button_layout(ttk_style: str) -> Element:
|
|
165
|
+
"""Create the standard button element layout.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
ttk_style: The TTK style name prefix for the button.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Element tree representing the button layout.
|
|
172
|
+
"""
|
|
173
|
+
return Element(f"{ttk_style}.Button.border", sticky="nsew").children(
|
|
174
|
+
[
|
|
175
|
+
Element("Button.padding", sticky="nsew").children(
|
|
176
|
+
[
|
|
177
|
+
Element("Button.label", sticky="nsew")
|
|
178
|
+
])
|
|
179
|
+
])
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def toolbutton_layout(ttk_style: str) -> Element:
|
|
183
|
+
"""Create the standard toolbutton element layout.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
ttk_style: The TTK style name prefix for the toolbutton.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Element tree representing the toolbutton layout.
|
|
190
|
+
"""
|
|
191
|
+
return Element(f"{ttk_style}.border", sticky="nsew").children(
|
|
192
|
+
[
|
|
193
|
+
Element("Toolbutton.padding", sticky="nsew").children(
|
|
194
|
+
[
|
|
195
|
+
Element("Toolbutton.label", sticky="nsew")
|
|
196
|
+
])
|
|
197
|
+
])
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def icon_size(icon_only: bool, density: str) -> int:
|
|
201
|
+
"""Determine icon size based on button density and icon_only flag.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
icon_only: Whether the button displays only an icon (no text).
|
|
205
|
+
density: The button density ('default' or 'compact').
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
The icon size in pixels.
|
|
209
|
+
"""
|
|
210
|
+
from tkinter import font
|
|
211
|
+
|
|
212
|
+
if icon_only:
|
|
213
|
+
return 23 if density != 'compact' else 18
|
|
214
|
+
|
|
215
|
+
# Get icon size from font ascent for proper alignment with text
|
|
216
|
+
# Different buffers compensate for y_bias effect per density
|
|
217
|
+
font_name = 'caption' if density == 'compact' else 'body'
|
|
218
|
+
f = font.nametofont(font_name)
|
|
219
|
+
buffer = 4 if density == 'compact' else 3
|
|
220
|
+
return f.metrics()['ascent'] + buffer
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def button_font(density: str) -> str:
|
|
224
|
+
"""Get the font token for a button based on its density.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
density: The button density ('default' or 'compact').
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
The font token name.
|
|
231
|
+
"""
|
|
232
|
+
return 'caption' if density == 'compact' else 'body'
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def button_padding(b: BootstyleBuilderTTk, icon_only: bool, density: Any) -> int | tuple[int, ...]:
|
|
236
|
+
"""Calculate button padding based on options.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
b: The bootstyle builder instance.
|
|
240
|
+
icon_only: Whether the button displays only an icon.
|
|
241
|
+
density: The button density ('default' or 'compact').
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Padding value (0 for icon_only, scaled tuple otherwise).
|
|
245
|
+
"""
|
|
246
|
+
if icon_only:
|
|
247
|
+
return b.scale((2, 3, 2, 3)) if density == 'compact' else 0
|
|
248
|
+
if density == 'compact':
|
|
249
|
+
# (left, top, right, bottom) - extra top padding to center text
|
|
250
|
+
return b.scale((6, 5, 6, 3))
|
|
251
|
+
return b.scale((8, 0))
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def apply_icon_mapping(
|
|
255
|
+
b: BootstyleBuilderTTk,
|
|
256
|
+
options: dict,
|
|
257
|
+
state_spec: dict,
|
|
258
|
+
default_size: int | None = None
|
|
259
|
+
) -> dict:
|
|
260
|
+
"""Apply icon mapping to a state specification dictionary.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
b: The bootstyle builder instance.
|
|
264
|
+
options: Style options dictionary containing 'icon' and 'icon_only' keys.
|
|
265
|
+
state_spec: The state specification dictionary to update.
|
|
266
|
+
default_size: Default icon size, or None to use normalize_icon_spec defaults.
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
Updated state_spec with icon mappings applied.
|
|
270
|
+
"""
|
|
271
|
+
icon = options.get('icon')
|
|
272
|
+
if icon is None:
|
|
273
|
+
return state_spec
|
|
274
|
+
|
|
275
|
+
if default_size is None:
|
|
276
|
+
icon = b.normalize_icon_spec(icon)
|
|
277
|
+
else:
|
|
278
|
+
icon = b.normalize_icon_spec(icon, default_size)
|
|
279
|
+
|
|
280
|
+
state_spec['image'] = b.map_stateful_icons(icon, state_spec['foreground'])
|
|
281
|
+
# Set compound to 'left' so text is visible alongside the icon
|
|
282
|
+
icon_only = options.get('icon_only', False)
|
|
283
|
+
if not icon_only:
|
|
284
|
+
state_spec['compound'] = 'left'
|
|
285
|
+
return state_spec
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# Entry/Field utilities
|
|
289
|
+
# These utilities are used by entry-type style builders (Entry, Combobox, Spinbox, Field).
|
|
290
|
+
|
|
291
|
+
def entry_font(density: str) -> str:
|
|
292
|
+
"""Get the font for an entry widget based on its density.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
density: The entry density ('default' or 'compact').
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
The Tk font name.
|
|
299
|
+
"""
|
|
300
|
+
from bootstack.style.typography import get_font
|
|
301
|
+
font_token = 'caption' if density == 'compact' else 'body'
|
|
302
|
+
return str(get_font(font_token))
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def entry_padding(b: BootstyleBuilderTTk, density: str) -> tuple:
|
|
306
|
+
"""Get entry padding based on density.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
b: The bootstyle builder instance.
|
|
310
|
+
density: The entry density ('default' or 'compact').
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Scaled padding tuple (horizontal, vertical).
|
|
314
|
+
"""
|
|
315
|
+
if density == 'compact':
|
|
316
|
+
return b.scale((6, 0))
|
|
317
|
+
return b.scale((6, 0))
|
|
318
|
+
|
|
319
|
+
def field_height(b: BootstyleBuilderTTk, density: str) -> int:
|
|
320
|
+
"""Get entry element height based on density.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
b: The bootstyle builder instance.
|
|
324
|
+
density: The entry density ('default' or 'compact').
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Scaled height in pixels.
|
|
328
|
+
"""
|
|
329
|
+
return b.scale(26) if density == 'compact' else b.scale(33)
|
|
330
|
+
|
|
331
|
+
def entry_height(b: BootstyleBuilderTTk, density: str) -> int:
|
|
332
|
+
"""Get entry element height based on density.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
b: The bootstyle builder instance.
|
|
336
|
+
density: The entry density ('default' or 'compact').
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
Scaled height in pixels.
|
|
340
|
+
"""
|
|
341
|
+
return b.scale(25) if density == 'compact' else b.scale(31)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def entry_icon_size(b: BootstyleBuilderTTk, density: str) -> int:
|
|
345
|
+
"""Get icon size for entry widgets (chevrons, spinner arrows).
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
b: The bootstyle builder instance.
|
|
349
|
+
density: The entry density ('default' or 'compact').
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
Scaled icon size in pixels.
|
|
353
|
+
"""
|
|
354
|
+
return b.scale(12) if density == 'compact' else b.scale(14)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def entry_image_key(base: str, density: str) -> str:
|
|
358
|
+
"""Get density-aware manifest key for entry elements.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
base: Base key name (e.g., 'input', 'input_before', 'input_after').
|
|
362
|
+
density: The entry density ('default' or 'compact').
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Full manifest key with density suffix (e.g., 'input_default', 'input_compact').
|
|
366
|
+
"""
|
|
367
|
+
return f'{base}_{density}'
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def spinner_arrow_height(b: BootstyleBuilderTTk, density: str) -> int:
|
|
371
|
+
"""Get height for spinner arrow elements based on density.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
b: The bootstyle builder instance.
|
|
375
|
+
density: The entry density ('default' or 'compact').
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
Scaled arrow height in pixels.
|
|
379
|
+
"""
|
|
380
|
+
return b.scale(10) if density == 'compact' else b.scale(13)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def spinner_arrow_width(b: BootstyleBuilderTTk) -> int:
|
|
384
|
+
"""Get width for spinner arrow elements.
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
b: The bootstyle builder instance.
|
|
388
|
+
|
|
389
|
+
Returns:
|
|
390
|
+
Scaled arrow width in pixels.
|
|
391
|
+
"""
|
|
392
|
+
return b.scale(16)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def chevron_width(b: BootstyleBuilderTTk) -> int:
|
|
396
|
+
"""Get width for combobox chevron element.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
b: The bootstyle builder instance.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Scaled chevron width in pixels.
|
|
403
|
+
"""
|
|
404
|
+
return b.scale(16)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Tk (legacy tkinter) widget builders for bootstack.
|
|
2
|
+
|
|
3
|
+
Importing this package registers default builder functions for common Tk
|
|
4
|
+
widgets using the BootstyleBuilderTk registry. Builders receive the actual
|
|
5
|
+
widget instance, plus theme/color utilities via the builder object.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
# Import defaults to trigger registration
|
|
11
|
+
from . import defaults # noqa: F401
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'defaults',
|
|
15
|
+
]
|
|
16
|
+
|