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,385 @@
|
|
|
1
|
+
"""Accordion widget - a container of mutually exclusive expanders."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, Callable, Literal, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from bootstack.widgets.primitives.frame import Frame
|
|
7
|
+
from bootstack.widgets.primitives.separator import Separator
|
|
8
|
+
from bootstack.widgets.composites.expander import Expander
|
|
9
|
+
from bootstack.widgets.mixins import configure_delegate
|
|
10
|
+
from bootstack.widgets.types import Master
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Accordion(Frame):
|
|
17
|
+
"""A container of Expander widgets with optional mutual exclusion.
|
|
18
|
+
|
|
19
|
+
The Accordion manages a group of Expanders, optionally enforcing that only
|
|
20
|
+
one can be expanded at a time. When `allow_multiple=False`, expanding one
|
|
21
|
+
section automatically collapses the others. When `allow_collapse_all=False`,
|
|
22
|
+
at least one section must remain open.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
expanders (list[Expander]): List of managed Expander widgets.
|
|
26
|
+
expanded (list[Expander]): Currently expanded Expander(s).
|
|
27
|
+
|
|
28
|
+
!!! note "Events"
|
|
29
|
+
- `<<AccordionChange>>`: Fired when the expanded section(s) change.
|
|
30
|
+
`event.data = {'expanded': list[Expander]}`
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
master: Master = None,
|
|
36
|
+
*,
|
|
37
|
+
allow_multiple: bool = False,
|
|
38
|
+
allow_collapse_all: bool = True,
|
|
39
|
+
show_separators: bool = False,
|
|
40
|
+
accent: str = None,
|
|
41
|
+
variant: str = None,
|
|
42
|
+
**kwargs
|
|
43
|
+
):
|
|
44
|
+
"""Create an Accordion widget.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
master (Master): Parent widget. If None, uses the default root window.
|
|
48
|
+
allow_multiple (bool): If True, multiple sections can be open at once.
|
|
49
|
+
If False (default), only one section can be open at a time.
|
|
50
|
+
allow_collapse_all (bool): If True (default), all sections can be collapsed.
|
|
51
|
+
If False, at least one section must remain open.
|
|
52
|
+
show_separators (bool): If True, show separators between expanders.
|
|
53
|
+
accent (str): Accent token for the expanders (e.g., 'success', 'primary').
|
|
54
|
+
variant (str): Variant for the expanders (e.g., 'solid', 'default').
|
|
55
|
+
**kwargs: Additional arguments passed to Frame.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
if 'show_border' in kwargs:
|
|
59
|
+
kwargs.setdefault('padding', 3) # required to avoid clipping corners
|
|
60
|
+
|
|
61
|
+
super().__init__(master, **kwargs)
|
|
62
|
+
|
|
63
|
+
self._allow_multiple = allow_multiple
|
|
64
|
+
self._allow_collapse_all = allow_collapse_all
|
|
65
|
+
self._show_separators = show_separators
|
|
66
|
+
self._accent = accent
|
|
67
|
+
self._variant = variant
|
|
68
|
+
self._expanders: dict[str, Expander] = {}
|
|
69
|
+
self._expander_order: list[str] = []
|
|
70
|
+
self._separator_widgets: list[Separator] = []
|
|
71
|
+
self._updating = False # Prevent recursive updates
|
|
72
|
+
self._counter = 0 # For auto-generating keys
|
|
73
|
+
|
|
74
|
+
def add(
|
|
75
|
+
self,
|
|
76
|
+
expander: Expander = None,
|
|
77
|
+
*,
|
|
78
|
+
key: str = None,
|
|
79
|
+
title: str = "",
|
|
80
|
+
icon: str | dict = None,
|
|
81
|
+
expanded: bool = None,
|
|
82
|
+
**kwargs
|
|
83
|
+
) -> Expander:
|
|
84
|
+
"""Add an expander to the accordion.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
expander (Expander | None): Existing Expander to add. If None, creates one.
|
|
88
|
+
key (str | None): Unique identifier for the expander. Auto-generated if not provided.
|
|
89
|
+
title (str): Title for the expander header (when creating new).
|
|
90
|
+
icon (str | dict): Icon for the expander header (when creating new).
|
|
91
|
+
expanded (bool | None): Initial expansion state. If None, first expander
|
|
92
|
+
is expanded when allow_collapse_all=False, otherwise collapsed.
|
|
93
|
+
**kwargs: When expander is None, passed to Expander constructor.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Expander: The added or created Expander widget.
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
ValueError: If an expander with the same key already exists.
|
|
100
|
+
"""
|
|
101
|
+
# Auto-generate key if not provided
|
|
102
|
+
if key is None:
|
|
103
|
+
key = f"expander_{self._counter}"
|
|
104
|
+
self._counter += 1
|
|
105
|
+
|
|
106
|
+
if key in self._expanders:
|
|
107
|
+
raise ValueError(f"An expander with the key '{key}' already exists.")
|
|
108
|
+
|
|
109
|
+
# Add separator before this expander (if not the first)
|
|
110
|
+
if self._show_separators and len(self._expanders) > 0:
|
|
111
|
+
sep = Separator(self, orient='horizontal')
|
|
112
|
+
sep.pack(fill='x')
|
|
113
|
+
self._separator_widgets.append(sep)
|
|
114
|
+
|
|
115
|
+
# Create expander if not provided
|
|
116
|
+
if expander is None:
|
|
117
|
+
# Determine initial expanded state
|
|
118
|
+
if expanded is None:
|
|
119
|
+
# If not collapsible and this is the first, expand it
|
|
120
|
+
if not self._allow_collapse_all and len(self._expanders) == 0:
|
|
121
|
+
expanded = True
|
|
122
|
+
else:
|
|
123
|
+
expanded = False
|
|
124
|
+
|
|
125
|
+
# Get accent/variant from kwargs or use accordion defaults
|
|
126
|
+
accent = self._accent or kwargs.pop('accent', None)
|
|
127
|
+
variant = self._variant or kwargs.pop('variant', None)
|
|
128
|
+
|
|
129
|
+
expander = Expander(
|
|
130
|
+
self,
|
|
131
|
+
title=title,
|
|
132
|
+
icon=icon,
|
|
133
|
+
expanded=expanded,
|
|
134
|
+
highlight=True,
|
|
135
|
+
accent=accent,
|
|
136
|
+
variant=variant,
|
|
137
|
+
**kwargs
|
|
138
|
+
)
|
|
139
|
+
else:
|
|
140
|
+
# Configure existing expander
|
|
141
|
+
expander.configure(highlight=True)
|
|
142
|
+
if expanded is not None:
|
|
143
|
+
if expanded:
|
|
144
|
+
expander.expand()
|
|
145
|
+
else:
|
|
146
|
+
expander.collapse()
|
|
147
|
+
|
|
148
|
+
expander.pack(fill='x')
|
|
149
|
+
self._expanders[key] = expander
|
|
150
|
+
self._expander_order.append(key)
|
|
151
|
+
|
|
152
|
+
# Bind to toggle events
|
|
153
|
+
expander.on_toggled(lambda e, exp=expander: self._on_expander_toggle(exp, e))
|
|
154
|
+
|
|
155
|
+
return expander
|
|
156
|
+
|
|
157
|
+
def remove(self, key: str) -> None:
|
|
158
|
+
"""Remove an expander from the accordion.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
key: The key of the expander to remove.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
KeyError: If no expander with the given key exists.
|
|
165
|
+
|
|
166
|
+
Note:
|
|
167
|
+
The expander widget is destroyed. If allow_collapse_all=False and
|
|
168
|
+
removing would leave no expanders, or would remove the only
|
|
169
|
+
open expander, another expander will be expanded automatically.
|
|
170
|
+
"""
|
|
171
|
+
if key not in self._expanders:
|
|
172
|
+
raise KeyError(f"No expander with key '{key}'")
|
|
173
|
+
|
|
174
|
+
expander = self._expanders[key]
|
|
175
|
+
index = self._expander_order.index(key)
|
|
176
|
+
was_expanded = expander['expanded']
|
|
177
|
+
|
|
178
|
+
# Remove associated separator
|
|
179
|
+
if self._show_separators and self._separator_widgets:
|
|
180
|
+
if index > 0:
|
|
181
|
+
# Remove the separator before this expander
|
|
182
|
+
sep_index = index - 1
|
|
183
|
+
elif len(self._expanders) > 1:
|
|
184
|
+
# Removing first expander - remove the separator after it
|
|
185
|
+
sep_index = 0
|
|
186
|
+
else:
|
|
187
|
+
sep_index = None
|
|
188
|
+
|
|
189
|
+
if sep_index is not None and sep_index < len(self._separator_widgets):
|
|
190
|
+
sep = self._separator_widgets.pop(sep_index)
|
|
191
|
+
sep.destroy()
|
|
192
|
+
|
|
193
|
+
# Remove expander from dict/list and destroy
|
|
194
|
+
del self._expanders[key]
|
|
195
|
+
self._expander_order.remove(key)
|
|
196
|
+
expander.destroy()
|
|
197
|
+
|
|
198
|
+
# Handle allow_collapse_all=False constraint
|
|
199
|
+
if not self._allow_collapse_all and was_expanded and self._expanders:
|
|
200
|
+
# The removed expander was open - need to open another
|
|
201
|
+
expander_list = [self._expanders[k] for k in self._expander_order]
|
|
202
|
+
any_open = any(exp['expanded'] for exp in expander_list)
|
|
203
|
+
if not any_open:
|
|
204
|
+
expander_list[0].expand()
|
|
205
|
+
|
|
206
|
+
# Fire change event
|
|
207
|
+
if self._expanders:
|
|
208
|
+
expander_list = [self._expanders[k] for k in self._expander_order]
|
|
209
|
+
self.event_generate('<<AccordionChange>>', data={
|
|
210
|
+
'expanded': [exp for exp in expander_list if exp['expanded']]
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
def _on_expander_toggle(self, expander: Expander, event):
|
|
214
|
+
"""Handle expander toggle events."""
|
|
215
|
+
if self._updating:
|
|
216
|
+
return
|
|
217
|
+
|
|
218
|
+
self._updating = True
|
|
219
|
+
try:
|
|
220
|
+
is_expanded = event.data.get('expanded', False)
|
|
221
|
+
expander_list = [self._expanders[k] for k in self._expander_order]
|
|
222
|
+
|
|
223
|
+
if is_expanded:
|
|
224
|
+
# Expander was just opened
|
|
225
|
+
if not self._allow_multiple:
|
|
226
|
+
# Collapse all others
|
|
227
|
+
for exp in expander_list:
|
|
228
|
+
if exp is not expander and exp['expanded']:
|
|
229
|
+
exp.collapse()
|
|
230
|
+
else:
|
|
231
|
+
# Expander was just closed
|
|
232
|
+
if not self._allow_collapse_all:
|
|
233
|
+
# Check if any are still open
|
|
234
|
+
any_open = any(exp['expanded'] for exp in expander_list)
|
|
235
|
+
if not any_open:
|
|
236
|
+
# Re-open this one - can't collapse all
|
|
237
|
+
expander.expand()
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
# Fire change event
|
|
241
|
+
self.event_generate('<<AccordionChange>>', data={
|
|
242
|
+
'expanded': [exp for exp in expander_list if exp['expanded']]
|
|
243
|
+
})
|
|
244
|
+
finally:
|
|
245
|
+
self._updating = False
|
|
246
|
+
|
|
247
|
+
def item(self, key: str) -> Expander:
|
|
248
|
+
"""Get an expander by its key.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
key: The key of the expander to retrieve.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
The Expander instance.
|
|
255
|
+
|
|
256
|
+
Raises:
|
|
257
|
+
KeyError: If no expander with the given key exists.
|
|
258
|
+
"""
|
|
259
|
+
if key not in self._expanders:
|
|
260
|
+
raise KeyError(f"No expander with key '{key}'")
|
|
261
|
+
return self._expanders[key]
|
|
262
|
+
|
|
263
|
+
def items(self) -> tuple[Expander, ...]:
|
|
264
|
+
"""Get all expander widgets in order.
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
A tuple of all Expander instances in the order they were added.
|
|
268
|
+
"""
|
|
269
|
+
return tuple(self._expanders[key] for key in self._expander_order)
|
|
270
|
+
|
|
271
|
+
def keys(self) -> tuple[str, ...]:
|
|
272
|
+
"""Get all expander keys in order.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
A tuple of all expander keys in the order they were added.
|
|
276
|
+
"""
|
|
277
|
+
return tuple(self._expander_order)
|
|
278
|
+
|
|
279
|
+
def configure_item(self, key: str, option: str = None, **kwargs: Any):
|
|
280
|
+
"""Configure a specific expander by its key.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
key: The key of the expander to configure.
|
|
284
|
+
option: If provided, return the value of this option.
|
|
285
|
+
**kwargs: Configuration options to apply to the expander.
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
If option is provided, returns the value of that option.
|
|
289
|
+
"""
|
|
290
|
+
expander = self.item(key)
|
|
291
|
+
if option is not None:
|
|
292
|
+
return expander.cget(option)
|
|
293
|
+
expander.configure(**kwargs)
|
|
294
|
+
|
|
295
|
+
def expand(self, key: str):
|
|
296
|
+
"""Expand the expander with the given key.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
key (str): Key of the expander to expand.
|
|
300
|
+
"""
|
|
301
|
+
if key in self._expanders:
|
|
302
|
+
self._expanders[key].expand()
|
|
303
|
+
|
|
304
|
+
def collapse(self, key: str):
|
|
305
|
+
"""Collapse the expander with the given key.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
key (str): Key of the expander to collapse.
|
|
309
|
+
|
|
310
|
+
Note:
|
|
311
|
+
If allow_collapse_all=False and this is the only open expander,
|
|
312
|
+
this call will be ignored.
|
|
313
|
+
"""
|
|
314
|
+
if key in self._expanders:
|
|
315
|
+
exp = self._expanders[key]
|
|
316
|
+
if not self._allow_collapse_all:
|
|
317
|
+
# Check if this is the only open one
|
|
318
|
+
expander_list = [self._expanders[k] for k in self._expander_order]
|
|
319
|
+
open_count = sum(1 for e in expander_list if e['expanded'])
|
|
320
|
+
if open_count <= 1 and exp['expanded']:
|
|
321
|
+
return # Can't collapse the last one
|
|
322
|
+
exp.collapse()
|
|
323
|
+
|
|
324
|
+
def expand_all(self):
|
|
325
|
+
"""Expand all expanders (only effective when allow_multiple=True)."""
|
|
326
|
+
if not self._allow_multiple:
|
|
327
|
+
return
|
|
328
|
+
for exp in self._expanders.values():
|
|
329
|
+
exp.expand()
|
|
330
|
+
|
|
331
|
+
def collapse_all(self):
|
|
332
|
+
"""Collapse all expanders (only effective when allow_collapse_all=True)."""
|
|
333
|
+
if not self._allow_collapse_all:
|
|
334
|
+
return
|
|
335
|
+
for exp in self._expanders.values():
|
|
336
|
+
exp.collapse()
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
def expanded(self) -> list[Expander]:
|
|
340
|
+
"""Get the list of currently expanded Expanders."""
|
|
341
|
+
return [self._expanders[k] for k in self._expander_order if self._expanders[k]['expanded']]
|
|
342
|
+
|
|
343
|
+
@configure_delegate('allow_multiple')
|
|
344
|
+
def _delegate_allow_multiple(self, value=None):
|
|
345
|
+
"""Get or set whether multiple sections can be open at once."""
|
|
346
|
+
if value is None:
|
|
347
|
+
return self._allow_multiple
|
|
348
|
+
self._allow_multiple = value
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
@configure_delegate('allow_collapse_all')
|
|
352
|
+
def _delegate_allow_collapse_all(self, value=None):
|
|
353
|
+
"""Get or set whether all sections can be collapsed."""
|
|
354
|
+
if value is None:
|
|
355
|
+
return self._allow_collapse_all
|
|
356
|
+
self._allow_collapse_all = value
|
|
357
|
+
return None
|
|
358
|
+
|
|
359
|
+
@configure_delegate('show_separators')
|
|
360
|
+
def _delegate_show_separators(self, value=None):
|
|
361
|
+
"""Get or set whether separators are shown between sections."""
|
|
362
|
+
if value is None:
|
|
363
|
+
return self._show_separators
|
|
364
|
+
self._show_separators = value
|
|
365
|
+
return None
|
|
366
|
+
|
|
367
|
+
def on_accordion_changed(self, callback: Callable) -> str:
|
|
368
|
+
"""Bind callback to `<<AccordionChange>>` events.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
callback: Function to call when expanded sections change.
|
|
372
|
+
Receives event with `event.data = {'expanded': list[Expander]}`.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Bind ID that can be passed to `off_accordion_changed` to remove this callback.
|
|
376
|
+
"""
|
|
377
|
+
return self.bind('<<AccordionChange>>', callback, add='+')
|
|
378
|
+
|
|
379
|
+
def off_accordion_changed(self, bind_id: str = None):
|
|
380
|
+
"""Unbind `<<AccordionChange>>` callback(s).
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
bind_id (str | None): Bind ID returned by `on_accordion_changed`. If None, unbinds all.
|
|
384
|
+
"""
|
|
385
|
+
self.unbind('<<AccordionChange>>', bind_id)
|