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,304 @@
|
|
|
1
|
+
"""Shared base for ttk wrapper widgets with bootstyle and config delegation.
|
|
2
|
+
|
|
3
|
+
This base class wires up:
|
|
4
|
+
- Constructor: delegates to Bootstyle's constructor wrapper for init-time style
|
|
5
|
+
setup, including surface color inheritance and default variants.
|
|
6
|
+
- Configure: routes keys annotated via @configure_delegate to their handlers,
|
|
7
|
+
then forwards remaining options to the underlying ttk widget.
|
|
8
|
+
- Index access: `w['key']` and `w['key'] = value` work for delegated keys and
|
|
9
|
+
for `style`/`bootstyle` queries.
|
|
10
|
+
- Bootstyle handler: implements @configure_delegate('bootstyle') so runtime
|
|
11
|
+
updates apply via the style engine without monkey-patching ttk.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from bootstack.style.bootstyle import (
|
|
19
|
+
Bootstyle,
|
|
20
|
+
extract_accent_from_style,
|
|
21
|
+
extract_variant_from_style,
|
|
22
|
+
)
|
|
23
|
+
from bootstack.style.token_maps import CONTAINER_CLASSES, ORIENT_CLASSES
|
|
24
|
+
from bootstack.widgets.mixins.configure_mixin import (
|
|
25
|
+
ConfigureDelegationMixin,
|
|
26
|
+
configure_delegate,
|
|
27
|
+
)
|
|
28
|
+
from bootstack.widgets.mixins.font_mixin import FontMixin
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TTKWrapperBase(FontMixin, ConfigureDelegationMixin):
|
|
32
|
+
"""Base class for all ttk wrapper widgets.
|
|
33
|
+
|
|
34
|
+
Subclasses must set `_ttk_base` to the underlying ttk class and inherit
|
|
35
|
+
from that ttk class as well (MRO: WrapperBase, ttk.Class).
|
|
36
|
+
|
|
37
|
+
Includes FontMixin for font modifier syntax support.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
_ttk_base: type
|
|
41
|
+
|
|
42
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore[override]
|
|
43
|
+
font_value = self._init_font_mixin(kwargs)
|
|
44
|
+
init_wrapper = Bootstyle.override_ttk_widget_constructor(self._ttk_base.__init__) # type: ignore[attr-defined]
|
|
45
|
+
init_wrapper(self, *args, **kwargs)
|
|
46
|
+
if font_value is not None:
|
|
47
|
+
self._delegate_font(font_value)
|
|
48
|
+
|
|
49
|
+
def configure(self, cnf: Any | None = None, **kwargs: Any): # type: ignore[override]
|
|
50
|
+
# First, route custom keys via delegation
|
|
51
|
+
if kwargs:
|
|
52
|
+
for _k in list(kwargs.keys()):
|
|
53
|
+
if _k in self._configure_delegate_map:
|
|
54
|
+
if self._config_delegate_set(_k, kwargs[_k]):
|
|
55
|
+
kwargs.pop(_k, None)
|
|
56
|
+
|
|
57
|
+
# Getter path for delegated keys
|
|
58
|
+
if isinstance(cnf, str) and cnf in self._configure_delegate_map:
|
|
59
|
+
handled, value = self._config_delegate_get(cnf)
|
|
60
|
+
if handled:
|
|
61
|
+
return value
|
|
62
|
+
|
|
63
|
+
# Forward remaining options directly to ttk
|
|
64
|
+
return self._ttk_base.configure(self, cnf, **kwargs) # type: ignore[misc]
|
|
65
|
+
|
|
66
|
+
# tk alias
|
|
67
|
+
config = configure
|
|
68
|
+
|
|
69
|
+
# Indexing support: delegate custom keys; handle style/bootstyle queries
|
|
70
|
+
def __setitem__(self, key: str, value: Any) -> None: # noqa: D401
|
|
71
|
+
if key in getattr(self, "_configure_delegate_map", {}):
|
|
72
|
+
self._config_delegate_set(key, value)
|
|
73
|
+
return None
|
|
74
|
+
if key in ("bootstyle", "style") and getattr(self, "__class__", None).__name__ != "OptionMenu":
|
|
75
|
+
return self.configure(**{key: value})
|
|
76
|
+
return self._ttk_base.__setitem__(self, key, value) # type: ignore[misc]
|
|
77
|
+
|
|
78
|
+
def __getitem__(self, key: str) -> Any: # noqa: D401
|
|
79
|
+
if key in getattr(self, "_configure_delegate_map", {}):
|
|
80
|
+
handled, value = self._config_delegate_get(key)
|
|
81
|
+
if handled:
|
|
82
|
+
return value
|
|
83
|
+
if key in ("bootstyle", "style") and getattr(self, "__class__", None).__name__ != "OptionMenu":
|
|
84
|
+
return self.configure(cnf=key)
|
|
85
|
+
return self._ttk_base.__getitem__(self, key) # type: ignore[misc]
|
|
86
|
+
|
|
87
|
+
def rebuild_style(self):
|
|
88
|
+
"""Recreate the widget's current style with updated style options.
|
|
89
|
+
|
|
90
|
+
This is useful when runtime style_options change (e.g., showing/hiding
|
|
91
|
+
dropdown chevrons) and you need the builder to regenerate assets.
|
|
92
|
+
|
|
93
|
+
Generates a new style name with the correct hash based on the new
|
|
94
|
+
style_options, then applies it to the widget.
|
|
95
|
+
|
|
96
|
+
NOTE: Style options are updated via the `style_options()` method.
|
|
97
|
+
"""
|
|
98
|
+
# Use stored _ttk_class if available (for custom style class like ButtonGroup)
|
|
99
|
+
# Otherwise fall back to actual widget class
|
|
100
|
+
widget_class = getattr(self, '_ttk_class', None) or self.winfo_class()
|
|
101
|
+
|
|
102
|
+
style_options = getattr(self, '_style_options', {})
|
|
103
|
+
|
|
104
|
+
# Use stored accent/variant if available
|
|
105
|
+
accent = getattr(self, '_accent', None)
|
|
106
|
+
variant = getattr(self, '_variant', None)
|
|
107
|
+
|
|
108
|
+
# Fall back to extraction from style if not stored
|
|
109
|
+
if accent is None or variant is None:
|
|
110
|
+
current_style = self._ttk_base.cget(self, "style") # type: ignore[misc]
|
|
111
|
+
if current_style:
|
|
112
|
+
if accent is None:
|
|
113
|
+
accent = extract_accent_from_style(current_style, default=None)
|
|
114
|
+
if variant is None:
|
|
115
|
+
variant = extract_variant_from_style(current_style, widget_class)
|
|
116
|
+
|
|
117
|
+
# Preserve surface and orientation in style_options
|
|
118
|
+
if not style_options:
|
|
119
|
+
style_options = {}
|
|
120
|
+
surface = getattr(self, "_surface", None)
|
|
121
|
+
if surface and surface != "content":
|
|
122
|
+
style_options["surface"] = surface
|
|
123
|
+
if widget_class in ORIENT_CLASSES:
|
|
124
|
+
try:
|
|
125
|
+
style_options["orient"] = str(self.cget("orient"))
|
|
126
|
+
except Exception:
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
# Generate NEW style name with NEW hash based on new options
|
|
130
|
+
ttk_style = Bootstyle.create_ttk_style(
|
|
131
|
+
widget_class=widget_class,
|
|
132
|
+
style_options=style_options or None,
|
|
133
|
+
accent=accent,
|
|
134
|
+
variant=variant,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Apply the new style
|
|
138
|
+
return self._ttk_base.configure(self, style=ttk_style) # type: ignore[misc]
|
|
139
|
+
|
|
140
|
+
# ----- Built-in delegated handlers -----
|
|
141
|
+
@configure_delegate("accent")
|
|
142
|
+
def _delegate_accent(self, value: Any = None):
|
|
143
|
+
"""Get or set the accent token for this widget.
|
|
144
|
+
|
|
145
|
+
- Query: returns the current accent token or None
|
|
146
|
+
- Set: updates the widget style with the new accent, preserving variant
|
|
147
|
+
"""
|
|
148
|
+
# Query path
|
|
149
|
+
if value is None:
|
|
150
|
+
# Try stored value first
|
|
151
|
+
stored = getattr(self, '_accent', None)
|
|
152
|
+
if stored:
|
|
153
|
+
return stored
|
|
154
|
+
# Fall back to extracting from current style
|
|
155
|
+
current_style = self._ttk_base.cget(self, "style") # type: ignore[misc]
|
|
156
|
+
if not current_style:
|
|
157
|
+
return None
|
|
158
|
+
return extract_accent_from_style(current_style, default=None)
|
|
159
|
+
|
|
160
|
+
# Set path - use stored _ttk_class if available
|
|
161
|
+
widget_class = getattr(self, '_ttk_class', None) or self.winfo_class()
|
|
162
|
+
current_variant = getattr(self, '_variant', None)
|
|
163
|
+
if current_variant is None:
|
|
164
|
+
current_style = self._ttk_base.cget(self, "style") # type: ignore[misc]
|
|
165
|
+
if current_style:
|
|
166
|
+
current_variant = extract_variant_from_style(current_style, widget_class)
|
|
167
|
+
|
|
168
|
+
# Store the new accent
|
|
169
|
+
setattr(self, '_accent', value)
|
|
170
|
+
|
|
171
|
+
# Use stored style_options
|
|
172
|
+
style_options = getattr(self, '_style_options', {}).copy()
|
|
173
|
+
|
|
174
|
+
surface = getattr(self, "_surface", None)
|
|
175
|
+
if surface and surface != "content":
|
|
176
|
+
style_options["surface"] = surface
|
|
177
|
+
|
|
178
|
+
if widget_class in ORIENT_CLASSES:
|
|
179
|
+
try:
|
|
180
|
+
style_options["orient"] = str(self.cget("orient"))
|
|
181
|
+
except Exception:
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
if widget_class in CONTAINER_CLASSES:
|
|
185
|
+
style_options["surface"] = value
|
|
186
|
+
setattr(self, "_surface", value)
|
|
187
|
+
|
|
188
|
+
ttk_style = Bootstyle.create_ttk_style(
|
|
189
|
+
widget_class=widget_class,
|
|
190
|
+
accent=value,
|
|
191
|
+
variant=current_variant,
|
|
192
|
+
style_options=style_options or None,
|
|
193
|
+
)
|
|
194
|
+
return self._ttk_base.configure(self, style=ttk_style) # type: ignore[misc]
|
|
195
|
+
|
|
196
|
+
@configure_delegate("variant")
|
|
197
|
+
def _delegate_variant(self, value: Any = None):
|
|
198
|
+
"""Get or set the variant for this widget.
|
|
199
|
+
|
|
200
|
+
- Query: returns the current variant name or None
|
|
201
|
+
- Set: updates the widget style with the new variant, preserving accent
|
|
202
|
+
|
|
203
|
+
Note: If the variant is not valid for this widget type, a BootstyleBuilderError
|
|
204
|
+
will be raised.
|
|
205
|
+
"""
|
|
206
|
+
# Query path
|
|
207
|
+
if value is None:
|
|
208
|
+
# Try stored value first
|
|
209
|
+
stored = getattr(self, '_variant', None)
|
|
210
|
+
if stored:
|
|
211
|
+
return stored
|
|
212
|
+
# Fall back to extracting from current style
|
|
213
|
+
current_style = self._ttk_base.cget(self, "style") # type: ignore[misc]
|
|
214
|
+
if not current_style:
|
|
215
|
+
return None
|
|
216
|
+
widget_class = getattr(self, '_ttk_class', None) or self.winfo_class()
|
|
217
|
+
return extract_variant_from_style(current_style, widget_class)
|
|
218
|
+
|
|
219
|
+
# Set path - use stored _ttk_class if available
|
|
220
|
+
widget_class = getattr(self, '_ttk_class', None) or self.winfo_class()
|
|
221
|
+
current_accent = getattr(self, '_accent', None)
|
|
222
|
+
if current_accent is None:
|
|
223
|
+
current_style = self._ttk_base.cget(self, "style") # type: ignore[misc]
|
|
224
|
+
if current_style:
|
|
225
|
+
current_accent = extract_accent_from_style(current_style, default=None)
|
|
226
|
+
|
|
227
|
+
# Store the new variant
|
|
228
|
+
setattr(self, '_variant', value)
|
|
229
|
+
|
|
230
|
+
# Use stored style_options
|
|
231
|
+
style_options = getattr(self, '_style_options', {}).copy()
|
|
232
|
+
|
|
233
|
+
surface = getattr(self, "_surface", None)
|
|
234
|
+
if surface and surface != "content":
|
|
235
|
+
style_options["surface"] = surface
|
|
236
|
+
|
|
237
|
+
if widget_class in ORIENT_CLASSES:
|
|
238
|
+
try:
|
|
239
|
+
style_options["orient"] = str(self.cget("orient"))
|
|
240
|
+
except Exception:
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
ttk_style = Bootstyle.create_ttk_style(
|
|
244
|
+
widget_class=widget_class,
|
|
245
|
+
accent=current_accent,
|
|
246
|
+
variant=value,
|
|
247
|
+
style_options=style_options or None,
|
|
248
|
+
)
|
|
249
|
+
return self._ttk_base.configure(self, style=ttk_style) # type: ignore[misc]
|
|
250
|
+
|
|
251
|
+
def configure_style_options(self, value=None, **kwargs):
|
|
252
|
+
"""Get or set the widget style options if handled by the widget's style builder.
|
|
253
|
+
|
|
254
|
+
Special cascading keys:
|
|
255
|
+
surface: Updates `_surface` on this widget and (via Frame subclass) triggers
|
|
256
|
+
`_refresh_descendant_surfaces` to propagate the change to children.
|
|
257
|
+
input_background: Updates `_input_background` on this widget and (via Frame
|
|
258
|
+
subclass) triggers `_refresh_descendant_input_backgrounds` to propagate
|
|
259
|
+
the change to all descendant input widgets.
|
|
260
|
+
"""
|
|
261
|
+
options = getattr(self, "_style_options", {})
|
|
262
|
+
if value is None:
|
|
263
|
+
options.update(**kwargs)
|
|
264
|
+
setattr(self, "_style_options", options)
|
|
265
|
+
if "surface" in kwargs:
|
|
266
|
+
surface = kwargs.get("surface")
|
|
267
|
+
setattr(self, "_surface", surface or "content")
|
|
268
|
+
if "input_background" in kwargs:
|
|
269
|
+
setattr(self, "_input_background", kwargs.get("input_background"))
|
|
270
|
+
return None
|
|
271
|
+
else:
|
|
272
|
+
return options.get(value, None)
|
|
273
|
+
|
|
274
|
+
def _capture_style_options(self, options: list[str] = None, source: Any = None):
|
|
275
|
+
"""Extract options from a dictionary source.
|
|
276
|
+
|
|
277
|
+
This method should be called before `super()` to capture the style options when they are explicitly exposed as
|
|
278
|
+
keyword arguments instead of being passed indirectly in the `style_options` parameter.
|
|
279
|
+
|
|
280
|
+
This method will also attempt to extract the style_options argument if provided.
|
|
281
|
+
|
|
282
|
+
Parameters:
|
|
283
|
+
options: A list of options to extract.
|
|
284
|
+
source: The dictionary of keyword arguments to extract from.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
A dict of style options. e.g. {"icon_only": True, "icon": "bootstrap-fill"}.
|
|
288
|
+
"""
|
|
289
|
+
if source is None:
|
|
290
|
+
return {}
|
|
291
|
+
|
|
292
|
+
style_options = source.pop("style_options", {})
|
|
293
|
+
|
|
294
|
+
captured = {}
|
|
295
|
+
for option in options:
|
|
296
|
+
if option in source:
|
|
297
|
+
captured[option] = source.pop(option)
|
|
298
|
+
if captured:
|
|
299
|
+
style_options.update(**captured)
|
|
300
|
+
|
|
301
|
+
return style_options
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
__all__ = ["TTKWrapperBase"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Widget mixins for bootstack."""
|
|
2
|
+
|
|
3
|
+
from bootstack.widgets.mixins.configure_mixin import (
|
|
4
|
+
ConfigureDelegationMixin,
|
|
5
|
+
CustomConfigMixin,
|
|
6
|
+
configure_delegate,
|
|
7
|
+
)
|
|
8
|
+
from bootstack.widgets.mixins.font_mixin import FontMixin
|
|
9
|
+
from bootstack.widgets.mixins.icon_mixin import IconMixin
|
|
10
|
+
from bootstack.widgets.mixins.signal_mixin import SignalMixin, TextSignalMixin
|
|
11
|
+
from bootstack.widgets.mixins.validation_mixin import ValidationMixin
|
|
12
|
+
from bootstack.widgets.mixins.entry_mixin import EntryMixin
|
|
13
|
+
from bootstack.widgets.mixins.localization_mixin import LocalizationMixin
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"ConfigureDelegationMixin",
|
|
17
|
+
"CustomConfigMixin",
|
|
18
|
+
"configure_delegate",
|
|
19
|
+
"FontMixin",
|
|
20
|
+
"IconMixin",
|
|
21
|
+
"SignalMixin",
|
|
22
|
+
"TextSignalMixin",
|
|
23
|
+
"ValidationMixin",
|
|
24
|
+
"LocalizationMixin",
|
|
25
|
+
]
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Configuration delegation helpers for widget classes.
|
|
2
|
+
|
|
3
|
+
Provides a decorator and mixin so widgets can handle custom configure keys
|
|
4
|
+
without large if/else blocks. Suited for use by bootstack wrapper
|
|
5
|
+
subclasses and custom widgets.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Callable, Dict, Tuple
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def configure_delegate(*names: str):
|
|
14
|
+
"""Decorator to mark a method as a configure handler for given names.
|
|
15
|
+
|
|
16
|
+
The decorated method should accept a single argument `value` to set,
|
|
17
|
+
and optionally return None. For getting values, the mixin will read
|
|
18
|
+
from self._<option_name> directly.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def _decorator(func: Callable[[Any, Any], Any]):
|
|
22
|
+
keys = set(getattr(func, "_bootstack_configure_keys", ()))
|
|
23
|
+
keys.update(names)
|
|
24
|
+
setattr(func, "_bootstack_configure_keys", tuple(keys))
|
|
25
|
+
return func
|
|
26
|
+
|
|
27
|
+
return _decorator
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ConfigureDelegationMixin:
|
|
31
|
+
"""Mix-in that dispatches configure keys to decorated handlers.
|
|
32
|
+
|
|
33
|
+
Subclasses can annotate methods with @configure_delegate("key") to handle
|
|
34
|
+
custom configuration entries without if/else chains.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
_configure_delegate_map: Dict[str, str] = {}
|
|
38
|
+
|
|
39
|
+
def __init_subclass__(cls, **kwargs: Any) -> None: # noqa: D401
|
|
40
|
+
super().__init_subclass__(**kwargs)
|
|
41
|
+
mapping: Dict[str, str] = {}
|
|
42
|
+
for base in reversed(cls.__mro__):
|
|
43
|
+
for name, member in getattr(base, "__dict__", {}).items():
|
|
44
|
+
keys = getattr(member, "_bootstack_configure_keys", None)
|
|
45
|
+
if keys:
|
|
46
|
+
for k in keys:
|
|
47
|
+
mapping[str(k)] = name
|
|
48
|
+
cls._configure_delegate_map = mapping
|
|
49
|
+
|
|
50
|
+
def _config_delegate_set(self, key: str, value: Any) -> bool:
|
|
51
|
+
method_name = self._configure_delegate_map.get(key)
|
|
52
|
+
if not method_name:
|
|
53
|
+
return False
|
|
54
|
+
handler = getattr(self, method_name)
|
|
55
|
+
handler(value)
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
def _config_delegate_get(self, key: str) -> Tuple[bool, Any]:
|
|
59
|
+
method_name = self._configure_delegate_map.get(key)
|
|
60
|
+
if not method_name:
|
|
61
|
+
return False, None
|
|
62
|
+
handler = getattr(self, method_name)
|
|
63
|
+
value = handler(None)
|
|
64
|
+
# For variable options, return the string name instead of the object
|
|
65
|
+
if key in ('variable', 'textvariable') and hasattr(value, '_name'):
|
|
66
|
+
return True, str(value)
|
|
67
|
+
return True, value
|
|
68
|
+
|
|
69
|
+
def configure(self, cnf=None, **kwargs):
|
|
70
|
+
"""Configure widget options, handling custom delegated options first."""
|
|
71
|
+
# Handle custom delegated keys
|
|
72
|
+
if kwargs:
|
|
73
|
+
for _k in list(kwargs.keys()):
|
|
74
|
+
if _k in self._configure_delegate_map:
|
|
75
|
+
if self._config_delegate_set(_k, kwargs[_k]):
|
|
76
|
+
kwargs.pop(_k, None)
|
|
77
|
+
|
|
78
|
+
# Getter path for delegated keys
|
|
79
|
+
if isinstance(cnf, str) and cnf in self._configure_delegate_map:
|
|
80
|
+
handled, value = self._config_delegate_get(cnf)
|
|
81
|
+
if handled:
|
|
82
|
+
# Return in standard Tkinter format: (name, dbName, dbClass, default, current)
|
|
83
|
+
return (cnf, cnf, cnf.capitalize(), None, value)
|
|
84
|
+
|
|
85
|
+
# Forward remaining options to parent
|
|
86
|
+
return super().configure(cnf, **kwargs)
|
|
87
|
+
|
|
88
|
+
config = configure
|
|
89
|
+
|
|
90
|
+
def __setitem__(self, key, value):
|
|
91
|
+
"""Set configuration option via indexing."""
|
|
92
|
+
if key in self._configure_delegate_map:
|
|
93
|
+
self._config_delegate_set(key, value)
|
|
94
|
+
return
|
|
95
|
+
return super().__setitem__(key, value)
|
|
96
|
+
|
|
97
|
+
def __getitem__(self, key):
|
|
98
|
+
"""Get configuration option via indexing."""
|
|
99
|
+
if key in self._configure_delegate_map:
|
|
100
|
+
handled, value = self._config_delegate_get(key)
|
|
101
|
+
if handled:
|
|
102
|
+
return value
|
|
103
|
+
return super().__getitem__(key)
|
|
104
|
+
|
|
105
|
+
def cget(self, key):
|
|
106
|
+
"""Get configuration option."""
|
|
107
|
+
if key in self._configure_delegate_map:
|
|
108
|
+
handled, value = self._config_delegate_get(key)
|
|
109
|
+
if handled:
|
|
110
|
+
return value
|
|
111
|
+
return super().cget(key)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class CustomConfigMixin(ConfigureDelegationMixin):
|
|
115
|
+
"""Tk-like configure/cget API for non-tkinter classes.
|
|
116
|
+
|
|
117
|
+
Stores arbitrary options locally while still honoring @configure_delegate
|
|
118
|
+
handlers for custom keys. Useful for helper classes that wrap tkinter
|
|
119
|
+
widgets but do not inherit from them directly.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
123
|
+
self._custom_config_store = {}
|
|
124
|
+
super().__init__(*args, **kwargs)
|
|
125
|
+
|
|
126
|
+
def _all_option_keys(self):
|
|
127
|
+
"""Return all known option keys."""
|
|
128
|
+
return set(self._custom_config_store.keys()) | set(self._configure_delegate_map.keys())
|
|
129
|
+
|
|
130
|
+
def configure(self, cnf=None, **kwargs):
|
|
131
|
+
"""Set or query options using a tkinter-compatible shape."""
|
|
132
|
+
# allow dict passthrough like tkinter
|
|
133
|
+
if isinstance(cnf, dict):
|
|
134
|
+
kwargs.update(cnf)
|
|
135
|
+
cnf = None
|
|
136
|
+
|
|
137
|
+
# Handle delegated setters first
|
|
138
|
+
if kwargs:
|
|
139
|
+
for _k in list(kwargs.keys()):
|
|
140
|
+
if _k in self._configure_delegate_map:
|
|
141
|
+
if self._config_delegate_set(_k, kwargs[_k]):
|
|
142
|
+
kwargs.pop(_k, None)
|
|
143
|
+
|
|
144
|
+
# Store any remaining options
|
|
145
|
+
for key, value in kwargs.items():
|
|
146
|
+
self._custom_config_store[key] = value
|
|
147
|
+
|
|
148
|
+
# Getter semantics
|
|
149
|
+
if cnf is None:
|
|
150
|
+
return {
|
|
151
|
+
key: (key, key, key.capitalize(), None, self.cget(key))
|
|
152
|
+
for key in self._all_option_keys()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if isinstance(cnf, str):
|
|
156
|
+
return (cnf, cnf, cnf.capitalize(), None, self.cget(cnf))
|
|
157
|
+
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
config = configure
|
|
161
|
+
|
|
162
|
+
def __setitem__(self, key, value):
|
|
163
|
+
"""Set option via dictionary style."""
|
|
164
|
+
if key in self._configure_delegate_map:
|
|
165
|
+
if self._config_delegate_set(key, value):
|
|
166
|
+
return
|
|
167
|
+
self._custom_config_store[key] = value
|
|
168
|
+
|
|
169
|
+
def __getitem__(self, key):
|
|
170
|
+
"""Get option via dictionary style."""
|
|
171
|
+
if key in self._configure_delegate_map:
|
|
172
|
+
handled, value = self._config_delegate_get(key)
|
|
173
|
+
if handled:
|
|
174
|
+
return value
|
|
175
|
+
return self._custom_config_store.get(key)
|
|
176
|
+
|
|
177
|
+
def cget(self, key):
|
|
178
|
+
"""Return the current value for an option."""
|
|
179
|
+
if key in self._configure_delegate_map:
|
|
180
|
+
handled, value = self._config_delegate_get(key)
|
|
181
|
+
if handled:
|
|
182
|
+
return value
|
|
183
|
+
return self._custom_config_store.get(key)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
__all__ = ["configure_delegate", "ConfigureDelegationMixin", "CustomConfigMixin"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from bootstack.widgets.parts.numberentry_part import NumberEntryPart
|
|
6
|
+
from bootstack.widgets.parts.numberentry_part import TextEntryPart
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EntryMixin:
|
|
10
|
+
"""A mixin that exposes the functionality of entry-like widgets on composite widgets"""
|
|
11
|
+
|
|
12
|
+
_entry: TextEntryPart | NumberEntryPart
|
|
13
|
+
|
|
14
|
+
def __init__(self, *args, **kwargs):
|
|
15
|
+
super().__init__(*args, **kwargs)
|
|
16
|
+
|
|
17
|
+
def bbox(self, index):
|
|
18
|
+
"""Return the bounding box of character at index"""
|
|
19
|
+
return self._entry.bbox(index)
|
|
20
|
+
|
|
21
|
+
def delete(self, first, last):
|
|
22
|
+
"""Delete text between indices"""
|
|
23
|
+
return self._entry.delete(first, last)
|
|
24
|
+
|
|
25
|
+
def insert(self, index, text):
|
|
26
|
+
"""Insert text at index"""
|
|
27
|
+
return self._entry.insert(index, text)
|
|
28
|
+
|
|
29
|
+
def icursor(self, index):
|
|
30
|
+
"""Set the cursor position"""
|
|
31
|
+
self._entry.icursor(index)
|
|
32
|
+
|
|
33
|
+
def index(self, index="insert"):
|
|
34
|
+
"""Return the character at index (defaults to 'cursor')"""
|
|
35
|
+
return self._entry.index(index)
|
|
36
|
+
|
|
37
|
+
def scan_mark(self, x):
|
|
38
|
+
"""Start drag-to-scroll behavior"""
|
|
39
|
+
return self._entry.scan_mark(x)
|
|
40
|
+
|
|
41
|
+
def scan_dragto(self, x):
|
|
42
|
+
"""Continue drag-to-scroll behavior"""
|
|
43
|
+
return self._entry.scan_dragto(x)
|
|
44
|
+
|
|
45
|
+
def selection_adjust(self, index):
|
|
46
|
+
"""Adjust selection endpoint"""
|
|
47
|
+
return self._entry.selection_adjust(index)
|
|
48
|
+
|
|
49
|
+
def selection_clear(self):
|
|
50
|
+
"""Clear text selection"""
|
|
51
|
+
return self._entry.selection_clear()
|
|
52
|
+
|
|
53
|
+
def selection_from(self, index):
|
|
54
|
+
"""Select text starting from index"""
|
|
55
|
+
return self._entry.selection_from(index)
|
|
56
|
+
|
|
57
|
+
def selection_to(self, index):
|
|
58
|
+
"""Extend selection to index"""
|
|
59
|
+
return self._entry.selection_to(index)
|
|
60
|
+
|
|
61
|
+
def selection_range(self, first, last):
|
|
62
|
+
"""Select text between first and last"""
|
|
63
|
+
return self._entry.selection_range(first, last)
|
|
64
|
+
|
|
65
|
+
def selection_present(self):
|
|
66
|
+
return self._entry.selection_present()
|
|
67
|
+
|
|
68
|
+
def selection_all(self):
|
|
69
|
+
"""Select all text"""
|
|
70
|
+
return self._entry.selection_range(0, 'end')
|