bootstack 0.1.0__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 +157 -0
- bootstack/__main__.py +5 -0
- bootstack/_core/__init__.py +21 -0
- bootstack/_core/capabilities/__init__.py +45 -0
- bootstack/_core/capabilities/after.py +103 -0
- bootstack/_core/capabilities/bind.py +192 -0
- bootstack/_core/capabilities/bindtags.py +112 -0
- bootstack/_core/capabilities/busy.py +72 -0
- bootstack/_core/capabilities/clipboard.py +89 -0
- bootstack/_core/capabilities/focus.py +118 -0
- bootstack/_core/capabilities/grab.py +65 -0
- bootstack/_core/capabilities/grid.py +211 -0
- bootstack/_core/capabilities/localization.py +231 -0
- bootstack/_core/capabilities/pack.py +140 -0
- bootstack/_core/capabilities/place.py +113 -0
- bootstack/_core/capabilities/selection.py +136 -0
- bootstack/_core/capabilities/signals.py +244 -0
- bootstack/_core/capabilities/winfo.py +315 -0
- bootstack/_core/colorutils.py +234 -0
- bootstack/_core/exceptions.py +25 -0
- bootstack/_core/images.py +463 -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/paths.py +49 -0
- bootstack/_core/publisher.py +149 -0
- bootstack/_core/variables.py +62 -0
- bootstack/_runtime/__init__.py +3 -0
- bootstack/_runtime/app.py +930 -0
- bootstack/_runtime/base_window.py +945 -0
- bootstack/_runtime/events.py +399 -0
- bootstack/_runtime/shortcuts.py +496 -0
- bootstack/_runtime/tk_patch.py +43 -0
- bootstack/_runtime/toplevel.py +276 -0
- bootstack/_runtime/utility.py +457 -0
- bootstack/_runtime/visual_focus.py +240 -0
- bootstack/_runtime/window_utilities.py +1123 -0
- bootstack/assets/__init__.py +21 -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/button-compact.png +0 -0
- bootstack/assets/elements/button-default.png +0 -0
- bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
- bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
- bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
- bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
- bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
- bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
- bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
- bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
- bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
- bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
- bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
- bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
- bootstack/assets/elements/card.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-addon-compact.png +0 -0
- bootstack/assets/elements/input-addon-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/listrow-compact.png +0 -0
- bootstack/assets/elements/listrow-default.png +0 -0
- bootstack/assets/elements/manifest.toml +361 -0
- bootstack/assets/elements/menu-item.png +0 -0
- bootstack/assets/elements/navitem-compact.png +0 -0
- bootstack/assets/elements/navitem-default.png +0 -0
- bootstack/assets/elements/progressbar-h-compact.png +0 -0
- bootstack/assets/elements/progressbar-h-default.png +0 -0
- bootstack/assets/elements/progressbar-v-compact.png +0 -0
- bootstack/assets/elements/progressbar-v-default.png +0 -0
- bootstack/assets/elements/radiobutton.png +0 -0
- bootstack/assets/elements/scrollbar-horizontal.png +0 -0
- bootstack/assets/elements/scrollbar-vertical.png +0 -0
- bootstack/assets/elements/slider-handle.png +0 -0
- bootstack/assets/elements/slider-track-h.png +0 -0
- bootstack/assets/elements/slider-track-v.png +0 -0
- bootstack/assets/elements/switch-off.png +0 -0
- bootstack/assets/elements/switch-on.png +0 -0
- bootstack/assets/elements/tab-h.png +0 -0
- bootstack/assets/elements/tab-v.png +0 -0
- bootstack/assets/icons/bootstrap.ttf +0 -0
- bootstack/assets/icons/glyphmap.json +2080 -0
- bootstack/assets/icons/icon_metrics.json +12470 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +878 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +878 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +854 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +844 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +917 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +844 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +844 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +845 -0
- bootstack/cli/__init__.py +133 -0
- bootstack/cli/__main__.py +6 -0
- bootstack/cli/add.py +395 -0
- bootstack/cli/appicon.py +285 -0
- bootstack/cli/build.py +115 -0
- bootstack/cli/config.py +313 -0
- bootstack/cli/demo.py +564 -0
- bootstack/cli/dev.py +153 -0
- bootstack/cli/doctor.py +195 -0
- bootstack/cli/icons.py +98 -0
- bootstack/cli/promote.py +120 -0
- bootstack/cli/pyinstaller.py +268 -0
- bootstack/cli/run.py +95 -0
- bootstack/cli/start.py +117 -0
- bootstack/cli/templates/__init__.py +931 -0
- bootstack/clipboard.py +48 -0
- bootstack/constants.py +318 -0
- bootstack/data/README.md +615 -0
- bootstack/data/__init__.py +78 -0
- bootstack/data/_observable.py +276 -0
- bootstack/data/base.py +780 -0
- bootstack/data/file_source.py +367 -0
- bootstack/data/memory_source.py +450 -0
- bootstack/data/query.py +367 -0
- bootstack/data/readers.py +289 -0
- bootstack/data/sqlite_source.py +869 -0
- bootstack/data/types.py +354 -0
- bootstack/data/writers.py +232 -0
- bootstack/dev/__init__.py +36 -0
- bootstack/dev/_capture.py +141 -0
- bootstack/dev/_env.py +43 -0
- bootstack/dev/_registry.py +140 -0
- bootstack/dev/_reloader.py +351 -0
- bootstack/dev/_reset.py +50 -0
- bootstack/dev/_watcher.py +91 -0
- bootstack/dialogs/__init__.py +948 -0
- bootstack/dialogs/_impl/__init__.py +47 -0
- bootstack/dialogs/_impl/colorchooser.py +588 -0
- bootstack/dialogs/_impl/datedialog.py +450 -0
- bootstack/dialogs/_impl/dialog.py +594 -0
- bootstack/dialogs/_impl/filterdialog.py +358 -0
- bootstack/dialogs/_impl/fontdialog.py +364 -0
- bootstack/dialogs/_impl/formdialog.py +564 -0
- bootstack/dialogs/_impl/message.py +486 -0
- bootstack/dialogs/_impl/query.py +570 -0
- bootstack/errors.py +67 -0
- bootstack/events/__init__.py +111 -0
- bootstack/events/_event.py +135 -0
- bootstack/events/_payloads.py +539 -0
- bootstack/events/_subscription.py +38 -0
- bootstack/i18n/README.md +77 -0
- bootstack/i18n/__init__.py +23 -0
- bootstack/i18n/catalog.py +121 -0
- bootstack/i18n/intl_format.py +584 -0
- bootstack/i18n/msgcat.py +425 -0
- bootstack/i18n/specs.py +156 -0
- bootstack/images.py +563 -0
- bootstack/py.typed +1 -0
- bootstack/scheduling/__init__.py +11 -0
- bootstack/scheduling/_schedule.py +218 -0
- bootstack/shortcuts.py +21 -0
- bootstack/signals/README.md +98 -0
- bootstack/signals/__init__.py +10 -0
- bootstack/signals/integration.py +100 -0
- bootstack/signals/signal.py +353 -0
- bootstack/signals/types.py +6 -0
- bootstack/store.py +286 -0
- bootstack/streams/__init__.py +12 -0
- bootstack/streams/_stream.py +321 -0
- bootstack/style/__init__.py +38 -0
- bootstack/style/builders/__init__.py +51 -0
- bootstack/style/builders/badge.py +46 -0
- bootstack/style/builders/button.py +339 -0
- bootstack/style/builders/buttongroup.py +311 -0
- bootstack/style/builders/calendar.py +271 -0
- bootstack/style/builders/checkbutton.py +110 -0
- bootstack/style/builders/combobox.py +113 -0
- bootstack/style/builders/contextmenu.py +268 -0
- bootstack/style/builders/entry.py +82 -0
- bootstack/style/builders/expander.py +148 -0
- bootstack/style/builders/field.py +335 -0
- bootstack/style/builders/frame.py +50 -0
- bootstack/style/builders/label.py +28 -0
- bootstack/style/builders/labelframe.py +34 -0
- bootstack/style/builders/listview.py +369 -0
- bootstack/style/builders/menubar.py +91 -0
- bootstack/style/builders/menubutton.py +359 -0
- bootstack/style/builders/panedwindow.py +25 -0
- bootstack/style/builders/progressbar.py +67 -0
- bootstack/style/builders/radiobutton.py +99 -0
- bootstack/style/builders/scale.py +64 -0
- bootstack/style/builders/scrollbar.py +225 -0
- bootstack/style/builders/separator.py +49 -0
- bootstack/style/builders/sidenav.py +643 -0
- bootstack/style/builders/sizegrip.py +15 -0
- bootstack/style/builders/spinbox.py +119 -0
- bootstack/style/builders/switch.py +70 -0
- bootstack/style/builders/tabitem.py +204 -0
- bootstack/style/builders/togglegroup.py +294 -0
- bootstack/style/builders/toolbutton.py +275 -0
- bootstack/style/builders/tooltip.py +26 -0
- bootstack/style/builders/treeview.py +193 -0
- bootstack/style/builders/utils.py +455 -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/fonts.py +123 -0
- bootstack/style/style.py +609 -0
- bootstack/style/style_builder_base.py +716 -0
- bootstack/style/style_builder_mixed.py +93 -0
- bootstack/style/style_builder_tk.py +109 -0
- bootstack/style/style_builder_ttk.py +353 -0
- bootstack/style/style_resolver.py +447 -0
- bootstack/style/theme.py +245 -0
- bootstack/style/theme_provider.py +471 -0
- bootstack/style/themes/__init__.py +128 -0
- bootstack/style/tk_patch.py +5 -0
- bootstack/style/token_maps.py +41 -0
- bootstack/style/types.py +32 -0
- bootstack/style/typography.py +523 -0
- bootstack/style/utility.py +746 -0
- bootstack/types.py +39 -0
- bootstack/validation/__init__.py +6 -0
- bootstack/validation/types.py +15 -0
- bootstack/validation/validation_result.py +17 -0
- bootstack/validation/validation_rules.py +205 -0
- bootstack/widgets/__init__.py +74 -0
- bootstack/widgets/_core/__init__.py +31 -0
- bootstack/widgets/_core/app_config.py +266 -0
- bootstack/widgets/_core/base.py +461 -0
- bootstack/widgets/_core/container.py +334 -0
- bootstack/widgets/_core/context.py +35 -0
- bootstack/widgets/_core/events.py +130 -0
- bootstack/widgets/_core/field_mixin.py +353 -0
- bootstack/widgets/_core/icon_image_props.py +72 -0
- bootstack/widgets/_core/image_binding.py +93 -0
- bootstack/widgets/_core/navmodel.py +345 -0
- bootstack/widgets/_core/options.py +210 -0
- bootstack/widgets/_core/selection_group.py +130 -0
- bootstack/widgets/_core/window_controls.py +96 -0
- bootstack/widgets/_core/window_menu.py +246 -0
- bootstack/widgets/_impl/__init__.py +1 -0
- bootstack/widgets/_impl/_internal/__init__.py +0 -0
- bootstack/widgets/_impl/_internal/wrapper_base.py +307 -0
- bootstack/widgets/_impl/_parts/__init__.py +11 -0
- bootstack/widgets/_impl/_parts/numberentry_part.py +385 -0
- bootstack/widgets/_impl/_parts/spinnerentry_part.py +434 -0
- bootstack/widgets/_impl/_parts/textentry_part.py +406 -0
- bootstack/widgets/_impl/composites/__init__.py +33 -0
- bootstack/widgets/_impl/composites/_dateutils.py +33 -0
- bootstack/widgets/_impl/composites/_image_fit.py +105 -0
- bootstack/widgets/_impl/composites/accordion.py +381 -0
- bootstack/widgets/_impl/composites/avatar.py +191 -0
- bootstack/widgets/_impl/composites/buttongroup.py +371 -0
- bootstack/widgets/_impl/composites/calendar.py +972 -0
- bootstack/widgets/_impl/composites/carousel.py +567 -0
- bootstack/widgets/_impl/composites/chart.py +882 -0
- bootstack/widgets/_impl/composites/compositeframe.py +298 -0
- bootstack/widgets/_impl/composites/contextmenu.py +1951 -0
- bootstack/widgets/_impl/composites/dateentry.py +404 -0
- bootstack/widgets/_impl/composites/dropdownbutton.py +325 -0
- bootstack/widgets/_impl/composites/expander.py +515 -0
- bootstack/widgets/_impl/composites/field.py +670 -0
- bootstack/widgets/_impl/composites/form.py +1066 -0
- bootstack/widgets/_impl/composites/gallery.py +551 -0
- bootstack/widgets/_impl/composites/list/__init__.py +15 -0
- bootstack/widgets/_impl/composites/list/listitem.py +802 -0
- bootstack/widgets/_impl/composites/list/listview.py +1433 -0
- bootstack/widgets/_impl/composites/menu/__init__.py +18 -0
- bootstack/widgets/_impl/composites/menu/model.py +358 -0
- bootstack/widgets/_impl/composites/menu/render_native.py +134 -0
- bootstack/widgets/_impl/composites/menu/render_themed.py +134 -0
- bootstack/widgets/_impl/composites/meter.py +860 -0
- bootstack/widgets/_impl/composites/numericentry.py +201 -0
- bootstack/widgets/_impl/composites/pagestack.py +395 -0
- bootstack/widgets/_impl/composites/passwordentry.py +142 -0
- bootstack/widgets/_impl/composites/pathentry.py +168 -0
- bootstack/widgets/_impl/composites/picture.py +289 -0
- bootstack/widgets/_impl/composites/radiogroup.py +511 -0
- bootstack/widgets/_impl/composites/scrolledtext.py +375 -0
- bootstack/widgets/_impl/composites/scrolledtext.pyi +186 -0
- bootstack/widgets/_impl/composites/scrollview.py +764 -0
- bootstack/widgets/_impl/composites/selectbox.py +1026 -0
- bootstack/widgets/_impl/composites/shell/__init__.py +40 -0
- bootstack/widgets/_impl/composites/shell/content_host.py +52 -0
- bootstack/widgets/_impl/composites/shell/layout.py +335 -0
- bootstack/widgets/_impl/composites/shell/nav_panel.py +345 -0
- bootstack/widgets/_impl/composites/shell/providers.py +558 -0
- bootstack/widgets/_impl/composites/shell/rail.py +117 -0
- bootstack/widgets/_impl/composites/shell/shell.py +581 -0
- bootstack/widgets/_impl/composites/shell/workspace.py +273 -0
- bootstack/widgets/_impl/composites/sidenav/__init__.py +16 -0
- bootstack/widgets/_impl/composites/sidenav/header.py +81 -0
- bootstack/widgets/_impl/composites/sidenav/separator.py +44 -0
- bootstack/widgets/_impl/composites/slider/__init__.py +7 -0
- bootstack/widgets/_impl/composites/slider/_shared.py +195 -0
- bootstack/widgets/_impl/composites/slider/rangeslider.py +982 -0
- bootstack/widgets/_impl/composites/slider/slider.py +851 -0
- bootstack/widgets/_impl/composites/spinnerentry.py +185 -0
- bootstack/widgets/_impl/composites/tableview/__init__.py +5 -0
- bootstack/widgets/_impl/composites/tableview/tableview.py +3388 -0
- bootstack/widgets/_impl/composites/tableview/types.py +169 -0
- bootstack/widgets/_impl/composites/tabs/__init__.py +23 -0
- bootstack/widgets/_impl/composites/tabs/tabitem.py +389 -0
- bootstack/widgets/_impl/composites/tabs/tabs.py +974 -0
- bootstack/widgets/_impl/composites/tabs/tabview.py +650 -0
- bootstack/widgets/_impl/composites/textarea/__init__.py +26 -0
- bootstack/widgets/_impl/composites/textarea/change.py +46 -0
- bootstack/widgets/_impl/composites/textarea/codeeditor.py +526 -0
- bootstack/widgets/_impl/composites/textarea/core.py +495 -0
- bootstack/widgets/_impl/composites/textarea/decoration.py +42 -0
- bootstack/widgets/_impl/composites/textarea/diff.py +127 -0
- bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +1 -0
- bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +138 -0
- bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +158 -0
- bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +138 -0
- bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +312 -0
- bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +177 -0
- bootstack/widgets/_impl/composites/textarea/filter.py +171 -0
- bootstack/widgets/_impl/composites/textarea/search_overlay.py +459 -0
- bootstack/widgets/_impl/composites/textarea/sidebar.py +88 -0
- bootstack/widgets/_impl/composites/textarea/style_registry.py +178 -0
- bootstack/widgets/_impl/composites/textarea/textarea.py +606 -0
- bootstack/widgets/_impl/composites/textarea/undo.py +217 -0
- bootstack/widgets/_impl/composites/textentry.py +57 -0
- bootstack/widgets/_impl/composites/timeentry.py +176 -0
- bootstack/widgets/_impl/composites/toast.py +390 -0
- bootstack/widgets/_impl/composites/toast_stack.py +156 -0
- bootstack/widgets/_impl/composites/togglegroup.py +418 -0
- bootstack/widgets/_impl/composites/toolbar.py +608 -0
- bootstack/widgets/_impl/composites/tooltip.py +491 -0
- bootstack/widgets/_impl/composites/tree/__init__.py +7 -0
- bootstack/widgets/_impl/composites/tree/source_binding.py +136 -0
- bootstack/widgets/_impl/composites/tree/treeitem.py +393 -0
- bootstack/widgets/_impl/composites/tree/treenode.py +174 -0
- bootstack/widgets/_impl/composites/tree/treeview.py +841 -0
- bootstack/widgets/_impl/mixins/__init__.py +24 -0
- bootstack/widgets/_impl/mixins/configure_mixin.py +216 -0
- bootstack/widgets/_impl/mixins/entry_mixin.py +134 -0
- bootstack/widgets/_impl/mixins/font_mixin.py +368 -0
- bootstack/widgets/_impl/mixins/icon_mixin.py +61 -0
- bootstack/widgets/_impl/mixins/localization_mixin.py +253 -0
- bootstack/widgets/_impl/mixins/signal_mixin.py +268 -0
- bootstack/widgets/_impl/mixins/validation_mixin.py +226 -0
- bootstack/widgets/_impl/primitives/__init__.py +49 -0
- bootstack/widgets/_impl/primitives/_menubutton.py +107 -0
- bootstack/widgets/_impl/primitives/badge.py +45 -0
- bootstack/widgets/_impl/primitives/button.py +76 -0
- bootstack/widgets/_impl/primitives/card.py +45 -0
- bootstack/widgets/_impl/primitives/checkbutton.py +124 -0
- bootstack/widgets/_impl/primitives/checktoggle.py +62 -0
- bootstack/widgets/_impl/primitives/combobox.py +156 -0
- bootstack/widgets/_impl/primitives/entry.py +87 -0
- bootstack/widgets/_impl/primitives/flexframe.py +448 -0
- bootstack/widgets/_impl/primitives/frame.py +185 -0
- bootstack/widgets/_impl/primitives/gridframe.py +546 -0
- bootstack/widgets/_impl/primitives/label.py +84 -0
- bootstack/widgets/_impl/primitives/labelframe.py +54 -0
- bootstack/widgets/_impl/primitives/optionmenu.py +387 -0
- bootstack/widgets/_impl/primitives/packframe.py +227 -0
- bootstack/widgets/_impl/primitives/panedwindow.py +45 -0
- bootstack/widgets/_impl/primitives/progressbar.py +83 -0
- bootstack/widgets/_impl/primitives/radiobutton.py +115 -0
- bootstack/widgets/_impl/primitives/radiotoggle.py +54 -0
- bootstack/widgets/_impl/primitives/scrollbar.py +42 -0
- bootstack/widgets/_impl/primitives/separator.py +43 -0
- bootstack/widgets/_impl/primitives/sizegrip.py +33 -0
- bootstack/widgets/_impl/primitives/spinbox.py +95 -0
- bootstack/widgets/_impl/primitives/switch.py +44 -0
- bootstack/widgets/_impl/primitives/treeview.py +69 -0
- bootstack/widgets/app.py +371 -0
- bootstack/widgets/appshell.py +1179 -0
- bootstack/widgets/avatar.py +140 -0
- bootstack/widgets/boolean_controls.py +455 -0
- bootstack/widgets/button.py +224 -0
- bootstack/widgets/buttongroup.py +239 -0
- bootstack/widgets/calendar.py +195 -0
- bootstack/widgets/card.py +159 -0
- bootstack/widgets/carousel.py +241 -0
- bootstack/widgets/chart.py +302 -0
- bootstack/widgets/codeeditor.py +675 -0
- bootstack/widgets/contextmenu.py +371 -0
- bootstack/widgets/datatable.py +688 -0
- bootstack/widgets/datefield.py +395 -0
- bootstack/widgets/divider.py +60 -0
- bootstack/widgets/expander.py +579 -0
- bootstack/widgets/form.py +200 -0
- bootstack/widgets/gallery.py +250 -0
- bootstack/widgets/gauge.py +168 -0
- bootstack/widgets/grid.py +121 -0
- bootstack/widgets/groupbox.py +162 -0
- bootstack/widgets/label.py +229 -0
- bootstack/widgets/listview.py +354 -0
- bootstack/widgets/menubutton.py +419 -0
- bootstack/widgets/numberfield.py +431 -0
- bootstack/widgets/pagestack.py +345 -0
- bootstack/widgets/passwordfield.py +383 -0
- bootstack/widgets/pathfield.py +454 -0
- bootstack/widgets/picture.py +251 -0
- bootstack/widgets/progressbar.py +106 -0
- bootstack/widgets/radio_variants.py +271 -0
- bootstack/widgets/radiogroup.py +228 -0
- bootstack/widgets/scrollbar.py +64 -0
- bootstack/widgets/scrollview.py +186 -0
- bootstack/widgets/select.py +302 -0
- bootstack/widgets/selectbutton.py +182 -0
- bootstack/widgets/sidebar_toggle.py +130 -0
- bootstack/widgets/sizegrip.py +42 -0
- bootstack/widgets/slider.py +408 -0
- bootstack/widgets/spinbox.py +147 -0
- bootstack/widgets/spinnerfield.py +413 -0
- bootstack/widgets/splash.py +367 -0
- bootstack/widgets/splitview.py +482 -0
- bootstack/widgets/stacks.py +249 -0
- bootstack/widgets/statusbar.py +189 -0
- bootstack/widgets/tabs.py +425 -0
- bootstack/widgets/textarea.py +459 -0
- bootstack/widgets/textfield.py +410 -0
- bootstack/widgets/theme_toggle.py +92 -0
- bootstack/widgets/timefield.py +340 -0
- bootstack/widgets/toast.py +314 -0
- bootstack/widgets/togglegroup.py +231 -0
- bootstack/widgets/toolbar.py +347 -0
- bootstack/widgets/tooltip.py +94 -0
- bootstack/widgets/tree.py +648 -0
- bootstack/widgets/types.py +305 -0
- bootstack/widgets/window.py +307 -0
- bootstack-0.1.0.dist-info/METADATA +301 -0
- bootstack-0.1.0.dist-info/RECORD +471 -0
- bootstack-0.1.0.dist-info/WHEEL +5 -0
- bootstack-0.1.0.dist-info/entry_points.txt +2 -0
- bootstack-0.1.0.dist-info/licenses/LICENSE +21 -0
- bootstack-0.1.0.dist-info/licenses/NOTICE +10 -0
- bootstack-0.1.0.dist-info/top_level.txt +1 -0
bootstack/__init__.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""bootstack — a Python desktop UI framework.
|
|
2
|
+
|
|
3
|
+
Build modern desktop apps with a clean, Pythonic API. No Tkinter knowledge required.
|
|
4
|
+
|
|
5
|
+
Example:
|
|
6
|
+
```python
|
|
7
|
+
import bootstack as bs
|
|
8
|
+
|
|
9
|
+
with bs.App(title="Hello") as app:
|
|
10
|
+
bs.Label("Hello, world!")
|
|
11
|
+
app.run()
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The top-level `bootstack` namespace holds what you *compose a UI* with: every
|
|
15
|
+
widget, `App`/`AppShell`/`Window`, `Signal`, the dialog verbs
|
|
16
|
+
(`alert`/`confirm`/`ask_*`/`toast`), and `set_theme`/`toggle_theme`.
|
|
17
|
+
Framework primitives you reference *by type to configure behavior* live in
|
|
18
|
+
submodules — for example::
|
|
19
|
+
|
|
20
|
+
from bootstack.data import SqliteDataSource, col
|
|
21
|
+
from bootstack.i18n import L, LV
|
|
22
|
+
from bootstack.validation import ValidationRule
|
|
23
|
+
from bootstack.style import Theme, get_theme_color
|
|
24
|
+
from bootstack.events import Event, Subscription
|
|
25
|
+
from bootstack.images import Image, get_icon, AppIcon
|
|
26
|
+
from bootstack.types import AccentToken
|
|
27
|
+
|
|
28
|
+
See the "API overview" in the documentation for the full map.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
from importlib.metadata import version as _pkg_version
|
|
32
|
+
__version__ = _pkg_version("bootstack")
|
|
33
|
+
except Exception:
|
|
34
|
+
__version__ = "unknown"
|
|
35
|
+
|
|
36
|
+
# ── Runtime patches — must run before widgets are created ─────────────────────
|
|
37
|
+
from bootstack._runtime.tk_patch import install_tk_autostyle as _install_autostyle
|
|
38
|
+
from bootstack._runtime.events import install_enhanced_events as _install_events
|
|
39
|
+
from bootstack._runtime.visual_focus import install_visual_focus as _install_focus
|
|
40
|
+
|
|
41
|
+
_install_autostyle()
|
|
42
|
+
_install_events()
|
|
43
|
+
_install_focus()
|
|
44
|
+
|
|
45
|
+
# ── Reactive state ────────────────────────────────────────────────────────────
|
|
46
|
+
from bootstack.signals import Signal
|
|
47
|
+
|
|
48
|
+
# ── Theme switching (full theming API lives in `bootstack.style`) ─────────────
|
|
49
|
+
from bootstack.style import set_theme, toggle_theme
|
|
50
|
+
|
|
51
|
+
# ── Dialog verbs (dialog classes live in `bootstack.dialogs`) ─────────────────
|
|
52
|
+
from bootstack.dialogs import (
|
|
53
|
+
alert, confirm, ask_string, ask_integer, ask_float,
|
|
54
|
+
ask_date, ask_date_range, ask_item,
|
|
55
|
+
ask_color, ask_font, ask_filter,
|
|
56
|
+
ask_save_file, ask_open_file, ask_open_files, ask_directory,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# ── Application & windows ─────────────────────────────────────────────────────
|
|
60
|
+
from bootstack.widgets.app import App
|
|
61
|
+
from bootstack.widgets.appshell import AppShell, Workbench
|
|
62
|
+
from bootstack.widgets.window import Window
|
|
63
|
+
from bootstack.widgets.splash import Splash
|
|
64
|
+
|
|
65
|
+
# ── Public widget layer ───────────────────────────────────────────────────────
|
|
66
|
+
from bootstack.widgets.stacks import Row, Column, Spacer
|
|
67
|
+
from bootstack.widgets.grid import Grid
|
|
68
|
+
from bootstack.widgets.boolean_controls import Checkbox, Switch, ToggleButton
|
|
69
|
+
from bootstack.widgets.theme_toggle import ThemeToggle
|
|
70
|
+
from bootstack.widgets.button import Button
|
|
71
|
+
from bootstack.widgets.card import Card
|
|
72
|
+
from bootstack.widgets.buttongroup import ButtonGroup
|
|
73
|
+
from bootstack.widgets.codeeditor import CodeEditor
|
|
74
|
+
from bootstack.widgets.contextmenu import ContextMenu, ContextMenuItem
|
|
75
|
+
from bootstack.widgets.datefield import DateField
|
|
76
|
+
from bootstack.widgets.expander import Accordion, AccordionSection
|
|
77
|
+
from bootstack.widgets.gauge import Gauge
|
|
78
|
+
from bootstack.widgets.groupbox import GroupBox
|
|
79
|
+
from bootstack.widgets.label import Badge, Label
|
|
80
|
+
from bootstack.widgets.listview import ListView
|
|
81
|
+
from bootstack.widgets.menubutton import MenuButton
|
|
82
|
+
from bootstack.widgets.numberfield import NumberField
|
|
83
|
+
from bootstack.widgets.pagestack import PageStack, StackPage
|
|
84
|
+
from bootstack.widgets.pathfield import PathField
|
|
85
|
+
from bootstack.widgets.avatar import Avatar
|
|
86
|
+
from bootstack.widgets.carousel import Carousel
|
|
87
|
+
from bootstack.widgets.chart import Chart
|
|
88
|
+
from bootstack.widgets.gallery import Gallery
|
|
89
|
+
from bootstack.widgets.passwordfield import PasswordField
|
|
90
|
+
from bootstack.widgets.picture import Picture
|
|
91
|
+
from bootstack.widgets.progressbar import ProgressBar
|
|
92
|
+
from bootstack.widgets.radio_variants import Radio, RadioToggleButton
|
|
93
|
+
from bootstack.widgets.radiogroup import RadioGroup
|
|
94
|
+
from bootstack.widgets.scrollview import ScrollView
|
|
95
|
+
from bootstack.widgets.select import Select
|
|
96
|
+
from bootstack.widgets.selectbutton import SelectButton
|
|
97
|
+
from bootstack.widgets.divider import Divider
|
|
98
|
+
from bootstack.widgets.splitview import SplitView, SplitPane
|
|
99
|
+
from bootstack.widgets.slider import RangeSlider, Slider
|
|
100
|
+
from bootstack.widgets.spinnerfield import SpinnerField
|
|
101
|
+
from bootstack.widgets.datatable import DataTable
|
|
102
|
+
from bootstack.widgets.tabs import TabPage, Tabs
|
|
103
|
+
from bootstack.widgets.textarea import TextArea
|
|
104
|
+
from bootstack.widgets.timefield import TimeField
|
|
105
|
+
from bootstack.widgets.tree import Tree, TreeNode
|
|
106
|
+
from bootstack.widgets.textfield import TextField
|
|
107
|
+
from bootstack.widgets.toast import toast, Notification, Snackbar, snackbar
|
|
108
|
+
from bootstack.widgets.togglegroup import ToggleGroup
|
|
109
|
+
from bootstack.widgets.toolbar import Toolbar
|
|
110
|
+
from bootstack.widgets.statusbar import StatusBar
|
|
111
|
+
from bootstack.widgets.tooltip import Tooltip
|
|
112
|
+
|
|
113
|
+
from bootstack.widgets.calendar import Calendar
|
|
114
|
+
from bootstack.widgets.form import Form
|
|
115
|
+
from bootstack.widgets.form import FormItem, FieldItem, GroupItem, TabsItem, TabItem
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ── Public API surface ────────────────────────────────────────────────────────
|
|
119
|
+
# The curated top-level namespace: things you compose a UI with. Framework
|
|
120
|
+
# primitives (data, i18n, validation, events, streams, scheduling, shortcuts,
|
|
121
|
+
# style, errors, store, types) live in their own submodules — see the docs'
|
|
122
|
+
# "API overview". This list is kept in sync with tests/test_public_surface.py.
|
|
123
|
+
__all__ = [
|
|
124
|
+
"__version__",
|
|
125
|
+
# Reactive state
|
|
126
|
+
"Signal",
|
|
127
|
+
# Theme switching
|
|
128
|
+
"set_theme", "toggle_theme",
|
|
129
|
+
# Dialog verbs
|
|
130
|
+
"alert", "confirm", "ask_string", "ask_integer", "ask_float", "ask_date",
|
|
131
|
+
"ask_date_range", "ask_item", "ask_color", "ask_font", "ask_filter",
|
|
132
|
+
"ask_save_file", "ask_open_file", "ask_open_files", "ask_directory",
|
|
133
|
+
# Application & windows
|
|
134
|
+
"App", "AppShell", "Workbench", "Window", "Splash",
|
|
135
|
+
# Layout
|
|
136
|
+
"Row", "Column", "Spacer", "Grid", "Card", "GroupBox", "Divider", "ScrollView",
|
|
137
|
+
"SplitView", "SplitPane", "Accordion", "AccordionSection",
|
|
138
|
+
# Actions
|
|
139
|
+
"Button", "ButtonGroup", "ThemeToggle", "MenuButton", "Toolbar", "StatusBar",
|
|
140
|
+
"ContextMenu", "ContextMenuItem",
|
|
141
|
+
# Inputs
|
|
142
|
+
"TextField", "PasswordField", "NumberField", "PathField", "SpinnerField",
|
|
143
|
+
"TextArea", "CodeEditor", "DateField", "TimeField", "Slider", "RangeSlider",
|
|
144
|
+
# Selection
|
|
145
|
+
"Checkbox", "Switch", "ToggleButton", "ToggleGroup", "Radio",
|
|
146
|
+
"RadioToggleButton", "RadioGroup", "Select", "SelectButton", "Calendar",
|
|
147
|
+
# Data display
|
|
148
|
+
"Label", "Badge", "ProgressBar", "Gauge", "ListView", "DataTable", "Tree", "TreeNode",
|
|
149
|
+
# Media
|
|
150
|
+
"Picture", "Gallery", "Carousel", "Avatar", "Chart",
|
|
151
|
+
# Navigation
|
|
152
|
+
"PageStack", "StackPage", "Tabs", "TabPage",
|
|
153
|
+
# Overlays
|
|
154
|
+
"Tooltip", "toast", "Notification", "Snackbar", "snackbar",
|
|
155
|
+
# Forms
|
|
156
|
+
"Form", "FormItem", "FieldItem", "GroupItem", "TabsItem", "TabItem",
|
|
157
|
+
]
|
bootstack/__main__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Core utilities and error types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from . import colorutils, publisher, capabilities
|
|
6
|
+
from bootstack._core.exceptions import (
|
|
7
|
+
ThemeError,
|
|
8
|
+
NavigationError,
|
|
9
|
+
StyleBuilderError,
|
|
10
|
+
ConfigurationWarning,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"colorutils",
|
|
15
|
+
"publisher",
|
|
16
|
+
"capabilities",
|
|
17
|
+
"ThemeError",
|
|
18
|
+
"NavigationError",
|
|
19
|
+
"StyleBuilderError",
|
|
20
|
+
"ConfigurationWarning",
|
|
21
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Core widget capabilities for bootstack.
|
|
2
|
+
|
|
3
|
+
This package provides framework services that can be used by widget mixins
|
|
4
|
+
and other parts of the library. Each capability module contains reusable
|
|
5
|
+
logic that mixins delegate to, keeping the mixins themselves as thin glue.
|
|
6
|
+
|
|
7
|
+
Capabilities:
|
|
8
|
+
signals: Signal/Variable binding and normalization
|
|
9
|
+
localization: Text translation and value formatting
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from bootstack._core.capabilities.signals import (
|
|
13
|
+
SignalBinding,
|
|
14
|
+
is_signal,
|
|
15
|
+
is_variable,
|
|
16
|
+
normalize_signal,
|
|
17
|
+
create_signal,
|
|
18
|
+
infer_default_value_for_widget,
|
|
19
|
+
query_binding,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from bootstack._core.capabilities.localization import (
|
|
23
|
+
resolve_text,
|
|
24
|
+
resolve_variable_text,
|
|
25
|
+
apply_spec,
|
|
26
|
+
get_current_locale,
|
|
27
|
+
create_formatted_signal,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
# Signals capability
|
|
32
|
+
"SignalBinding",
|
|
33
|
+
"is_signal",
|
|
34
|
+
"is_variable",
|
|
35
|
+
"normalize_signal",
|
|
36
|
+
"create_signal",
|
|
37
|
+
"infer_default_value_for_widget",
|
|
38
|
+
"query_binding",
|
|
39
|
+
# Localization capability
|
|
40
|
+
"resolve_text",
|
|
41
|
+
"resolve_variable_text",
|
|
42
|
+
"apply_spec",
|
|
43
|
+
"get_current_locale",
|
|
44
|
+
"create_formatted_signal",
|
|
45
|
+
]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AfterMixin:
|
|
7
|
+
"""Scheduling helpers (after).
|
|
8
|
+
|
|
9
|
+
Tk’s `after` family lets you schedule callbacks to run later on the Tk event loop.
|
|
10
|
+
|
|
11
|
+
Common uses:
|
|
12
|
+
- Debounce user input (schedule a callback and cancel previous ones).
|
|
13
|
+
- Run periodic UI updates (schedule, then reschedule from inside the callback).
|
|
14
|
+
- Defer work until the UI is idle (`after_idle`) so layout/paint can complete.
|
|
15
|
+
|
|
16
|
+
Notes:
|
|
17
|
+
- Callbacks run on the Tk thread/event loop. If you have long-running work,
|
|
18
|
+
run it off-thread/process and schedule UI updates back onto Tk using `after`.
|
|
19
|
+
- `after` returns an identifier that can be canceled with `after_cancel`.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def after(self, ms: int, func: Callable[..., Any] | None = None, *args: Any) -> str:
|
|
23
|
+
"""Schedule a callback to run after a delay.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
ms: Delay in milliseconds.
|
|
27
|
+
func: Callback to run. If omitted/None, Tk blocks for `ms` milliseconds
|
|
28
|
+
while still processing events (use sparingly).
|
|
29
|
+
*args: Arguments to pass to `func` when it is called.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
An identifier that can be used with `after_cancel`.
|
|
33
|
+
"""
|
|
34
|
+
return super().after(ms, func, *args) # type: ignore[misc]
|
|
35
|
+
|
|
36
|
+
def after_idle(self, func: Callable[..., Any], *args: Any) -> str:
|
|
37
|
+
"""Schedule a callback to run when the event loop is idle.
|
|
38
|
+
|
|
39
|
+
Idle callbacks run after Tk has finished processing the current batch of
|
|
40
|
+
events and pending UI work.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
func: Callback to run.
|
|
44
|
+
*args: Arguments to pass to `func` when it is called.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
An identifier that can be used with `after_cancel`.
|
|
48
|
+
"""
|
|
49
|
+
return super().after_idle(func, *args) # type: ignore[misc]
|
|
50
|
+
|
|
51
|
+
def after_cancel(self, id: str) -> None:
|
|
52
|
+
"""Cancel a scheduled callback.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
id: The identifier returned by `after` or `after_idle`.
|
|
56
|
+
"""
|
|
57
|
+
return super().after_cancel(id) # type: ignore[misc]
|
|
58
|
+
|
|
59
|
+
# -------------------------------------------------------------------------
|
|
60
|
+
# Convenience helpers (optional)
|
|
61
|
+
# -------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
def after_repeat(self, ms: int, func: Callable[..., Any], *args: Any) -> Callable[[], None]:
|
|
64
|
+
"""Call `func` repeatedly every `ms` milliseconds.
|
|
65
|
+
|
|
66
|
+
This helper schedules `func` and then automatically reschedules it after
|
|
67
|
+
each run. It returns a `cancel()` function you can call to stop repetition.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
ms: Interval in milliseconds.
|
|
71
|
+
func: Callback to run each interval.
|
|
72
|
+
*args: Arguments to pass to `func`.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
A `cancel()` callable. Call it to stop the repeating schedule.
|
|
76
|
+
|
|
77
|
+
Examples:
|
|
78
|
+
>>> cancel = widget.after_repeat(250, tick)
|
|
79
|
+
>>> cancel()
|
|
80
|
+
"""
|
|
81
|
+
cancelled = False
|
|
82
|
+
token: str | None = None
|
|
83
|
+
|
|
84
|
+
def _run():
|
|
85
|
+
nonlocal token
|
|
86
|
+
if cancelled:
|
|
87
|
+
return
|
|
88
|
+
func(*args)
|
|
89
|
+
token = self.after(ms, _run)
|
|
90
|
+
|
|
91
|
+
token = self.after(ms, _run)
|
|
92
|
+
|
|
93
|
+
def cancel() -> None:
|
|
94
|
+
nonlocal cancelled, token
|
|
95
|
+
cancelled = True
|
|
96
|
+
if token is not None:
|
|
97
|
+
try:
|
|
98
|
+
self.after_cancel(token)
|
|
99
|
+
except Exception:
|
|
100
|
+
pass
|
|
101
|
+
token = None
|
|
102
|
+
|
|
103
|
+
return cancel
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Event binding capabilities mixin for bootstack widgets."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, Callable, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from typing_extensions import TypedDict
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from typing_extensions import Unpack
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EventGenerateKwargs(TypedDict, total=False):
|
|
13
|
+
"""Keyword options for `event_generate` (Tk event field overrides).
|
|
14
|
+
|
|
15
|
+
All fields are optional. Only supply fields relevant to the event type
|
|
16
|
+
being synthesized (e.g., `x`/`y` for mouse events, `keysym` for key events).
|
|
17
|
+
"""
|
|
18
|
+
x: int
|
|
19
|
+
"""Widget-relative x-coordinate in pixels."""
|
|
20
|
+
y: int
|
|
21
|
+
"""Widget-relative y-coordinate in pixels."""
|
|
22
|
+
rootx: int
|
|
23
|
+
"""Screen (root) x-coordinate in pixels."""
|
|
24
|
+
rooty: int
|
|
25
|
+
"""Screen (root) y-coordinate in pixels."""
|
|
26
|
+
state: int
|
|
27
|
+
"""Modifier key bitmask (Shift, Ctrl, Alt, etc.)."""
|
|
28
|
+
time: int
|
|
29
|
+
"""Event timestamp in milliseconds."""
|
|
30
|
+
keycode: int
|
|
31
|
+
"""Key code for keyboard events."""
|
|
32
|
+
keysym: str
|
|
33
|
+
"""Key symbol name for keyboard events (e.g., `'Return'`, `'Escape'`, `'a'`)."""
|
|
34
|
+
button: int
|
|
35
|
+
"""Mouse button number — 1=left, 2=middle, 3=right."""
|
|
36
|
+
delta: int
|
|
37
|
+
"""Scroll wheel delta (positive = up, negative = down)."""
|
|
38
|
+
width: int
|
|
39
|
+
"""Width value for Configure events."""
|
|
40
|
+
height: int
|
|
41
|
+
"""Height value for Configure events."""
|
|
42
|
+
when: str
|
|
43
|
+
"""When to deliver the event — `'now'`, `'tail'`, `'mark'`, or `'head'`. Defaults to `'tail'`."""
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class BindingsMixin:
|
|
47
|
+
"""Event binding and virtual event generation.
|
|
48
|
+
|
|
49
|
+
This mixin documents the *Tkinter-style* binding API (`bind`, `unbind`,
|
|
50
|
+
`bind_all`, etc.) while reflecting bootstack v2's enhanced event system.
|
|
51
|
+
|
|
52
|
+
Differences from stock Tkinter:
|
|
53
|
+
- Virtual events generated via `event_generate("<<Name>>", data=...)` may
|
|
54
|
+
carry **arbitrary Python objects** as event payload.
|
|
55
|
+
- Event handlers receive an event object with a consistent `.data` attribute:
|
|
56
|
+
- `.data` is the Python object you passed for virtual events.
|
|
57
|
+
- `.data` is `None` for non-virtual events.
|
|
58
|
+
|
|
59
|
+
Notes:
|
|
60
|
+
- Prefer `bind` over `bind_all` unless you truly need a global binding.
|
|
61
|
+
- Return the string `"break"` from a handler to stop further processing.
|
|
62
|
+
- Virtual event data is intended for application-local messaging.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------
|
|
66
|
+
# Binding (widget, class, and application/global)
|
|
67
|
+
# ---------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
def bind(
|
|
70
|
+
self,
|
|
71
|
+
sequence: str | None = None,
|
|
72
|
+
func: Callable[..., Any] | None = None,
|
|
73
|
+
add: bool | str | None = None,
|
|
74
|
+
) -> str | None:
|
|
75
|
+
"""Bind an event sequence to a handler.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
sequence: Event pattern string (e.g. `"<Button-1>"`, `"<KeyPress>"`, `"<<MyEvent>>"`).
|
|
79
|
+
If None, returns a string describing all bindings on this widget.
|
|
80
|
+
func: Handler callable. The handler is called with a single argument:
|
|
81
|
+
the event object. For bootstack enhanced events, `event.data`
|
|
82
|
+
is always present (None for regular events, payload for virtual events).
|
|
83
|
+
add: If true/`"+"` then this binding is added in addition to existing bindings.
|
|
84
|
+
If false/None then any existing binding for this sequence is replaced.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
If `func` is provided, returns an internal Tk binding id that can be used
|
|
88
|
+
with `unbind(sequence, funcid)`. If `func` is None, returns a Tcl binding
|
|
89
|
+
script string (Tkinter behavior varies by version) or None.
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
Bind a regular event:
|
|
93
|
+
|
|
94
|
+
widget.bind("<Button-1>", on_click)
|
|
95
|
+
|
|
96
|
+
Bind a virtual event that carries Python data:
|
|
97
|
+
|
|
98
|
+
widget.bind("<<Save>>", on_save)
|
|
99
|
+
widget.event_generate("<<Save>>", data={"path": "doc.txt"})
|
|
100
|
+
"""
|
|
101
|
+
return super().bind(sequence, func, add) # type: ignore[misc]
|
|
102
|
+
|
|
103
|
+
def unbind(self, sequence: str, funcid: str | None = None) -> None:
|
|
104
|
+
"""Remove a binding for an event sequence.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
sequence: The event sequence that was previously bound.
|
|
108
|
+
funcid: The binding id returned from `bind`. If omitted, removes all
|
|
109
|
+
handlers for the given sequence on this widget.
|
|
110
|
+
"""
|
|
111
|
+
return super().unbind(sequence, funcid) # type: ignore[misc]
|
|
112
|
+
|
|
113
|
+
def bind_all(
|
|
114
|
+
self,
|
|
115
|
+
sequence: str | None = None,
|
|
116
|
+
func: Callable[..., Any] | None = None,
|
|
117
|
+
add: bool | str | None = None,
|
|
118
|
+
) -> str | None:
|
|
119
|
+
"""Bind an event sequence at the application level (all widgets).
|
|
120
|
+
|
|
121
|
+
Use sparingly. This affects *every* widget in the application.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
sequence: Event pattern string.
|
|
125
|
+
func: Handler callable.
|
|
126
|
+
add: Whether to add alongside existing bindings.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
A binding id when setting a binding, otherwise a binding script string
|
|
130
|
+
(version-dependent) or None.
|
|
131
|
+
"""
|
|
132
|
+
return super().bind_all(sequence, func, add) # type: ignore[misc]
|
|
133
|
+
|
|
134
|
+
def unbind_all(self, sequence: str) -> None:
|
|
135
|
+
"""Remove an application-level binding for the given sequence.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
sequence: The event sequence to unbind.
|
|
139
|
+
"""
|
|
140
|
+
return super().unbind_all(sequence) # type: ignore[misc]
|
|
141
|
+
|
|
142
|
+
def bind_class(
|
|
143
|
+
self,
|
|
144
|
+
className: str,
|
|
145
|
+
sequence: str | None = None,
|
|
146
|
+
func: Callable[..., Any] | None = None,
|
|
147
|
+
add: bool | str | None = None,
|
|
148
|
+
) -> str | None:
|
|
149
|
+
"""Bind an event sequence to a Tk widget class.
|
|
150
|
+
|
|
151
|
+
This attaches a handler to *all widgets of a given Tk class name*
|
|
152
|
+
(e.g. `"TButton"`, `"TEntry"`).
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
className: Tk class name.
|
|
156
|
+
sequence: Event pattern string.
|
|
157
|
+
func: Handler callable.
|
|
158
|
+
add: Whether to add alongside existing bindings.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
A binding id when setting a binding, otherwise a binding script string
|
|
162
|
+
(version-dependent) or None.
|
|
163
|
+
"""
|
|
164
|
+
return super().bind_class(className, sequence, func, add) # type: ignore[misc]
|
|
165
|
+
|
|
166
|
+
def unbind_class(self, className: str, sequence: str) -> None:
|
|
167
|
+
"""Remove a class-level binding.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
className: Tk class name.
|
|
171
|
+
sequence: Event sequence to unbind for that class.
|
|
172
|
+
"""
|
|
173
|
+
return super().unbind_class(className, sequence) # type: ignore[misc]
|
|
174
|
+
|
|
175
|
+
# ---------------------------------------------------------------------
|
|
176
|
+
# Event generation (including virtual-event payloads)
|
|
177
|
+
# ---------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
def event_generate(self, sequence: str, data: Any | None = None, **kw: Unpack[EventGenerateKwargs]) -> None:
|
|
180
|
+
"""Generate an event.
|
|
181
|
+
|
|
182
|
+
Synthesizes both physical events (e.g. `"<Button-1>"`) and virtual events
|
|
183
|
+
(e.g. `"<<MyEvent>>"`). For virtual events, bootstack supports attaching
|
|
184
|
+
a Python payload via `data`.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
sequence: Event sequence to generate (commonly `"<<Name>>"` for virtual events).
|
|
188
|
+
data: Optional Python object payload for virtual events. Handlers receive
|
|
189
|
+
an event whose `.data` is this value. Ignored for non-virtual events.
|
|
190
|
+
**kw: See `EventGenerateKwargs` for Tk event field overrides (x, y, state, etc.).
|
|
191
|
+
"""
|
|
192
|
+
return super().event_generate(sequence, data=data, **kw) # type: ignore[misc]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Sequence
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BindtagsMixin:
|
|
7
|
+
"""Bindtags helpers (bindtags).
|
|
8
|
+
|
|
9
|
+
Bindtags control **the order in which Tk processes bindings** for an event.
|
|
10
|
+
|
|
11
|
+
Every widget has a list of bindtags. When an event occurs on a widget, Tk
|
|
12
|
+
processes bindings in tag order. Each tag may have bindings associated with it.
|
|
13
|
+
|
|
14
|
+
Typical default bindtags for a widget look like:
|
|
15
|
+
|
|
16
|
+
(widget_pathname, widget_class, toplevel_pathname, "all")
|
|
17
|
+
|
|
18
|
+
Practical uses:
|
|
19
|
+
- Insert a custom tag (e.g. "MyApp") to apply shared behaviors across widgets.
|
|
20
|
+
- Reorder tags to change precedence (e.g. run class bindings before widget bindings).
|
|
21
|
+
- Remove a tag to disable a layer of default behavior (use with care).
|
|
22
|
+
|
|
23
|
+
Notes:
|
|
24
|
+
- Bindtags affect event dispatch only; they do not change focus or grab behavior.
|
|
25
|
+
- Misordering tags can break default widget behaviors (Tab traversal, selection,
|
|
26
|
+
text editing, etc.), so keep changes minimal and well-scoped.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def bindtags(self, tags: Sequence[str] | None = None) -> tuple[str, ...]:
|
|
30
|
+
"""Get or set the bindtags for this widget.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
tags: The bindtags to set. If None, returns the current bindtags.
|
|
34
|
+
Tags are processed in order when dispatching events.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
The current bindtags as a tuple.
|
|
38
|
+
"""
|
|
39
|
+
# Tkinter's `bindtags()` returns a tuple and accepts a sequence for setting.
|
|
40
|
+
if tags is None:
|
|
41
|
+
return super().bindtags() # type: ignore[misc]
|
|
42
|
+
return super().bindtags(tags) # type: ignore[misc]
|
|
43
|
+
|
|
44
|
+
# -------------------------------------------------------------------------
|
|
45
|
+
# Convenience helpers (optional)
|
|
46
|
+
# -------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
def bindtags_prepend(self, tag: str) -> tuple[str, ...]:
|
|
49
|
+
"""Prepend a tag to the bindtags list.
|
|
50
|
+
|
|
51
|
+
This increases the tag's priority (it will be processed earlier).
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
tag: Tag name to prepend.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The updated bindtags tuple.
|
|
58
|
+
"""
|
|
59
|
+
current = list(self.bindtags())
|
|
60
|
+
if tag not in current:
|
|
61
|
+
current.insert(0, tag)
|
|
62
|
+
self.bindtags(current)
|
|
63
|
+
return tuple(current)
|
|
64
|
+
|
|
65
|
+
def bindtags_append(self, tag: str) -> tuple[str, ...]:
|
|
66
|
+
"""Append a tag to the bindtags list.
|
|
67
|
+
|
|
68
|
+
This decreases the tag's priority (it will be processed later).
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
tag: Tag name to append.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
The updated bindtags tuple.
|
|
75
|
+
"""
|
|
76
|
+
current = list(self.bindtags())
|
|
77
|
+
if tag not in current:
|
|
78
|
+
current.append(tag)
|
|
79
|
+
self.bindtags(current)
|
|
80
|
+
return tuple(current)
|
|
81
|
+
|
|
82
|
+
def bindtags_remove(self, tag: str) -> tuple[str, ...]:
|
|
83
|
+
"""Remove a tag from the bindtags list.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
tag: Tag name to remove.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
The updated bindtags tuple.
|
|
90
|
+
"""
|
|
91
|
+
current = [t for t in self.bindtags() if t != tag]
|
|
92
|
+
self.bindtags(current)
|
|
93
|
+
return tuple(current)
|
|
94
|
+
|
|
95
|
+
def bindtags_replace(self, old: str, new: str) -> tuple[str, ...]:
|
|
96
|
+
"""Replace a bindtag with another tag.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
old: Existing tag name.
|
|
100
|
+
new: Replacement tag name.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
The updated bindtags tuple.
|
|
104
|
+
"""
|
|
105
|
+
current = list(self.bindtags())
|
|
106
|
+
try:
|
|
107
|
+
idx = current.index(old)
|
|
108
|
+
except ValueError:
|
|
109
|
+
return tuple(current)
|
|
110
|
+
current[idx] = new
|
|
111
|
+
self.bindtags(current)
|
|
112
|
+
return tuple(current)
|