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,786 @@
|
|
|
1
|
+
"""Base window functionality shared between App (Tk) and Toplevel.
|
|
2
|
+
|
|
3
|
+
This module provides the BaseWindow mixin class that encapsulates common
|
|
4
|
+
window management functionality used by both the main App and Toplevel classes.
|
|
5
|
+
This eliminates code duplication and ensures consistent behavior across all
|
|
6
|
+
window types.
|
|
7
|
+
|
|
8
|
+
Standard widget APIs (events, scheduling, clipboard, geometry managers, winfo) are documented under capabilities and are
|
|
9
|
+
available through normal Tk/Ttk inheritance.”
|
|
10
|
+
|
|
11
|
+
The BaseWindow mixin provides:
|
|
12
|
+
- Window manager (wm) pass-throughs with modern docstrings
|
|
13
|
+
- Window configuration (size, position, constraints)
|
|
14
|
+
- Alpha transparency handling (platform-aware)
|
|
15
|
+
- Icon management
|
|
16
|
+
- Positioning utilities
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import tkinter
|
|
22
|
+
from typing import Literal, Optional, Tuple, Callable, Any
|
|
23
|
+
|
|
24
|
+
from bootstack.core.localization import MessageCatalog
|
|
25
|
+
from bootstack.runtime.window_utilities import AnchorPoint, WindowPositioning, WindowSizing
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def on_visibility_alpha(event: tkinter.Event) -> None:
|
|
29
|
+
"""Set Window or Toplevel alpha value on Visibility (X11).
|
|
30
|
+
|
|
31
|
+
X11 requires alpha to be set after the window is visible, so we bind
|
|
32
|
+
to the <Visibility> event and set alpha then, unbinding after first use.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
event: The visibility event containing the widget.
|
|
36
|
+
"""
|
|
37
|
+
widget = event.widget
|
|
38
|
+
if hasattr(widget, 'alpha') and hasattr(widget, 'alpha_bind'):
|
|
39
|
+
if widget.alpha_bind:
|
|
40
|
+
widget.unbind(widget.alpha_bind)
|
|
41
|
+
widget.attributes("-alpha", widget.alpha)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class BaseWindow:
|
|
45
|
+
"""Base window behavior shared by bootstack windows.
|
|
46
|
+
|
|
47
|
+
This class is intended to be used as a mixin alongside `tkinter.Tk` or
|
|
48
|
+
`tkinter.Toplevel`, for example:
|
|
49
|
+
|
|
50
|
+
class App(BaseWindow, tkinter.Tk): ...
|
|
51
|
+
class Window(BaseWindow, tkinter.Toplevel): ...
|
|
52
|
+
|
|
53
|
+
The methods below are thin pass-throughs to Tk's window manager ("wm")
|
|
54
|
+
functionality, primarily to provide modern, consistent docstrings and a
|
|
55
|
+
curated, documented API surface.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
_title_message_id: str | None = None
|
|
59
|
+
|
|
60
|
+
# -------------------------------------------------------------------------
|
|
61
|
+
# Setup methods (bootstack-specific)
|
|
62
|
+
# -------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
def _setup_window(
|
|
65
|
+
self,
|
|
66
|
+
title: str = "bootstack",
|
|
67
|
+
size: Optional[tuple[int, int]] = None,
|
|
68
|
+
position: Optional[tuple[int, int]] = None,
|
|
69
|
+
minsize: Optional[tuple[int, int]] = None,
|
|
70
|
+
maxsize: Optional[tuple[int, int]] = None,
|
|
71
|
+
resizable: Optional[tuple[bool, bool]] = None,
|
|
72
|
+
transient: Optional[tkinter.Misc] = None,
|
|
73
|
+
overrideredirect: bool = False,
|
|
74
|
+
alpha: float = 1.0,
|
|
75
|
+
window_style: Optional[str] = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Configure common window properties.
|
|
78
|
+
|
|
79
|
+
This method should be called during window initialization to set up
|
|
80
|
+
standard window properties. It handles platform differences automatically.
|
|
81
|
+
The window is temporarily hidden during setup so that sizing and
|
|
82
|
+
positioning are applied before it is shown.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
title: Window title shown in titlebar.
|
|
86
|
+
size: Optional (width, height) in pixels.
|
|
87
|
+
position: Optional (x, y) position on screen.
|
|
88
|
+
minsize: Optional (width, height) minimum window size.
|
|
89
|
+
maxsize: Optional (width, height) maximum window size.
|
|
90
|
+
resizable: Optional (width, height) resizable flags.
|
|
91
|
+
transient: Optional master window for transient behavior.
|
|
92
|
+
overrideredirect: If True, removes window decorations.
|
|
93
|
+
alpha: Transparency level (0.0 to 1.0). Platform-aware.
|
|
94
|
+
window_style: Windows-only pywinstyles effect. Options include
|
|
95
|
+
'mica', 'acrylic', 'aero', 'transparent', 'win7', etc.
|
|
96
|
+
If None, uses AppSettings.window_style (defaults to 'mica').
|
|
97
|
+
|
|
98
|
+
Note:
|
|
99
|
+
The window must already be initialized (tkinter.Tk.__init__ or
|
|
100
|
+
tkinter.Toplevel.__init__ called) before calling this method.
|
|
101
|
+
"""
|
|
102
|
+
# Get window_style from AppSettings if not explicitly provided
|
|
103
|
+
if window_style is None:
|
|
104
|
+
try:
|
|
105
|
+
from bootstack.runtime.app import get_app_settings
|
|
106
|
+
window_style = get_app_settings().window_style
|
|
107
|
+
except (ImportError, RuntimeError):
|
|
108
|
+
# No app registered yet, use default
|
|
109
|
+
window_style = 'mica'
|
|
110
|
+
|
|
111
|
+
# Store window style for later application
|
|
112
|
+
self._window_style = window_style
|
|
113
|
+
# Hide window until we finish applying geometry/resizing to avoid flicker
|
|
114
|
+
self.withdraw()
|
|
115
|
+
|
|
116
|
+
# Store window system for platform-specific behavior
|
|
117
|
+
if not hasattr(self, 'winsys'):
|
|
118
|
+
self.winsys = self.tk.call('tk', 'windowingsystem')
|
|
119
|
+
|
|
120
|
+
# Basic configuration - localize title automatically
|
|
121
|
+
self.title(title)
|
|
122
|
+
|
|
123
|
+
# Bind locale changes
|
|
124
|
+
self.winfo_toplevel().bind("<<LocaleChanged>>", self._handle_locale_changed)
|
|
125
|
+
|
|
126
|
+
# Geometry
|
|
127
|
+
if size is not None:
|
|
128
|
+
width, height = size
|
|
129
|
+
self.geometry(f"{width}x{height}")
|
|
130
|
+
|
|
131
|
+
# Track whether we should center (defer until after constraints)
|
|
132
|
+
_should_center = (position is None)
|
|
133
|
+
|
|
134
|
+
if position is not None:
|
|
135
|
+
xpos, ypos = position
|
|
136
|
+
self.geometry(f"+{xpos}+{ypos}")
|
|
137
|
+
|
|
138
|
+
# Size constraints
|
|
139
|
+
if minsize is not None:
|
|
140
|
+
width, height = minsize
|
|
141
|
+
self.minsize(width, height)
|
|
142
|
+
|
|
143
|
+
if maxsize is not None:
|
|
144
|
+
width, height = maxsize
|
|
145
|
+
self.maxsize(width, height)
|
|
146
|
+
|
|
147
|
+
if resizable is not None:
|
|
148
|
+
width, height = resizable
|
|
149
|
+
self.resizable(width, height)
|
|
150
|
+
|
|
151
|
+
# Window attributes
|
|
152
|
+
if transient is not None:
|
|
153
|
+
self.transient(transient)
|
|
154
|
+
|
|
155
|
+
if overrideredirect:
|
|
156
|
+
# Skip overrideredirect on macOS - causes click handling issues and crashes
|
|
157
|
+
if self.winsys != 'aqua':
|
|
158
|
+
self.overrideredirect(1)
|
|
159
|
+
|
|
160
|
+
# Alpha transparency (platform-aware)
|
|
161
|
+
self._setup_alpha(alpha)
|
|
162
|
+
|
|
163
|
+
# Center window on screen if no explicit position was provided
|
|
164
|
+
if _should_center:
|
|
165
|
+
# Update geometry to ensure size is applied before centering
|
|
166
|
+
self.update_idletasks()
|
|
167
|
+
x, y = WindowPositioning.center_on_screen(self)
|
|
168
|
+
x, y = WindowPositioning.ensure_on_screen(self, x, y)
|
|
169
|
+
self.geometry(f'+{x}+{y}')
|
|
170
|
+
|
|
171
|
+
def _apply_window_style(self) -> None:
|
|
172
|
+
"""Apply pywinstyles effect on Windows.
|
|
173
|
+
|
|
174
|
+
Uses the window_style set during initialization. Only applies on Windows
|
|
175
|
+
and only if the style hasn't already been applied.
|
|
176
|
+
"""
|
|
177
|
+
if getattr(self, '_window_style_applied', False):
|
|
178
|
+
return
|
|
179
|
+
window_style = getattr(self, '_window_style', 'mica')
|
|
180
|
+
if window_style is None:
|
|
181
|
+
return
|
|
182
|
+
if not hasattr(self, 'winsys') or self.winsys != 'win32':
|
|
183
|
+
return
|
|
184
|
+
try:
|
|
185
|
+
import pywinstyles
|
|
186
|
+
pywinstyles.apply_style(self, window_style)
|
|
187
|
+
self._window_style_applied = True
|
|
188
|
+
except Exception:
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
def _setup_alpha(self, alpha: float) -> None:
|
|
192
|
+
"""Configure window alpha transparency in a platform-aware manner.
|
|
193
|
+
|
|
194
|
+
Handles platform differences in alpha transparency support:
|
|
195
|
+
- X11: Requires setting alpha after window is visible
|
|
196
|
+
- Windows/macOS: Can set alpha immediately
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
alpha: Transparency level (0.0 = fully transparent, 1.0 = opaque).
|
|
200
|
+
|
|
201
|
+
Note:
|
|
202
|
+
On X11, this binds to <Visibility> event to set alpha after
|
|
203
|
+
the window becomes visible. The binding is automatically
|
|
204
|
+
removed after first use.
|
|
205
|
+
"""
|
|
206
|
+
if alpha is not None and alpha != 1.0:
|
|
207
|
+
if self.winsys == 'x11':
|
|
208
|
+
# X11 requires alpha to be set after window is visible
|
|
209
|
+
self.alpha = alpha
|
|
210
|
+
self.alpha_bind = self.bind("<Visibility>", on_visibility_alpha, '+')
|
|
211
|
+
else:
|
|
212
|
+
# Windows and macOS can set alpha immediately
|
|
213
|
+
self.attributes("-alpha", alpha)
|
|
214
|
+
|
|
215
|
+
def _setup_icon(self, iconphoto: Optional[str], default_icon_enabled: bool = True) -> None:
|
|
216
|
+
"""Configure window icon from file path or use default.
|
|
217
|
+
|
|
218
|
+
Sets up the window icon, with support for:
|
|
219
|
+
- Custom icon from file path or PhotoImage object
|
|
220
|
+
- Default bootstack.png from package assets (when iconphoto is None and default_icon_enabled=True)
|
|
221
|
+
- No icon (when iconphoto is None and default_icon_enabled=False)
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
iconphoto: Path to icon image file, PhotoImage object, or None for default/no icon.
|
|
225
|
+
default_icon_enabled: Whether to use default icon when iconphoto is None.
|
|
226
|
+
|
|
227
|
+
Note:
|
|
228
|
+
The icon is stored in self._icon to prevent garbage collection (for PhotoImage icons).
|
|
229
|
+
On failure to load custom icon, falls back to default icon if enabled.
|
|
230
|
+
"""
|
|
231
|
+
if iconphoto is None:
|
|
232
|
+
# No custom icon provided - use default if enabled
|
|
233
|
+
if default_icon_enabled:
|
|
234
|
+
try:
|
|
235
|
+
from pathlib import Path
|
|
236
|
+
import bootstack
|
|
237
|
+
icon_path = Path(bootstack.__file__).parent / 'assets' / 'bootstack.png'
|
|
238
|
+
self._icon = tkinter.PhotoImage(file=str(icon_path), master=self)
|
|
239
|
+
self.iconphoto(True, self._icon)
|
|
240
|
+
except (ImportError, FileNotFoundError, tkinter.TclError, Exception):
|
|
241
|
+
# Icon file not available or failed to load - silently continue
|
|
242
|
+
pass
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
# User provided a custom icon
|
|
246
|
+
try:
|
|
247
|
+
# Check if it's already a PhotoImage object
|
|
248
|
+
if isinstance(iconphoto, tkinter.PhotoImage):
|
|
249
|
+
self._icon = iconphoto
|
|
250
|
+
self.iconphoto(True, self._icon)
|
|
251
|
+
else:
|
|
252
|
+
# Assume it's a file path
|
|
253
|
+
self._icon = tkinter.PhotoImage(file=iconphoto, master=self)
|
|
254
|
+
self.iconphoto(True, self._icon)
|
|
255
|
+
except (tkinter.TclError, Exception) as e:
|
|
256
|
+
# Failed to load user icon
|
|
257
|
+
print(f'Failed to load icon: {iconphoto} - {e}')
|
|
258
|
+
if default_icon_enabled:
|
|
259
|
+
# Fall back to default bootstack.png
|
|
260
|
+
try:
|
|
261
|
+
from pathlib import Path
|
|
262
|
+
import bootstack
|
|
263
|
+
icon_path = Path(bootstack.__file__).parent / 'assets' / 'bootstack.png'
|
|
264
|
+
self._icon = tkinter.PhotoImage(file=str(icon_path), master=self)
|
|
265
|
+
self.iconphoto(True, self._icon)
|
|
266
|
+
except (ImportError, FileNotFoundError, tkinter.TclError, Exception):
|
|
267
|
+
pass
|
|
268
|
+
|
|
269
|
+
def _handle_locale_changed(self, *_):
|
|
270
|
+
"""Handle locale change events by updating the localized title."""
|
|
271
|
+
if self._title_message_id:
|
|
272
|
+
self.title(self._title_message_id)
|
|
273
|
+
|
|
274
|
+
# -------------------------------------------------------------------------
|
|
275
|
+
# Window manager (wm) — pass-throughs with modern docstrings
|
|
276
|
+
# -------------------------------------------------------------------------
|
|
277
|
+
|
|
278
|
+
def show(self) -> None:
|
|
279
|
+
"""Show the window after it has been fully initialized.
|
|
280
|
+
|
|
281
|
+
This forces a geometry/layout pass before mapping the window, which is
|
|
282
|
+
useful if you have performed setup that affects sizing.
|
|
283
|
+
"""
|
|
284
|
+
# Apply Windows window style while still withdrawn to prevent flash.
|
|
285
|
+
# The update() flushes input/IO events so pywinstyles can attach to a
|
|
286
|
+
# fully realized HWND on Windows; on Aqua it can hang indefinitely
|
|
287
|
+
# processing children's pending events (see Dialog._position_dialog
|
|
288
|
+
# for the same pattern), so gate it on the platform that needs it.
|
|
289
|
+
self.update_idletasks()
|
|
290
|
+
self._apply_window_style()
|
|
291
|
+
if getattr(self, 'winsys', None) == 'win32':
|
|
292
|
+
self.update()
|
|
293
|
+
self.deiconify()
|
|
294
|
+
|
|
295
|
+
def title(self, value: str | None = None) -> str:
|
|
296
|
+
"""Get or set the window title.
|
|
297
|
+
|
|
298
|
+
If you localize UI text (e.g., via a message catalog), the title is
|
|
299
|
+
automatically translated using the MessageCatalog.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
value: The new title text. If None, return the current title.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
The current title string (getter) or the title string after setting.
|
|
306
|
+
"""
|
|
307
|
+
if value is None:
|
|
308
|
+
return super().title()
|
|
309
|
+
self._title_message_id = value
|
|
310
|
+
return super().title(MessageCatalog.translate(self._title_message_id))
|
|
311
|
+
|
|
312
|
+
def geometry(self, new_geometry: str | None = None) -> str:
|
|
313
|
+
"""Get or set the window geometry.
|
|
314
|
+
|
|
315
|
+
Geometry strings use the standard Tk format:
|
|
316
|
+
|
|
317
|
+
- "{width}x{height}" (size only)
|
|
318
|
+
- "+{x}+{y}" (position only)
|
|
319
|
+
- "{width}x{height}+{x}+{y}" (size + position)
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
new_geometry: The geometry string to apply. If None, return the
|
|
323
|
+
current geometry string.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
The current geometry string (getter) or the geometry after setting.
|
|
327
|
+
"""
|
|
328
|
+
return super().geometry(new_geometry)
|
|
329
|
+
|
|
330
|
+
def state(self, newstate: str | None = None) -> str:
|
|
331
|
+
"""Get or set the window manager state.
|
|
332
|
+
|
|
333
|
+
Common states include:
|
|
334
|
+
|
|
335
|
+
- "normal": displayed normally
|
|
336
|
+
- "iconic": minimized (iconified)
|
|
337
|
+
- "withdrawn": hidden (not shown)
|
|
338
|
+
- "zoomed": maximized (platform/window-manager dependent)
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
newstate: State to apply. If None, return the current state.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
The current state string.
|
|
345
|
+
"""
|
|
346
|
+
return super().state(newstate)
|
|
347
|
+
|
|
348
|
+
def attributes(self, *args: Any) -> Any:
|
|
349
|
+
"""Get or set platform-specific window attributes.
|
|
350
|
+
|
|
351
|
+
This method forwards to Tk's "wm attributes" command. Common attributes:
|
|
352
|
+
|
|
353
|
+
- "-alpha" (float 0.0-1.0): transparency
|
|
354
|
+
- "-fullscreen" (bool): fullscreen mode
|
|
355
|
+
- "-topmost" (bool): keep window above others
|
|
356
|
+
|
|
357
|
+
The exact supported attributes vary by platform/window manager.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
*args: Arguments accepted by Tk's `wm attributes`. Common forms are:
|
|
361
|
+
- (name,) to query a single attribute
|
|
362
|
+
- (name, value) to set an attribute
|
|
363
|
+
- () to query all supported attributes (platform dependent)
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
The queried attribute value(s), or an implementation-dependent
|
|
367
|
+
result when setting.
|
|
368
|
+
"""
|
|
369
|
+
return super().attributes(*args)
|
|
370
|
+
|
|
371
|
+
def iconify(self) -> None:
|
|
372
|
+
"""Minimize (iconify) the window."""
|
|
373
|
+
return super().iconify()
|
|
374
|
+
|
|
375
|
+
def deiconify(self) -> None:
|
|
376
|
+
"""Show a minimized or withdrawn window.
|
|
377
|
+
|
|
378
|
+
This restores a window that has been hidden with `withdraw()` or
|
|
379
|
+
minimized with `iconify()`.
|
|
380
|
+
"""
|
|
381
|
+
return super().deiconify()
|
|
382
|
+
|
|
383
|
+
def withdraw(self) -> None:
|
|
384
|
+
"""Hide the window without destroying it.
|
|
385
|
+
|
|
386
|
+
A withdrawn window is unmapped and typically removed from
|
|
387
|
+
taskbar/window lists. Use `deiconify()` to show it again.
|
|
388
|
+
"""
|
|
389
|
+
return super().withdraw()
|
|
390
|
+
|
|
391
|
+
def resizable(self, width: bool | None = None, height: bool | None = None) -> tuple[int, int] | None:
|
|
392
|
+
"""Get or set whether the user can resize the window.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
width: If provided, enable/disable horizontal resizing.
|
|
396
|
+
height: If provided, enable/disable vertical resizing.
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
When called as a getter (both args None), returns `(width_flag, height_flag)`
|
|
400
|
+
where each flag is 0/1. When called as a setter, Tk returns None.
|
|
401
|
+
"""
|
|
402
|
+
return super().resizable(width, height)
|
|
403
|
+
|
|
404
|
+
def minsize(self, width: int | None = None, height: int | None = None) -> tuple[int, int] | None:
|
|
405
|
+
"""Get or set the minimum window size in pixels.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
width: Minimum width in pixels. If None, act as a getter.
|
|
409
|
+
height: Minimum height in pixels. If None, act as a getter.
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
When called as a getter (both args None), returns `(width, height)`.
|
|
413
|
+
When called as a setter, Tk returns None.
|
|
414
|
+
"""
|
|
415
|
+
return super().minsize(width, height)
|
|
416
|
+
|
|
417
|
+
def maxsize(self, width: int | None = None, height: int | None = None) -> tuple[int, int] | None:
|
|
418
|
+
"""Get or set the maximum window size in pixels.
|
|
419
|
+
|
|
420
|
+
Args:
|
|
421
|
+
width: Maximum width in pixels. If None, act as a getter.
|
|
422
|
+
height: Maximum height in pixels. If None, act as a getter.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
When called as a getter (both args None), returns `(width, height)`.
|
|
426
|
+
When called as a setter, Tk returns None.
|
|
427
|
+
"""
|
|
428
|
+
return super().maxsize(width, height)
|
|
429
|
+
|
|
430
|
+
def transient(self, master: tkinter.Misc | None = None) -> tkinter.Misc | None:
|
|
431
|
+
"""Get or set the transient parent (window relationship).
|
|
432
|
+
|
|
433
|
+
Transient windows typically stay on top of their parent and may be
|
|
434
|
+
omitted from the taskbar. This is commonly used for dialogs.
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
master: The parent window. If None, return the current transient parent.
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
The current transient parent (getter) or the provided master (setter),
|
|
441
|
+
depending on Tk/platform behavior.
|
|
442
|
+
"""
|
|
443
|
+
return super().transient(master)
|
|
444
|
+
|
|
445
|
+
def protocol(self, name: str, func: Callable[[], Any] | None = None) -> Any:
|
|
446
|
+
"""Get or set a window manager protocol handler.
|
|
447
|
+
|
|
448
|
+
The most common protocol is "WM_DELETE_WINDOW" (close button).
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
name: Protocol name.
|
|
452
|
+
func: Handler to register. If None, return the current handler (if any).
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
The current handler when queried, or an implementation-dependent result
|
|
456
|
+
when setting.
|
|
457
|
+
"""
|
|
458
|
+
return super().protocol(name, func)
|
|
459
|
+
|
|
460
|
+
def overrideredirect(self, boolean: bool | None = None) -> bool | None:
|
|
461
|
+
"""Get or set override-redirect mode.
|
|
462
|
+
|
|
463
|
+
When enabled, the window manager typically does not decorate or manage
|
|
464
|
+
the window (no title bar/borders). Useful for popups/menus; use with care.
|
|
465
|
+
|
|
466
|
+
Note:
|
|
467
|
+
On macOS (Aqua), overrideredirect is disabled due to Tk/Cocoa issues
|
|
468
|
+
with click handling and event processing that can cause crashes.
|
|
469
|
+
|
|
470
|
+
Args:
|
|
471
|
+
boolean: True to enable override-redirect, False to disable. If None,
|
|
472
|
+
return the current value.
|
|
473
|
+
|
|
474
|
+
Returns:
|
|
475
|
+
The current override-redirect value when queried, or None when set.
|
|
476
|
+
"""
|
|
477
|
+
# Skip overrideredirect on macOS - causes click handling issues and crashes
|
|
478
|
+
if boolean and hasattr(self, 'winsys') and self.winsys == 'aqua':
|
|
479
|
+
return None
|
|
480
|
+
return super().overrideredirect(boolean)
|
|
481
|
+
|
|
482
|
+
# -------------------------------------------------------------------------
|
|
483
|
+
# Convenience wrappers: intent-based names for common tasks
|
|
484
|
+
# -------------------------------------------------------------------------
|
|
485
|
+
|
|
486
|
+
def on_close(self, handler: Callable[[], Any]) -> None:
|
|
487
|
+
"""Register a handler for the window close button.
|
|
488
|
+
|
|
489
|
+
This is a convenience wrapper for:
|
|
490
|
+
|
|
491
|
+
protocol("WM_DELETE_WINDOW", handler)
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
handler: A callable invoked when the user requests to close the window.
|
|
495
|
+
"""
|
|
496
|
+
self.protocol("WM_DELETE_WINDOW", handler)
|
|
497
|
+
|
|
498
|
+
def hide(self) -> None:
|
|
499
|
+
"""Hide the window (alias for `withdraw()`)."""
|
|
500
|
+
self.withdraw()
|
|
501
|
+
|
|
502
|
+
def minimize(self) -> None:
|
|
503
|
+
"""Minimize the window (alias for `iconify()`)."""
|
|
504
|
+
self.iconify()
|
|
505
|
+
|
|
506
|
+
def maximize(self) -> None:
|
|
507
|
+
"""Maximize the window where supported.
|
|
508
|
+
|
|
509
|
+
Tk uses `state("zoomed")` to request maximized windows on some platforms.
|
|
510
|
+
On unsupported window managers this may raise `tkinter.TclError`.
|
|
511
|
+
"""
|
|
512
|
+
try:
|
|
513
|
+
self.state("zoomed")
|
|
514
|
+
except tkinter.TclError:
|
|
515
|
+
pass
|
|
516
|
+
|
|
517
|
+
def set_topmost(self, value: bool = True) -> None:
|
|
518
|
+
"""Enable/disable always-on-top behavior where supported.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
value: True to keep the window above others; False to disable.
|
|
522
|
+
"""
|
|
523
|
+
try:
|
|
524
|
+
self.attributes("-topmost", bool(value))
|
|
525
|
+
except tkinter.TclError:
|
|
526
|
+
pass
|
|
527
|
+
|
|
528
|
+
# Backward compatibility alias
|
|
529
|
+
keep_on_top = set_topmost
|
|
530
|
+
|
|
531
|
+
def set_fullscreen(self, value: bool = True) -> None:
|
|
532
|
+
"""Enable/disable fullscreen where supported.
|
|
533
|
+
|
|
534
|
+
Args:
|
|
535
|
+
value: True to enter fullscreen; False to exit.
|
|
536
|
+
"""
|
|
537
|
+
try:
|
|
538
|
+
self.attributes("-fullscreen", bool(value))
|
|
539
|
+
except tkinter.TclError:
|
|
540
|
+
pass
|
|
541
|
+
|
|
542
|
+
def set_alpha(self, value: float) -> None:
|
|
543
|
+
"""Set window opacity where supported.
|
|
544
|
+
|
|
545
|
+
Args:
|
|
546
|
+
value: Opacity from 0.0 (transparent) to 1.0 (opaque).
|
|
547
|
+
"""
|
|
548
|
+
try:
|
|
549
|
+
self.attributes("-alpha", float(value))
|
|
550
|
+
except tkinter.TclError:
|
|
551
|
+
pass
|
|
552
|
+
|
|
553
|
+
# -------------------------------------------------------------------------
|
|
554
|
+
# Positioning utilities
|
|
555
|
+
# -------------------------------------------------------------------------
|
|
556
|
+
|
|
557
|
+
def place_center(self) -> None:
|
|
558
|
+
"""Position the window in the center of the screen.
|
|
559
|
+
|
|
560
|
+
Centers the window on the primary display. For multi-monitor setups,
|
|
561
|
+
this typically centers on the monitor containing the mouse pointer.
|
|
562
|
+
|
|
563
|
+
The window geometry is updated immediately.
|
|
564
|
+
|
|
565
|
+
Examples:
|
|
566
|
+
>>> app = App()
|
|
567
|
+
>>> app.place_center()
|
|
568
|
+
>>> app.mainloop()
|
|
569
|
+
"""
|
|
570
|
+
x, y = WindowPositioning.center_on_screen(self)
|
|
571
|
+
x, y = WindowPositioning.ensure_on_screen(self, x, y)
|
|
572
|
+
self.geometry(f'+{x}+{y}')
|
|
573
|
+
|
|
574
|
+
def place_center_on(self, parent: tkinter.Misc) -> None:
|
|
575
|
+
"""Position the window centered on a parent widget or window.
|
|
576
|
+
|
|
577
|
+
Centers this window on the specified parent widget or window.
|
|
578
|
+
Commonly used for dialogs to center them on their parent window.
|
|
579
|
+
|
|
580
|
+
Args:
|
|
581
|
+
parent: The parent widget or window to center on.
|
|
582
|
+
|
|
583
|
+
Examples:
|
|
584
|
+
>>> parent = App()
|
|
585
|
+
>>> dialog = Toplevel()
|
|
586
|
+
>>> dialog.place_center_on(parent)
|
|
587
|
+
"""
|
|
588
|
+
x, y = WindowPositioning.center_on_parent(self, parent)
|
|
589
|
+
x, y = WindowPositioning.ensure_on_screen(self, x, y)
|
|
590
|
+
self.geometry(f'+{x}+{y}')
|
|
591
|
+
|
|
592
|
+
def place_at(self, x: int, y: int, ensure_visible: bool = True) -> None:
|
|
593
|
+
"""Position the window at specific screen coordinates.
|
|
594
|
+
|
|
595
|
+
Places the window at the given (x, y) coordinates, optionally
|
|
596
|
+
adjusting the position to ensure the window remains fully visible
|
|
597
|
+
on screen.
|
|
598
|
+
|
|
599
|
+
Args:
|
|
600
|
+
x: X coordinate on screen (in pixels from left edge).
|
|
601
|
+
y: Y coordinate on screen (in pixels from top edge).
|
|
602
|
+
ensure_visible: If True, adjusts coordinates to keep window on screen.
|
|
603
|
+
|
|
604
|
+
Examples:
|
|
605
|
+
>>> window = App()
|
|
606
|
+
>>> window.place_at(100, 100)
|
|
607
|
+
"""
|
|
608
|
+
if ensure_visible:
|
|
609
|
+
x, y = WindowPositioning.ensure_on_screen(self, x, y)
|
|
610
|
+
self.geometry(f'+{x}+{y}')
|
|
611
|
+
|
|
612
|
+
def place_anchor(
|
|
613
|
+
self,
|
|
614
|
+
anchor_to: tkinter.Misc,
|
|
615
|
+
anchor_point: AnchorPoint = 'sw',
|
|
616
|
+
window_point: AnchorPoint = 'nw',
|
|
617
|
+
offset: Tuple[int, int] = (0, 0),
|
|
618
|
+
ensure_visible: bool = True
|
|
619
|
+
) -> None:
|
|
620
|
+
"""Position window relative to another widget using anchor points.
|
|
621
|
+
|
|
622
|
+
Uses tkinter's standard anchor naming (n, s, e, w, ne, nw, se, sw, center).
|
|
623
|
+
This is useful for dropdowns, tooltips, context menus, and popovers.
|
|
624
|
+
|
|
625
|
+
Args:
|
|
626
|
+
anchor_to: The widget to anchor this window to.
|
|
627
|
+
anchor_point: Which point on the anchor widget to use (default 'sw').
|
|
628
|
+
window_point: Which point on this window to align (default 'nw').
|
|
629
|
+
offset: Additional (x, y) offset in pixels.
|
|
630
|
+
ensure_visible: If True, adjusts position to keep window on screen.
|
|
631
|
+
|
|
632
|
+
Examples:
|
|
633
|
+
>>> # Show dialog below button
|
|
634
|
+
>>> dialog = Toplevel()
|
|
635
|
+
>>> dialog.place_anchor(
|
|
636
|
+
... anchor_to=button,
|
|
637
|
+
... anchor_point='sw', # button's bottom-left
|
|
638
|
+
... window_point='nw', # dialog's top-left
|
|
639
|
+
... offset=(0, 5)
|
|
640
|
+
... )
|
|
641
|
+
"""
|
|
642
|
+
WindowPositioning.position_with_anchor(
|
|
643
|
+
window=self,
|
|
644
|
+
anchor_to=anchor_to,
|
|
645
|
+
anchor_point=anchor_point,
|
|
646
|
+
window_point=window_point,
|
|
647
|
+
offset=offset,
|
|
648
|
+
ensure_visible=ensure_visible
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
def place_dropdown(
|
|
652
|
+
self,
|
|
653
|
+
trigger_widget: tkinter.Misc,
|
|
654
|
+
prefer_below: bool = True,
|
|
655
|
+
align: Literal['left', 'right', 'center'] = 'left',
|
|
656
|
+
offset: Tuple[int, int] = (0, 2),
|
|
657
|
+
ensure_visible: bool = True,
|
|
658
|
+
auto_flip: bool = True
|
|
659
|
+
) -> None:
|
|
660
|
+
"""Position window as a dropdown relative to a trigger widget.
|
|
661
|
+
|
|
662
|
+
Smart positioning that automatically flips above/below based on
|
|
663
|
+
available space. Perfect for combobox dropdowns, autocomplete
|
|
664
|
+
suggestions, and dropdown menus.
|
|
665
|
+
|
|
666
|
+
Args:
|
|
667
|
+
trigger_widget: The widget that triggers the dropdown.
|
|
668
|
+
prefer_below: If True, tries to show below trigger; else tries above.
|
|
669
|
+
align: Horizontal alignment ('left', 'right', or 'center').
|
|
670
|
+
offset: Additional (x, y) offset in pixels.
|
|
671
|
+
ensure_visible: If True, adjusts position to keep window on screen.
|
|
672
|
+
auto_flip: If True, automatically flips above/below if no room.
|
|
673
|
+
|
|
674
|
+
Examples:
|
|
675
|
+
>>> # Dropdown menu below button
|
|
676
|
+
>>> menu = Toplevel()
|
|
677
|
+
>>> menu.place_dropdown(
|
|
678
|
+
... trigger_widget=button,
|
|
679
|
+
... prefer_below=True,
|
|
680
|
+
... align='left'
|
|
681
|
+
... )
|
|
682
|
+
"""
|
|
683
|
+
WindowPositioning.position_dropdown(
|
|
684
|
+
window=self,
|
|
685
|
+
trigger_widget=trigger_widget,
|
|
686
|
+
prefer_below=prefer_below,
|
|
687
|
+
align=align,
|
|
688
|
+
offset=offset,
|
|
689
|
+
ensure_visible=ensure_visible,
|
|
690
|
+
auto_flip=auto_flip
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
def place_cursor(
|
|
694
|
+
self,
|
|
695
|
+
offset: Tuple[int, int] = (5, 5),
|
|
696
|
+
ensure_visible: bool = True
|
|
697
|
+
) -> None:
|
|
698
|
+
"""Position window at the current mouse cursor location.
|
|
699
|
+
|
|
700
|
+
Useful for context menus, tooltips that follow the cursor, or
|
|
701
|
+
click-to-show dialogs.
|
|
702
|
+
|
|
703
|
+
Args:
|
|
704
|
+
offset: Additional (x, y) offset from cursor in pixels.
|
|
705
|
+
ensure_visible: If True, adjusts position to keep window on screen.
|
|
706
|
+
|
|
707
|
+
Examples:
|
|
708
|
+
>>> # Show context menu at cursor
|
|
709
|
+
>>> menu = Toplevel()
|
|
710
|
+
>>> menu.place_cursor(offset=(2, 2))
|
|
711
|
+
"""
|
|
712
|
+
WindowPositioning.position_at_cursor(
|
|
713
|
+
window=self,
|
|
714
|
+
offset=offset,
|
|
715
|
+
ensure_visible=ensure_visible
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
# Backward compatibility aliases
|
|
719
|
+
def place_window_center(self) -> None:
|
|
720
|
+
"""Alias for place_center(). Deprecated, use place_center() instead."""
|
|
721
|
+
self.place_center()
|
|
722
|
+
|
|
723
|
+
position_center = place_center # Additional alias for compatibility
|
|
724
|
+
|
|
725
|
+
# -------------------------------------------------------------------------
|
|
726
|
+
# Sizing utilities
|
|
727
|
+
# -------------------------------------------------------------------------
|
|
728
|
+
|
|
729
|
+
def set_default_size(
|
|
730
|
+
self,
|
|
731
|
+
width_ratio: float = 0.6,
|
|
732
|
+
height_ratio: float = 0.7,
|
|
733
|
+
min_width: int = 400,
|
|
734
|
+
min_height: int = 300,
|
|
735
|
+
max_width: Optional[int] = None,
|
|
736
|
+
max_height: Optional[int] = None
|
|
737
|
+
) -> None:
|
|
738
|
+
"""Set window size as a percentage of screen size.
|
|
739
|
+
|
|
740
|
+
Calculates and applies a window size based on screen dimensions,
|
|
741
|
+
constrained by minimum and optional maximum sizes. Useful for
|
|
742
|
+
creating responsive windows that adapt to different screen sizes.
|
|
743
|
+
|
|
744
|
+
Args:
|
|
745
|
+
width_ratio: Proportion of screen width (0.0 to 1.0).
|
|
746
|
+
height_ratio: Proportion of screen height (0.0 to 1.0).
|
|
747
|
+
min_width: Minimum window width in pixels.
|
|
748
|
+
min_height: Minimum window height in pixels.
|
|
749
|
+
max_width: Optional maximum window width in pixels.
|
|
750
|
+
max_height: Optional maximum window height in pixels.
|
|
751
|
+
|
|
752
|
+
Examples:
|
|
753
|
+
>>> window = App()
|
|
754
|
+
>>> window.set_default_size(width_ratio=0.8, height_ratio=0.8)
|
|
755
|
+
>>> # Window will be 80% of screen size
|
|
756
|
+
"""
|
|
757
|
+
width, height = WindowSizing.get_default_size(
|
|
758
|
+
self, width_ratio, height_ratio,
|
|
759
|
+
min_width, min_height, max_width, max_height
|
|
760
|
+
)
|
|
761
|
+
self.geometry(f"{width}x{height}")
|
|
762
|
+
|
|
763
|
+
def apply_size_constraints(
|
|
764
|
+
self,
|
|
765
|
+
minsize: Optional[tuple[int, int]] = None,
|
|
766
|
+
maxsize: Optional[tuple[int, int]] = None,
|
|
767
|
+
resizable: Optional[tuple[bool, bool]] = None
|
|
768
|
+
) -> None:
|
|
769
|
+
"""Apply multiple size constraints at once.
|
|
770
|
+
|
|
771
|
+
Convenience method to set minsize, maxsize, and resizable in one call.
|
|
772
|
+
|
|
773
|
+
Args:
|
|
774
|
+
minsize: Optional (width, height) minimum size.
|
|
775
|
+
maxsize: Optional (width, height) maximum size.
|
|
776
|
+
resizable: Optional (width, height) resizable flags.
|
|
777
|
+
|
|
778
|
+
Examples:
|
|
779
|
+
>>> window = App()
|
|
780
|
+
>>> window.apply_size_constraints(
|
|
781
|
+
... minsize=(400, 300),
|
|
782
|
+
... resizable=(True, False) # Width resizable, height fixed
|
|
783
|
+
... )
|
|
784
|
+
"""
|
|
785
|
+
WindowSizing.apply_size_constraints(self, minsize, maxsize, resizable)
|
|
786
|
+
|