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,345 @@
|
|
|
1
|
+
"""Numeric entry widget with manual stepping and validation.
|
|
2
|
+
|
|
3
|
+
This module provides a number entry widget that extends TextEntryPart with
|
|
4
|
+
numeric-specific features like min/max bounds, stepping, and keyboard/mouse
|
|
5
|
+
wheel support.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Union
|
|
9
|
+
|
|
10
|
+
from bootstack.widgets.mixins.configure_mixin import configure_delegate
|
|
11
|
+
from bootstack.widgets.parts.textentry_part import TextEntryPart
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class NumberEntryPart(TextEntryPart):
|
|
15
|
+
"""Numeric entry widget with stepping and bounds validation.
|
|
16
|
+
|
|
17
|
+
Extends TextEntryPart to provide numeric input with constraints and
|
|
18
|
+
stepping functionality. Supports min/max bounds, increment/decrement
|
|
19
|
+
via keyboard and mouse wheel, and optional wrapping.
|
|
20
|
+
|
|
21
|
+
!!! note "Events"
|
|
22
|
+
- `<<Increment>>`: Fired when an increment is requested (before step occurs). `event.data = {'value': current_value}`
|
|
23
|
+
- `<<Decrement>>`: Fired when a decrement is requested (before step occurs). `event.data = {'value': current_value}`
|
|
24
|
+
- Plus all events from TextEntryPart: `<<Input>>`, `<<Change>>`, `<Return>`
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
master=None,
|
|
30
|
+
*,
|
|
31
|
+
value: Union[int, float, str] = 0,
|
|
32
|
+
value_format: str = None,
|
|
33
|
+
minvalue: Union[int, float, None] = None,
|
|
34
|
+
maxvalue: Union[int, float, None] = None,
|
|
35
|
+
increment: Union[int, float] = 1,
|
|
36
|
+
wrap: bool = False,
|
|
37
|
+
initial_focus: bool = False,
|
|
38
|
+
allow_blank: bool = True,
|
|
39
|
+
**kwargs
|
|
40
|
+
):
|
|
41
|
+
"""Initialize a NumberEntryPart widget.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
master: Parent widget
|
|
45
|
+
value: Initial numeric value (int, float, string, or None)
|
|
46
|
+
value_format: Number format specification for IntlFormatter.
|
|
47
|
+
Examples: 'decimal', 'percent', 'currency', '#,##0.00', etc.
|
|
48
|
+
minvalue: Minimum allowed value (inclusive), or None for no lower bound
|
|
49
|
+
maxvalue: Maximum allowed value (inclusive), or None for no upper bound
|
|
50
|
+
increment: Step size for increment/decrement operations
|
|
51
|
+
wrap: If True, values wrap around at min/max boundaries.
|
|
52
|
+
If False, values are clamped at boundaries.
|
|
53
|
+
initial_focus: If True, widget receives focus on creation
|
|
54
|
+
allow_blank: If True, empty input is allowed (sets value to None)
|
|
55
|
+
locale: Locale identifier for number formatting (e.g., 'en_US')
|
|
56
|
+
**kwargs: Additional keyword arguments passed to TextEntryPart
|
|
57
|
+
"""
|
|
58
|
+
# Store numeric configuration
|
|
59
|
+
self._minvalue = minvalue
|
|
60
|
+
self._maxvalue = maxvalue
|
|
61
|
+
self._increment = increment
|
|
62
|
+
self._wrap = wrap
|
|
63
|
+
|
|
64
|
+
# Determine numeric type (float if any parameter is float)
|
|
65
|
+
def _has_fractional(x: Union[int, float, None]) -> bool:
|
|
66
|
+
if x is None:
|
|
67
|
+
return False
|
|
68
|
+
if isinstance(x, float):
|
|
69
|
+
return True
|
|
70
|
+
if isinstance(x, (int, float)) and float(x) != int(x):
|
|
71
|
+
return True
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
self._num_type = float if any(
|
|
75
|
+
_has_fractional(x) for x in (
|
|
76
|
+
minvalue, maxvalue, increment,
|
|
77
|
+
value if not isinstance(value, str) else 0
|
|
78
|
+
)
|
|
79
|
+
) else int
|
|
80
|
+
|
|
81
|
+
# Initialize base TextEntryPart
|
|
82
|
+
# Convert initial value to appropriate type
|
|
83
|
+
if isinstance(value, str):
|
|
84
|
+
initial_value = value
|
|
85
|
+
else:
|
|
86
|
+
initial_value = None if value is None else self._num_type(value)
|
|
87
|
+
|
|
88
|
+
super().__init__(
|
|
89
|
+
master=master,
|
|
90
|
+
value=initial_value,
|
|
91
|
+
value_format=value_format,
|
|
92
|
+
initial_focus=initial_focus,
|
|
93
|
+
allow_blank=allow_blank,
|
|
94
|
+
**kwargs
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Apply bounds to initial value
|
|
98
|
+
if self._value is not None:
|
|
99
|
+
self._value = self._apply_bounds(float(self._value))
|
|
100
|
+
if self._num_type is int:
|
|
101
|
+
self._value = int(round(self._value))
|
|
102
|
+
# Update display with bounded value
|
|
103
|
+
formatted_text = self._format_value(self._value)
|
|
104
|
+
self.textsignal.set(formatted_text)
|
|
105
|
+
self._prev_changed_value = self._value
|
|
106
|
+
|
|
107
|
+
# Bind keyboard stepping (Up/Down arrows)
|
|
108
|
+
self.bind('<Up>', self._handle_up_key, add=True)
|
|
109
|
+
self.bind('<Down>', self._handle_down_key, add=True)
|
|
110
|
+
|
|
111
|
+
# Bind mouse wheel (Windows/macOS)
|
|
112
|
+
self.bind('<MouseWheel>', self._handle_mouse_wheel, add=True)
|
|
113
|
+
|
|
114
|
+
# Bind mouse wheel (Linux/X11)
|
|
115
|
+
self.bind('<Button-4>', self._handle_wheel_up, add=True)
|
|
116
|
+
self.bind('<Button-5>', self._handle_wheel_down, add=True)
|
|
117
|
+
|
|
118
|
+
# Listen for increment/decrement events to invoke step
|
|
119
|
+
self.bind('<<Increment>>', self._handle_increment_event, add=True)
|
|
120
|
+
self.bind('<<Decrement>>', self._handle_decrement_event, add=True)
|
|
121
|
+
|
|
122
|
+
def _handle_up_key(self, event):
|
|
123
|
+
"""Handle Up arrow key press - emit increment event."""
|
|
124
|
+
if not self._is_interactive():
|
|
125
|
+
return 'break'
|
|
126
|
+
self.event_generate('<<Increment>>', data={'value': self._value})
|
|
127
|
+
return 'break' # Prevent default behavior
|
|
128
|
+
|
|
129
|
+
def _handle_down_key(self, event):
|
|
130
|
+
"""Handle Down arrow key press - emit decrement event."""
|
|
131
|
+
if not self._is_interactive():
|
|
132
|
+
return 'break'
|
|
133
|
+
self.event_generate('<<Decrement>>', data={'value': self._value})
|
|
134
|
+
return 'break' # Prevent default behavior
|
|
135
|
+
|
|
136
|
+
def _handle_mouse_wheel(self, event):
|
|
137
|
+
"""Handle mouse wheel on Windows/macOS."""
|
|
138
|
+
if not self._is_interactive():
|
|
139
|
+
return 'break'
|
|
140
|
+
try:
|
|
141
|
+
delta = int(event.delta)
|
|
142
|
+
except (AttributeError, ValueError):
|
|
143
|
+
delta = 0
|
|
144
|
+
|
|
145
|
+
if delta != 0:
|
|
146
|
+
if delta > 0:
|
|
147
|
+
self.event_generate('<<Increment>>', data={'value': self._value})
|
|
148
|
+
else:
|
|
149
|
+
self.event_generate('<<Decrement>>', data={'value': self._value})
|
|
150
|
+
return 'break'
|
|
151
|
+
|
|
152
|
+
def _handle_wheel_up(self, event):
|
|
153
|
+
"""Handle mouse wheel up on Linux/X11."""
|
|
154
|
+
if not self._is_interactive():
|
|
155
|
+
return 'break'
|
|
156
|
+
self.event_generate('<<Increment>>', data={'value': self._value})
|
|
157
|
+
return 'break'
|
|
158
|
+
|
|
159
|
+
def _handle_wheel_down(self, event):
|
|
160
|
+
"""Handle mouse wheel down on Linux/X11."""
|
|
161
|
+
if not self._is_interactive():
|
|
162
|
+
return 'break'
|
|
163
|
+
self.event_generate('<<Decrement>>', data={'value': self._value})
|
|
164
|
+
return 'break'
|
|
165
|
+
|
|
166
|
+
def _handle_increment_event(self, event):
|
|
167
|
+
"""Handle <<Increment>> event by stepping up."""
|
|
168
|
+
if not self._is_interactive():
|
|
169
|
+
return 'break'
|
|
170
|
+
self.step(+1)
|
|
171
|
+
|
|
172
|
+
def _handle_decrement_event(self, event):
|
|
173
|
+
"""Handle <<Decrement>> event by stepping down."""
|
|
174
|
+
if not self._is_interactive():
|
|
175
|
+
return 'break'
|
|
176
|
+
self.step(-1)
|
|
177
|
+
|
|
178
|
+
def _apply_bounds(self, x: float) -> float:
|
|
179
|
+
"""Apply min/max bounds with optional wrapping."""
|
|
180
|
+
lo = float(self._minvalue) if self._minvalue is not None else None
|
|
181
|
+
hi = float(self._maxvalue) if self._maxvalue is not None else None
|
|
182
|
+
|
|
183
|
+
if self._wrap and lo is not None and hi is not None:
|
|
184
|
+
if hi <= lo:
|
|
185
|
+
return lo
|
|
186
|
+
|
|
187
|
+
span = hi - lo
|
|
188
|
+
while x < lo:
|
|
189
|
+
x += span
|
|
190
|
+
while x > hi:
|
|
191
|
+
x -= span
|
|
192
|
+
return x
|
|
193
|
+
|
|
194
|
+
if lo is not None and x < lo:
|
|
195
|
+
x = lo
|
|
196
|
+
if hi is not None and x > hi:
|
|
197
|
+
x = hi
|
|
198
|
+
|
|
199
|
+
return x
|
|
200
|
+
|
|
201
|
+
def _is_interactive(self) -> bool:
|
|
202
|
+
"""Return True if the widget is not readonly or disabled."""
|
|
203
|
+
current_states = self.state()
|
|
204
|
+
return 'disabled' not in current_states and 'readonly' not in current_states
|
|
205
|
+
|
|
206
|
+
def step(self, n: int = 1):
|
|
207
|
+
"""Increment or decrement value by n steps."""
|
|
208
|
+
if not self._is_interactive():
|
|
209
|
+
return self
|
|
210
|
+
# Get current value (default to min if None)
|
|
211
|
+
current = self._value
|
|
212
|
+
if current is None:
|
|
213
|
+
base = float(self._minvalue) if self._minvalue is not None else 0.0
|
|
214
|
+
else:
|
|
215
|
+
base = float(current)
|
|
216
|
+
|
|
217
|
+
# Calculate new value
|
|
218
|
+
new_value = base + float(self._increment) * float(n)
|
|
219
|
+
|
|
220
|
+
# Apply bounds/wrapping
|
|
221
|
+
new_value = self._apply_bounds(new_value)
|
|
222
|
+
|
|
223
|
+
# Coerce to desired type
|
|
224
|
+
if self._num_type is float:
|
|
225
|
+
coerced = float(new_value)
|
|
226
|
+
else:
|
|
227
|
+
coerced = int(round(new_value))
|
|
228
|
+
|
|
229
|
+
# Store previous value for change detection
|
|
230
|
+
prev_value = self._value
|
|
231
|
+
|
|
232
|
+
# Update internal value
|
|
233
|
+
self._value = coerced
|
|
234
|
+
|
|
235
|
+
# Update display
|
|
236
|
+
self._normalize_display_from_value()
|
|
237
|
+
|
|
238
|
+
# Emit changed event if value actually changed
|
|
239
|
+
if self._value != prev_value:
|
|
240
|
+
self._prev_changed_value = self._value
|
|
241
|
+
self.event_generate(
|
|
242
|
+
'<<Change>>', data={
|
|
243
|
+
"value": self._value,
|
|
244
|
+
"prev_value": prev_value,
|
|
245
|
+
"text": self.textsignal.get()
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
return self
|
|
249
|
+
|
|
250
|
+
def _normalize_display_from_value(self):
|
|
251
|
+
"""Update display text from internal value without triggering input events."""
|
|
252
|
+
# Format the value
|
|
253
|
+
new_text = self._format_value(self._value)
|
|
254
|
+
|
|
255
|
+
# Only update if text changed
|
|
256
|
+
if new_text != self.textsignal.get():
|
|
257
|
+
# Temporarily unsubscribe from input signal to avoid spurious events
|
|
258
|
+
fid = getattr(self, '_on_input_fid', None)
|
|
259
|
+
if fid:
|
|
260
|
+
try:
|
|
261
|
+
self.textsignal.unsubscribe(fid)
|
|
262
|
+
except Exception:
|
|
263
|
+
pass
|
|
264
|
+
|
|
265
|
+
# Update display
|
|
266
|
+
self.textsignal.set(new_text)
|
|
267
|
+
|
|
268
|
+
# Re-subscribe to input signal
|
|
269
|
+
if fid:
|
|
270
|
+
self._on_input_fid = self.textsignal.subscribe(self._handle_change)
|
|
271
|
+
|
|
272
|
+
def commit(self):
|
|
273
|
+
"""Override commit to apply bounds validation after parsing.
|
|
274
|
+
|
|
275
|
+
This ensures user-entered values are constrained to valid range.
|
|
276
|
+
"""
|
|
277
|
+
# Call parent commit to parse and format
|
|
278
|
+
super().commit()
|
|
279
|
+
|
|
280
|
+
# Apply bounds to the parsed value
|
|
281
|
+
if self._value is not None:
|
|
282
|
+
bounded_value = self._apply_bounds(float(self._value))
|
|
283
|
+
|
|
284
|
+
# Coerce to appropriate type
|
|
285
|
+
if self._num_type is float:
|
|
286
|
+
self._value = float(bounded_value)
|
|
287
|
+
else:
|
|
288
|
+
self._value = int(round(bounded_value))
|
|
289
|
+
|
|
290
|
+
# Update display if value changed due to bounds
|
|
291
|
+
self._normalize_display_from_value()
|
|
292
|
+
|
|
293
|
+
def on_increment(self, callback) -> str:
|
|
294
|
+
"""Bind to `<<Increment>>`. Callback receives `event.data = {'value': current_value}`."""
|
|
295
|
+
return self.bind('<<Increment>>', callback, add=True)
|
|
296
|
+
|
|
297
|
+
def off_increment(self, bind_id: str | None = None) -> None:
|
|
298
|
+
"""Unbind from `<<Increment>>`."""
|
|
299
|
+
self.unbind('<<Increment>>', bind_id)
|
|
300
|
+
|
|
301
|
+
def on_decrement(self, callback) -> str:
|
|
302
|
+
"""Bind to `<<Decrement>>`. Callback receives `event.data = {'value': current_value}`."""
|
|
303
|
+
return self.bind('<<Decrement>>', callback, add=True)
|
|
304
|
+
|
|
305
|
+
def off_decrement(self, bind_id: str | None = None) -> None:
|
|
306
|
+
"""Unbind from `<<Decrement>>`."""
|
|
307
|
+
self.unbind('<<Decrement>>', bind_id)
|
|
308
|
+
|
|
309
|
+
@configure_delegate('minvalue')
|
|
310
|
+
def _delegate_minvalue(self, value: Union[int, float]):
|
|
311
|
+
"""Get or set the minimum allowed value and re-validate current value."""
|
|
312
|
+
if value is None:
|
|
313
|
+
return self._minvalue
|
|
314
|
+
|
|
315
|
+
self._minvalue = value
|
|
316
|
+
if self._value is not None:
|
|
317
|
+
self._value = self._apply_bounds(float(self._value))
|
|
318
|
+
self._normalize_display_from_value()
|
|
319
|
+
|
|
320
|
+
@configure_delegate('maxvalue')
|
|
321
|
+
def _delegate_maxvalue(self, value: Union[int, float]):
|
|
322
|
+
"""Get or set the maximum allowed value and re-validate current value."""
|
|
323
|
+
if value is None:
|
|
324
|
+
return self._maxvalue
|
|
325
|
+
|
|
326
|
+
self._maxvalue = value
|
|
327
|
+
if self._value is not None:
|
|
328
|
+
self._value = self._apply_bounds(float(self._value))
|
|
329
|
+
self._normalize_display_from_value()
|
|
330
|
+
|
|
331
|
+
@configure_delegate('increment')
|
|
332
|
+
def _delegate_increment(self, value: Union[int, float]):
|
|
333
|
+
"""Get or set the step increment value."""
|
|
334
|
+
if value is None:
|
|
335
|
+
return self._increment
|
|
336
|
+
|
|
337
|
+
self._increment = value
|
|
338
|
+
|
|
339
|
+
@configure_delegate('wrap')
|
|
340
|
+
def _delegate_wrap(self, value: bool):
|
|
341
|
+
"""Get or set the wrap setting."""
|
|
342
|
+
if value is None:
|
|
343
|
+
return self._wrap
|
|
344
|
+
|
|
345
|
+
self._wrap = bool(value)
|