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,423 @@
|
|
|
1
|
+
"""Cross-platform keyboard shortcut management.
|
|
2
|
+
|
|
3
|
+
This module provides a service for managing keyboard shortcuts with
|
|
4
|
+
automatic platform detection and modifier key translation.
|
|
5
|
+
|
|
6
|
+
Examples:
|
|
7
|
+
```python
|
|
8
|
+
import bootstack as bs
|
|
9
|
+
|
|
10
|
+
app = bs.App()
|
|
11
|
+
shortcuts = bs.get_shortcuts()
|
|
12
|
+
|
|
13
|
+
# Register shortcuts
|
|
14
|
+
shortcuts.register("save", "Mod+S", save_file)
|
|
15
|
+
shortcuts.register("open", "Mod+O", open_file)
|
|
16
|
+
shortcuts.register("quit", "Mod+Q", app.quit)
|
|
17
|
+
|
|
18
|
+
# Bind to app window
|
|
19
|
+
shortcuts.bind_to(app)
|
|
20
|
+
|
|
21
|
+
# Menu displays shortcut text automatically
|
|
22
|
+
menu.add_command(text="Save", shortcut="save", command=save_file)
|
|
23
|
+
```
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import sys
|
|
28
|
+
from dataclasses import dataclass, field
|
|
29
|
+
from typing import Callable, Any
|
|
30
|
+
from weakref import WeakSet
|
|
31
|
+
|
|
32
|
+
IS_MAC = sys.platform == 'darwin'
|
|
33
|
+
IS_WIN = sys.platform == 'win32'
|
|
34
|
+
|
|
35
|
+
# Modifier display symbols for Mac
|
|
36
|
+
_MAC_SYMBOLS = {
|
|
37
|
+
'mod': '\u2318', # ⌘ Command
|
|
38
|
+
'command': '\u2318', # ⌘
|
|
39
|
+
'ctrl': '\u2303', # ⌃ Control
|
|
40
|
+
'control': '\u2303', # ⌃
|
|
41
|
+
'alt': '\u2325', # ⌥ Option
|
|
42
|
+
'option': '\u2325', # ⌥
|
|
43
|
+
'shift': '\u21E7', # ⇧
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Modifier display names for Windows/Linux
|
|
47
|
+
_WIN_NAMES = {
|
|
48
|
+
'mod': 'Ctrl',
|
|
49
|
+
'command': 'Ctrl',
|
|
50
|
+
'ctrl': 'Ctrl',
|
|
51
|
+
'control': 'Ctrl',
|
|
52
|
+
'alt': 'Alt',
|
|
53
|
+
'option': 'Alt',
|
|
54
|
+
'shift': 'Shift',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Tkinter binding modifiers
|
|
58
|
+
_BINDING_MODIFIERS = {
|
|
59
|
+
'mod': 'Command' if IS_MAC else 'Control',
|
|
60
|
+
'command': 'Command',
|
|
61
|
+
'ctrl': 'Control',
|
|
62
|
+
'control': 'Control',
|
|
63
|
+
'alt': 'Option' if IS_MAC else 'Alt',
|
|
64
|
+
'option': 'Option',
|
|
65
|
+
'shift': 'Shift',
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class Shortcut:
|
|
71
|
+
"""A registered keyboard shortcut.
|
|
72
|
+
|
|
73
|
+
Attributes:
|
|
74
|
+
key: Unique identifier for lookup (e.g., "save", "file.open")
|
|
75
|
+
pattern: Shortcut pattern (e.g., "Mod+S", "Shift+Alt+N")
|
|
76
|
+
command: Function to execute when triggered
|
|
77
|
+
"""
|
|
78
|
+
key: str
|
|
79
|
+
pattern: str
|
|
80
|
+
command: Callable
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def display(self) -> str:
|
|
84
|
+
"""Platform-appropriate display string for menus.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
On Mac: "⇧⌘S" (symbols, no separators)
|
|
88
|
+
On Windows/Linux: "Ctrl+Shift+S" (names with + separators)
|
|
89
|
+
"""
|
|
90
|
+
parts = self.pattern.split('+')
|
|
91
|
+
key_part = parts[-1]
|
|
92
|
+
mod_parts = [p.lower() for p in parts[:-1]]
|
|
93
|
+
|
|
94
|
+
if IS_MAC:
|
|
95
|
+
# Mac style: symbols without separators, specific order
|
|
96
|
+
# Standard order: Control, Option, Shift, Command
|
|
97
|
+
ordered_mods = []
|
|
98
|
+
for mod in ['ctrl', 'control', 'alt', 'option', 'shift', 'mod', 'command']:
|
|
99
|
+
if mod in mod_parts:
|
|
100
|
+
symbol = _MAC_SYMBOLS.get(mod, mod)
|
|
101
|
+
if symbol not in ordered_mods:
|
|
102
|
+
ordered_mods.append(symbol)
|
|
103
|
+
return ''.join(ordered_mods) + key_part.upper()
|
|
104
|
+
else:
|
|
105
|
+
# Windows/Linux style: names with + separators
|
|
106
|
+
mod_names = []
|
|
107
|
+
for mod in mod_parts:
|
|
108
|
+
name = _WIN_NAMES.get(mod, mod.capitalize())
|
|
109
|
+
if name not in mod_names:
|
|
110
|
+
mod_names.append(name)
|
|
111
|
+
return '+'.join(mod_names + [key_part.upper()])
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def binding(self) -> str:
|
|
115
|
+
"""Tkinter binding string.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Binding string like "<Control-s>" or "<Command-Shift-s>"
|
|
119
|
+
"""
|
|
120
|
+
parts = self.pattern.split('+')
|
|
121
|
+
key_part = parts[-1].lower()
|
|
122
|
+
mod_parts = [p.lower() for p in parts[:-1]]
|
|
123
|
+
|
|
124
|
+
# Convert to Tkinter modifier names
|
|
125
|
+
tk_mods = []
|
|
126
|
+
for mod in mod_parts:
|
|
127
|
+
tk_mod = _BINDING_MODIFIERS.get(mod, mod.capitalize())
|
|
128
|
+
if tk_mod not in tk_mods:
|
|
129
|
+
tk_mods.append(tk_mod)
|
|
130
|
+
|
|
131
|
+
# Handle function keys - keep uppercase
|
|
132
|
+
if key_part.upper().startswith('F') and key_part[1:].isdigit():
|
|
133
|
+
key_part = key_part.upper()
|
|
134
|
+
|
|
135
|
+
return f"<{'-'.join(tk_mods + [key_part])}>"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class Shortcuts:
|
|
139
|
+
"""Singleton service for managing keyboard shortcuts.
|
|
140
|
+
|
|
141
|
+
Provides cross-platform keyboard shortcut registration and binding.
|
|
142
|
+
The service automatically translates modifier keys for each platform:
|
|
143
|
+
|
|
144
|
+
- `Mod` becomes `Ctrl` on Windows/Linux, `Command` on Mac
|
|
145
|
+
- `Alt` becomes `Alt` on Windows/Linux, `Option` on Mac
|
|
146
|
+
- `Shift` works the same on all platforms
|
|
147
|
+
|
|
148
|
+
Examples:
|
|
149
|
+
```python
|
|
150
|
+
shortcuts = get_shortcuts()
|
|
151
|
+
|
|
152
|
+
# Register shortcuts
|
|
153
|
+
shortcuts.register("save", "Mod+S", save_file)
|
|
154
|
+
shortcuts.register("undo", "Mod+Z", undo)
|
|
155
|
+
shortcuts.register("find", "Mod+F", find)
|
|
156
|
+
|
|
157
|
+
# Bind all to window
|
|
158
|
+
shortcuts.bind_to(app)
|
|
159
|
+
|
|
160
|
+
# Get display string for menu
|
|
161
|
+
shortcuts.display("save") # "Ctrl+S" on Windows, "⌘S" on Mac
|
|
162
|
+
```
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
_instance: 'Shortcuts | None' = None
|
|
166
|
+
|
|
167
|
+
def __new__(cls):
|
|
168
|
+
if cls._instance is None:
|
|
169
|
+
cls._instance = super().__new__(cls)
|
|
170
|
+
cls._instance._shortcuts: dict[str, Shortcut] = {}
|
|
171
|
+
cls._instance._bound_windows: WeakSet = WeakSet()
|
|
172
|
+
cls._instance._bindings: dict[int, list[tuple[str, str]]] = {}
|
|
173
|
+
return cls._instance
|
|
174
|
+
|
|
175
|
+
def register(self, key: str, pattern: str, command: Callable) -> Shortcut:
|
|
176
|
+
"""Register a keyboard shortcut.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
key: Unique identifier (e.g., "save", "file.open")
|
|
180
|
+
pattern: Shortcut pattern using symbolic modifiers:
|
|
181
|
+
- `Mod+S` - Primary modifier + S
|
|
182
|
+
- `Mod+Shift+S` - Primary modifier + Shift + S
|
|
183
|
+
- `Alt+F4` - Alt + F4
|
|
184
|
+
- `F5` - Function key alone
|
|
185
|
+
command: Function to call when triggered
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
The created Shortcut object.
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
ValueError: If key is already registered.
|
|
192
|
+
|
|
193
|
+
Examples:
|
|
194
|
+
```python
|
|
195
|
+
shortcuts.register("save", "Mod+S", save_file)
|
|
196
|
+
shortcuts.register("quit", "Mod+Q", app.quit)
|
|
197
|
+
shortcuts.register("refresh", "F5", refresh)
|
|
198
|
+
```
|
|
199
|
+
"""
|
|
200
|
+
if key in self._shortcuts:
|
|
201
|
+
raise ValueError(f"Shortcut key '{key}' is already registered")
|
|
202
|
+
|
|
203
|
+
shortcut = Shortcut(key=key, pattern=pattern, command=command)
|
|
204
|
+
self._shortcuts[key] = shortcut
|
|
205
|
+
|
|
206
|
+
# Bind to any already-bound windows
|
|
207
|
+
for window in self._bound_windows:
|
|
208
|
+
self._bind_shortcut(window, shortcut)
|
|
209
|
+
|
|
210
|
+
return shortcut
|
|
211
|
+
|
|
212
|
+
def unregister(self, key: str) -> None:
|
|
213
|
+
"""Remove a registered shortcut.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
key: The shortcut key to remove.
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
KeyError: If key is not registered.
|
|
220
|
+
"""
|
|
221
|
+
if key not in self._shortcuts:
|
|
222
|
+
raise KeyError(f"Shortcut key '{key}' is not registered")
|
|
223
|
+
|
|
224
|
+
shortcut = self._shortcuts.pop(key)
|
|
225
|
+
|
|
226
|
+
# Unbind from all windows
|
|
227
|
+
for window in self._bound_windows:
|
|
228
|
+
self._unbind_shortcut(window, shortcut)
|
|
229
|
+
|
|
230
|
+
def get(self, key: str) -> Shortcut | None:
|
|
231
|
+
"""Get a shortcut by key.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
key: The shortcut key to look up.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
The Shortcut object, or None if not found.
|
|
238
|
+
"""
|
|
239
|
+
return self._shortcuts.get(key)
|
|
240
|
+
|
|
241
|
+
def display(self, key: str) -> str:
|
|
242
|
+
"""Get display string for a shortcut key.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
key: The shortcut key to look up.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Platform-appropriate display string (e.g., "Ctrl+S" or "⌘S"),
|
|
249
|
+
or empty string if not found.
|
|
250
|
+
"""
|
|
251
|
+
shortcut = self._shortcuts.get(key)
|
|
252
|
+
return shortcut.display if shortcut else ''
|
|
253
|
+
|
|
254
|
+
def binding(self, key: str) -> str:
|
|
255
|
+
"""Get Tkinter binding string for a shortcut key.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
key: The shortcut key to look up.
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Tkinter binding string (e.g., "<Control-s>"),
|
|
262
|
+
or empty string if not found.
|
|
263
|
+
"""
|
|
264
|
+
shortcut = self._shortcuts.get(key)
|
|
265
|
+
return shortcut.binding if shortcut else ''
|
|
266
|
+
|
|
267
|
+
def bind_to(self, window: Any) -> None:
|
|
268
|
+
"""Bind all registered shortcuts to a window.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
window: The window (App, Toplevel, Tk) to bind shortcuts to.
|
|
272
|
+
|
|
273
|
+
Note:
|
|
274
|
+
Shortcuts registered after calling bind_to will also be
|
|
275
|
+
automatically bound to this window.
|
|
276
|
+
"""
|
|
277
|
+
if window in self._bound_windows:
|
|
278
|
+
return
|
|
279
|
+
|
|
280
|
+
self._bound_windows.add(window)
|
|
281
|
+
window_id = id(window)
|
|
282
|
+
self._bindings[window_id] = []
|
|
283
|
+
|
|
284
|
+
for shortcut in self._shortcuts.values():
|
|
285
|
+
self._bind_shortcut(window, shortcut)
|
|
286
|
+
|
|
287
|
+
def unbind_from(self, window: Any) -> None:
|
|
288
|
+
"""Remove all shortcut bindings from a window.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
window: The window to unbind shortcuts from.
|
|
292
|
+
"""
|
|
293
|
+
if window not in self._bound_windows:
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
self._bound_windows.discard(window)
|
|
297
|
+
window_id = id(window)
|
|
298
|
+
|
|
299
|
+
# Unbind all shortcuts
|
|
300
|
+
bindings = self._bindings.pop(window_id, [])
|
|
301
|
+
for binding_str, func_id in bindings:
|
|
302
|
+
try:
|
|
303
|
+
window.unbind(binding_str, func_id)
|
|
304
|
+
except Exception:
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
def all(self) -> dict[str, Shortcut]:
|
|
308
|
+
"""Get all registered shortcuts.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Dictionary mapping keys to Shortcut objects.
|
|
312
|
+
"""
|
|
313
|
+
return dict(self._shortcuts)
|
|
314
|
+
|
|
315
|
+
def _bind_shortcut(self, window: Any, shortcut: Shortcut) -> None:
|
|
316
|
+
"""Bind a single shortcut to a window."""
|
|
317
|
+
window_id = id(window)
|
|
318
|
+
binding_str = shortcut.binding
|
|
319
|
+
|
|
320
|
+
def handler(event):
|
|
321
|
+
shortcut.command()
|
|
322
|
+
return 'break'
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
func_id = window.bind(binding_str, handler, add='+')
|
|
326
|
+
if window_id in self._bindings:
|
|
327
|
+
self._bindings[window_id].append((binding_str, func_id))
|
|
328
|
+
except Exception:
|
|
329
|
+
pass
|
|
330
|
+
|
|
331
|
+
def _unbind_shortcut(self, window: Any, shortcut: Shortcut) -> None:
|
|
332
|
+
"""Unbind a single shortcut from a window."""
|
|
333
|
+
window_id = id(window)
|
|
334
|
+
binding_str = shortcut.binding
|
|
335
|
+
|
|
336
|
+
if window_id not in self._bindings:
|
|
337
|
+
return
|
|
338
|
+
|
|
339
|
+
# Find and remove the binding
|
|
340
|
+
bindings = self._bindings[window_id]
|
|
341
|
+
for i, (b_str, func_id) in enumerate(bindings):
|
|
342
|
+
if b_str == binding_str:
|
|
343
|
+
try:
|
|
344
|
+
window.unbind(binding_str, func_id)
|
|
345
|
+
except Exception:
|
|
346
|
+
pass
|
|
347
|
+
bindings.pop(i)
|
|
348
|
+
break
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def get_shortcuts() -> Shortcuts:
|
|
352
|
+
"""Get the global Shortcuts service instance.
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
The singleton Shortcuts instance.
|
|
356
|
+
|
|
357
|
+
Examples:
|
|
358
|
+
```python
|
|
359
|
+
import bootstack as bs
|
|
360
|
+
|
|
361
|
+
shortcuts = bs.get_shortcuts()
|
|
362
|
+
shortcuts.register("save", "Mod+S", save_file)
|
|
363
|
+
shortcuts.bind_to(app)
|
|
364
|
+
```
|
|
365
|
+
"""
|
|
366
|
+
return Shortcuts()
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def format_shortcut(spec: str | None) -> str:
|
|
370
|
+
"""Resolve a shortcut spec to its platform-appropriate display string.
|
|
371
|
+
|
|
372
|
+
Accepts three forms in order of precedence:
|
|
373
|
+
|
|
374
|
+
1. **Registered key** — the key passed to `Shortcuts.register`
|
|
375
|
+
(e.g. `"save"`, `"file.open"`). Returns the registered
|
|
376
|
+
shortcut's `display`.
|
|
377
|
+
2. **Pattern** — a modifier expression like `"Mod+S"`,
|
|
378
|
+
`"Ctrl+Shift+N"`, or `"F5"`. Treated as a transient pattern;
|
|
379
|
+
returns the pattern's platform display without registering anything.
|
|
380
|
+
3. **Plain text** — anything that doesn't parse as a pattern (no
|
|
381
|
+
modifier separator, not a function key) is returned unchanged so
|
|
382
|
+
callers can still pass a literal display string.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
spec: A registered key, modifier pattern, or literal display.
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
Platform-appropriate display string, or empty string when `spec`
|
|
389
|
+
is empty/None.
|
|
390
|
+
|
|
391
|
+
Examples:
|
|
392
|
+
```python
|
|
393
|
+
format_shortcut("save") # "⌘S" on Mac, "Ctrl+S" on Win/Linux
|
|
394
|
+
# (assumes 'save' is registered)
|
|
395
|
+
format_shortcut("Mod+Shift+N") # "⇧⌘N" on Mac, "Ctrl+Shift+N" on Win
|
|
396
|
+
format_shortcut("F5") # "F5" everywhere
|
|
397
|
+
format_shortcut("⌘S") # "⌘S" — passes through unchanged
|
|
398
|
+
```
|
|
399
|
+
"""
|
|
400
|
+
if not spec:
|
|
401
|
+
return ''
|
|
402
|
+
|
|
403
|
+
# 1) Registered key wins.
|
|
404
|
+
registered = Shortcuts().get(spec)
|
|
405
|
+
if registered is not None:
|
|
406
|
+
return registered.display
|
|
407
|
+
|
|
408
|
+
# 2) Pattern-shaped strings (contain '+' or are bare F-keys) get
|
|
409
|
+
# parsed into a transient Shortcut for display only — no registration,
|
|
410
|
+
# no binding side effect.
|
|
411
|
+
looks_like_pattern = '+' in spec or (
|
|
412
|
+
len(spec) >= 2
|
|
413
|
+
and spec[0].upper() == 'F'
|
|
414
|
+
and spec[1:].isdigit()
|
|
415
|
+
)
|
|
416
|
+
if looks_like_pattern:
|
|
417
|
+
return Shortcut(key='', pattern=spec, command=lambda: None).display
|
|
418
|
+
|
|
419
|
+
# 3) Anything else is treated as a literal display string.
|
|
420
|
+
return spec
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
__all__ = ['Shortcut', 'Shortcuts', 'get_shortcuts', 'format_shortcut']
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Install-time patching for Tk widgets only.
|
|
2
|
+
|
|
3
|
+
This module applies bootstack's Tk autostyle behavior to Tk widgets by
|
|
4
|
+
wrapping their constructors. It does not affect ttk widgets, which are
|
|
5
|
+
provided as explicit subclasses in the bootstack.widgets package.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from bootstack.style.bootstyle import Bootstyle
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def install_tk_autostyle() -> None:
|
|
14
|
+
"""Patch Tk widgets to enable autostyle via Bootstyle.
|
|
15
|
+
|
|
16
|
+
- Wraps Tk widget `__init__` with surface color inheritance and theme
|
|
17
|
+
background application using registered Tk builders.
|
|
18
|
+
- Leaves ttk widgets untouched; ttk integration is done via wrappers.
|
|
19
|
+
"""
|
|
20
|
+
# Ensure Tk builders are registered
|
|
21
|
+
import bootstack.style.builders_tk # noqa: F401
|
|
22
|
+
|
|
23
|
+
# Import Tk widget classes list
|
|
24
|
+
from bootstack.widgets import TK_WIDGETS
|
|
25
|
+
|
|
26
|
+
for widget in TK_WIDGETS:
|
|
27
|
+
_init = Bootstyle.override_tk_widget_constructor(widget.__init__)
|
|
28
|
+
widget.__init__ = _init
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__ = ["install_tk_autostyle"]
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""Themed top-level window for secondary application windows."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import tkinter
|
|
5
|
+
from typing import Any, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
from bootstack.core.mixins.widget import WidgetCapabilitiesMixin
|
|
8
|
+
from bootstack.runtime.base_window import BaseWindow
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Toplevel(BaseWindow, WidgetCapabilitiesMixin, tkinter.Toplevel):
|
|
12
|
+
"""A themed top-level window.
|
|
13
|
+
|
|
14
|
+
This class wraps `tkinter.Toplevel` and adds bootstack window conveniences
|
|
15
|
+
(title/geometry helpers, centering, alpha/topmost/toolwindow helpers, etc.).
|
|
16
|
+
|
|
17
|
+
The standard widget API (events, scheduling, clipboard, geometry managers,
|
|
18
|
+
winfo, etc.) is available through inheritance and is documented under
|
|
19
|
+
bootstack capabilities.
|
|
20
|
+
|
|
21
|
+
For additional information on the underlying Tk/Tkinter behavior, see:
|
|
22
|
+
- Tcl/Tk `toplevel` command documentation
|
|
23
|
+
- Python `tkinter.Toplevel` documentation
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
>>> win = Toplevel(title="My Toplevel")
|
|
27
|
+
>>> win.mainloop()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
title: str = "bootstack",
|
|
33
|
+
icon: tkinter.PhotoImage | None = None,
|
|
34
|
+
size: Optional[Tuple[int, int]] = None,
|
|
35
|
+
position: Optional[Tuple[int, int]] = None,
|
|
36
|
+
minsize: Optional[Tuple[int, int]] = None,
|
|
37
|
+
maxsize: Optional[Tuple[int, int]] = None,
|
|
38
|
+
resizable: Optional[Tuple[bool, bool]] = None,
|
|
39
|
+
transient: Optional[tkinter.Misc] = None,
|
|
40
|
+
overrideredirect: bool = False,
|
|
41
|
+
windowtype: Optional[str] = None,
|
|
42
|
+
topmost: bool = False,
|
|
43
|
+
toolwindow: bool = False,
|
|
44
|
+
alpha: float = 1.0,
|
|
45
|
+
window_style: Optional[str] = None,
|
|
46
|
+
**kwargs: Any,
|
|
47
|
+
) -> None:
|
|
48
|
+
"""Initialize a top-level window.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
title: The title that appears on the window titlebar.
|
|
52
|
+
icon: A PhotoImage used for the titlebar icon. If None, the default bootstack icon is used.
|
|
53
|
+
size: Window size as (width, height). Applied via `geometry`.
|
|
54
|
+
position: Window position as (x, y). Applied via `geometry`.
|
|
55
|
+
minsize: Minimum permissible window size as (width, height).
|
|
56
|
+
maxsize: Maximum permissible window size as (width, height).
|
|
57
|
+
resizable: Whether the user may resize the window as (x, y).
|
|
58
|
+
transient: Mark this window as transient for the given master.
|
|
59
|
+
overrideredirect: If True, instruct the window manager to ignore this window.
|
|
60
|
+
windowtype: On X11, request a specific window manager type via `-type`.
|
|
61
|
+
topmost: If True, keep this window above others (`-topmost`).
|
|
62
|
+
toolwindow: On Windows, request a toolwindow style (`-toolwindow`).
|
|
63
|
+
alpha: On Windows, the window alpha transparency (0.0–1.0) via `-alpha`.
|
|
64
|
+
window_style: Windows-only pywinstyles effect. Options include
|
|
65
|
+
'mica', 'acrylic', 'aero', 'transparent', 'win7', etc.
|
|
66
|
+
Defaults to 'mica'. Set to None to disable.
|
|
67
|
+
**kwargs: Other keyword arguments passed to `tkinter.Toplevel`.
|
|
68
|
+
"""
|
|
69
|
+
# Extract iconify kwarg if present
|
|
70
|
+
iconify = kwargs.pop("iconify", None)
|
|
71
|
+
|
|
72
|
+
# Initialize Toplevel
|
|
73
|
+
tkinter.Toplevel.__init__(self, **kwargs)
|
|
74
|
+
|
|
75
|
+
# Setup window system info
|
|
76
|
+
self.winsys: str = self.tk.call("tk", "windowingsystem")
|
|
77
|
+
|
|
78
|
+
# Apply Aqua MacWindowStyle BEFORE any setup that might pump the
|
|
79
|
+
# event loop (icons, geometry, update_idletasks). Tk's docs require
|
|
80
|
+
# the style to be set on a freshly-created, never-mapped window;
|
|
81
|
+
# after the first event-loop trip the call silently has no effect
|
|
82
|
+
# and the window keeps its default chrome. We withdraw immediately
|
|
83
|
+
# so the window is unmapped, set the style, then continue.
|
|
84
|
+
self.withdraw()
|
|
85
|
+
if windowtype is not None and self.winsys == "aqua":
|
|
86
|
+
aqua_style = {
|
|
87
|
+
"tooltip": ("help", "none"),
|
|
88
|
+
"splash": ("plain", "none"),
|
|
89
|
+
"utility": ("utility", "none"),
|
|
90
|
+
"dock": ("plain", "none"),
|
|
91
|
+
}.get(windowtype)
|
|
92
|
+
if aqua_style is not None:
|
|
93
|
+
try:
|
|
94
|
+
self.tk.call(
|
|
95
|
+
"::tk::unsupported::MacWindowStyle", "style",
|
|
96
|
+
self, aqua_style[0], aqua_style[1],
|
|
97
|
+
)
|
|
98
|
+
except tkinter.TclError:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
# Setup icon (use default bootstack icon if no icon provided)
|
|
102
|
+
self._setup_icon(icon, default_icon_enabled=True)
|
|
103
|
+
|
|
104
|
+
# Setup window using BaseWindow
|
|
105
|
+
self._setup_window(
|
|
106
|
+
title=title,
|
|
107
|
+
size=size,
|
|
108
|
+
position=position,
|
|
109
|
+
minsize=minsize,
|
|
110
|
+
maxsize=maxsize,
|
|
111
|
+
resizable=resizable,
|
|
112
|
+
transient=transient,
|
|
113
|
+
overrideredirect=overrideredirect,
|
|
114
|
+
alpha=alpha,
|
|
115
|
+
window_style=window_style,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Handle iconify
|
|
119
|
+
if iconify:
|
|
120
|
+
self.iconify()
|
|
121
|
+
|
|
122
|
+
# X11 -type attribute. The Aqua case was handled before
|
|
123
|
+
# _setup_window above (style must be set pre-map).
|
|
124
|
+
if windowtype is not None and self.winsys == "x11":
|
|
125
|
+
self.attributes("-type", windowtype)
|
|
126
|
+
|
|
127
|
+
if topmost:
|
|
128
|
+
self.attributes("-topmost", 1)
|
|
129
|
+
|
|
130
|
+
if toolwindow and self.winsys == "win32":
|
|
131
|
+
self.attributes("-toolwindow", 1)
|