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,404 @@
|
|
|
1
|
+
import tkinter as tk
|
|
2
|
+
from tkinter import Misc
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
from typing import Any, Literal, Optional, Union
|
|
5
|
+
|
|
6
|
+
from bootstack.constants import *
|
|
7
|
+
from bootstack.runtime.toplevel import Toplevel
|
|
8
|
+
from bootstack.runtime.utility import scale_size
|
|
9
|
+
from bootstack.runtime.window_utilities import WindowPositioning, AnchorPoint
|
|
10
|
+
from bootstack.widgets.primitives import Button, Frame, Label
|
|
11
|
+
|
|
12
|
+
ttk = SimpleNamespace(
|
|
13
|
+
Button=Button,
|
|
14
|
+
Frame=Frame,
|
|
15
|
+
Label=Label,
|
|
16
|
+
window=SimpleNamespace(Toplevel=Toplevel),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ToolTip:
|
|
21
|
+
# Position offset from mouse pointer
|
|
22
|
+
_MOUSE_OFFSET_X = 25
|
|
23
|
+
_MOUSE_OFFSET_Y = 10
|
|
24
|
+
|
|
25
|
+
# Spacing between tooltip and widget when anchored
|
|
26
|
+
_WIDGET_SPACING = 1
|
|
27
|
+
|
|
28
|
+
# Fallback dimensions for tooltip sizing
|
|
29
|
+
_FALLBACK_WIDTH = 200
|
|
30
|
+
_FALLBACK_HEIGHT = 50
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
widget: Misc,
|
|
35
|
+
text: str = "widget info",
|
|
36
|
+
padding: int = 10,
|
|
37
|
+
justify: Literal["left", "center", "right"] = "left",
|
|
38
|
+
accent: Optional[str] = None,
|
|
39
|
+
wraplength: Optional[int] = None,
|
|
40
|
+
delay: int = 250, # milliseconds
|
|
41
|
+
image: Any = None,
|
|
42
|
+
anchor_point: Optional[AnchorPoint] = None,
|
|
43
|
+
window_point: Optional[AnchorPoint] = None,
|
|
44
|
+
auto_flip: Union[bool, Literal['vertical', 'horizontal']] = True,
|
|
45
|
+
**kwargs: Any,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Initialize a ToolTip instance for the specified widget.
|
|
48
|
+
|
|
49
|
+
Creates a tooltip that appears after a configurable delay when the mouse
|
|
50
|
+
enters the widget and disappears when the mouse leaves or on button press.
|
|
51
|
+
The tooltip can either follow the mouse pointer or be anchored to a specific
|
|
52
|
+
position relative to the widget.
|
|
53
|
+
|
|
54
|
+
The tooltip window is created with semi-transparency (alpha=0.95 by default)
|
|
55
|
+
and uses the Bootstrap styling system for consistent theming. Text automatically
|
|
56
|
+
wraps based on the specified wraplength, and optional images can be displayed
|
|
57
|
+
alongside the text.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
widget: The tkinter widget to attach this tooltip to. The tooltip will
|
|
61
|
+
appear when hovering over this widget.
|
|
62
|
+
text: The text content to display in the tooltip. Supports multi-line
|
|
63
|
+
text that will wrap according to wraplength. Defaults to "widget info".
|
|
64
|
+
padding: The internal padding in pixels between the tooltip text and the
|
|
65
|
+
tooltip border. Defaults to 10.
|
|
66
|
+
justify: Text alignment within the tooltip. Valid options are "left",
|
|
67
|
+
"center", or "right". Defaults to "left".
|
|
68
|
+
accent: Accent token for the tooltip frame (e.g., "danger", "info").
|
|
69
|
+
If None, uses default elevated background styling.
|
|
70
|
+
bootstyle: DEPRECATED - Use `accent` instead. Bootstrap style(s) to apply
|
|
71
|
+
to the tooltip frame.
|
|
72
|
+
wraplength: Maximum width in screen units before text wraps to a new line.
|
|
73
|
+
If None, defaults to a scaled value of 300 based on the widget's display.
|
|
74
|
+
delay: Time in milliseconds to wait before showing the tooltip after mouse
|
|
75
|
+
enters the widget. Defaults to 250ms.
|
|
76
|
+
image: Optional image to display in the tooltip below the text. Should be
|
|
77
|
+
a PhotoImage or compatible tkinter image object.
|
|
78
|
+
anchor_point: Point on the widget to anchor to (n, s, e, w, ne, nw, se, sw, center).
|
|
79
|
+
If None, tooltip follows the mouse pointer.
|
|
80
|
+
window_point: Point on the tooltip window to align with anchor_point
|
|
81
|
+
(n, s, e, w, ne, nw, se, sw, center). If None, auto-defaults to the
|
|
82
|
+
opposite of anchor_point for natural positioning.
|
|
83
|
+
auto_flip: Smart positioning to keep tooltip on screen. Defaults to True.
|
|
84
|
+
- False: No flipping
|
|
85
|
+
- True: Flip both vertically and horizontally as needed
|
|
86
|
+
- 'vertical': Only flip up/down
|
|
87
|
+
- 'horizontal': Only flip left/right
|
|
88
|
+
**kwargs: Additional keyword arguments passed to the Toplevel window
|
|
89
|
+
constructor. Common options include alpha, topmost, etc. The arguments
|
|
90
|
+
overrideredirect, master, and windowtype are set automatically.
|
|
91
|
+
"""
|
|
92
|
+
# Configuration
|
|
93
|
+
self._widget = widget
|
|
94
|
+
self._text = text
|
|
95
|
+
self._padding = padding
|
|
96
|
+
self._justify = justify
|
|
97
|
+
self._accent = accent
|
|
98
|
+
self._wraplength = wraplength if wraplength is not None else scale_size(self._widget, 300)
|
|
99
|
+
self._delay = delay
|
|
100
|
+
self._image = image
|
|
101
|
+
self._anchor_point = anchor_point
|
|
102
|
+
self._window_point = window_point
|
|
103
|
+
self._auto_flip = auto_flip
|
|
104
|
+
|
|
105
|
+
self._toplevel = None
|
|
106
|
+
self._id = None
|
|
107
|
+
|
|
108
|
+
# Set keyword arguments (create copy to avoid mutating caller's dict)
|
|
109
|
+
self.toplevel_kwargs = kwargs.copy()
|
|
110
|
+
self.toplevel_kwargs["overrideredirect"] = True
|
|
111
|
+
self.toplevel_kwargs["master"] = self._widget
|
|
112
|
+
self.toplevel_kwargs["windowtype"] = "tooltip"
|
|
113
|
+
if "alpha" not in self.toplevel_kwargs:
|
|
114
|
+
self.toplevel_kwargs["alpha"] = 0.95
|
|
115
|
+
|
|
116
|
+
# event binding
|
|
117
|
+
self._widget.bind("<Enter>", self._on_enter)
|
|
118
|
+
self._widget.bind("<Leave>", self._on_leave)
|
|
119
|
+
self._widget.bind("<Motion>", self._move_tip)
|
|
120
|
+
self._widget.bind("<ButtonPress>", self._on_leave)
|
|
121
|
+
|
|
122
|
+
def destroy(self) -> None:
|
|
123
|
+
"""Cleanup tooltip resources and unbind all event handlers.
|
|
124
|
+
|
|
125
|
+
This method should be called when the tooltip is no longer needed to prevent
|
|
126
|
+
memory leaks. It cancels any pending tooltip display, hides any visible tooltip,
|
|
127
|
+
and removes all event bindings from the widget.
|
|
128
|
+
"""
|
|
129
|
+
self._unschedule()
|
|
130
|
+
self._hide_tip()
|
|
131
|
+
self._widget.unbind("<Enter>")
|
|
132
|
+
self._widget.unbind("<Leave>")
|
|
133
|
+
self._widget.unbind("<Motion>")
|
|
134
|
+
self._widget.unbind("<ButtonPress>")
|
|
135
|
+
|
|
136
|
+
def _on_enter(self, _) -> None:
|
|
137
|
+
"""Handle mouse enter event by scheduling tooltip display."""
|
|
138
|
+
self._schedule()
|
|
139
|
+
|
|
140
|
+
def _on_leave(self, _) -> None:
|
|
141
|
+
"""Handle mouse leave event by canceling and hiding tooltip."""
|
|
142
|
+
self._unschedule()
|
|
143
|
+
self._hide_tip()
|
|
144
|
+
|
|
145
|
+
def _schedule(self) -> None:
|
|
146
|
+
"""Schedule the tooltip to appear after the configured delay."""
|
|
147
|
+
self._unschedule()
|
|
148
|
+
self._id = self._widget.after(self._delay, self._show_tip)
|
|
149
|
+
|
|
150
|
+
def _unschedule(self) -> None:
|
|
151
|
+
"""Cancel any pending scheduled tooltip display."""
|
|
152
|
+
_id = self._id
|
|
153
|
+
self._id = None
|
|
154
|
+
if _id:
|
|
155
|
+
self._widget.after_cancel(_id)
|
|
156
|
+
|
|
157
|
+
def _show_tip(self, *_: Any) -> None:
|
|
158
|
+
"""Create and display the tooltip window at the appropriate position."""
|
|
159
|
+
if self._toplevel:
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
# Check if widget still exists before showing tooltip
|
|
163
|
+
try:
|
|
164
|
+
if not self._widget.winfo_exists():
|
|
165
|
+
return
|
|
166
|
+
except tk.TclError:
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
# Create the tooltip window (position will be set after content is built)
|
|
170
|
+
self._toplevel = Toplevel(**self.toplevel_kwargs)
|
|
171
|
+
# Use accent with tooltip variant
|
|
172
|
+
accent = 'background[+1]' if self._accent is None else self._accent
|
|
173
|
+
frame = ttk.Frame(
|
|
174
|
+
self._toplevel,
|
|
175
|
+
accent=accent,
|
|
176
|
+
variant='tooltip',
|
|
177
|
+
padding=self._padding
|
|
178
|
+
)
|
|
179
|
+
frame.pack(fill=BOTH, expand=YES)
|
|
180
|
+
|
|
181
|
+
lbl = ttk.Label(
|
|
182
|
+
master=frame,
|
|
183
|
+
text=self._text,
|
|
184
|
+
image=self._image,
|
|
185
|
+
compound='bottom',
|
|
186
|
+
justify=self._justify,
|
|
187
|
+
font="caption",
|
|
188
|
+
wraplength=self._wraplength,
|
|
189
|
+
)
|
|
190
|
+
lbl.pack(fill=BOTH, expand=YES)
|
|
191
|
+
|
|
192
|
+
# Wait until size is known, then position
|
|
193
|
+
self._toplevel.update_idletasks()
|
|
194
|
+
|
|
195
|
+
if self._anchor_point:
|
|
196
|
+
# Use WindowPositioning for anchored tooltips (sets geometry directly)
|
|
197
|
+
self._position_anchored()
|
|
198
|
+
else:
|
|
199
|
+
# Mouse-following tooltip
|
|
200
|
+
x, y = self._get_mouse_position()
|
|
201
|
+
self._toplevel.geometry(f"+{x}+{y}")
|
|
202
|
+
|
|
203
|
+
# Ensure the tooltip is visible
|
|
204
|
+
self._toplevel.deiconify()
|
|
205
|
+
|
|
206
|
+
def _move_tip(self, *_: Any) -> None:
|
|
207
|
+
"""Update the tooltip position based on mouse or anchor position."""
|
|
208
|
+
if self._toplevel:
|
|
209
|
+
if self._anchor_point:
|
|
210
|
+
# Anchored tooltips don't move
|
|
211
|
+
pass
|
|
212
|
+
else:
|
|
213
|
+
# Update mouse-following tooltip
|
|
214
|
+
x, y = self._get_mouse_position()
|
|
215
|
+
self._toplevel.geometry(f"+{x}+{y}")
|
|
216
|
+
|
|
217
|
+
def _hide_tip(self, *_: Any) -> None:
|
|
218
|
+
"""Hide and destroy the tooltip window."""
|
|
219
|
+
if self._toplevel:
|
|
220
|
+
self._toplevel.destroy()
|
|
221
|
+
self._toplevel = None
|
|
222
|
+
|
|
223
|
+
def _get_mouse_position(self) -> tuple[int, int]:
|
|
224
|
+
"""Get tooltip position offset from the current mouse pointer.
|
|
225
|
+
|
|
226
|
+
Uses WindowPositioning to ensure the tooltip stays on screen.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Tuple of (x, y) screen coordinates for the tooltip.
|
|
230
|
+
"""
|
|
231
|
+
x = self._widget.winfo_pointerx() + self._MOUSE_OFFSET_X
|
|
232
|
+
y = self._widget.winfo_pointery() + self._MOUSE_OFFSET_Y
|
|
233
|
+
|
|
234
|
+
# Ensure tooltip stays on screen (no titlebar since overrideredirect=True)
|
|
235
|
+
if self._toplevel:
|
|
236
|
+
x, y = WindowPositioning.ensure_on_screen(
|
|
237
|
+
self._toplevel, x, y, padding=5, titlebar_height=0
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
return x, y
|
|
241
|
+
|
|
242
|
+
def _position_anchored(self) -> None:
|
|
243
|
+
"""Position tooltip using WindowPositioning for intelligent anchor-based positioning.
|
|
244
|
+
|
|
245
|
+
Uses anchor_point and window_point attributes and applies auto-flip
|
|
246
|
+
to keep tooltip on screen.
|
|
247
|
+
"""
|
|
248
|
+
if not self._toplevel or not self._anchor_point:
|
|
249
|
+
return
|
|
250
|
+
|
|
251
|
+
# Ensure the widget is fully laid out before calculating position
|
|
252
|
+
self._widget.update_idletasks()
|
|
253
|
+
|
|
254
|
+
# Default window_point based on anchor_point if not specified
|
|
255
|
+
window_point = self._window_point
|
|
256
|
+
if window_point is None:
|
|
257
|
+
# Auto-determine opposite anchor point for natural positioning
|
|
258
|
+
opposite = {
|
|
259
|
+
'n': 's', 's': 'n', 'e': 'w', 'w': 'e',
|
|
260
|
+
'ne': 'sw', 'nw': 'se', 'se': 'nw', 'sw': 'ne',
|
|
261
|
+
'center': 'center'
|
|
262
|
+
}
|
|
263
|
+
window_point = opposite.get(self._anchor_point, 's')
|
|
264
|
+
|
|
265
|
+
# Get widget dimensions using max of requested and actual size
|
|
266
|
+
widget_x = self._widget.winfo_rootx()
|
|
267
|
+
widget_y = self._widget.winfo_rooty()
|
|
268
|
+
widget_w = max(self._widget.winfo_reqwidth(), self._widget.winfo_width())
|
|
269
|
+
widget_h = max(self._widget.winfo_reqheight(), self._widget.winfo_height())
|
|
270
|
+
|
|
271
|
+
# Calculate anchor coordinates based on anchor_point
|
|
272
|
+
if self._anchor_point == 'nw':
|
|
273
|
+
anchor_x, anchor_y = widget_x, widget_y
|
|
274
|
+
elif self._anchor_point == 'n':
|
|
275
|
+
anchor_x, anchor_y = widget_x + widget_w // 2, widget_y
|
|
276
|
+
elif self._anchor_point == 'ne':
|
|
277
|
+
anchor_x, anchor_y = widget_x + widget_w, widget_y
|
|
278
|
+
elif self._anchor_point == 'w':
|
|
279
|
+
anchor_x, anchor_y = widget_x, widget_y + widget_h // 2
|
|
280
|
+
elif self._anchor_point == 'center':
|
|
281
|
+
anchor_x, anchor_y = widget_x + widget_w // 2, widget_y + widget_h // 2
|
|
282
|
+
elif self._anchor_point == 'e':
|
|
283
|
+
anchor_x, anchor_y = widget_x + widget_w, widget_y + widget_h // 2
|
|
284
|
+
elif self._anchor_point == 'sw':
|
|
285
|
+
anchor_x, anchor_y = widget_x, widget_y + widget_h
|
|
286
|
+
elif self._anchor_point == 's':
|
|
287
|
+
anchor_x, anchor_y = widget_x + widget_w // 2, widget_y + widget_h
|
|
288
|
+
elif self._anchor_point == 'se':
|
|
289
|
+
anchor_x, anchor_y = widget_x + widget_w, widget_y + widget_h
|
|
290
|
+
else:
|
|
291
|
+
anchor_x, anchor_y = widget_x, widget_y
|
|
292
|
+
|
|
293
|
+
# Calculate window offset based on window_point
|
|
294
|
+
w_width = max(self._toplevel.winfo_reqwidth(), self._toplevel.winfo_width())
|
|
295
|
+
w_height = max(self._toplevel.winfo_reqheight(), self._toplevel.winfo_height())
|
|
296
|
+
|
|
297
|
+
x_offset, y_offset = 0, 0
|
|
298
|
+
if window_point == 'nw':
|
|
299
|
+
x_offset, y_offset = 0, 0
|
|
300
|
+
elif window_point == 'n':
|
|
301
|
+
x_offset, y_offset = -w_width // 2, 0
|
|
302
|
+
elif window_point == 'ne':
|
|
303
|
+
x_offset, y_offset = -w_width, 0
|
|
304
|
+
elif window_point == 'w':
|
|
305
|
+
x_offset, y_offset = 0, -w_height // 2
|
|
306
|
+
elif window_point == 'center':
|
|
307
|
+
x_offset, y_offset = -w_width // 2, -w_height // 2
|
|
308
|
+
elif window_point == 'e':
|
|
309
|
+
x_offset, y_offset = -w_width, -w_height // 2
|
|
310
|
+
elif window_point == 'sw':
|
|
311
|
+
x_offset, y_offset = 0, -w_height
|
|
312
|
+
elif window_point == 's':
|
|
313
|
+
x_offset, y_offset = -w_width // 2, -w_height
|
|
314
|
+
elif window_point == 'se':
|
|
315
|
+
x_offset, y_offset = -w_width, -w_height
|
|
316
|
+
|
|
317
|
+
# Calculate position with offset
|
|
318
|
+
x = int(anchor_x + x_offset + self._WIDGET_SPACING)
|
|
319
|
+
y = int(anchor_y + y_offset + self._WIDGET_SPACING)
|
|
320
|
+
|
|
321
|
+
# Auto-flip logic
|
|
322
|
+
if self._auto_flip:
|
|
323
|
+
vertical_offscreen, horizontal_offscreen = WindowPositioning._check_offscreen(
|
|
324
|
+
self._toplevel, x, y, padding=5
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
should_flip_vertical = False
|
|
328
|
+
should_flip_horizontal = False
|
|
329
|
+
|
|
330
|
+
if self._auto_flip is True or self._auto_flip == 'vertical':
|
|
331
|
+
should_flip_vertical = vertical_offscreen
|
|
332
|
+
|
|
333
|
+
if self._auto_flip is True or self._auto_flip == 'horizontal':
|
|
334
|
+
should_flip_horizontal = horizontal_offscreen
|
|
335
|
+
|
|
336
|
+
# Flip if needed
|
|
337
|
+
if should_flip_vertical or should_flip_horizontal:
|
|
338
|
+
flipped_anchor_point = self._anchor_point
|
|
339
|
+
flipped_window_point = window_point
|
|
340
|
+
|
|
341
|
+
if should_flip_vertical:
|
|
342
|
+
flipped_anchor_point = WindowPositioning._flip_anchor_vertical(flipped_anchor_point)
|
|
343
|
+
flipped_window_point = WindowPositioning._flip_anchor_vertical(flipped_window_point)
|
|
344
|
+
|
|
345
|
+
if should_flip_horizontal:
|
|
346
|
+
flipped_anchor_point = WindowPositioning._flip_anchor_horizontal(flipped_anchor_point)
|
|
347
|
+
flipped_window_point = WindowPositioning._flip_anchor_horizontal(flipped_window_point)
|
|
348
|
+
|
|
349
|
+
# Recalculate anchor coordinates with flipped anchor point
|
|
350
|
+
if flipped_anchor_point == 'nw':
|
|
351
|
+
anchor_x, anchor_y = widget_x, widget_y
|
|
352
|
+
elif flipped_anchor_point == 'n':
|
|
353
|
+
anchor_x, anchor_y = widget_x + widget_w // 2, widget_y
|
|
354
|
+
elif flipped_anchor_point == 'ne':
|
|
355
|
+
anchor_x, anchor_y = widget_x + widget_w, widget_y
|
|
356
|
+
elif flipped_anchor_point == 'w':
|
|
357
|
+
anchor_x, anchor_y = widget_x, widget_y + widget_h // 2
|
|
358
|
+
elif flipped_anchor_point == 'center':
|
|
359
|
+
anchor_x, anchor_y = widget_x + widget_w // 2, widget_y + widget_h // 2
|
|
360
|
+
elif flipped_anchor_point == 'e':
|
|
361
|
+
anchor_x, anchor_y = widget_x + widget_w, widget_y + widget_h // 2
|
|
362
|
+
elif flipped_anchor_point == 'sw':
|
|
363
|
+
anchor_x, anchor_y = widget_x, widget_y + widget_h
|
|
364
|
+
elif flipped_anchor_point == 's':
|
|
365
|
+
anchor_x, anchor_y = widget_x + widget_w // 2, widget_y + widget_h
|
|
366
|
+
elif flipped_anchor_point == 'se':
|
|
367
|
+
anchor_x, anchor_y = widget_x + widget_w, widget_y + widget_h
|
|
368
|
+
else:
|
|
369
|
+
anchor_x, anchor_y = widget_x, widget_y
|
|
370
|
+
|
|
371
|
+
# Recalculate window offset with flipped window point
|
|
372
|
+
if flipped_window_point == 'nw':
|
|
373
|
+
x_offset, y_offset = 0, 0
|
|
374
|
+
elif flipped_window_point == 'n':
|
|
375
|
+
x_offset, y_offset = -w_width // 2, 0
|
|
376
|
+
elif flipped_window_point == 'ne':
|
|
377
|
+
x_offset, y_offset = -w_width, 0
|
|
378
|
+
elif flipped_window_point == 'w':
|
|
379
|
+
x_offset, y_offset = 0, -w_height // 2
|
|
380
|
+
elif flipped_window_point == 'center':
|
|
381
|
+
x_offset, y_offset = -w_width // 2, -w_height // 2
|
|
382
|
+
elif flipped_window_point == 'e':
|
|
383
|
+
x_offset, y_offset = -w_width, -w_height // 2
|
|
384
|
+
elif flipped_window_point == 'sw':
|
|
385
|
+
x_offset, y_offset = 0, -w_height
|
|
386
|
+
elif flipped_window_point == 's':
|
|
387
|
+
x_offset, y_offset = -w_width // 2, -w_height
|
|
388
|
+
elif flipped_window_point == 'se':
|
|
389
|
+
x_offset, y_offset = -w_width, -w_height
|
|
390
|
+
|
|
391
|
+
# Recalculate position with flipped anchors
|
|
392
|
+
x = int(anchor_x + x_offset + self._WIDGET_SPACING)
|
|
393
|
+
y = int(anchor_y + y_offset + self._WIDGET_SPACING)
|
|
394
|
+
|
|
395
|
+
# Ensure on screen (final safety check)
|
|
396
|
+
try:
|
|
397
|
+
x, y = WindowPositioning.ensure_on_screen(
|
|
398
|
+
self._toplevel, x, y, padding=5, titlebar_height=0
|
|
399
|
+
)
|
|
400
|
+
except Exception:
|
|
401
|
+
pass
|
|
402
|
+
|
|
403
|
+
# Set geometry
|
|
404
|
+
self._toplevel.geometry(f"+{x}+{y}")
|
|
File without changes
|