bootstack 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bootstack/__init__.py +157 -0
- bootstack/__main__.py +5 -0
- bootstack/_core/__init__.py +21 -0
- bootstack/_core/capabilities/__init__.py +45 -0
- bootstack/_core/capabilities/after.py +103 -0
- bootstack/_core/capabilities/bind.py +192 -0
- bootstack/_core/capabilities/bindtags.py +112 -0
- bootstack/_core/capabilities/busy.py +72 -0
- bootstack/_core/capabilities/clipboard.py +89 -0
- bootstack/_core/capabilities/focus.py +118 -0
- bootstack/_core/capabilities/grab.py +65 -0
- bootstack/_core/capabilities/grid.py +211 -0
- bootstack/_core/capabilities/localization.py +231 -0
- bootstack/_core/capabilities/pack.py +140 -0
- bootstack/_core/capabilities/place.py +113 -0
- bootstack/_core/capabilities/selection.py +136 -0
- bootstack/_core/capabilities/signals.py +244 -0
- bootstack/_core/capabilities/winfo.py +315 -0
- bootstack/_core/colorutils.py +234 -0
- bootstack/_core/exceptions.py +25 -0
- bootstack/_core/images.py +463 -0
- bootstack/_core/mixins/__init__.py +1 -0
- bootstack/_core/mixins/ttk_state.py +35 -0
- bootstack/_core/mixins/widget.py +132 -0
- bootstack/_core/paths.py +49 -0
- bootstack/_core/publisher.py +149 -0
- bootstack/_core/variables.py +62 -0
- bootstack/_runtime/__init__.py +3 -0
- bootstack/_runtime/app.py +930 -0
- bootstack/_runtime/base_window.py +945 -0
- bootstack/_runtime/events.py +399 -0
- bootstack/_runtime/shortcuts.py +496 -0
- bootstack/_runtime/tk_patch.py +43 -0
- bootstack/_runtime/toplevel.py +276 -0
- bootstack/_runtime/utility.py +457 -0
- bootstack/_runtime/visual_focus.py +240 -0
- bootstack/_runtime/window_utilities.py +1123 -0
- bootstack/assets/__init__.py +21 -0
- bootstack/assets/bootstack.ico +0 -0
- bootstack/assets/bootstack.png +0 -0
- bootstack/assets/elements/__init__.py +0 -0
- bootstack/assets/elements/badge-pill.png +0 -0
- bootstack/assets/elements/badge-square.png +0 -0
- bootstack/assets/elements/button-compact.png +0 -0
- bootstack/assets/elements/button-default.png +0 -0
- bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
- bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
- bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
- bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
- bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
- bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
- bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
- bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
- bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
- bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
- bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
- bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
- bootstack/assets/elements/card.png +0 -0
- bootstack/assets/elements/checkbox-checked.png +0 -0
- bootstack/assets/elements/checkbox-indeterminate.png +0 -0
- bootstack/assets/elements/checkbox-unchecked.png +0 -0
- bootstack/assets/elements/field.png +0 -0
- bootstack/assets/elements/input-addon-compact.png +0 -0
- bootstack/assets/elements/input-addon-default.png +0 -0
- bootstack/assets/elements/input-compact.png +0 -0
- bootstack/assets/elements/input-default.png +0 -0
- bootstack/assets/elements/list-item-separated.png +0 -0
- bootstack/assets/elements/list-item.png +0 -0
- bootstack/assets/elements/listrow-compact.png +0 -0
- bootstack/assets/elements/listrow-default.png +0 -0
- bootstack/assets/elements/manifest.toml +361 -0
- bootstack/assets/elements/menu-item.png +0 -0
- bootstack/assets/elements/navitem-compact.png +0 -0
- bootstack/assets/elements/navitem-default.png +0 -0
- bootstack/assets/elements/progressbar-h-compact.png +0 -0
- bootstack/assets/elements/progressbar-h-default.png +0 -0
- bootstack/assets/elements/progressbar-v-compact.png +0 -0
- bootstack/assets/elements/progressbar-v-default.png +0 -0
- bootstack/assets/elements/radiobutton.png +0 -0
- bootstack/assets/elements/scrollbar-horizontal.png +0 -0
- bootstack/assets/elements/scrollbar-vertical.png +0 -0
- bootstack/assets/elements/slider-handle.png +0 -0
- bootstack/assets/elements/slider-track-h.png +0 -0
- bootstack/assets/elements/slider-track-v.png +0 -0
- bootstack/assets/elements/switch-off.png +0 -0
- bootstack/assets/elements/switch-on.png +0 -0
- bootstack/assets/elements/tab-h.png +0 -0
- bootstack/assets/elements/tab-v.png +0 -0
- bootstack/assets/icons/bootstrap.ttf +0 -0
- bootstack/assets/icons/glyphmap.json +2080 -0
- bootstack/assets/icons/icon_metrics.json +12470 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +878 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +878 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +856 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +854 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +844 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +917 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +844 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +844 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +845 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +845 -0
- bootstack/cli/__init__.py +133 -0
- bootstack/cli/__main__.py +6 -0
- bootstack/cli/add.py +395 -0
- bootstack/cli/appicon.py +285 -0
- bootstack/cli/build.py +115 -0
- bootstack/cli/config.py +313 -0
- bootstack/cli/demo.py +564 -0
- bootstack/cli/dev.py +153 -0
- bootstack/cli/doctor.py +195 -0
- bootstack/cli/icons.py +98 -0
- bootstack/cli/promote.py +120 -0
- bootstack/cli/pyinstaller.py +268 -0
- bootstack/cli/run.py +95 -0
- bootstack/cli/start.py +117 -0
- bootstack/cli/templates/__init__.py +931 -0
- bootstack/clipboard.py +48 -0
- bootstack/constants.py +318 -0
- bootstack/data/README.md +615 -0
- bootstack/data/__init__.py +78 -0
- bootstack/data/_observable.py +276 -0
- bootstack/data/base.py +780 -0
- bootstack/data/file_source.py +367 -0
- bootstack/data/memory_source.py +450 -0
- bootstack/data/query.py +367 -0
- bootstack/data/readers.py +289 -0
- bootstack/data/sqlite_source.py +869 -0
- bootstack/data/types.py +354 -0
- bootstack/data/writers.py +232 -0
- bootstack/dev/__init__.py +36 -0
- bootstack/dev/_capture.py +141 -0
- bootstack/dev/_env.py +43 -0
- bootstack/dev/_registry.py +140 -0
- bootstack/dev/_reloader.py +351 -0
- bootstack/dev/_reset.py +50 -0
- bootstack/dev/_watcher.py +91 -0
- bootstack/dialogs/__init__.py +948 -0
- bootstack/dialogs/_impl/__init__.py +47 -0
- bootstack/dialogs/_impl/colorchooser.py +588 -0
- bootstack/dialogs/_impl/datedialog.py +450 -0
- bootstack/dialogs/_impl/dialog.py +594 -0
- bootstack/dialogs/_impl/filterdialog.py +358 -0
- bootstack/dialogs/_impl/fontdialog.py +364 -0
- bootstack/dialogs/_impl/formdialog.py +564 -0
- bootstack/dialogs/_impl/message.py +486 -0
- bootstack/dialogs/_impl/query.py +570 -0
- bootstack/errors.py +67 -0
- bootstack/events/__init__.py +111 -0
- bootstack/events/_event.py +135 -0
- bootstack/events/_payloads.py +539 -0
- bootstack/events/_subscription.py +38 -0
- bootstack/i18n/README.md +77 -0
- bootstack/i18n/__init__.py +23 -0
- bootstack/i18n/catalog.py +121 -0
- bootstack/i18n/intl_format.py +584 -0
- bootstack/i18n/msgcat.py +425 -0
- bootstack/i18n/specs.py +156 -0
- bootstack/images.py +563 -0
- bootstack/py.typed +1 -0
- bootstack/scheduling/__init__.py +11 -0
- bootstack/scheduling/_schedule.py +218 -0
- bootstack/shortcuts.py +21 -0
- bootstack/signals/README.md +98 -0
- bootstack/signals/__init__.py +10 -0
- bootstack/signals/integration.py +100 -0
- bootstack/signals/signal.py +353 -0
- bootstack/signals/types.py +6 -0
- bootstack/store.py +286 -0
- bootstack/streams/__init__.py +12 -0
- bootstack/streams/_stream.py +321 -0
- bootstack/style/__init__.py +38 -0
- bootstack/style/builders/__init__.py +51 -0
- bootstack/style/builders/badge.py +46 -0
- bootstack/style/builders/button.py +339 -0
- bootstack/style/builders/buttongroup.py +311 -0
- bootstack/style/builders/calendar.py +271 -0
- bootstack/style/builders/checkbutton.py +110 -0
- bootstack/style/builders/combobox.py +113 -0
- bootstack/style/builders/contextmenu.py +268 -0
- bootstack/style/builders/entry.py +82 -0
- bootstack/style/builders/expander.py +148 -0
- bootstack/style/builders/field.py +335 -0
- bootstack/style/builders/frame.py +50 -0
- bootstack/style/builders/label.py +28 -0
- bootstack/style/builders/labelframe.py +34 -0
- bootstack/style/builders/listview.py +369 -0
- bootstack/style/builders/menubar.py +91 -0
- bootstack/style/builders/menubutton.py +359 -0
- bootstack/style/builders/panedwindow.py +25 -0
- bootstack/style/builders/progressbar.py +67 -0
- bootstack/style/builders/radiobutton.py +99 -0
- bootstack/style/builders/scale.py +64 -0
- bootstack/style/builders/scrollbar.py +225 -0
- bootstack/style/builders/separator.py +49 -0
- bootstack/style/builders/sidenav.py +643 -0
- bootstack/style/builders/sizegrip.py +15 -0
- bootstack/style/builders/spinbox.py +119 -0
- bootstack/style/builders/switch.py +70 -0
- bootstack/style/builders/tabitem.py +204 -0
- bootstack/style/builders/togglegroup.py +294 -0
- bootstack/style/builders/toolbutton.py +275 -0
- bootstack/style/builders/tooltip.py +26 -0
- bootstack/style/builders/treeview.py +193 -0
- bootstack/style/builders/utils.py +455 -0
- bootstack/style/builders_tk/__init__.py +16 -0
- bootstack/style/builders_tk/defaults.py +229 -0
- bootstack/style/element.py +173 -0
- bootstack/style/fonts.py +123 -0
- bootstack/style/style.py +609 -0
- bootstack/style/style_builder_base.py +716 -0
- bootstack/style/style_builder_mixed.py +93 -0
- bootstack/style/style_builder_tk.py +109 -0
- bootstack/style/style_builder_ttk.py +353 -0
- bootstack/style/style_resolver.py +447 -0
- bootstack/style/theme.py +245 -0
- bootstack/style/theme_provider.py +471 -0
- bootstack/style/themes/__init__.py +128 -0
- bootstack/style/tk_patch.py +5 -0
- bootstack/style/token_maps.py +41 -0
- bootstack/style/types.py +32 -0
- bootstack/style/typography.py +523 -0
- bootstack/style/utility.py +746 -0
- bootstack/types.py +39 -0
- bootstack/validation/__init__.py +6 -0
- bootstack/validation/types.py +15 -0
- bootstack/validation/validation_result.py +17 -0
- bootstack/validation/validation_rules.py +205 -0
- bootstack/widgets/__init__.py +74 -0
- bootstack/widgets/_core/__init__.py +31 -0
- bootstack/widgets/_core/app_config.py +266 -0
- bootstack/widgets/_core/base.py +461 -0
- bootstack/widgets/_core/container.py +334 -0
- bootstack/widgets/_core/context.py +35 -0
- bootstack/widgets/_core/events.py +130 -0
- bootstack/widgets/_core/field_mixin.py +353 -0
- bootstack/widgets/_core/icon_image_props.py +72 -0
- bootstack/widgets/_core/image_binding.py +93 -0
- bootstack/widgets/_core/navmodel.py +345 -0
- bootstack/widgets/_core/options.py +210 -0
- bootstack/widgets/_core/selection_group.py +130 -0
- bootstack/widgets/_core/window_controls.py +96 -0
- bootstack/widgets/_core/window_menu.py +246 -0
- bootstack/widgets/_impl/__init__.py +1 -0
- bootstack/widgets/_impl/_internal/__init__.py +0 -0
- bootstack/widgets/_impl/_internal/wrapper_base.py +307 -0
- bootstack/widgets/_impl/_parts/__init__.py +11 -0
- bootstack/widgets/_impl/_parts/numberentry_part.py +385 -0
- bootstack/widgets/_impl/_parts/spinnerentry_part.py +434 -0
- bootstack/widgets/_impl/_parts/textentry_part.py +406 -0
- bootstack/widgets/_impl/composites/__init__.py +33 -0
- bootstack/widgets/_impl/composites/_dateutils.py +33 -0
- bootstack/widgets/_impl/composites/_image_fit.py +105 -0
- bootstack/widgets/_impl/composites/accordion.py +381 -0
- bootstack/widgets/_impl/composites/avatar.py +191 -0
- bootstack/widgets/_impl/composites/buttongroup.py +371 -0
- bootstack/widgets/_impl/composites/calendar.py +972 -0
- bootstack/widgets/_impl/composites/carousel.py +567 -0
- bootstack/widgets/_impl/composites/chart.py +882 -0
- bootstack/widgets/_impl/composites/compositeframe.py +298 -0
- bootstack/widgets/_impl/composites/contextmenu.py +1951 -0
- bootstack/widgets/_impl/composites/dateentry.py +404 -0
- bootstack/widgets/_impl/composites/dropdownbutton.py +325 -0
- bootstack/widgets/_impl/composites/expander.py +515 -0
- bootstack/widgets/_impl/composites/field.py +670 -0
- bootstack/widgets/_impl/composites/form.py +1066 -0
- bootstack/widgets/_impl/composites/gallery.py +551 -0
- bootstack/widgets/_impl/composites/list/__init__.py +15 -0
- bootstack/widgets/_impl/composites/list/listitem.py +802 -0
- bootstack/widgets/_impl/composites/list/listview.py +1433 -0
- bootstack/widgets/_impl/composites/menu/__init__.py +18 -0
- bootstack/widgets/_impl/composites/menu/model.py +358 -0
- bootstack/widgets/_impl/composites/menu/render_native.py +134 -0
- bootstack/widgets/_impl/composites/menu/render_themed.py +134 -0
- bootstack/widgets/_impl/composites/meter.py +860 -0
- bootstack/widgets/_impl/composites/numericentry.py +201 -0
- bootstack/widgets/_impl/composites/pagestack.py +395 -0
- bootstack/widgets/_impl/composites/passwordentry.py +142 -0
- bootstack/widgets/_impl/composites/pathentry.py +168 -0
- bootstack/widgets/_impl/composites/picture.py +289 -0
- bootstack/widgets/_impl/composites/radiogroup.py +511 -0
- bootstack/widgets/_impl/composites/scrolledtext.py +375 -0
- bootstack/widgets/_impl/composites/scrolledtext.pyi +186 -0
- bootstack/widgets/_impl/composites/scrollview.py +764 -0
- bootstack/widgets/_impl/composites/selectbox.py +1026 -0
- bootstack/widgets/_impl/composites/shell/__init__.py +40 -0
- bootstack/widgets/_impl/composites/shell/content_host.py +52 -0
- bootstack/widgets/_impl/composites/shell/layout.py +335 -0
- bootstack/widgets/_impl/composites/shell/nav_panel.py +345 -0
- bootstack/widgets/_impl/composites/shell/providers.py +558 -0
- bootstack/widgets/_impl/composites/shell/rail.py +117 -0
- bootstack/widgets/_impl/composites/shell/shell.py +581 -0
- bootstack/widgets/_impl/composites/shell/workspace.py +273 -0
- bootstack/widgets/_impl/composites/sidenav/__init__.py +16 -0
- bootstack/widgets/_impl/composites/sidenav/header.py +81 -0
- bootstack/widgets/_impl/composites/sidenav/separator.py +44 -0
- bootstack/widgets/_impl/composites/slider/__init__.py +7 -0
- bootstack/widgets/_impl/composites/slider/_shared.py +195 -0
- bootstack/widgets/_impl/composites/slider/rangeslider.py +982 -0
- bootstack/widgets/_impl/composites/slider/slider.py +851 -0
- bootstack/widgets/_impl/composites/spinnerentry.py +185 -0
- bootstack/widgets/_impl/composites/tableview/__init__.py +5 -0
- bootstack/widgets/_impl/composites/tableview/tableview.py +3388 -0
- bootstack/widgets/_impl/composites/tableview/types.py +169 -0
- bootstack/widgets/_impl/composites/tabs/__init__.py +23 -0
- bootstack/widgets/_impl/composites/tabs/tabitem.py +389 -0
- bootstack/widgets/_impl/composites/tabs/tabs.py +974 -0
- bootstack/widgets/_impl/composites/tabs/tabview.py +650 -0
- bootstack/widgets/_impl/composites/textarea/__init__.py +26 -0
- bootstack/widgets/_impl/composites/textarea/change.py +46 -0
- bootstack/widgets/_impl/composites/textarea/codeeditor.py +526 -0
- bootstack/widgets/_impl/composites/textarea/core.py +495 -0
- bootstack/widgets/_impl/composites/textarea/decoration.py +42 -0
- bootstack/widgets/_impl/composites/textarea/diff.py +127 -0
- bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +1 -0
- bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +138 -0
- bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +158 -0
- bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +138 -0
- bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +312 -0
- bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +177 -0
- bootstack/widgets/_impl/composites/textarea/filter.py +171 -0
- bootstack/widgets/_impl/composites/textarea/search_overlay.py +459 -0
- bootstack/widgets/_impl/composites/textarea/sidebar.py +88 -0
- bootstack/widgets/_impl/composites/textarea/style_registry.py +178 -0
- bootstack/widgets/_impl/composites/textarea/textarea.py +606 -0
- bootstack/widgets/_impl/composites/textarea/undo.py +217 -0
- bootstack/widgets/_impl/composites/textentry.py +57 -0
- bootstack/widgets/_impl/composites/timeentry.py +176 -0
- bootstack/widgets/_impl/composites/toast.py +390 -0
- bootstack/widgets/_impl/composites/toast_stack.py +156 -0
- bootstack/widgets/_impl/composites/togglegroup.py +418 -0
- bootstack/widgets/_impl/composites/toolbar.py +608 -0
- bootstack/widgets/_impl/composites/tooltip.py +491 -0
- bootstack/widgets/_impl/composites/tree/__init__.py +7 -0
- bootstack/widgets/_impl/composites/tree/source_binding.py +136 -0
- bootstack/widgets/_impl/composites/tree/treeitem.py +393 -0
- bootstack/widgets/_impl/composites/tree/treenode.py +174 -0
- bootstack/widgets/_impl/composites/tree/treeview.py +841 -0
- bootstack/widgets/_impl/mixins/__init__.py +24 -0
- bootstack/widgets/_impl/mixins/configure_mixin.py +216 -0
- bootstack/widgets/_impl/mixins/entry_mixin.py +134 -0
- bootstack/widgets/_impl/mixins/font_mixin.py +368 -0
- bootstack/widgets/_impl/mixins/icon_mixin.py +61 -0
- bootstack/widgets/_impl/mixins/localization_mixin.py +253 -0
- bootstack/widgets/_impl/mixins/signal_mixin.py +268 -0
- bootstack/widgets/_impl/mixins/validation_mixin.py +226 -0
- bootstack/widgets/_impl/primitives/__init__.py +49 -0
- bootstack/widgets/_impl/primitives/_menubutton.py +107 -0
- bootstack/widgets/_impl/primitives/badge.py +45 -0
- bootstack/widgets/_impl/primitives/button.py +76 -0
- bootstack/widgets/_impl/primitives/card.py +45 -0
- bootstack/widgets/_impl/primitives/checkbutton.py +124 -0
- bootstack/widgets/_impl/primitives/checktoggle.py +62 -0
- bootstack/widgets/_impl/primitives/combobox.py +156 -0
- bootstack/widgets/_impl/primitives/entry.py +87 -0
- bootstack/widgets/_impl/primitives/flexframe.py +448 -0
- bootstack/widgets/_impl/primitives/frame.py +185 -0
- bootstack/widgets/_impl/primitives/gridframe.py +546 -0
- bootstack/widgets/_impl/primitives/label.py +84 -0
- bootstack/widgets/_impl/primitives/labelframe.py +54 -0
- bootstack/widgets/_impl/primitives/optionmenu.py +387 -0
- bootstack/widgets/_impl/primitives/packframe.py +227 -0
- bootstack/widgets/_impl/primitives/panedwindow.py +45 -0
- bootstack/widgets/_impl/primitives/progressbar.py +83 -0
- bootstack/widgets/_impl/primitives/radiobutton.py +115 -0
- bootstack/widgets/_impl/primitives/radiotoggle.py +54 -0
- bootstack/widgets/_impl/primitives/scrollbar.py +42 -0
- bootstack/widgets/_impl/primitives/separator.py +43 -0
- bootstack/widgets/_impl/primitives/sizegrip.py +33 -0
- bootstack/widgets/_impl/primitives/spinbox.py +95 -0
- bootstack/widgets/_impl/primitives/switch.py +44 -0
- bootstack/widgets/_impl/primitives/treeview.py +69 -0
- bootstack/widgets/app.py +371 -0
- bootstack/widgets/appshell.py +1179 -0
- bootstack/widgets/avatar.py +140 -0
- bootstack/widgets/boolean_controls.py +455 -0
- bootstack/widgets/button.py +224 -0
- bootstack/widgets/buttongroup.py +239 -0
- bootstack/widgets/calendar.py +195 -0
- bootstack/widgets/card.py +159 -0
- bootstack/widgets/carousel.py +241 -0
- bootstack/widgets/chart.py +302 -0
- bootstack/widgets/codeeditor.py +675 -0
- bootstack/widgets/contextmenu.py +371 -0
- bootstack/widgets/datatable.py +688 -0
- bootstack/widgets/datefield.py +395 -0
- bootstack/widgets/divider.py +60 -0
- bootstack/widgets/expander.py +579 -0
- bootstack/widgets/form.py +200 -0
- bootstack/widgets/gallery.py +250 -0
- bootstack/widgets/gauge.py +168 -0
- bootstack/widgets/grid.py +121 -0
- bootstack/widgets/groupbox.py +162 -0
- bootstack/widgets/label.py +229 -0
- bootstack/widgets/listview.py +354 -0
- bootstack/widgets/menubutton.py +419 -0
- bootstack/widgets/numberfield.py +431 -0
- bootstack/widgets/pagestack.py +345 -0
- bootstack/widgets/passwordfield.py +383 -0
- bootstack/widgets/pathfield.py +454 -0
- bootstack/widgets/picture.py +251 -0
- bootstack/widgets/progressbar.py +106 -0
- bootstack/widgets/radio_variants.py +271 -0
- bootstack/widgets/radiogroup.py +228 -0
- bootstack/widgets/scrollbar.py +64 -0
- bootstack/widgets/scrollview.py +186 -0
- bootstack/widgets/select.py +302 -0
- bootstack/widgets/selectbutton.py +182 -0
- bootstack/widgets/sidebar_toggle.py +130 -0
- bootstack/widgets/sizegrip.py +42 -0
- bootstack/widgets/slider.py +408 -0
- bootstack/widgets/spinbox.py +147 -0
- bootstack/widgets/spinnerfield.py +413 -0
- bootstack/widgets/splash.py +367 -0
- bootstack/widgets/splitview.py +482 -0
- bootstack/widgets/stacks.py +249 -0
- bootstack/widgets/statusbar.py +189 -0
- bootstack/widgets/tabs.py +425 -0
- bootstack/widgets/textarea.py +459 -0
- bootstack/widgets/textfield.py +410 -0
- bootstack/widgets/theme_toggle.py +92 -0
- bootstack/widgets/timefield.py +340 -0
- bootstack/widgets/toast.py +314 -0
- bootstack/widgets/togglegroup.py +231 -0
- bootstack/widgets/toolbar.py +347 -0
- bootstack/widgets/tooltip.py +94 -0
- bootstack/widgets/tree.py +648 -0
- bootstack/widgets/types.py +305 -0
- bootstack/widgets/window.py +307 -0
- bootstack-0.1.0.dist-info/METADATA +301 -0
- bootstack-0.1.0.dist-info/RECORD +471 -0
- bootstack-0.1.0.dist-info/WHEEL +5 -0
- bootstack-0.1.0.dist-info/entry_points.txt +2 -0
- bootstack-0.1.0.dist-info/licenses/LICENSE +21 -0
- bootstack-0.1.0.dist-info/licenses/NOTICE +10 -0
- bootstack-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
"""Query dialogs and querybox facade for data input."""
|
|
2
|
+
|
|
3
|
+
import textwrap
|
|
4
|
+
import tkinter
|
|
5
|
+
from datetime import date
|
|
6
|
+
from types import SimpleNamespace
|
|
7
|
+
from typing import Any, Callable, List, Optional
|
|
8
|
+
|
|
9
|
+
from bootstack.widgets._impl.primitives import Frame, Label
|
|
10
|
+
from bootstack.widgets._impl.composites.selectbox import SelectBox
|
|
11
|
+
from bootstack.constants import *
|
|
12
|
+
|
|
13
|
+
ttk = SimpleNamespace(
|
|
14
|
+
Frame=Frame,
|
|
15
|
+
Label=Label,
|
|
16
|
+
)
|
|
17
|
+
from bootstack.i18n import MessageCatalog
|
|
18
|
+
from bootstack.dialogs._impl.datedialog import DateDialog
|
|
19
|
+
from bootstack.dialogs._impl.dialog import Dialog, DialogButton
|
|
20
|
+
from bootstack.dialogs._impl.fontdialog import FontDialog
|
|
21
|
+
from bootstack.dialogs._impl.message import MessageBox
|
|
22
|
+
from bootstack.widgets._impl.composites.textentry import TextEntry
|
|
23
|
+
from bootstack.widgets._impl.composites.numericentry import NumericEntry
|
|
24
|
+
from bootstack.widgets._impl.composites.dateentry import DateEntry
|
|
25
|
+
|
|
26
|
+
EntryWidget = TextEntry | NumericEntry | DateEntry
|
|
27
|
+
|
|
28
|
+
class QueryDialog:
|
|
29
|
+
"""A modal dialog for collecting user input with validation.
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
prompt: str,
|
|
36
|
+
title: str = " ",
|
|
37
|
+
value: Any = "",
|
|
38
|
+
minvalue: Optional[Any] = None,
|
|
39
|
+
maxvalue: Optional[Any] = None,
|
|
40
|
+
width: int = 65,
|
|
41
|
+
datatype: Any = str,
|
|
42
|
+
padding: tuple[int, int] | int = (20, 20),
|
|
43
|
+
master: Optional[tkinter.Misc] = None,
|
|
44
|
+
items: Optional[List[str]] = None,
|
|
45
|
+
value_format: Optional[str] = None,
|
|
46
|
+
increment: Optional[int | float] = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
"""Create a query dialog for collecting user input.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
prompt: The prompt text to display above the input field. Supports multiline strings.
|
|
52
|
+
title: The dialog window title.
|
|
53
|
+
value: The initial value to populate in the input field.
|
|
54
|
+
value_format: Optional ICU format pattern for formatting/parsing values.
|
|
55
|
+
For numbers: e.g., '$#,##0.00' for currency, '#,##0.##' for decimals
|
|
56
|
+
For dates: e.g., 'shortDate', 'longDate', 'yyyy-MM-dd'
|
|
57
|
+
When provided, uses specialized Field widgets (TextEntry, NumericEntry, DateEntry).
|
|
58
|
+
minvalue: Minimum allowed value for numeric data types. Ignored for strings.
|
|
59
|
+
maxvalue: Maximum allowed value for numeric data types. Ignored for strings.
|
|
60
|
+
increment: Step size for numeric fields (passed to NumericEntry).
|
|
61
|
+
width: Maximum width in characters for text wrapping of the prompt.
|
|
62
|
+
datatype: Expected data type for validation (str, int, float, date, complex).
|
|
63
|
+
padding: Padding around the dialog content.
|
|
64
|
+
master: Parent widget for the dialog.
|
|
65
|
+
items: Optional list of items for dropdown selection. Shows a Combobox instead of Entry.
|
|
66
|
+
"""
|
|
67
|
+
self._prompt = prompt
|
|
68
|
+
self._value = value
|
|
69
|
+
self._items = items
|
|
70
|
+
self._minvalue = minvalue
|
|
71
|
+
self._maxvalue = maxvalue
|
|
72
|
+
self._width = width
|
|
73
|
+
self._datatype = datatype
|
|
74
|
+
self._padding = padding
|
|
75
|
+
self._value_format = value_format
|
|
76
|
+
self._increment = increment
|
|
77
|
+
self._entry_widget: Optional[EntryWidget] = None
|
|
78
|
+
self._master = master
|
|
79
|
+
|
|
80
|
+
# Create the underlying dialog with inline button specifications
|
|
81
|
+
self._dialog = Dialog(
|
|
82
|
+
title=title,
|
|
83
|
+
content_builder=self._create_content,
|
|
84
|
+
_raw_content=True,
|
|
85
|
+
buttons=[
|
|
86
|
+
DialogButton(
|
|
87
|
+
text="button.cancel",
|
|
88
|
+
role="cancel",
|
|
89
|
+
result=None,
|
|
90
|
+
),
|
|
91
|
+
DialogButton(
|
|
92
|
+
text="button.submit",
|
|
93
|
+
role="primary",
|
|
94
|
+
default=True,
|
|
95
|
+
command=lambda dlg: self._on_submit(),
|
|
96
|
+
closes=False,
|
|
97
|
+
),
|
|
98
|
+
],
|
|
99
|
+
min_size=(350, 120),
|
|
100
|
+
parent=master,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def _create_content(self, parent: tkinter.Widget) -> None:
|
|
104
|
+
"""Create the dialog body with prompt and input field."""
|
|
105
|
+
frame = ttk.Frame(parent, padding=self._padding)
|
|
106
|
+
|
|
107
|
+
# Create prompt label(s)
|
|
108
|
+
if self._prompt:
|
|
109
|
+
for p in self._prompt.split("\n"):
|
|
110
|
+
prompt = "\n".join(textwrap.wrap(p, width=self._width))
|
|
111
|
+
prompt_label = ttk.Label(frame, text=prompt)
|
|
112
|
+
prompt_label.pack(pady=(0, 5), fill=X, anchor=N)
|
|
113
|
+
|
|
114
|
+
# Create appropriate input field based on datatype and options
|
|
115
|
+
if self._items is not None and len(self._items) > 0:
|
|
116
|
+
entry = SelectBox(
|
|
117
|
+
frame,
|
|
118
|
+
items=self._items,
|
|
119
|
+
value=self._value if self._value else None,
|
|
120
|
+
allow_custom_values=False,
|
|
121
|
+
enable_search=True,
|
|
122
|
+
initial_focus=True,
|
|
123
|
+
show_message=False,
|
|
124
|
+
label=None,
|
|
125
|
+
)
|
|
126
|
+
elif self._datatype == date:
|
|
127
|
+
# DateEntry for date input
|
|
128
|
+
kwargs = {"value": self._value} if self._value else {}
|
|
129
|
+
if self._value_format:
|
|
130
|
+
kwargs["value_format"] = self._value_format
|
|
131
|
+
kwargs.setdefault("initial_focus", True)
|
|
132
|
+
entry = DateEntry(master=frame, label=None, show_message=False, **kwargs)
|
|
133
|
+
elif self._datatype in (int, float):
|
|
134
|
+
# NumericEntry for numeric input with validation
|
|
135
|
+
kwargs = {"value": self._value if self._value else 0}
|
|
136
|
+
if self._minvalue is not None:
|
|
137
|
+
kwargs["minvalue"] = self._minvalue
|
|
138
|
+
if self._maxvalue is not None:
|
|
139
|
+
kwargs["maxvalue"] = self._maxvalue
|
|
140
|
+
if self._value_format:
|
|
141
|
+
kwargs["value_format"] = self._value_format
|
|
142
|
+
if self._increment is not None:
|
|
143
|
+
kwargs["increment"] = self._increment
|
|
144
|
+
kwargs.setdefault("initial_focus", True)
|
|
145
|
+
entry = NumericEntry(master=frame, label=None, show_message=False, **kwargs)
|
|
146
|
+
else:
|
|
147
|
+
# TextEntry for string input
|
|
148
|
+
kwargs = {"value": str(self._value) if self._value else ""}
|
|
149
|
+
if self._value_format:
|
|
150
|
+
kwargs["value_format"] = self._value_format
|
|
151
|
+
kwargs.setdefault("initial_focus", True)
|
|
152
|
+
entry = TextEntry(master=frame, label=None, show_message=False, **kwargs)
|
|
153
|
+
|
|
154
|
+
entry.pack(pady=(0, 5), fill=X)
|
|
155
|
+
entry.bind("<Return>", self._on_submit)
|
|
156
|
+
entry.bind("<KP_Enter>", self._on_submit)
|
|
157
|
+
|
|
158
|
+
# Focus the entry field
|
|
159
|
+
def _focus():
|
|
160
|
+
if hasattr(entry, 'entry_widget'):
|
|
161
|
+
entry.entry_widget.focus_set()
|
|
162
|
+
else:
|
|
163
|
+
entry.focus_set()
|
|
164
|
+
|
|
165
|
+
_focus()
|
|
166
|
+
# Ensure focus after dialog buttons set their own focus
|
|
167
|
+
entry.after_idle(_focus)
|
|
168
|
+
|
|
169
|
+
frame.pack(fill=X, expand=True)
|
|
170
|
+
self._entry_widget = entry
|
|
171
|
+
|
|
172
|
+
def _on_submit(self, *_: Any) -> None:
|
|
173
|
+
"""Handle submit (Enter key or button click)."""
|
|
174
|
+
if not self._entry_widget:
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
# Get value from widget - Field widgets use .value, Entry/Combobox use .get()
|
|
178
|
+
if hasattr(self._entry_widget, 'value'):
|
|
179
|
+
result = self._entry_widget.value
|
|
180
|
+
# For item-selection dialogs, reject values not in the list
|
|
181
|
+
if self._items and result not in self._items:
|
|
182
|
+
msg = MessageCatalog.translate("validation.select_item")
|
|
183
|
+
MessageBox.ok(
|
|
184
|
+
message=msg,
|
|
185
|
+
title=MessageCatalog.translate("validation.out_of_range"),
|
|
186
|
+
master=self._dialog.toplevel,
|
|
187
|
+
)
|
|
188
|
+
return
|
|
189
|
+
if result is not None:
|
|
190
|
+
self._dialog.result = result
|
|
191
|
+
if self._dialog.toplevel:
|
|
192
|
+
self._dialog.toplevel.destroy()
|
|
193
|
+
else:
|
|
194
|
+
# Regular Entry/Combobox - use old validation logic
|
|
195
|
+
result = self._entry_widget.get()
|
|
196
|
+
if self._validate(result):
|
|
197
|
+
self._dialog.result = self._datatype(result) if self._datatype != str else result
|
|
198
|
+
if self._dialog.toplevel:
|
|
199
|
+
self._dialog.toplevel.destroy()
|
|
200
|
+
|
|
201
|
+
def _on_filter_list(self, event: tkinter.Event) -> None:
|
|
202
|
+
"""Filter combobox items based on user input."""
|
|
203
|
+
value = event.widget.get().lower()
|
|
204
|
+
if not value:
|
|
205
|
+
event.widget["values"] = self._items
|
|
206
|
+
else:
|
|
207
|
+
data = [k for k in self._items if value in k.lower()]
|
|
208
|
+
event.widget["values"] = data
|
|
209
|
+
|
|
210
|
+
def _validate(self, result: str) -> bool:
|
|
211
|
+
"""Validate the input data."""
|
|
212
|
+
# No validation for string data types unless there's a list of items
|
|
213
|
+
if self._datatype not in [float, int, complex] and (self._items is None or len(self._items) == 0):
|
|
214
|
+
return True
|
|
215
|
+
|
|
216
|
+
# Convert result to appropriate data type
|
|
217
|
+
try:
|
|
218
|
+
converted_result = self._datatype(result)
|
|
219
|
+
except ValueError:
|
|
220
|
+
msg = MessageCatalog.translate("validation.should_be_type")
|
|
221
|
+
MessageBox.ok(
|
|
222
|
+
message=f"{msg} `{self._datatype}`",
|
|
223
|
+
title=MessageCatalog.translate("validation.invalid_type"),
|
|
224
|
+
master=self._dialog.toplevel,
|
|
225
|
+
)
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
# Check max value range
|
|
229
|
+
if self._maxvalue is not None and converted_result > self._maxvalue:
|
|
230
|
+
msg = MessageCatalog.translate("validation.greater_than")
|
|
231
|
+
MessageBox.ok(
|
|
232
|
+
message=f"{msg} {self._maxvalue}",
|
|
233
|
+
title=MessageCatalog.translate("validation.out_of_range"),
|
|
234
|
+
master=self._dialog.toplevel,
|
|
235
|
+
)
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
# Check min value range
|
|
239
|
+
if self._minvalue is not None and converted_result < self._minvalue:
|
|
240
|
+
msg = MessageCatalog.translate("validation.less_than")
|
|
241
|
+
MessageBox.ok(
|
|
242
|
+
message=f"{msg} {self._minvalue}",
|
|
243
|
+
title=MessageCatalog.translate("validation.out_of_range"),
|
|
244
|
+
master=self._dialog.toplevel,
|
|
245
|
+
)
|
|
246
|
+
return False
|
|
247
|
+
|
|
248
|
+
# Check if item is in list
|
|
249
|
+
if self._items is not None and len(self._items) > 0 and result not in self._items:
|
|
250
|
+
msg = MessageCatalog.translate("validation.select_item")
|
|
251
|
+
MessageBox.ok(
|
|
252
|
+
message=msg,
|
|
253
|
+
title=MessageCatalog.translate("validation.out_of_range"),
|
|
254
|
+
master=self._dialog.toplevel,
|
|
255
|
+
)
|
|
256
|
+
return False
|
|
257
|
+
|
|
258
|
+
return True
|
|
259
|
+
|
|
260
|
+
def show(self, position: Optional[tuple[int, int]] = None) -> None:
|
|
261
|
+
"""Show the dialog.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
position: x and y coordinates to position the dialog. If None, centers on parent.
|
|
265
|
+
"""
|
|
266
|
+
self._dialog.show(position=position, modal=True)
|
|
267
|
+
target = self._dialog.toplevel or self._master
|
|
268
|
+
if target:
|
|
269
|
+
payload = {"result": self._dialog.result, "confirmed": self._dialog.result is not None}
|
|
270
|
+
try:
|
|
271
|
+
target.event_generate("<<DialogResult>>", data=payload)
|
|
272
|
+
except Exception:
|
|
273
|
+
try:
|
|
274
|
+
target.event_generate("<<DialogResult>>")
|
|
275
|
+
except Exception:
|
|
276
|
+
pass
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def result(self) -> Any:
|
|
280
|
+
"""The dialog result value."""
|
|
281
|
+
return self._dialog.result
|
|
282
|
+
|
|
283
|
+
def on_dialog_result(self, callback: Callable[[Any], None]) -> Optional[str]:
|
|
284
|
+
"""Bind a callback fired when the dialog produces a result.
|
|
285
|
+
|
|
286
|
+
The callback receives `event.data["result"]` when available.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
callback: Callable that receives the result payload.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
Binding identifier for use with `off_dialog_result`.
|
|
293
|
+
"""
|
|
294
|
+
target = self._dialog.toplevel or self._master
|
|
295
|
+
if target is None:
|
|
296
|
+
return None
|
|
297
|
+
|
|
298
|
+
def handler(event):
|
|
299
|
+
callback(getattr(event, "data", None))
|
|
300
|
+
|
|
301
|
+
return target.bind("<<DialogResult>>", handler, add="+")
|
|
302
|
+
|
|
303
|
+
def off_dialog_result(self, funcid: str) -> None:
|
|
304
|
+
"""Unbind a previously bound dialog result callback."""
|
|
305
|
+
target = self._dialog.toplevel or self._master
|
|
306
|
+
if target is None:
|
|
307
|
+
return
|
|
308
|
+
target.unbind("<<DialogResult>>", funcid)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class QueryBox:
|
|
312
|
+
"""Static methods for displaying query dialogs."""
|
|
313
|
+
|
|
314
|
+
@staticmethod
|
|
315
|
+
def get_color(
|
|
316
|
+
master: Optional[tkinter.Misc] = None,
|
|
317
|
+
title: str = "Color Chooser",
|
|
318
|
+
value: Optional[str] = None,
|
|
319
|
+
**kwargs: Any,
|
|
320
|
+
) -> Any:
|
|
321
|
+
"""Show a color picker dialog.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
master: Parent widget for the dialog.
|
|
325
|
+
title: The dialog window title.
|
|
326
|
+
value: Initial color to display.
|
|
327
|
+
**kwargs: Additional arguments including 'position'.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Selected color or None if canceled.
|
|
331
|
+
"""
|
|
332
|
+
from bootstack.dialogs._impl.colorchooser import ColorChooserDialog
|
|
333
|
+
|
|
334
|
+
position = kwargs.pop("position", None)
|
|
335
|
+
dialog = ColorChooserDialog(master, title, value)
|
|
336
|
+
dialog.show(position)
|
|
337
|
+
return dialog.result
|
|
338
|
+
|
|
339
|
+
@staticmethod
|
|
340
|
+
def get_date(
|
|
341
|
+
master: Optional[tkinter.Misc] = None,
|
|
342
|
+
title: str = " ",
|
|
343
|
+
first_weekday: int = 6,
|
|
344
|
+
value: Optional[date] = None,
|
|
345
|
+
accent: str = None,
|
|
346
|
+
hide_window_chrome: bool = False,
|
|
347
|
+
on_result: Optional[Callable[[Any], None]] = None,
|
|
348
|
+
**kwargs: Any,
|
|
349
|
+
) -> Optional[date]:
|
|
350
|
+
"""Show a date picker dialog.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
master: Parent widget for the dialog.
|
|
354
|
+
title: The dialog window title.
|
|
355
|
+
first_weekday: First day of the week (0=Monday, 6=Sunday).
|
|
356
|
+
value: Initial date to display.
|
|
357
|
+
accent: Accent token for the calendar (e.g., 'primary', 'success').
|
|
358
|
+
hide_window_chrome: If True, shows the dialog with override-redirect
|
|
359
|
+
to hide window decorations.
|
|
360
|
+
on_result: Optional callback receiving the dialog result payload.
|
|
361
|
+
**kwargs: Additional arguments including 'position'.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
Selected date or None if canceled.
|
|
365
|
+
"""
|
|
366
|
+
position = kwargs.pop("position", None)
|
|
367
|
+
dialog = DateDialog(
|
|
368
|
+
master=master,
|
|
369
|
+
title=title,
|
|
370
|
+
first_weekday=first_weekday,
|
|
371
|
+
initial_date=value,
|
|
372
|
+
accent=accent or "primary",
|
|
373
|
+
hide_window_chrome=hide_window_chrome,
|
|
374
|
+
)
|
|
375
|
+
if on_result:
|
|
376
|
+
dialog.on_result(on_result)
|
|
377
|
+
dialog.show(position)
|
|
378
|
+
return dialog.result
|
|
379
|
+
|
|
380
|
+
@staticmethod
|
|
381
|
+
def get_string(
|
|
382
|
+
prompt: str = "",
|
|
383
|
+
title: str = " ",
|
|
384
|
+
value: Optional[str] = None,
|
|
385
|
+
master: Optional[tkinter.Misc] = None,
|
|
386
|
+
value_format: Optional[str] = None,
|
|
387
|
+
on_result: Optional[Callable[[Any], None]] = None,
|
|
388
|
+
**kwargs: Any,
|
|
389
|
+
) -> Optional[str]:
|
|
390
|
+
"""Show a string input dialog.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
prompt: The prompt text to display.
|
|
394
|
+
title: The dialog window title.
|
|
395
|
+
value: Initial value for the input field.
|
|
396
|
+
master: Parent widget for the dialog.
|
|
397
|
+
value_format: Optional ICU format pattern for parsing/formatting.
|
|
398
|
+
on_result: Optional callback receiving the dialog result payload.
|
|
399
|
+
**kwargs: Additional arguments including 'position'.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Input string or None if canceled.
|
|
403
|
+
"""
|
|
404
|
+
value = value or ""
|
|
405
|
+
position = kwargs.pop("position", None)
|
|
406
|
+
dialog = QueryDialog(
|
|
407
|
+
prompt,
|
|
408
|
+
title,
|
|
409
|
+
value,
|
|
410
|
+
master=master,
|
|
411
|
+
value_format=value_format,
|
|
412
|
+
**kwargs,
|
|
413
|
+
)
|
|
414
|
+
if on_result:
|
|
415
|
+
dialog.on_dialog_result(on_result)
|
|
416
|
+
dialog.show(position)
|
|
417
|
+
return dialog.result
|
|
418
|
+
|
|
419
|
+
@staticmethod
|
|
420
|
+
def get_item(
|
|
421
|
+
prompt: str = "",
|
|
422
|
+
title: str = " ",
|
|
423
|
+
value: Optional[str] = None,
|
|
424
|
+
items: Optional[List[str]] = None,
|
|
425
|
+
master: Optional[tkinter.Misc] = None,
|
|
426
|
+
on_result: Optional[Callable[[Any], None]] = None,
|
|
427
|
+
**kwargs: Any,
|
|
428
|
+
) -> Optional[str]:
|
|
429
|
+
"""Show a dropdown selection dialog.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
prompt: The prompt text to display.
|
|
433
|
+
title: The dialog window title.
|
|
434
|
+
value: Initial value for the input field.
|
|
435
|
+
items: List of items to choose from.
|
|
436
|
+
master: Parent widget for the dialog.
|
|
437
|
+
on_result: Optional callback receiving the dialog result payload.
|
|
438
|
+
**kwargs: Additional arguments including 'position'.
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
Selected item or None if canceled.
|
|
442
|
+
"""
|
|
443
|
+
value = value or ""
|
|
444
|
+
position = kwargs.pop("position", None)
|
|
445
|
+
dialog = QueryDialog(
|
|
446
|
+
prompt,
|
|
447
|
+
title,
|
|
448
|
+
value,
|
|
449
|
+
items=items,
|
|
450
|
+
master=master,
|
|
451
|
+
**kwargs,
|
|
452
|
+
)
|
|
453
|
+
if on_result:
|
|
454
|
+
dialog.on_dialog_result(on_result)
|
|
455
|
+
dialog.show(position)
|
|
456
|
+
return dialog.result
|
|
457
|
+
|
|
458
|
+
@staticmethod
|
|
459
|
+
def get_integer(
|
|
460
|
+
prompt: str = "",
|
|
461
|
+
title: str = " ",
|
|
462
|
+
value: Optional[int] = None,
|
|
463
|
+
minvalue: Optional[int] = None,
|
|
464
|
+
maxvalue: Optional[int] = None,
|
|
465
|
+
master: Optional[tkinter.Misc] = None,
|
|
466
|
+
value_format: Optional[str] = None,
|
|
467
|
+
increment: Optional[int] = None,
|
|
468
|
+
on_result: Optional[Callable[[Any], None]] = None,
|
|
469
|
+
**kwargs: Any,
|
|
470
|
+
) -> Optional[int]:
|
|
471
|
+
"""Show an integer input dialog with validation.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
prompt: The prompt text to display.
|
|
475
|
+
title: The dialog window title.
|
|
476
|
+
value: Initial value for the input field.
|
|
477
|
+
minvalue: Minimum allowed value.
|
|
478
|
+
maxvalue: Maximum allowed value.
|
|
479
|
+
increment: Step size for increment/decrement buttons.
|
|
480
|
+
value_format: Optional ICU format pattern for parsing/formatting.
|
|
481
|
+
master: Parent widget for the dialog.
|
|
482
|
+
on_result: Optional callback receiving the dialog result payload.
|
|
483
|
+
**kwargs: Additional arguments including 'position'.
|
|
484
|
+
|
|
485
|
+
Returns:
|
|
486
|
+
Integer value or None if canceled.
|
|
487
|
+
"""
|
|
488
|
+
value = value or ""
|
|
489
|
+
position = kwargs.pop("position", None)
|
|
490
|
+
dialog = QueryDialog(
|
|
491
|
+
prompt,
|
|
492
|
+
title,
|
|
493
|
+
value,
|
|
494
|
+
minvalue,
|
|
495
|
+
maxvalue,
|
|
496
|
+
datatype=int,
|
|
497
|
+
master=master,
|
|
498
|
+
value_format=value_format,
|
|
499
|
+
increment=increment,
|
|
500
|
+
**kwargs,
|
|
501
|
+
)
|
|
502
|
+
if on_result:
|
|
503
|
+
dialog.on_dialog_result(on_result)
|
|
504
|
+
dialog.show(position)
|
|
505
|
+
return dialog.result
|
|
506
|
+
|
|
507
|
+
@staticmethod
|
|
508
|
+
def get_float(
|
|
509
|
+
prompt: str = "",
|
|
510
|
+
title: str = " ",
|
|
511
|
+
value: Optional[float] = None,
|
|
512
|
+
minvalue: Optional[float] = None,
|
|
513
|
+
maxvalue: Optional[float] = None,
|
|
514
|
+
master: Optional[tkinter.Misc] = None,
|
|
515
|
+
value_format: Optional[str] = None,
|
|
516
|
+
increment: Optional[float] = None,
|
|
517
|
+
on_result: Optional[Callable[[Any], None]] = None,
|
|
518
|
+
**kwargs: Any,
|
|
519
|
+
) -> Optional[float]:
|
|
520
|
+
"""Show a float input dialog with validation.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
prompt: The prompt text to display.
|
|
524
|
+
title: The dialog window title.
|
|
525
|
+
value: Initial value for the input field.
|
|
526
|
+
minvalue: Minimum allowed value.
|
|
527
|
+
maxvalue: Maximum allowed value.
|
|
528
|
+
master: Parent widget for the dialog.
|
|
529
|
+
value_format: Optional ICU format pattern for parsing/formatting.
|
|
530
|
+
increment: Step size for increment/decrement buttons.
|
|
531
|
+
on_result: Optional callback receiving the dialog result payload.
|
|
532
|
+
**kwargs: Additional arguments including 'position'.
|
|
533
|
+
|
|
534
|
+
Returns:
|
|
535
|
+
Float value or None if canceled.
|
|
536
|
+
"""
|
|
537
|
+
value = value or ""
|
|
538
|
+
position = kwargs.pop("position", None)
|
|
539
|
+
dialog = QueryDialog(
|
|
540
|
+
prompt,
|
|
541
|
+
title,
|
|
542
|
+
value,
|
|
543
|
+
minvalue,
|
|
544
|
+
maxvalue,
|
|
545
|
+
datatype=float,
|
|
546
|
+
master=master,
|
|
547
|
+
value_format=value_format,
|
|
548
|
+
increment=increment,
|
|
549
|
+
**kwargs,
|
|
550
|
+
)
|
|
551
|
+
if on_result:
|
|
552
|
+
dialog.on_dialog_result(on_result)
|
|
553
|
+
dialog.show(position)
|
|
554
|
+
return dialog.result
|
|
555
|
+
|
|
556
|
+
@staticmethod
|
|
557
|
+
def get_font(master: Optional[tkinter.Misc] = None, **kwargs: Any) -> Any:
|
|
558
|
+
"""Show a font selection dialog.
|
|
559
|
+
|
|
560
|
+
Args:
|
|
561
|
+
master: Parent widget for the dialog.
|
|
562
|
+
**kwargs: Additional arguments including 'position'.
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
Selected font or None if canceled.
|
|
566
|
+
"""
|
|
567
|
+
position = kwargs.pop("position", None)
|
|
568
|
+
dialog = FontDialog(master=master, **kwargs)
|
|
569
|
+
dialog.show(position=position)
|
|
570
|
+
return dialog.result
|
bootstack/errors.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Public exception types raised by the bootstack API."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BootstackError(Exception):
|
|
5
|
+
"""Base class for all public API errors."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UnknownEventError(BootstackError):
|
|
9
|
+
"""Raised by `widget.on(name, ...)` when `name` cannot be resolved."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ParentResolutionError(BootstackError):
|
|
13
|
+
"""Raised when a widget cannot resolve its parent."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DuplicateIdError(BootstackError):
|
|
17
|
+
"""Raised when a data source receives a record whose id already exists.
|
|
18
|
+
|
|
19
|
+
Record ids must be unique — they identify rows for selection and events.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SerializationError(BootstackError):
|
|
24
|
+
"""Raised when a file-backed store or data source receives a value it
|
|
25
|
+
cannot persist.
|
|
26
|
+
|
|
27
|
+
File- and database-backed sources carry non-scalar fields as JSON, and
|
|
28
|
+
`Store` persists its values as JSON, so values must be JSON-serializable
|
|
29
|
+
(scalars, lists, dicts). Store arbitrary Python objects in an in-memory
|
|
30
|
+
source instead.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NavigationError(BootstackError):
|
|
35
|
+
"""Raised when a navigation operation references a wrong key.
|
|
36
|
+
|
|
37
|
+
Examples: adding a page, tab, or workspace whose key already exists, or
|
|
38
|
+
selecting, looking up, or removing one whose key does not exist.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ThemeError(BootstackError):
|
|
43
|
+
"""Raised when a theme-related operation fails.
|
|
44
|
+
|
|
45
|
+
Examples: requesting an unknown theme name, or loading a malformed theme
|
|
46
|
+
definition.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class StyleBuilderError(BootstackError):
|
|
51
|
+
"""Raised when a widget style cannot be built.
|
|
52
|
+
|
|
53
|
+
Examples: an unsupported `variant` for a widget, or a missing required
|
|
54
|
+
theme color token.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
__all__ = [
|
|
59
|
+
"BootstackError",
|
|
60
|
+
"DuplicateIdError",
|
|
61
|
+
"NavigationError",
|
|
62
|
+
"ParentResolutionError",
|
|
63
|
+
"SerializationError",
|
|
64
|
+
"StyleBuilderError",
|
|
65
|
+
"ThemeError",
|
|
66
|
+
"UnknownEventError",
|
|
67
|
+
]
|