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,231 @@
|
|
|
1
|
+
"""Localization capability for bootstack widgets.
|
|
2
|
+
|
|
3
|
+
This module provides the core framework service for localizing widget text
|
|
4
|
+
and values. It handles text resolution, value formatting, and locale change
|
|
5
|
+
propagation.
|
|
6
|
+
|
|
7
|
+
The widget mixin (LocalizationMixin) delegates to these functions to remain
|
|
8
|
+
a thin glue layer.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any, TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
from bootstack.core.localization.msgcat import MessageCatalog
|
|
16
|
+
from bootstack.core.localization.specs import (
|
|
17
|
+
LocalizedSpec,
|
|
18
|
+
LocalizedTextSpec,
|
|
19
|
+
LocalizedValueSpec,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from bootstack.core.signals import Signal
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# Text Resolution
|
|
28
|
+
# =============================================================================
|
|
29
|
+
|
|
30
|
+
def resolve_text(
|
|
31
|
+
value: Any,
|
|
32
|
+
*,
|
|
33
|
+
localize_mode: bool | str = True,
|
|
34
|
+
) -> LocalizedTextSpec | None:
|
|
35
|
+
"""Resolve a text value into a LocalizedTextSpec.
|
|
36
|
+
|
|
37
|
+
This function handles the logic for creating localization specs from
|
|
38
|
+
string values based on the localization mode.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value: The value to resolve. Can be:
|
|
42
|
+
- A LocalizedSpec: returned as-is (if it's a LocalizedTextSpec)
|
|
43
|
+
- A string: wrapped in LocalizedTextSpec if localize_mode is truthy
|
|
44
|
+
- None or empty string: returns None
|
|
45
|
+
localize_mode: Controls auto-wrapping of literals:
|
|
46
|
+
- True or "auto": wrap strings in LocalizedTextSpec
|
|
47
|
+
- False: return None (no localization)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
A LocalizedTextSpec if the value should be localized, None otherwise.
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
>>> spec = resolve_text("Hello World")
|
|
54
|
+
>>> spec.key
|
|
55
|
+
'Hello World'
|
|
56
|
+
|
|
57
|
+
>>> spec = resolve_text("Hello", localize_mode=False)
|
|
58
|
+
>>> spec is None
|
|
59
|
+
True
|
|
60
|
+
|
|
61
|
+
>>> from bootstack.core.localization.specs import L
|
|
62
|
+
>>> spec = resolve_text(L("greeting"))
|
|
63
|
+
>>> spec.key
|
|
64
|
+
'greeting'
|
|
65
|
+
"""
|
|
66
|
+
if value is None:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
if isinstance(value, str) and value == "":
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
# If already a LocalizedSpec, return as-is
|
|
73
|
+
if isinstance(value, LocalizedTextSpec):
|
|
74
|
+
return value
|
|
75
|
+
if isinstance(value, LocalizedSpec):
|
|
76
|
+
# Other spec types (like LocalizedValueSpec) - cannot use as text
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
# Check localize mode
|
|
80
|
+
if localize_mode is False:
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
# Wrap string in LocalizedTextSpec
|
|
84
|
+
if isinstance(value, str):
|
|
85
|
+
return LocalizedTextSpec(key=value, original=value)
|
|
86
|
+
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def resolve_variable_text(
|
|
91
|
+
value: Any,
|
|
92
|
+
*,
|
|
93
|
+
value_format: str | None = None,
|
|
94
|
+
default_format: str = "decimal",
|
|
95
|
+
) -> LocalizedValueSpec | None:
|
|
96
|
+
"""Resolve a non-string value into a LocalizedValueSpec for formatting.
|
|
97
|
+
|
|
98
|
+
This function handles the logic for creating value formatting specs from
|
|
99
|
+
numeric or other values.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
value: The value to format. Should be a number, date, or other
|
|
103
|
+
formattable type.
|
|
104
|
+
value_format: The IntlFormatter spec (e.g., "currency", "decimal",
|
|
105
|
+
"percent"). If None, uses default_format.
|
|
106
|
+
default_format: Fallback format spec when value_format is None.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
A LocalizedValueSpec if the value can be formatted, None otherwise.
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
>>> spec = resolve_variable_text(1234.56, value_format="currency")
|
|
113
|
+
>>> spec.value
|
|
114
|
+
1234.56
|
|
115
|
+
>>> spec.format_spec
|
|
116
|
+
'currency'
|
|
117
|
+
|
|
118
|
+
>>> spec = resolve_variable_text(0.5, value_format="percent")
|
|
119
|
+
>>> spec.format_spec
|
|
120
|
+
'percent'
|
|
121
|
+
"""
|
|
122
|
+
if value is None:
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
if isinstance(value, LocalizedValueSpec):
|
|
126
|
+
return value
|
|
127
|
+
|
|
128
|
+
if isinstance(value, str):
|
|
129
|
+
# Strings are handled by resolve_text, not this function
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
fmt = value_format or default_format
|
|
133
|
+
return LocalizedValueSpec(value=value, format_spec=fmt)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def apply_spec(spec: LocalizedSpec, locale: str | None = None) -> str:
|
|
137
|
+
"""Apply a localization spec and return the resolved string.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
spec: The LocalizedSpec to resolve.
|
|
141
|
+
locale: The locale to use. If None, uses the current locale from
|
|
142
|
+
MessageCatalog.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
The resolved, localized string value.
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
>>> from bootstack.core.localization.specs import L, LV
|
|
149
|
+
>>> spec = L("hello")
|
|
150
|
+
>>> result = apply_spec(spec) # Uses current locale
|
|
151
|
+
>>> isinstance(result, str)
|
|
152
|
+
True
|
|
153
|
+
|
|
154
|
+
>>> spec = LV(1234.56, "decimal")
|
|
155
|
+
>>> result = apply_spec(spec)
|
|
156
|
+
>>> isinstance(result, str)
|
|
157
|
+
True
|
|
158
|
+
"""
|
|
159
|
+
if not spec.enabled:
|
|
160
|
+
# Return original if possible, else empty
|
|
161
|
+
if isinstance(spec, LocalizedTextSpec):
|
|
162
|
+
return spec.original or spec.key
|
|
163
|
+
elif isinstance(spec, LocalizedValueSpec):
|
|
164
|
+
return str(spec.value)
|
|
165
|
+
return ""
|
|
166
|
+
|
|
167
|
+
current_locale = locale or MessageCatalog.locale()
|
|
168
|
+
return spec.resolve(current_locale)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def get_current_locale() -> str:
|
|
172
|
+
"""Get the current locale from MessageCatalog.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
The current locale code (e.g., "en_US", "de_DE").
|
|
176
|
+
"""
|
|
177
|
+
return MessageCatalog.locale()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# =============================================================================
|
|
181
|
+
# Signal Formatting
|
|
182
|
+
# =============================================================================
|
|
183
|
+
|
|
184
|
+
def create_formatted_signal(
|
|
185
|
+
source_signal: 'Signal[Any]',
|
|
186
|
+
value_format: str,
|
|
187
|
+
) -> tuple['Signal[str]', Any]:
|
|
188
|
+
"""Create a formatted signal that tracks a source signal.
|
|
189
|
+
|
|
190
|
+
This creates a new Signal for formatted display that subscribes to the
|
|
191
|
+
source signal and automatically formats values when they change.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
source_signal: The source Signal to subscribe to.
|
|
195
|
+
value_format: The IntlFormatter spec for formatting values.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
A tuple of (formatted_signal, formatter_callback) where:
|
|
199
|
+
- formatted_signal: A new Signal[str] containing the formatted value
|
|
200
|
+
- formatter_callback: The callback function for locale change updates
|
|
201
|
+
|
|
202
|
+
Examples:
|
|
203
|
+
>>> from bootstack.core.signals import Signal
|
|
204
|
+
>>> price = Signal(1234.56)
|
|
205
|
+
>>> formatted, formatter = create_formatted_signal(price, "currency")
|
|
206
|
+
>>> # formatted.get() returns locale-formatted currency string
|
|
207
|
+
"""
|
|
208
|
+
from bootstack.core.signals import Signal
|
|
209
|
+
|
|
210
|
+
formatted_signal: Signal[str] = Signal("")
|
|
211
|
+
|
|
212
|
+
def format_signal_value(value: Any) -> None:
|
|
213
|
+
"""Format the signal value using the current locale."""
|
|
214
|
+
spec = LocalizedValueSpec(value=value, format_spec=value_format)
|
|
215
|
+
locale = MessageCatalog.locale()
|
|
216
|
+
formatted = spec.resolve(locale)
|
|
217
|
+
formatted_signal.set(formatted)
|
|
218
|
+
|
|
219
|
+
# Subscribe with immediate execution to format initial value
|
|
220
|
+
source_signal.subscribe(format_signal_value, immediate=True)
|
|
221
|
+
|
|
222
|
+
return formatted_signal, format_signal_value
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
__all__ = [
|
|
226
|
+
"resolve_text",
|
|
227
|
+
"resolve_variable_text",
|
|
228
|
+
"apply_spec",
|
|
229
|
+
"get_current_locale",
|
|
230
|
+
"create_formatted_signal",
|
|
231
|
+
]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Pack geometry manager capabilities mixin for bootstack widgets."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, Literal, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from typing_extensions import Self
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PackMixin:
|
|
11
|
+
"""Pack geometry manager helpers (pack).
|
|
12
|
+
|
|
13
|
+
Tk's `pack` geometry manager places widgets relative to the sides of a container.
|
|
14
|
+
|
|
15
|
+
In bootstack v2 you may prefer higher-level layout containers (e.g. `PackFrame`)
|
|
16
|
+
for most UI layout. This mixin documents the underlying Tkinter `pack_*` API
|
|
17
|
+
as an escape hatch and for interoperability with existing Tk code.
|
|
18
|
+
|
|
19
|
+
Notes:
|
|
20
|
+
- `pack()` attaches a widget to a parent container that is using pack.
|
|
21
|
+
- `pack_propagate(False)` prevents a container from resizing to fit its children.
|
|
22
|
+
- `fill`, `expand`, and `side` control how a widget consumes available space.
|
|
23
|
+
- If the parent has a `_on_child_pack` hook (e.g. PackFrame), layout defaults
|
|
24
|
+
are applied automatically.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# -------------------------------------------------------------------------
|
|
28
|
+
# Core widget methods
|
|
29
|
+
# -------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
def pack(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
|
|
32
|
+
"""Position this widget using the pack geometry manager.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
cnf: Optional dict of pack options.
|
|
36
|
+
**kw: Pack options. Common options include:
|
|
37
|
+
- side: Which side to pack against ("top", "bottom", "left", "right").
|
|
38
|
+
- fill: How the widget should fill extra space ("x", "y", "both", "none").
|
|
39
|
+
- expand: Whether the widget expands to fill extra space (0/1 or False/True).
|
|
40
|
+
- anchor: Where to place the widget if it does not fill the space.
|
|
41
|
+
- padx, pady: External padding around the widget.
|
|
42
|
+
- ipadx, ipady: Internal padding inside the widget.
|
|
43
|
+
- before, after: Pack relative to another widget.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Self for method chaining.
|
|
47
|
+
"""
|
|
48
|
+
options = cnf or {}
|
|
49
|
+
options.update(kw)
|
|
50
|
+
|
|
51
|
+
parent = self.master # type: ignore[attr-defined]
|
|
52
|
+
if hasattr(parent, '_on_child_pack'):
|
|
53
|
+
parent._on_child_pack(self, **options)
|
|
54
|
+
else:
|
|
55
|
+
super().pack(**options) # type: ignore[misc]
|
|
56
|
+
return self # type: ignore[return-value]
|
|
57
|
+
|
|
58
|
+
def pack_configure(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
|
|
59
|
+
"""Alias for `pack()`.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
cnf: Optional dict of pack options.
|
|
63
|
+
**kw: Pack options (see `pack`).
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Self for method chaining.
|
|
67
|
+
"""
|
|
68
|
+
return self.pack(cnf, **kw)
|
|
69
|
+
|
|
70
|
+
def pack_forget(self) -> Self:
|
|
71
|
+
"""Unmap this widget and forget its pack configuration.
|
|
72
|
+
|
|
73
|
+
The widget is removed from the layout, and its previous pack options
|
|
74
|
+
are discarded.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Self for method chaining.
|
|
78
|
+
"""
|
|
79
|
+
parent = self.master # type: ignore[attr-defined]
|
|
80
|
+
if hasattr(parent, '_on_child_pack_forget'):
|
|
81
|
+
parent._on_child_pack_forget(self)
|
|
82
|
+
else:
|
|
83
|
+
super().pack_forget() # type: ignore[misc]
|
|
84
|
+
return self # type: ignore[return-value]
|
|
85
|
+
|
|
86
|
+
def pack_info(self) -> dict[str, Any]:
|
|
87
|
+
"""Return this widget's current pack configuration.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A dict containing the current pack options for this widget
|
|
91
|
+
(side, fill, expand, padx, pady, etc.).
|
|
92
|
+
"""
|
|
93
|
+
return super().pack_info() # type: ignore[misc]
|
|
94
|
+
|
|
95
|
+
# -------------------------------------------------------------------------
|
|
96
|
+
# Container methods (applied to the pack parent container)
|
|
97
|
+
# -------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def pack_propagate(self, flag: bool | None = None) -> bool | None:
|
|
100
|
+
"""Get or set pack geometry propagation for this container.
|
|
101
|
+
|
|
102
|
+
When propagation is enabled (default), the container may resize itself
|
|
103
|
+
to fit the size requests of its children.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
flag: True/False to enable/disable propagation. If None, acts as a getter.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
When queried, returns the current propagation flag. When set, returns None.
|
|
110
|
+
"""
|
|
111
|
+
return super().pack_propagate(flag) # type: ignore[misc]
|
|
112
|
+
|
|
113
|
+
def pack_slaves(self) -> list[Any]:
|
|
114
|
+
"""Return the widgets managed by pack in this container.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
A list of child widgets managed by pack (in packing order).
|
|
118
|
+
"""
|
|
119
|
+
return super().pack_slaves() # type: ignore[misc]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from typing_extensions import Self
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PlaceMixin:
|
|
10
|
+
"""Place geometry manager helpers (place).
|
|
11
|
+
|
|
12
|
+
Tk's `place` geometry manager positions widgets using absolute coordinates
|
|
13
|
+
and/or relative fractions of the container size.
|
|
14
|
+
|
|
15
|
+
`place` is useful for:
|
|
16
|
+
- overlays (badges, floating buttons, popovers)
|
|
17
|
+
- precise positioning inside a fixed-size container
|
|
18
|
+
- small "anchor" adjustments that don't fit grid/pack well
|
|
19
|
+
|
|
20
|
+
Notes:
|
|
21
|
+
- `place` is generally less adaptive than `grid` or `pack` for resizable UIs.
|
|
22
|
+
- Relative coordinates (`relx`, `rely`, `relwidth`, `relheight`) are fractions
|
|
23
|
+
of the container size (0.0–1.0).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# -------------------------------------------------------------------------
|
|
27
|
+
# Core widget methods
|
|
28
|
+
# -------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
def place(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
|
|
31
|
+
"""Position this widget using the place geometry manager.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
cnf: Optional dict of place options.
|
|
35
|
+
**kw: Place options. Common options include:
|
|
36
|
+
- x, y: Absolute coordinates in pixels (relative to container).
|
|
37
|
+
- relx, rely: Relative coordinates (0.0–1.0) of the container size.
|
|
38
|
+
- width, height: Absolute size in pixels.
|
|
39
|
+
- relwidth, relheight: Relative size (0.0–1.0) of the container size.
|
|
40
|
+
- anchor: Which point of the widget is placed at (x, y) / (relx, rely)
|
|
41
|
+
(e.g. "nw", "center", "se").
|
|
42
|
+
- bordermode: How to interpret x/y relative to container borders.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Self for method chaining.
|
|
46
|
+
"""
|
|
47
|
+
options = cnf or {}
|
|
48
|
+
options.update(kw)
|
|
49
|
+
super().place(**options) # type: ignore[misc]
|
|
50
|
+
return self # type: ignore[return-value]
|
|
51
|
+
|
|
52
|
+
def place_configure(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
|
|
53
|
+
"""Alias for `place()`.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
cnf: Optional dict of place options.
|
|
57
|
+
**kw: Place options (see `place`).
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Self for method chaining.
|
|
61
|
+
"""
|
|
62
|
+
return self.place(cnf, **kw)
|
|
63
|
+
|
|
64
|
+
def place_forget(self) -> Self:
|
|
65
|
+
"""Unmap this widget and forget its place configuration.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Self for method chaining.
|
|
69
|
+
"""
|
|
70
|
+
super().place_forget() # type: ignore[misc]
|
|
71
|
+
return self # type: ignore[return-value]
|
|
72
|
+
|
|
73
|
+
def place_info(self) -> dict[str, Any]:
|
|
74
|
+
"""Return this widget's current place configuration.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
A dict containing the current place options for this widget
|
|
78
|
+
(x, y, relx, rely, width, height, etc.).
|
|
79
|
+
"""
|
|
80
|
+
return super().place_info() # type: ignore[misc]
|
|
81
|
+
|
|
82
|
+
# -------------------------------------------------------------------------
|
|
83
|
+
# Container methods
|
|
84
|
+
# -------------------------------------------------------------------------
|
|
85
|
+
|
|
86
|
+
def place_slaves(self) -> list[Any]:
|
|
87
|
+
"""Return the widgets managed by place in this container.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A list of child widgets managed by place.
|
|
91
|
+
"""
|
|
92
|
+
return super().place_slaves() # type: ignore[misc]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SelectionMixin:
|
|
7
|
+
"""X selection helpers (selection).
|
|
8
|
+
|
|
9
|
+
Tk’s `selection` command provides access to the X selection mechanism (ICCCM),
|
|
10
|
+
most commonly the **PRIMARY** selection, and also supports **CLIPBOARD** and
|
|
11
|
+
other named selections.
|
|
12
|
+
|
|
13
|
+
Portability notes:
|
|
14
|
+
- On X11, PRIMARY is a system-wide selection shared across processes.
|
|
15
|
+
- On Windows, PRIMARY is provided by Tk (not the OS) and is shared only
|
|
16
|
+
within related interpreters, not across processes.
|
|
17
|
+
- For clipboard-style usage, Tk also provides the `clipboard_*` methods,
|
|
18
|
+
which are often a better cross-platform fit.
|
|
19
|
+
|
|
20
|
+
Intended usage:
|
|
21
|
+
class Widget(SelectionMixin, ttk.Widget): ...
|
|
22
|
+
class App(SelectionMixin, tkinter.Tk): ...
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def selection_clear(self, **kw: Any) -> None:
|
|
26
|
+
"""Clear a selection so that no window owns it.
|
|
27
|
+
|
|
28
|
+
This corresponds to `selection clear` and clears the specified selection
|
|
29
|
+
on the target display (if it exists).
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
**kw: Selection options forwarded to Tkinter. Common options include:
|
|
33
|
+
- selection: The selection name (e.g. "PRIMARY", "CLIPBOARD").
|
|
34
|
+
Defaults to "PRIMARY".
|
|
35
|
+
- displayof: A widget/window whose display should be targeted.
|
|
36
|
+
Defaults to "." (the application’s main display).
|
|
37
|
+
"""
|
|
38
|
+
return super().selection_clear(**kw) # type: ignore[misc]
|
|
39
|
+
|
|
40
|
+
def selection_get(self, **kw: Any) -> str:
|
|
41
|
+
"""Return the current contents of a selection.
|
|
42
|
+
|
|
43
|
+
This corresponds to `selection get` and retrieves a selection from the
|
|
44
|
+
target display. The default selection is "PRIMARY" and the default type
|
|
45
|
+
is "STRING".
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
**kw: Selection options forwarded to Tkinter. Common options include:
|
|
49
|
+
- selection: The selection name (e.g. "PRIMARY", "CLIPBOARD").
|
|
50
|
+
Defaults to "PRIMARY".
|
|
51
|
+
- type: The desired “target” type for conversion (e.g. "STRING",
|
|
52
|
+
"UTF8_STRING", "TARGETS", "FILE_NAME"). Defaults to "STRING".
|
|
53
|
+
- displayof: A widget/window whose display should be targeted.
|
|
54
|
+
Defaults to ".".
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The selection contents as a string.
|
|
58
|
+
|
|
59
|
+
Notes:
|
|
60
|
+
- If the owner returns a non-string representation (e.g. ATOM or INTEGER),
|
|
61
|
+
Tk converts it to a space-separated string representation.
|
|
62
|
+
- Tk will not retrieve UTF-8 formatted data unless you request
|
|
63
|
+
`type="UTF8_STRING"`.
|
|
64
|
+
"""
|
|
65
|
+
return super().selection_get(**kw) # type: ignore[misc]
|
|
66
|
+
|
|
67
|
+
def selection_handle(self, command: str | None, **kw: Any) -> None:
|
|
68
|
+
"""Register or remove a handler for selection retrieval requests.
|
|
69
|
+
|
|
70
|
+
This corresponds to `selection handle`. When this widget owns a selection,
|
|
71
|
+
Tk will execute *command* when another client attempts to retrieve the
|
|
72
|
+
selection in the requested type.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
command: A Tcl command (string) to execute to supply selection data.
|
|
76
|
+
If an empty string or None, removes any existing handler for the
|
|
77
|
+
given selection/type combination.
|
|
78
|
+
**kw: Handler options forwarded to Tkinter. Common options include:
|
|
79
|
+
- selection: Selection name (defaults to "PRIMARY").
|
|
80
|
+
- type: Requested type (defaults to "STRING").
|
|
81
|
+
- format: Representation format used to transmit the selection
|
|
82
|
+
(defaults to "STRING"). Usually only needed for compatibility
|
|
83
|
+
with non-Tk requesters.
|
|
84
|
+
|
|
85
|
+
Notes:
|
|
86
|
+
- When handling type "STRING", Tk will also handle "UTF8_STRING"
|
|
87
|
+
automatically.
|
|
88
|
+
- The command is invoked with two additional arguments appended:
|
|
89
|
+
`offset` and `maxChars`. The command should return up to `maxChars`
|
|
90
|
+
characters starting at `offset`. Large selections are retrieved
|
|
91
|
+
in multiple chunks.
|
|
92
|
+
"""
|
|
93
|
+
# Tkinter expects `command` to be a Tcl script; keep the pass-through shape.
|
|
94
|
+
if command is None:
|
|
95
|
+
command = ""
|
|
96
|
+
return super().selection_handle(command, **kw) # type: ignore[misc]
|
|
97
|
+
|
|
98
|
+
def selection_own(self, **kw: Any) -> str:
|
|
99
|
+
"""Query the current selection owner within this application.
|
|
100
|
+
|
|
101
|
+
This corresponds to the *query* form of `selection own`, returning the
|
|
102
|
+
pathname of the window in this application that owns the selection on
|
|
103
|
+
the target display, or an empty string if none.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
**kw: Query options forwarded to Tkinter. Common options include:
|
|
107
|
+
- selection: Selection name (defaults to "PRIMARY").
|
|
108
|
+
- displayof: A widget/window whose display should be targeted.
|
|
109
|
+
Defaults to ".".
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
The pathname of the owner window in this application, or an empty
|
|
113
|
+
string if no window in this application owns the selection.
|
|
114
|
+
"""
|
|
115
|
+
return super().selection_own(**kw) # type: ignore[misc]
|
|
116
|
+
|
|
117
|
+
def selection_own_set(
|
|
118
|
+
self,
|
|
119
|
+
owner: Any,
|
|
120
|
+
command: Callable[[], Any] | None = None,
|
|
121
|
+
*,
|
|
122
|
+
selection: str = "PRIMARY",
|
|
123
|
+
) -> None:
|
|
124
|
+
"""Make *owner* the selection owner (convenience helper).
|
|
125
|
+
|
|
126
|
+
Tk’s `selection own` *setter* form is easy to confuse with the query form.
|
|
127
|
+
This helper makes the intent explicit while still using Tk’s semantics.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
owner: The widget/window that should own the selection.
|
|
131
|
+
command: Optional callback invoked when this widget loses ownership
|
|
132
|
+
of the selection (i.e., another window claims it).
|
|
133
|
+
selection: The selection name to claim (defaults to "PRIMARY").
|
|
134
|
+
"""
|
|
135
|
+
# `selection_own` in Tkinter supports setting with `command` and `selection`.
|
|
136
|
+
return super().selection_own(owner, command=command, selection=selection) # type: ignore[misc]
|