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,508 @@
|
|
|
1
|
+
"""Expander widget - a collapsible container with header and content."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from tkinter import Widget, Variable
|
|
5
|
+
from typing import Any, Callable, Literal, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from bootstack.widgets.primitives.frame import Frame
|
|
8
|
+
from bootstack.widgets.primitives.label import Label
|
|
9
|
+
from bootstack.widgets.composites.compositeframe import CompositeFrame
|
|
10
|
+
from bootstack.widgets.mixins import configure_delegate
|
|
11
|
+
from bootstack.widgets.types import Master
|
|
12
|
+
from bootstack.core.capabilities.signals import normalize_signal
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from bootstack.core.signals import Signal
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Expander(Frame):
|
|
19
|
+
"""A collapsible container with a clickable header and expandable content.
|
|
20
|
+
|
|
21
|
+
The Expander displays a header with an optional icon, title, and chevron
|
|
22
|
+
button. Clicking anywhere on the header toggles the visibility of the
|
|
23
|
+
content area.
|
|
24
|
+
|
|
25
|
+
Expander also supports selection state via `signal`/`variable` and
|
|
26
|
+
`value`, similar to RadioButton. When clicked, it sets the variable to
|
|
27
|
+
its value, enabling radio-group-like behavior for navigation.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
content (Frame): The content container frame (read-only).
|
|
31
|
+
is_selected (bool): Whether this expander's value matches the variable (read-only).
|
|
32
|
+
|
|
33
|
+
!!! note "Events"
|
|
34
|
+
- `<<Toggle>>`: Fired when expanded/collapsed.
|
|
35
|
+
`event.data = {'expanded': bool}`
|
|
36
|
+
- `<<Selected>>`: Fired when this expander is selected.
|
|
37
|
+
`event.data = {'value': Any}`
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
master: Master = None,
|
|
43
|
+
title: str = "",
|
|
44
|
+
icon: str | dict = None,
|
|
45
|
+
expanded: bool = True,
|
|
46
|
+
collapsible: bool = True,
|
|
47
|
+
highlight: bool = False,
|
|
48
|
+
icon_expanded: str | dict = None,
|
|
49
|
+
icon_collapsed: str | dict = None,
|
|
50
|
+
icon_position: Literal["before", "after"] = "after",
|
|
51
|
+
signal: 'Signal[Any]' = None,
|
|
52
|
+
variable: Variable = None,
|
|
53
|
+
value: Any = None,
|
|
54
|
+
**kwargs
|
|
55
|
+
):
|
|
56
|
+
"""Create an Expander widget.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
master (Master): Parent widget. If None, uses the default root window.
|
|
60
|
+
title (str): Header title text.
|
|
61
|
+
icon (str | dict): Icon to display in header (left of title).
|
|
62
|
+
expanded (bool): Initial expansion state. Default is True (expanded).
|
|
63
|
+
collapsible (bool): Whether the expander can be toggled. Default is True.
|
|
64
|
+
highlight (bool): If True, header shows 'selected' state when expanded.
|
|
65
|
+
icon_expanded (str | dict): Icon spec for expanded state. Default is chevron-up.
|
|
66
|
+
icon_collapsed (str | dict): Icon spec for collapsed state. Default is chevron-down.
|
|
67
|
+
icon_position (Literal["before", "after"]): Position of chevron relative to title.
|
|
68
|
+
signal (Signal): Reactive Signal for selection state (preferred over variable).
|
|
69
|
+
variable (Variable): Tk variable for selection state (synced with signal).
|
|
70
|
+
value (Any): Value to set on signal/variable when selected.
|
|
71
|
+
**kwargs: Additional arguments passed to Frame. Use `accent` and `variant`
|
|
72
|
+
for styling the header and chevron.
|
|
73
|
+
"""
|
|
74
|
+
self._header_accent = kwargs.pop('accent', None)
|
|
75
|
+
self._header_variant = kwargs.pop('variant', None)
|
|
76
|
+
if 'show_border' in kwargs:
|
|
77
|
+
kwargs.setdefault('padding', 3) # need 3 pixels to avoid cutting off corners
|
|
78
|
+
kwargs.setdefault('takefocus', False) # Outer container shouldn't take focus
|
|
79
|
+
super().__init__(master, **kwargs)
|
|
80
|
+
|
|
81
|
+
self._title = title
|
|
82
|
+
self._icon = icon
|
|
83
|
+
self._expanded = expanded
|
|
84
|
+
self._collapsible = collapsible
|
|
85
|
+
self._highlight = highlight
|
|
86
|
+
self._icon_expanded = icon_expanded
|
|
87
|
+
self._icon_collapsed = icon_collapsed
|
|
88
|
+
self._icon_position = icon_position
|
|
89
|
+
self._content_widget = None
|
|
90
|
+
self._value = value
|
|
91
|
+
self._compact = False
|
|
92
|
+
|
|
93
|
+
# Selection state - signal/variable syncing
|
|
94
|
+
self._signal: Signal[Any] | None = None
|
|
95
|
+
self._variable: Variable | None = None
|
|
96
|
+
self._trace_id: str | None = None
|
|
97
|
+
|
|
98
|
+
# Widget references
|
|
99
|
+
self._icon_label: Label | None = None
|
|
100
|
+
self._title_label: Label | None = None
|
|
101
|
+
|
|
102
|
+
self._build_widget()
|
|
103
|
+
|
|
104
|
+
# Set up signal/variable after widget is built
|
|
105
|
+
# Prefer signal if both provided
|
|
106
|
+
if signal is not None:
|
|
107
|
+
self._set_signal_or_variable(signal)
|
|
108
|
+
elif variable is not None:
|
|
109
|
+
self._set_signal_or_variable(variable)
|
|
110
|
+
|
|
111
|
+
def _set_signal_or_variable(self, value: Any):
|
|
112
|
+
"""Set up signal/variable binding with trace for selection updates."""
|
|
113
|
+
# Remove old trace if exists
|
|
114
|
+
if self._variable is not None and self._trace_id is not None:
|
|
115
|
+
try:
|
|
116
|
+
self._variable.trace_remove('write', self._trace_id)
|
|
117
|
+
except Exception:
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
# Normalize to get both signal and variable
|
|
121
|
+
binding = normalize_signal(value)
|
|
122
|
+
if binding is not None:
|
|
123
|
+
self._signal = binding.signal
|
|
124
|
+
self._variable = binding.variable
|
|
125
|
+
else:
|
|
126
|
+
# Direct variable
|
|
127
|
+
self._variable = value
|
|
128
|
+
self._signal = None
|
|
129
|
+
|
|
130
|
+
# Add trace to update selection state
|
|
131
|
+
if self._variable is not None:
|
|
132
|
+
self._trace_id = self._variable.trace_add('write', self._on_variable_changed)
|
|
133
|
+
# Initial update
|
|
134
|
+
self._update_selection_state()
|
|
135
|
+
|
|
136
|
+
def _on_variable_changed(self, *args):
|
|
137
|
+
"""Handle variable changes to update selection state."""
|
|
138
|
+
self._update_selection_state()
|
|
139
|
+
|
|
140
|
+
def _update_selection_state(self):
|
|
141
|
+
"""Update visual state based on selection."""
|
|
142
|
+
# For now, just track state - visual updates can be added later
|
|
143
|
+
# when a dedicated nav style is created
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def _current_chevron_icon(self):
|
|
148
|
+
"""Get the appropriate chevron icon for current state."""
|
|
149
|
+
if self._expanded:
|
|
150
|
+
return self._icon_expanded or {'name': 'chevron-up', 'size': 16}
|
|
151
|
+
else:
|
|
152
|
+
return self._icon_collapsed or {'name': 'chevron-down', 'size': 16}
|
|
153
|
+
|
|
154
|
+
def _build_widget(self):
|
|
155
|
+
"""Build the internal widget structure."""
|
|
156
|
+
accent = self._header_accent
|
|
157
|
+
variant = self._header_variant
|
|
158
|
+
|
|
159
|
+
# Use CompositeFrame for header to enable hover/pressed/focus states
|
|
160
|
+
self._header_frame = CompositeFrame(
|
|
161
|
+
self, ttk_class='Expander.TFrame',
|
|
162
|
+
accent=accent, variant=variant, padding=8, takefocus=True
|
|
163
|
+
)
|
|
164
|
+
self._header_frame.pack(fill='x')
|
|
165
|
+
|
|
166
|
+
# Icon (optional, before title)
|
|
167
|
+
if self._icon:
|
|
168
|
+
self._icon_label = Label(
|
|
169
|
+
self._header_frame,
|
|
170
|
+
icon=self._icon,
|
|
171
|
+
icon_only=True,
|
|
172
|
+
ttk_class='Expander.TLabel',
|
|
173
|
+
accent=accent, variant=variant,
|
|
174
|
+
takefocus=False,
|
|
175
|
+
)
|
|
176
|
+
self._header_frame.register_composite(self._icon_label)
|
|
177
|
+
self._icon_label.pack(side='left', padx=(0, 8))
|
|
178
|
+
|
|
179
|
+
# Title label
|
|
180
|
+
self._title_label = Label(
|
|
181
|
+
self._header_frame,
|
|
182
|
+
text=self._title,
|
|
183
|
+
anchor='w',
|
|
184
|
+
ttk_class='Expander.TLabel',
|
|
185
|
+
accent=accent, variant=variant,
|
|
186
|
+
takefocus=False,
|
|
187
|
+
)
|
|
188
|
+
self._header_frame.register_composite(self._title_label)
|
|
189
|
+
|
|
190
|
+
# Toggle button (chevron)
|
|
191
|
+
self._toggle_button = Label(
|
|
192
|
+
self._header_frame,
|
|
193
|
+
icon=self._current_chevron_icon,
|
|
194
|
+
icon_only=True,
|
|
195
|
+
accent=accent, variant=variant,
|
|
196
|
+
ttk_class='Expander.TLabel',
|
|
197
|
+
takefocus=False,
|
|
198
|
+
)
|
|
199
|
+
self._header_frame.register_composite(self._toggle_button)
|
|
200
|
+
|
|
201
|
+
# Layout based on icon_position
|
|
202
|
+
if self._icon_position == "before":
|
|
203
|
+
self._toggle_button.pack(side='left')
|
|
204
|
+
self._title_label.pack(side='left', fill='x', expand=True)
|
|
205
|
+
else:
|
|
206
|
+
self._title_label.pack(side='left', fill='x', expand=True)
|
|
207
|
+
self._toggle_button.pack(side='right')
|
|
208
|
+
|
|
209
|
+
# Hide button if not collapsible
|
|
210
|
+
if not self._collapsible:
|
|
211
|
+
self._toggle_button.pack_forget()
|
|
212
|
+
|
|
213
|
+
# Content frame
|
|
214
|
+
self._content_frame = Frame(self)
|
|
215
|
+
if self._expanded:
|
|
216
|
+
self._content_frame.pack(fill='both', expand=True)
|
|
217
|
+
|
|
218
|
+
# Set initial highlight state
|
|
219
|
+
if self._highlight and self._expanded:
|
|
220
|
+
self._header_frame.set_selected(True)
|
|
221
|
+
|
|
222
|
+
# Bind header events
|
|
223
|
+
self._bind_header_events()
|
|
224
|
+
|
|
225
|
+
def _bind_header_events(self):
|
|
226
|
+
"""Make entire header clickable and keyboard accessible."""
|
|
227
|
+
# Always bind for selection, even if not collapsible
|
|
228
|
+
self._header_frame.bind('<Button-1>', self._on_header_click, add='+')
|
|
229
|
+
self._title_label.bind('<Button-1>', self._on_header_click, add='+')
|
|
230
|
+
if self._icon_label:
|
|
231
|
+
self._icon_label.bind('<Button-1>', self._on_header_click, add='+')
|
|
232
|
+
|
|
233
|
+
# Keyboard support
|
|
234
|
+
self._header_frame.bind('<Return>', self._on_header_click, add='+')
|
|
235
|
+
self._header_frame.bind('<space>', self._on_header_click, add='+')
|
|
236
|
+
|
|
237
|
+
def _on_header_click(self, event=None):
|
|
238
|
+
"""Handle header click - select and optionally toggle."""
|
|
239
|
+
# Request focus on click
|
|
240
|
+
self._header_frame.focus_set()
|
|
241
|
+
|
|
242
|
+
# Set selection if variable is configured
|
|
243
|
+
if self._variable is not None and self._value is not None:
|
|
244
|
+
self._variable.set(self._value)
|
|
245
|
+
self.event_generate('<<Selected>>', data={'value': self._value})
|
|
246
|
+
|
|
247
|
+
# Toggle expansion if collapsible
|
|
248
|
+
if self._collapsible:
|
|
249
|
+
self.toggle()
|
|
250
|
+
|
|
251
|
+
def toggle(self):
|
|
252
|
+
"""Toggle expanded/collapsed state."""
|
|
253
|
+
if not self._collapsible:
|
|
254
|
+
return
|
|
255
|
+
|
|
256
|
+
if self._expanded:
|
|
257
|
+
self.collapse()
|
|
258
|
+
else:
|
|
259
|
+
self.expand()
|
|
260
|
+
|
|
261
|
+
def expand(self):
|
|
262
|
+
"""Expand the content area."""
|
|
263
|
+
if self._expanded:
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
self._expanded = True
|
|
267
|
+
self._content_frame.pack(fill='both', expand=True)
|
|
268
|
+
self._toggle_button.configure(icon=self._current_chevron_icon)
|
|
269
|
+
if self._highlight:
|
|
270
|
+
self._header_frame.set_selected(True)
|
|
271
|
+
self.event_generate('<<Toggle>>', data={'expanded': True})
|
|
272
|
+
|
|
273
|
+
def collapse(self):
|
|
274
|
+
"""Collapse the content area."""
|
|
275
|
+
if not self._expanded:
|
|
276
|
+
return
|
|
277
|
+
|
|
278
|
+
self._expanded = False
|
|
279
|
+
self._content_frame.pack_forget()
|
|
280
|
+
self._toggle_button.configure(icon=self._current_chevron_icon)
|
|
281
|
+
if self._highlight:
|
|
282
|
+
self._header_frame.set_selected(False)
|
|
283
|
+
self.event_generate('<<Toggle>>', data={'expanded': False})
|
|
284
|
+
|
|
285
|
+
def select(self):
|
|
286
|
+
"""Select this expander (set variable to this expander's value)."""
|
|
287
|
+
if self._variable is not None and self._value is not None:
|
|
288
|
+
self._variable.set(self._value)
|
|
289
|
+
|
|
290
|
+
def add(self, widget: Widget = None, **kwargs) -> Widget:
|
|
291
|
+
"""Add content widget, or create and return an empty frame.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
widget (Widget | None): Optional widget to use as content. If None, creates a Frame.
|
|
295
|
+
**kwargs: When widget is None, these are passed to Frame (e.g., padding).
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
Widget: The content widget (passed or created).
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
ValueError: If content already exists and widget is provided.
|
|
302
|
+
"""
|
|
303
|
+
# If content exists and no widget passed, return existing (idempotent)
|
|
304
|
+
if self._content_widget is not None:
|
|
305
|
+
if widget is not None:
|
|
306
|
+
raise ValueError("Expander already has content.")
|
|
307
|
+
return self._content_widget
|
|
308
|
+
|
|
309
|
+
if widget is None:
|
|
310
|
+
widget = Frame(self._content_frame, **kwargs)
|
|
311
|
+
|
|
312
|
+
self._content_widget = widget
|
|
313
|
+
widget.pack(fill='both', expand=True)
|
|
314
|
+
return widget
|
|
315
|
+
|
|
316
|
+
@property
|
|
317
|
+
def content(self) -> Frame:
|
|
318
|
+
"""Get the content frame (for direct child parenting)."""
|
|
319
|
+
return self._content_frame
|
|
320
|
+
|
|
321
|
+
@property
|
|
322
|
+
def is_selected(self) -> bool:
|
|
323
|
+
"""Check if this expander is currently selected."""
|
|
324
|
+
if self._variable is not None and self._value is not None:
|
|
325
|
+
return self._variable.get() == self._value
|
|
326
|
+
return False
|
|
327
|
+
|
|
328
|
+
def on_toggled(self, callback: Callable) -> str:
|
|
329
|
+
"""Bind callback to `<<Toggle>>` events.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
callback: Function to call when toggled. Receives event with
|
|
333
|
+
`event.data = {'expanded': bool}`.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
Bind ID that can be passed to `off_toggled` to remove this callback.
|
|
337
|
+
"""
|
|
338
|
+
return self.bind('<<Toggle>>', callback, add='+')
|
|
339
|
+
|
|
340
|
+
def off_toggled(self, bind_id: str | None = None) -> None:
|
|
341
|
+
"""Unbind `<<Toggle>>` callback(s).
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
bind_id: Bind ID returned by `on_toggled`. If None, unbinds all.
|
|
345
|
+
"""
|
|
346
|
+
self.unbind('<<Toggle>>', bind_id)
|
|
347
|
+
|
|
348
|
+
def on_selected(self, callback: Callable) -> str:
|
|
349
|
+
"""Bind callback to `<<Selected>>` events.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
callback: Function to call when selected. Receives event with
|
|
353
|
+
`event.data = {'value': Any}`.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Bind ID that can be passed to `off_selected` to remove this callback.
|
|
357
|
+
"""
|
|
358
|
+
return self.bind('<<Selected>>', callback, add='+')
|
|
359
|
+
|
|
360
|
+
def off_selected(self, bind_id: str = None):
|
|
361
|
+
"""Unbind `<<Selected>>` callback(s).
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
bind_id (str | None): Bind ID returned by `on_selected`. If None, unbinds all.
|
|
365
|
+
"""
|
|
366
|
+
self.unbind('<<Selected>>', bind_id)
|
|
367
|
+
|
|
368
|
+
@configure_delegate('title')
|
|
369
|
+
def _delegate_title(self, value=None):
|
|
370
|
+
"""Get or set the title text."""
|
|
371
|
+
if value is None:
|
|
372
|
+
return self._title
|
|
373
|
+
self._title = value
|
|
374
|
+
self._title_label.configure(text=value)
|
|
375
|
+
return None
|
|
376
|
+
|
|
377
|
+
@configure_delegate('icon')
|
|
378
|
+
def _delegate_icon(self, value=None):
|
|
379
|
+
"""Get or set the header icon."""
|
|
380
|
+
if value is None:
|
|
381
|
+
return self._icon
|
|
382
|
+
self._icon = value
|
|
383
|
+
if self._icon_label is not None:
|
|
384
|
+
self._icon_label.configure(icon=value)
|
|
385
|
+
elif value is not None:
|
|
386
|
+
# Create icon label if it doesn't exist
|
|
387
|
+
self._icon_label = Label(
|
|
388
|
+
self._header_frame,
|
|
389
|
+
icon=value,
|
|
390
|
+
icon_only=True,
|
|
391
|
+
ttk_class='Expander.TLabel',
|
|
392
|
+
accent=self._header_accent, variant=self._header_variant,
|
|
393
|
+
takefocus=False,
|
|
394
|
+
)
|
|
395
|
+
self._header_frame.register_composite(self._icon_label)
|
|
396
|
+
# Insert at beginning of header
|
|
397
|
+
self._icon_label.pack(side='left', padx=(0, 8), before=self._title_label)
|
|
398
|
+
self._icon_label.bind('<Button-1>', self._on_header_click, add='+')
|
|
399
|
+
return None
|
|
400
|
+
|
|
401
|
+
@configure_delegate('collapsible')
|
|
402
|
+
def _delegate_collapsible(self, value=None):
|
|
403
|
+
"""Get or set whether the expander can be toggled."""
|
|
404
|
+
if value is None:
|
|
405
|
+
return self._collapsible
|
|
406
|
+
self._collapsible = value
|
|
407
|
+
if value:
|
|
408
|
+
side = 'left' if self._icon_position == 'before' else 'right'
|
|
409
|
+
self._toggle_button.pack(side=side)
|
|
410
|
+
else:
|
|
411
|
+
self._toggle_button.pack_forget()
|
|
412
|
+
return None
|
|
413
|
+
|
|
414
|
+
@configure_delegate('icon_expanded')
|
|
415
|
+
def _delegate_icon_expanded(self, value=None):
|
|
416
|
+
"""Get or set the expanded state chevron icon."""
|
|
417
|
+
if value is None:
|
|
418
|
+
return self._icon_expanded
|
|
419
|
+
self._icon_expanded = value
|
|
420
|
+
if self._expanded:
|
|
421
|
+
self._toggle_button.configure(icon=self._current_chevron_icon)
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
@configure_delegate('icon_collapsed')
|
|
425
|
+
def _delegate_icon_collapsed(self, value=None):
|
|
426
|
+
"""Get or set the collapsed state chevron icon."""
|
|
427
|
+
if value is None:
|
|
428
|
+
return self._icon_collapsed
|
|
429
|
+
self._icon_collapsed = value
|
|
430
|
+
if not self._expanded:
|
|
431
|
+
self._toggle_button.configure(icon=self._current_chevron_icon)
|
|
432
|
+
return None
|
|
433
|
+
|
|
434
|
+
@configure_delegate('value')
|
|
435
|
+
def _delegate_value(self, value=None):
|
|
436
|
+
"""Get or set the selection value."""
|
|
437
|
+
if value is None:
|
|
438
|
+
return self._value
|
|
439
|
+
self._value = value
|
|
440
|
+
return None
|
|
441
|
+
|
|
442
|
+
@configure_delegate('compact')
|
|
443
|
+
def _delegate_compact(self, value=None):
|
|
444
|
+
"""Get or set compact mode (hides title, shows icon only)."""
|
|
445
|
+
if value is None:
|
|
446
|
+
return self._compact
|
|
447
|
+
self._compact = value
|
|
448
|
+
if value:
|
|
449
|
+
# Hide title
|
|
450
|
+
if self._title_label is not None:
|
|
451
|
+
self._title_label.pack_forget()
|
|
452
|
+
# Center the icon
|
|
453
|
+
if self._icon_label is not None:
|
|
454
|
+
self._icon_label.pack_forget()
|
|
455
|
+
self._icon_label.pack(expand=True)
|
|
456
|
+
else:
|
|
457
|
+
# Restore icon to left-aligned
|
|
458
|
+
if self._icon_label is not None:
|
|
459
|
+
self._icon_label.pack_forget()
|
|
460
|
+
self._icon_label.pack(side='left', padx=(0, 8))
|
|
461
|
+
# Re-pack title in correct position
|
|
462
|
+
if self._title_label is not None:
|
|
463
|
+
if self._icon_position == "before":
|
|
464
|
+
self._title_label.pack(side='left', fill='x', expand=True)
|
|
465
|
+
else:
|
|
466
|
+
# Pack after icon (if exists) or at left
|
|
467
|
+
if self._icon_label is not None:
|
|
468
|
+
self._title_label.pack(side='left', fill='x', expand=True, after=self._icon_label)
|
|
469
|
+
else:
|
|
470
|
+
self._title_label.pack(side='left', fill='x', expand=True)
|
|
471
|
+
return None
|
|
472
|
+
|
|
473
|
+
@configure_delegate('highlight')
|
|
474
|
+
def _delegate_highlight(self, value=None):
|
|
475
|
+
"""Get or set highlight mode (shows 'selected' state when expanded)."""
|
|
476
|
+
if value is None:
|
|
477
|
+
return self._highlight
|
|
478
|
+
self._highlight = value
|
|
479
|
+
# Update the current state based on new highlight value
|
|
480
|
+
self._header_frame.set_selected(value and self._expanded)
|
|
481
|
+
return None
|
|
482
|
+
|
|
483
|
+
@configure_delegate('expanded')
|
|
484
|
+
def _delegate_expanded(self, value=None):
|
|
485
|
+
"""Get or set the expansion state."""
|
|
486
|
+
if value is None:
|
|
487
|
+
return self._expanded
|
|
488
|
+
if value:
|
|
489
|
+
self.expand()
|
|
490
|
+
else:
|
|
491
|
+
self.collapse()
|
|
492
|
+
return None
|
|
493
|
+
|
|
494
|
+
@configure_delegate('signal')
|
|
495
|
+
def _delegate_signal(self, value=None):
|
|
496
|
+
"""Get or set the signal for selection state."""
|
|
497
|
+
if value is None:
|
|
498
|
+
return self._signal
|
|
499
|
+
self._set_signal_or_variable(value)
|
|
500
|
+
return None
|
|
501
|
+
|
|
502
|
+
@configure_delegate('variable')
|
|
503
|
+
def _delegate_variable(self, value=None):
|
|
504
|
+
"""Get or set the variable for selection state."""
|
|
505
|
+
if value is None:
|
|
506
|
+
return self._variable
|
|
507
|
+
self._set_signal_or_variable(value)
|
|
508
|
+
return None
|