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,248 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tkinter import StringVar
|
|
4
|
+
from typing import Any, Callable, Literal, Optional, TYPE_CHECKING, TypedDict
|
|
5
|
+
|
|
6
|
+
from typing_extensions import Unpack
|
|
7
|
+
|
|
8
|
+
from bootstack.widgets.composites.contextmenu import ContextMenu, ContextMenuItem
|
|
9
|
+
from bootstack.widgets.primitives.menubutton import MenuButton
|
|
10
|
+
from bootstack.widgets.mixins import configure_delegate
|
|
11
|
+
from bootstack.widgets.types import Master
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from bootstack.core.signals import Signal
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OptionMenuKwargs(TypedDict, total=False):
|
|
18
|
+
command: Optional[Callable[[], Any]]
|
|
19
|
+
image: Any
|
|
20
|
+
icon: Any
|
|
21
|
+
icon_only: bool
|
|
22
|
+
compound: Literal['text', 'image', 'top', 'bottom', 'left', 'right', 'center', 'none'] | str
|
|
23
|
+
padding: Any
|
|
24
|
+
width: int
|
|
25
|
+
underline: int
|
|
26
|
+
state: Literal['normal', 'active', 'disabled', 'readonly'] | str
|
|
27
|
+
takefocus: Any
|
|
28
|
+
style: str
|
|
29
|
+
class_: str
|
|
30
|
+
cursor: str
|
|
31
|
+
default: Any
|
|
32
|
+
name: str
|
|
33
|
+
textvariable: Any
|
|
34
|
+
textsignal: Signal[str]
|
|
35
|
+
bootstyle: str # DEPRECATED: Use accent and variant instead
|
|
36
|
+
accent: str
|
|
37
|
+
variant: str
|
|
38
|
+
surface: str
|
|
39
|
+
style_options: dict[str, Any]
|
|
40
|
+
show_dropdown_button: bool
|
|
41
|
+
dropdown_button_icon: str | dict
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class OptionMenu(MenuButton):
|
|
45
|
+
"""A single-selection dropdown menu backed by a ContextMenu.
|
|
46
|
+
|
|
47
|
+
Renders as a `MenuButton` with a chevron icon. Clicking the button opens
|
|
48
|
+
a popup menu containing the provided options as radiobutton items. Selecting
|
|
49
|
+
an item updates the displayed text and fires a `<<Change>>` event.
|
|
50
|
+
|
|
51
|
+
!!! note "Events"
|
|
52
|
+
- `<<Change>>`: Fired when the selected value changes.
|
|
53
|
+
`event.data = {'value': Any}`
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
master: Master = None,
|
|
59
|
+
value: Any = None,
|
|
60
|
+
options: list[Any] = None,
|
|
61
|
+
**kwargs: Unpack[OptionMenuKwargs],
|
|
62
|
+
):
|
|
63
|
+
"""Create an OptionMenu backed by a ContextMenu.
|
|
64
|
+
|
|
65
|
+
!!! note "Events"
|
|
66
|
+
- `<<Change>>`: Fired when the selected value changes. `event.data = {'value': Any}`
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
master: Parent widget. If None, uses the default root window.
|
|
70
|
+
value: Initial selected value.
|
|
71
|
+
options (list): List of values to populate the menu.
|
|
72
|
+
|
|
73
|
+
Other Parameters:
|
|
74
|
+
command (Callable): Callback invoked when the value changes via menu selection.
|
|
75
|
+
image (PhotoImage): Tk image to display.
|
|
76
|
+
icon (str | dict): Bootstyle icon spec for the label content.
|
|
77
|
+
icon_only (bool): Whether to reserve label padding when showing only an icon.
|
|
78
|
+
compound (str): Placement of image relative to text.
|
|
79
|
+
padding (int | tuple): Extra padding around the menubutton content.
|
|
80
|
+
width (int): Width of the menubutton.
|
|
81
|
+
underline (int): Index of underlined character in text.
|
|
82
|
+
state (str): Widget state ('normal', 'active', 'disabled', 'readonly').
|
|
83
|
+
takefocus (bool): Participation in focus traversal.
|
|
84
|
+
style (str): Explicit ttk style name (overrides accent/variant).
|
|
85
|
+
textvariable (Variable): Existing Tk variable to bind; new StringVar created if omitted.
|
|
86
|
+
textsignal (Signal[str]): Signal bound to the textvariable.
|
|
87
|
+
accent (str): Accent token for styling, e.g. 'primary', 'danger', 'success'.
|
|
88
|
+
variant (str): Style variant, e.g. 'solid', 'outline'.
|
|
89
|
+
bootstyle (str): DEPRECATED - Use `accent` and `variant` instead.
|
|
90
|
+
Combined style tokens (e.g., 'primary-outline').
|
|
91
|
+
surface (str): Surface token for style.
|
|
92
|
+
style_options (dict): Dict forwarded to the style builder (e.g., icon_only, surface).
|
|
93
|
+
show_dropdown_button (bool): Toggle visibility of the dropdown chevron.
|
|
94
|
+
dropdown_button_icon (str | dict): Icon name for the chevron; defaults to 'caret-down-fill'.
|
|
95
|
+
"""
|
|
96
|
+
style_options = kwargs.pop('style_options', {})
|
|
97
|
+
style_options.update(
|
|
98
|
+
self._capture_style_options(
|
|
99
|
+
options=['icon_only', 'icon', 'show_dropdown_button', 'dropdown_button_icon'],
|
|
100
|
+
source=kwargs
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
self._bind_id = None
|
|
105
|
+
self._menu_options = options if options is not None else []
|
|
106
|
+
|
|
107
|
+
# Store the textvariable if provided, or create a new one
|
|
108
|
+
self._textvariable = kwargs.pop('textvariable', None)
|
|
109
|
+
if self._textvariable is None:
|
|
110
|
+
self._textvariable = StringVar(value=str(value) if value is not None else "")
|
|
111
|
+
|
|
112
|
+
super().__init__(master, text=value, **kwargs)
|
|
113
|
+
|
|
114
|
+
# Configure the menubutton to use the textvariable
|
|
115
|
+
self.configure(textvariable=self._textvariable)
|
|
116
|
+
|
|
117
|
+
# Bind signal to change event
|
|
118
|
+
self._bind_id = self._bind_change_event()
|
|
119
|
+
|
|
120
|
+
# Create menu items that update the shared variable
|
|
121
|
+
self._context_menu = self._build_context_menu()
|
|
122
|
+
|
|
123
|
+
# Bind menu display to button events
|
|
124
|
+
self.bind('<Button-1>', lambda _: self.show_menu(), add="+")
|
|
125
|
+
self.bind('<Return>', lambda _: self.show_menu(), add="+")
|
|
126
|
+
self.bind('<KP_Enter>', lambda _: self.show_menu(), add="+")
|
|
127
|
+
|
|
128
|
+
def _bind_change_event(self):
|
|
129
|
+
"""(Re)bind textsignal to emit <<Change>> Tk events."""
|
|
130
|
+
if self._bind_id is not None:
|
|
131
|
+
self.textsignal.unsubscribe(self._bind_id)
|
|
132
|
+
return self.textsignal.subscribe(lambda v: self.event_generate('<<Change>>', data={"value": v}))
|
|
133
|
+
|
|
134
|
+
def _build_context_menu(self):
|
|
135
|
+
# Affordance baked into the button image (focus ring + border line in
|
|
136
|
+
# source-px); aligning the menu's left edge to it matches the visible
|
|
137
|
+
# button border the same way the combobox popdown does.
|
|
138
|
+
from bootstack.style.bootstyle_builder_base import BootstyleBuilderBase
|
|
139
|
+
offset_x = BootstyleBuilderBase.scale_from_source(10)
|
|
140
|
+
|
|
141
|
+
density = self.configure_style_options('density') or 'default'
|
|
142
|
+
|
|
143
|
+
menu_items = [
|
|
144
|
+
ContextMenuItem(
|
|
145
|
+
type="radiobutton",
|
|
146
|
+
text=str(item),
|
|
147
|
+
variable=self._textvariable,
|
|
148
|
+
value=str(item)
|
|
149
|
+
)
|
|
150
|
+
for item in self._menu_options
|
|
151
|
+
]
|
|
152
|
+
return ContextMenu(
|
|
153
|
+
self, target=self, items=menu_items,
|
|
154
|
+
anchor="nw", attach="sw",
|
|
155
|
+
offset=(offset_x, 0),
|
|
156
|
+
density=density,
|
|
157
|
+
# OptionMenu drives activation via `show_menu` (left-click,
|
|
158
|
+
# Return/KP_Enter), not ContextMenu's auto-trigger.
|
|
159
|
+
trigger=None,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def show_menu(self):
|
|
163
|
+
"""Show the dropdown menu unless disabled or readonly."""
|
|
164
|
+
if not self.instate(("!disabled", "!readonly")):
|
|
165
|
+
return
|
|
166
|
+
# Match the menu's minimum width to the visible button width so the
|
|
167
|
+
# dropdown never renders narrower than its trigger.
|
|
168
|
+
from bootstack.style.bootstyle_builder_base import BootstyleBuilderBase
|
|
169
|
+
affordance = BootstyleBuilderBase.scale_from_source(10)
|
|
170
|
+
target_w = self.winfo_width() - 2 * affordance
|
|
171
|
+
if target_w > 0:
|
|
172
|
+
self._context_menu.configure(minwidth=max(150, target_w))
|
|
173
|
+
self._context_menu.show()
|
|
174
|
+
|
|
175
|
+
def get(self) -> str:
|
|
176
|
+
"""Return the current value."""
|
|
177
|
+
return self._textvariable.get()
|
|
178
|
+
|
|
179
|
+
def set(self, value: Any) -> None:
|
|
180
|
+
"""Set the current value (coerced to string)."""
|
|
181
|
+
self._textvariable.set(str(value))
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def value(self) -> str:
|
|
185
|
+
"""Get or set the current value."""
|
|
186
|
+
return self.get()
|
|
187
|
+
|
|
188
|
+
@value.setter
|
|
189
|
+
def value(self, value: Any) -> None:
|
|
190
|
+
self.set(value)
|
|
191
|
+
|
|
192
|
+
def on_changed(self, callback: Callable) -> str:
|
|
193
|
+
"""Bind to `<<Change>>`. Callback receives `event.data = {'value': Any}`."""
|
|
194
|
+
return self.bind('<<Change>>', callback, add="+")
|
|
195
|
+
|
|
196
|
+
def off_changed(self, bind_id: str | None = None) -> None:
|
|
197
|
+
"""Unbind from `<<Change>>`."""
|
|
198
|
+
self.unbind('<<Change>>', bind_id)
|
|
199
|
+
|
|
200
|
+
@configure_delegate('options')
|
|
201
|
+
def _delegate_options(self, value=None):
|
|
202
|
+
"""Get or set the menu options list."""
|
|
203
|
+
if value is None:
|
|
204
|
+
return self._menu_options
|
|
205
|
+
else:
|
|
206
|
+
self._menu_options = value
|
|
207
|
+
if self._context_menu:
|
|
208
|
+
self._context_menu.destroy()
|
|
209
|
+
self._context_menu = self._build_context_menu()
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
@configure_delegate('value')
|
|
213
|
+
def _delegate_value(self, value):
|
|
214
|
+
"""Get or set the current value."""
|
|
215
|
+
if value is None:
|
|
216
|
+
return self.value
|
|
217
|
+
else:
|
|
218
|
+
self.value = value
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
@configure_delegate('textsignal')
|
|
222
|
+
def _delegate_textsignal(self, value=None):
|
|
223
|
+
"""Get or set the textsignal binding."""
|
|
224
|
+
if value is None:
|
|
225
|
+
return super()._delegate_textsignal()
|
|
226
|
+
else:
|
|
227
|
+
super()._delegate_textsignal(value)
|
|
228
|
+
self._bind_change_event()
|
|
229
|
+
return None
|
|
230
|
+
|
|
231
|
+
@configure_delegate('show_dropdown_button')
|
|
232
|
+
def _delegate_show_dropdown_button(self, value=None):
|
|
233
|
+
"""Get or set visibility of the dropdown chevron."""
|
|
234
|
+
if value is None:
|
|
235
|
+
return self.configure_style_options('show_dropdown_button')
|
|
236
|
+
else:
|
|
237
|
+
self.configure_style_options(show_dropdown_button=value)
|
|
238
|
+
return self.rebuild_style()
|
|
239
|
+
|
|
240
|
+
@configure_delegate('dropdown_button_icon')
|
|
241
|
+
def _delegate_dropdown_button_icon(self, value):
|
|
242
|
+
"""Get or set the dropdown chevron icon name."""
|
|
243
|
+
if value is None:
|
|
244
|
+
return self.configure_style_options('dropdown_button_icon')
|
|
245
|
+
else:
|
|
246
|
+
self.configure_style_options(dropdown_button_icon=value)
|
|
247
|
+
return self.rebuild_style()
|
|
248
|
+
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tkinter as tk
|
|
4
|
+
from typing import Literal, Optional, Any
|
|
5
|
+
|
|
6
|
+
from bootstack.widgets.primitives.frame import Frame
|
|
7
|
+
from bootstack.widgets.mixins.configure_mixin import configure_delegate
|
|
8
|
+
from bootstack.widgets.types import Master
|
|
9
|
+
|
|
10
|
+
Direction = Literal["vertical", "horizontal", "row", "column", "row-reverse", "column-reverse"]
|
|
11
|
+
Fill = Literal["none", "x", "y", "both"]
|
|
12
|
+
Side = Literal["top", "bottom", "left", "right"]
|
|
13
|
+
Anchor = Literal["n", "ne", "e", "se", "s", "sw", "w", "nw", "center"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PackFrame(Frame):
|
|
17
|
+
"""A Frame with simplified pack-based layout management.
|
|
18
|
+
|
|
19
|
+
PackFrame extends the bootstack Frame with automatic pack-based
|
|
20
|
+
layout management, including support for direction, gap spacing,
|
|
21
|
+
and default fill/expand behavior.
|
|
22
|
+
|
|
23
|
+
Children packed into this frame automatically receive the frame's
|
|
24
|
+
default layout options. Simply use the standard `pack()` method
|
|
25
|
+
on child widgets — no special `add()` method is needed.
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
```python
|
|
29
|
+
frame = PackFrame(direction="vertical", gap=10, fill_items="x")
|
|
30
|
+
Label(frame, text="First").pack()
|
|
31
|
+
Label(frame, text="Second").pack()
|
|
32
|
+
Button(frame, text="Click").pack(expand=True) # override default
|
|
33
|
+
```
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
SIDE_MAP: dict[Direction, Side] = {
|
|
37
|
+
"vertical": "top",
|
|
38
|
+
"column": "top",
|
|
39
|
+
"column-reverse": "bottom",
|
|
40
|
+
"horizontal": "left",
|
|
41
|
+
"row": "left",
|
|
42
|
+
"row-reverse": "right",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
master: Master = None,
|
|
48
|
+
*,
|
|
49
|
+
direction: Direction = "vertical",
|
|
50
|
+
gap: int = 0,
|
|
51
|
+
fill_items: Optional[Fill] = None,
|
|
52
|
+
expand_items: Optional[bool] = None,
|
|
53
|
+
anchor_items: Optional[Anchor] = None,
|
|
54
|
+
propagate: Optional[bool] = None,
|
|
55
|
+
**kwargs: Any,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Create a PackFrame with automatic pack-based layout.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
master: Parent widget. If None, uses the default root window.
|
|
61
|
+
direction: Layout direction — `'vertical'`, `'horizontal'`,
|
|
62
|
+
`'row'`, `'column'`, `'row-reverse'`, or `'column-reverse'`.
|
|
63
|
+
Defaults to `'vertical'`.
|
|
64
|
+
gap: Spacing between children in pixels. Defaults to 0.
|
|
65
|
+
fill_items: Default `fill` option for children
|
|
66
|
+
(`'none'`, `'x'`, `'y'`, or `'both'`). If None, no default fill
|
|
67
|
+
is applied.
|
|
68
|
+
expand_items: Default `expand` option for children. If None, no
|
|
69
|
+
default expand is applied.
|
|
70
|
+
anchor_items: Default `anchor` for children. If None, no default
|
|
71
|
+
anchor is applied.
|
|
72
|
+
propagate: If False, the frame will not resize to fit its contents.
|
|
73
|
+
Defaults to None (Tk default behaviour).
|
|
74
|
+
**kwargs: Additional keyword arguments forwarded to `Frame`.
|
|
75
|
+
"""
|
|
76
|
+
super().__init__(master, **kwargs)
|
|
77
|
+
|
|
78
|
+
self._direction = direction
|
|
79
|
+
self._gap = gap
|
|
80
|
+
self._default_fill = fill_items
|
|
81
|
+
self._default_expand = expand_items
|
|
82
|
+
self._default_anchor = anchor_items
|
|
83
|
+
|
|
84
|
+
# Ordered list of (widget, user_options) tuples for gap tracking
|
|
85
|
+
self._managed: list[tuple[tk.Widget, dict[str, Any]]] = []
|
|
86
|
+
|
|
87
|
+
if propagate is not None:
|
|
88
|
+
self.pack_propagate(propagate)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def _side(self) -> Side:
|
|
92
|
+
"""Get the pack side based on direction."""
|
|
93
|
+
return self.SIDE_MAP.get(self._direction, "top")
|
|
94
|
+
|
|
95
|
+
@configure_delegate('direction')
|
|
96
|
+
def _delegate_direction(self, value=None) -> Direction:
|
|
97
|
+
"""Get or set the layout direction."""
|
|
98
|
+
if value is None:
|
|
99
|
+
return self._direction
|
|
100
|
+
self._direction = value
|
|
101
|
+
# Repack all widgets with new direction
|
|
102
|
+
self._repack_all()
|
|
103
|
+
|
|
104
|
+
@configure_delegate('gap')
|
|
105
|
+
def _delegate_gap(self, value=None) -> int:
|
|
106
|
+
"""Get or set the gap between children."""
|
|
107
|
+
if value is None:
|
|
108
|
+
return self._gap
|
|
109
|
+
self._gap = value
|
|
110
|
+
# Repack all widgets with new gap
|
|
111
|
+
self._repack_all()
|
|
112
|
+
|
|
113
|
+
def _compute_gap(self, index: int) -> dict[str, Any]:
|
|
114
|
+
"""Compute padding for gap based on position and direction."""
|
|
115
|
+
if index == 0 or self._gap == 0:
|
|
116
|
+
return {}
|
|
117
|
+
|
|
118
|
+
if self._direction in ("vertical", "column"):
|
|
119
|
+
return {"pady": (self._gap, 0)}
|
|
120
|
+
elif self._direction == "column-reverse":
|
|
121
|
+
return {"pady": (0, self._gap)}
|
|
122
|
+
elif self._direction in ("horizontal", "row"):
|
|
123
|
+
return {"padx": (self._gap, 0)}
|
|
124
|
+
elif self._direction == "row-reverse":
|
|
125
|
+
return {"padx": (0, self._gap)}
|
|
126
|
+
return {}
|
|
127
|
+
|
|
128
|
+
def _build_options(self, index: int, user_options: dict[str, Any]) -> dict[str, Any]:
|
|
129
|
+
"""Build final pack options by merging defaults with user options."""
|
|
130
|
+
options: dict[str, Any] = {"in_": self, "side": self._side}
|
|
131
|
+
|
|
132
|
+
# Apply gap based on position
|
|
133
|
+
options.update(self._compute_gap(index))
|
|
134
|
+
|
|
135
|
+
# Apply container-level defaults
|
|
136
|
+
if self._default_fill is not None:
|
|
137
|
+
options["fill"] = self._default_fill
|
|
138
|
+
if self._default_expand is not None:
|
|
139
|
+
options["expand"] = self._default_expand
|
|
140
|
+
if self._default_anchor is not None:
|
|
141
|
+
options["anchor"] = self._default_anchor
|
|
142
|
+
|
|
143
|
+
# User options override everything
|
|
144
|
+
options.update(user_options)
|
|
145
|
+
return options
|
|
146
|
+
|
|
147
|
+
def _repack_all(self) -> None:
|
|
148
|
+
"""Unpack and repack all widgets to maintain correct order and gaps."""
|
|
149
|
+
# Unpack all
|
|
150
|
+
for widget, _ in self._managed:
|
|
151
|
+
tk.Pack.forget(widget)
|
|
152
|
+
|
|
153
|
+
# Repack in order
|
|
154
|
+
for i, (widget, user_options) in enumerate(self._managed):
|
|
155
|
+
options = self._build_options(i, user_options)
|
|
156
|
+
tk.Pack.configure(widget, **options)
|
|
157
|
+
|
|
158
|
+
def _find_widget_index(self, widget: tk.Widget) -> int:
|
|
159
|
+
"""Find index of widget in managed list, return -1 if not found."""
|
|
160
|
+
for i, (w, _) in enumerate(self._managed):
|
|
161
|
+
if w is widget:
|
|
162
|
+
return i
|
|
163
|
+
return -1
|
|
164
|
+
|
|
165
|
+
def _find_insert_index(self, before: tk.Widget = None, after: tk.Widget = None) -> int:
|
|
166
|
+
"""Determine insertion index based on before/after options."""
|
|
167
|
+
if before is not None:
|
|
168
|
+
idx = self._find_widget_index(before)
|
|
169
|
+
if idx >= 0:
|
|
170
|
+
return idx
|
|
171
|
+
if after is not None:
|
|
172
|
+
idx = self._find_widget_index(after)
|
|
173
|
+
if idx >= 0:
|
|
174
|
+
return idx + 1
|
|
175
|
+
return len(self._managed)
|
|
176
|
+
|
|
177
|
+
# -------------------------------------------------------------------------
|
|
178
|
+
# Hook methods called by PackMixin
|
|
179
|
+
# -------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
def _on_child_pack(self, widget: tk.Widget, **options: Any) -> None:
|
|
182
|
+
"""Hook called when a child widget calls pack().
|
|
183
|
+
|
|
184
|
+
Applies frame defaults, handles gap spacing, and tracks the widget.
|
|
185
|
+
"""
|
|
186
|
+
# Check if widget is already managed (reconfigure case)
|
|
187
|
+
existing_idx = self._find_widget_index(widget)
|
|
188
|
+
|
|
189
|
+
# Determine insertion position from before/after
|
|
190
|
+
before = options.pop("before", None)
|
|
191
|
+
after = options.pop("after", None)
|
|
192
|
+
|
|
193
|
+
if existing_idx >= 0:
|
|
194
|
+
# Widget already managed - update its options
|
|
195
|
+
self._managed[existing_idx] = (widget, options)
|
|
196
|
+
self._repack_all()
|
|
197
|
+
else:
|
|
198
|
+
# New widget - find insertion point
|
|
199
|
+
insert_idx = self._find_insert_index(before, after)
|
|
200
|
+
|
|
201
|
+
if insert_idx < len(self._managed):
|
|
202
|
+
# Inserting in the middle - need to repack all
|
|
203
|
+
self._managed.insert(insert_idx, (widget, options))
|
|
204
|
+
self._repack_all()
|
|
205
|
+
else:
|
|
206
|
+
# Appending at the end - just pack it
|
|
207
|
+
pack_options = self._build_options(len(self._managed), options)
|
|
208
|
+
tk.Pack.configure(widget, **pack_options)
|
|
209
|
+
self._managed.append((widget, options))
|
|
210
|
+
|
|
211
|
+
def _on_child_pack_forget(self, widget: tk.Widget) -> None:
|
|
212
|
+
"""Hook called when a child widget calls pack_forget().
|
|
213
|
+
|
|
214
|
+
Removes widget from tracking and repacks remaining widgets if needed.
|
|
215
|
+
"""
|
|
216
|
+
idx = self._find_widget_index(widget)
|
|
217
|
+
if idx < 0:
|
|
218
|
+
# Not managed by us, just forget it normally
|
|
219
|
+
tk.Pack.forget(widget)
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
# Remove from our tracking
|
|
223
|
+
tk.Pack.forget(widget)
|
|
224
|
+
self._managed.pop(idx)
|
|
225
|
+
|
|
226
|
+
# Only repack if we removed something that affects gaps (not the last item)
|
|
227
|
+
if idx < len(self._managed):
|
|
228
|
+
self._repack_all()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tkinter import ttk
|
|
4
|
+
from typing import Any, TypedDict
|
|
5
|
+
from typing_extensions import Unpack
|
|
6
|
+
|
|
7
|
+
from bootstack.core.mixins.ttk_state import TtkStateMixin
|
|
8
|
+
from bootstack.core.mixins.widget import WidgetCapabilitiesMixin
|
|
9
|
+
from bootstack.widgets.internal.wrapper_base import TTKWrapperBase
|
|
10
|
+
from bootstack.widgets.types import Master
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PanedWindowKwargs(TypedDict, total=False):
|
|
14
|
+
# Standard ttk.Panedwindow options
|
|
15
|
+
orient: Any
|
|
16
|
+
padding: Any
|
|
17
|
+
width: int
|
|
18
|
+
height: int
|
|
19
|
+
style: str
|
|
20
|
+
class_: str
|
|
21
|
+
cursor: str
|
|
22
|
+
name: str
|
|
23
|
+
|
|
24
|
+
# bootstack-specific extensions
|
|
25
|
+
bootstyle: str # DEPRECATED: Use accent and variant instead
|
|
26
|
+
accent: str
|
|
27
|
+
variant: str
|
|
28
|
+
surface: str
|
|
29
|
+
style_options: dict[str, Any]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class PanedWindow(TTKWrapperBase, WidgetCapabilitiesMixin, TtkStateMixin, ttk.PanedWindow):
|
|
33
|
+
"""bootstack wrapper for `ttk.Panedwindow` with bootstyle support."""
|
|
34
|
+
|
|
35
|
+
_ttk_base = ttk.Panedwindow
|
|
36
|
+
|
|
37
|
+
def __init__(self, master: Master = None, **kwargs: Unpack[PanedWindowKwargs]) -> None:
|
|
38
|
+
"""Create a themed bootstack Panedwindow.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
master: Parent widget. If None, uses the default root window.
|
|
42
|
+
|
|
43
|
+
Other Parameters:
|
|
44
|
+
orient (str): Orientation of panes ('horizontal' or 'vertical').
|
|
45
|
+
padding (int | tuple): Extra internal padding.
|
|
46
|
+
width (int): Requested width in pixels.
|
|
47
|
+
height (int): Requested height in pixels.
|
|
48
|
+
style (str): Explicit ttk style name (overrides accent/variant).
|
|
49
|
+
accent (str): Accent token for styling, e.g. 'primary', 'secondary'.
|
|
50
|
+
variant (str): Style variant (if applicable).
|
|
51
|
+
bootstyle (str): DEPRECATED - Use `accent` and `variant` instead.
|
|
52
|
+
Combined style tokens.
|
|
53
|
+
surface (str): Optional surface token; otherwise inherited.
|
|
54
|
+
style_options (dict): Optional dict forwarded to the style builder.
|
|
55
|
+
"""
|
|
56
|
+
super().__init__(master, **kwargs)
|
|
57
|
+
|
|
58
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tkinter import ttk
|
|
4
|
+
from typing import Any, Literal, TypedDict, TYPE_CHECKING
|
|
5
|
+
from typing_extensions import Unpack
|
|
6
|
+
|
|
7
|
+
from bootstack.core.mixins.ttk_state import TtkStateMixin
|
|
8
|
+
from bootstack.core.mixins.widget import WidgetCapabilitiesMixin
|
|
9
|
+
from bootstack.widgets.internal.wrapper_base import TTKWrapperBase
|
|
10
|
+
from bootstack.widgets.mixins.configure_mixin import configure_delegate
|
|
11
|
+
from bootstack.widgets.types import Master
|
|
12
|
+
from ..mixins import SignalMixin
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from bootstack.core.signals import Signal
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProgressbarKwargs(TypedDict, total=False):
|
|
19
|
+
# Standard ttk.Progressbar options
|
|
20
|
+
mode: Literal['determinate', 'indeterminate'] | str
|
|
21
|
+
orient: Any
|
|
22
|
+
length: Any
|
|
23
|
+
maximum: float
|
|
24
|
+
value: float
|
|
25
|
+
variable: Any
|
|
26
|
+
signal: Signal[Any]
|
|
27
|
+
phase: int
|
|
28
|
+
style: str
|
|
29
|
+
class_: str
|
|
30
|
+
cursor: str
|
|
31
|
+
name: str
|
|
32
|
+
|
|
33
|
+
# bootstack-specific extensions
|
|
34
|
+
bootstyle: str # DEPRECATED: Use accent and variant instead
|
|
35
|
+
accent: str
|
|
36
|
+
variant: str
|
|
37
|
+
surface: str
|
|
38
|
+
style_options: dict[str, Any]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Progressbar(SignalMixin, TTKWrapperBase, WidgetCapabilitiesMixin, TtkStateMixin, ttk.Progressbar):
|
|
42
|
+
"""bootstack wrapper for `ttk.Progressbar` with bootstyle support."""
|
|
43
|
+
|
|
44
|
+
_ttk_base = ttk.Progressbar
|
|
45
|
+
|
|
46
|
+
def __init__(self, master: Master = None, **kwargs: Unpack[ProgressbarKwargs]) -> None:
|
|
47
|
+
"""Create a themed bootstack Progressbar.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
master: Parent widget. If None, uses the default root window.
|
|
51
|
+
|
|
52
|
+
Other Parameters:
|
|
53
|
+
mode (str): Progress mode ('determinate' or 'indeterminate').
|
|
54
|
+
orient (str): Orientation of the bar ('horizontal' or 'vertical').
|
|
55
|
+
length (int): Requested length of the progress bar in pixels.
|
|
56
|
+
maximum (float): Maximum value.
|
|
57
|
+
value (float): Current value.
|
|
58
|
+
variable (Variable): Tk variable linked to the value.
|
|
59
|
+
signal (Signal): Reactive Signal linked to the value (auto-synced with variable).
|
|
60
|
+
phase (int): Animation phase for indeterminate mode.
|
|
61
|
+
style (str): Explicit ttk style name (overrides accent/variant).
|
|
62
|
+
accent (str): Accent token for styling, e.g. 'primary', 'success', 'danger'.
|
|
63
|
+
variant (str): Style variant, e.g. 'default', 'striped', 'thin'.
|
|
64
|
+
bootstyle (str): DEPRECATED - Use `accent` and `variant` instead.
|
|
65
|
+
Combined style tokens (e.g., 'success', 'striped').
|
|
66
|
+
surface (str): Optional surface token; otherwise inherited.
|
|
67
|
+
style_options (dict): Optional dict forwarded to the style builder.
|
|
68
|
+
"""
|
|
69
|
+
super().__init__(master, **kwargs)
|
|
70
|
+
|
|
71
|
+
def get(self) -> float:
|
|
72
|
+
"""Return the current progress value."""
|
|
73
|
+
return self.cget('value')
|
|
74
|
+
|
|
75
|
+
def set(self, value: float) -> None:
|
|
76
|
+
"""Set the progress value."""
|
|
77
|
+
self.configure(value=value)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def value(self) -> float:
|
|
81
|
+
"""Get or set the progress value."""
|
|
82
|
+
return self.get()
|
|
83
|
+
|
|
84
|
+
@value.setter
|
|
85
|
+
def value(self, value: float) -> None:
|
|
86
|
+
self.set(value)
|
|
87
|
+
|
|
88
|
+
@configure_delegate('value')
|
|
89
|
+
def _delegate_value(self, value=None):
|
|
90
|
+
"""Get or set the value via configure."""
|
|
91
|
+
if value is None:
|
|
92
|
+
return self.get()
|
|
93
|
+
self.set(value)
|
|
94
|
+
|
|
95
|
+
|