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,395 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tkinter
|
|
4
|
+
from datetime import date
|
|
5
|
+
from typing import overload, Any, Callable, Iterable, Literal, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from bootstack.widgets._impl.composites.dateentry import DateEntry as _InternalDateEntry
|
|
8
|
+
from bootstack.widgets._core.base import PublicWidgetBase, adapt_handler
|
|
9
|
+
from bootstack.widgets._core.events import resolve_event, register_widget_events
|
|
10
|
+
from bootstack.widgets._core.field_mixin import FieldAddonMixin, ValueSignalMixin
|
|
11
|
+
from bootstack.events import ChangeEvent, Subscription, ValidationEvent
|
|
12
|
+
from bootstack.streams import Stream
|
|
13
|
+
from bootstack.widgets.textfield import _INNER_ENTRY_SEQUENCES
|
|
14
|
+
from bootstack.widgets.types import AccentToken, Event, WidgetDensity
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from bootstack.signals import Signal
|
|
18
|
+
|
|
19
|
+
_DATEFIELD_EVENTS: dict[str, str] = {
|
|
20
|
+
"change": "<<Change>>",
|
|
21
|
+
"validate": "<<Validate>>",
|
|
22
|
+
"valid": "<<Valid>>",
|
|
23
|
+
"invalid": "<<Invalid>>",
|
|
24
|
+
"submit": "<Return>",
|
|
25
|
+
"focus": "<FocusIn>",
|
|
26
|
+
"blur": "<FocusOut>",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class DateField(ValueSignalMixin, FieldAddonMixin, PublicWidgetBase):
|
|
31
|
+
"""A date input field with an optional calendar picker button.
|
|
32
|
+
|
|
33
|
+
In `'single'` mode `value` returns a `date`; in `'range'` mode it returns
|
|
34
|
+
a `(start, end)` tuple of dates.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
value: Initial date value — a `date` object or an ISO string
|
|
38
|
+
(`'YYYY-MM-DD'`). `None` for an empty field.
|
|
39
|
+
value_format: Format applied to the displayed date — a named preset
|
|
40
|
+
(e.g. `'shortDate'`, `'longDate'`) or a custom pattern (e.g.
|
|
41
|
+
`'dd.MM.yy'`). Default `'longDate'`. See
|
|
42
|
+
:ref:`format specs <value-formats>`.
|
|
43
|
+
label: Label displayed above the field.
|
|
44
|
+
message: Hint text displayed below the field.
|
|
45
|
+
signal: Reactive `Signal` two-way bound to the field's `date` value (not
|
|
46
|
+
its text). When given, it seeds the initial value. This is the usual
|
|
47
|
+
way to bind a date field.
|
|
48
|
+
show_picker_button: Show the calendar icon button. Default `True`.
|
|
49
|
+
picker_title: Title of the picker dialog.
|
|
50
|
+
picker_first_weekday: First day of week in the picker (0=Mon … 6=Sun).
|
|
51
|
+
Default `6` (Sunday).
|
|
52
|
+
selection_mode: Single date or a start/end range. In range mode the
|
|
53
|
+
entry is read-only and dates must be selected via the picker.
|
|
54
|
+
Default `'single'`.
|
|
55
|
+
range_start: Pre-selected range start date (range mode only).
|
|
56
|
+
range_end: Pre-selected range end date (range mode only).
|
|
57
|
+
min_date: Earliest selectable date.
|
|
58
|
+
max_date: Latest selectable date.
|
|
59
|
+
disabled_dates: Dates that cannot be selected.
|
|
60
|
+
required: Mark field as required; blocks empty submission.
|
|
61
|
+
disabled: If `True`, field is non-interactive.
|
|
62
|
+
read_only: If `True`, value is visible but not editable.
|
|
63
|
+
accent: Accent color applied to the focus ring. Default `'primary'`.
|
|
64
|
+
density: Widget density.
|
|
65
|
+
parent: Override the context-stack parent.
|
|
66
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
67
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
68
|
+
See :doc:`/tasks/layout`.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
_VALIDATION_KIND = "date"
|
|
72
|
+
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
value: str | date | None = None,
|
|
76
|
+
*,
|
|
77
|
+
signal: "Signal | None" = None,
|
|
78
|
+
value_format: str = "longDate",
|
|
79
|
+
label: str | None = None,
|
|
80
|
+
message: str | None = None,
|
|
81
|
+
show_picker_button: bool = True,
|
|
82
|
+
picker_title: str | None = None,
|
|
83
|
+
picker_first_weekday: int = 6,
|
|
84
|
+
selection_mode: Literal["single", "range"] = "single",
|
|
85
|
+
range_start: date | str | None = None,
|
|
86
|
+
range_end: date | str | None = None,
|
|
87
|
+
min_date: date | str | None = None,
|
|
88
|
+
max_date: date | str | None = None,
|
|
89
|
+
disabled_dates: Iterable[date | str] | None = None,
|
|
90
|
+
required: bool = False,
|
|
91
|
+
disabled: bool = False,
|
|
92
|
+
read_only: bool = False,
|
|
93
|
+
accent: AccentToken | str | None = None,
|
|
94
|
+
density: WidgetDensity | None = None,
|
|
95
|
+
parent: Any = None,
|
|
96
|
+
**kwargs: Any,
|
|
97
|
+
) -> None:
|
|
98
|
+
self._parent = self._resolve_parent(parent)
|
|
99
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
100
|
+
if "textsignal" in kwargs:
|
|
101
|
+
raise TypeError(
|
|
102
|
+
"DateField does not accept 'textsignal=' — a date field binds its "
|
|
103
|
+
"date value. Use signal= with a date-typed Signal "
|
|
104
|
+
"(e.g. Signal(date.today()))."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
108
|
+
|
|
109
|
+
internal_kwargs: dict[str, Any] = {
|
|
110
|
+
"value_format": value_format,
|
|
111
|
+
"show_picker_button": show_picker_button,
|
|
112
|
+
"picker_first_weekday": picker_first_weekday,
|
|
113
|
+
"selection_mode": selection_mode,
|
|
114
|
+
}
|
|
115
|
+
if value is not None:
|
|
116
|
+
internal_kwargs["value"] = value
|
|
117
|
+
if label is not None:
|
|
118
|
+
internal_kwargs["label"] = label
|
|
119
|
+
if message is not None:
|
|
120
|
+
internal_kwargs["message"] = message
|
|
121
|
+
if picker_title is not None:
|
|
122
|
+
internal_kwargs["picker_title"] = picker_title
|
|
123
|
+
if range_start is not None:
|
|
124
|
+
internal_kwargs["start_date"] = range_start
|
|
125
|
+
if range_end is not None:
|
|
126
|
+
internal_kwargs["end_date"] = range_end
|
|
127
|
+
if min_date is not None:
|
|
128
|
+
internal_kwargs["min_date"] = min_date
|
|
129
|
+
if max_date is not None:
|
|
130
|
+
internal_kwargs["max_date"] = max_date
|
|
131
|
+
if disabled_dates is not None:
|
|
132
|
+
internal_kwargs["disabled_dates"] = disabled_dates
|
|
133
|
+
if required:
|
|
134
|
+
internal_kwargs["required"] = True
|
|
135
|
+
if disabled:
|
|
136
|
+
internal_kwargs["state"] = "disabled"
|
|
137
|
+
elif read_only:
|
|
138
|
+
internal_kwargs["state"] = "readonly"
|
|
139
|
+
if accent is not None:
|
|
140
|
+
internal_kwargs["accent"] = accent
|
|
141
|
+
if density is not None:
|
|
142
|
+
internal_kwargs["density"] = density
|
|
143
|
+
|
|
144
|
+
self._internal = _InternalDateEntry(tk_master, **internal_kwargs)
|
|
145
|
+
self._attach_to_parent(layout_kw)
|
|
146
|
+
|
|
147
|
+
if signal is not None:
|
|
148
|
+
self._bind_value_signal(signal)
|
|
149
|
+
|
|
150
|
+
# ----- Event routing -----
|
|
151
|
+
|
|
152
|
+
def _entry_widget(self) -> tkinter.Misc:
|
|
153
|
+
return self._internal._entry
|
|
154
|
+
|
|
155
|
+
@overload
|
|
156
|
+
def on(self, event: str) -> Stream: ...
|
|
157
|
+
@overload
|
|
158
|
+
def on(self, event: str, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
159
|
+
def on(self, event: str, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
160
|
+
"""Register a callback for an event by name.
|
|
161
|
+
|
|
162
|
+
A generic, string-keyed escape hatch — prefer the typed `on_*`
|
|
163
|
+
shorthands (e.g. `on_change`), which carry the precise payload type.
|
|
164
|
+
Called with no handler, returns a composable `Stream`; with a handler,
|
|
165
|
+
binds it and returns a `Subscription`.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
event: Event name (for example `'change'` or `'focus'`).
|
|
169
|
+
handler: Called with the event payload. Omit to get a composable
|
|
170
|
+
:class:`~bootstack.streams.Stream` instead.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
A cancellable :class:`~bootstack.events.Subscription` when a handler
|
|
174
|
+
is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
175
|
+
"""
|
|
176
|
+
sequence = resolve_event(self, str(event))
|
|
177
|
+
widget = self._entry_widget() if sequence in _INNER_ENTRY_SEQUENCES else self._internal
|
|
178
|
+
if handler is None:
|
|
179
|
+
from bootstack.streams import Stream as _Stream
|
|
180
|
+
def _source(h):
|
|
181
|
+
_w = self._entry_widget() if sequence in _INNER_ENTRY_SEQUENCES else self._internal
|
|
182
|
+
_bid = _w.bind(sequence, adapt_handler(h), add="+")
|
|
183
|
+
return Subscription(_w, sequence, _bid)
|
|
184
|
+
return _Stream(self._internal, _source=_source)
|
|
185
|
+
bind_id = widget.bind(sequence, adapt_handler(handler), add="+")
|
|
186
|
+
return Subscription(widget, sequence, bind_id)
|
|
187
|
+
|
|
188
|
+
# ----- Properties -----
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def picker_button(self):
|
|
192
|
+
"""The calendar picker button widget, or `None` if hidden."""
|
|
193
|
+
return self._internal.addons.get('date-picker')
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def value(self) -> "date | tuple[date, date] | None":
|
|
197
|
+
"""Selected date, or `(start, end)` tuple in range mode."""
|
|
198
|
+
return self._internal.value
|
|
199
|
+
|
|
200
|
+
@value.setter
|
|
201
|
+
def value(self, v: "date | str | None") -> None:
|
|
202
|
+
self._internal.value = v
|
|
203
|
+
self._sync_value_set(self._internal.value)
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def disabled(self) -> bool:
|
|
207
|
+
"""Whether the field is disabled (non-interactive and greyed out)."""
|
|
208
|
+
return str(self._entry_widget().cget("state")) == "disabled"
|
|
209
|
+
|
|
210
|
+
@disabled.setter
|
|
211
|
+
def disabled(self, v: bool) -> None:
|
|
212
|
+
self._internal.configure(state="disabled" if v else "normal")
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def read_only(self) -> bool:
|
|
216
|
+
"""Whether the field is read-only (selectable but not editable)."""
|
|
217
|
+
return str(self._entry_widget().cget("state")) == "readonly"
|
|
218
|
+
|
|
219
|
+
@read_only.setter
|
|
220
|
+
def read_only(self, v: bool) -> None:
|
|
221
|
+
self._internal.configure(state="readonly" if v else "normal")
|
|
222
|
+
|
|
223
|
+
# ----- Date constraints -----
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def min_date(self) -> date | None:
|
|
227
|
+
"""Earliest selectable date. Assigning takes effect the next time the picker opens."""
|
|
228
|
+
return self._internal._coerce_date(self._internal._min_date)
|
|
229
|
+
|
|
230
|
+
@min_date.setter
|
|
231
|
+
def min_date(self, value: date | str | None) -> None:
|
|
232
|
+
self._internal.set_min_date(value)
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def max_date(self) -> date | None:
|
|
236
|
+
"""Latest selectable date. Assigning takes effect the next time the picker opens."""
|
|
237
|
+
return self._internal._coerce_date(self._internal._max_date)
|
|
238
|
+
|
|
239
|
+
@max_date.setter
|
|
240
|
+
def max_date(self, value: date | str | None) -> None:
|
|
241
|
+
self._internal.set_max_date(value)
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def disabled_dates(self) -> tuple[date, ...]:
|
|
245
|
+
"""Dates disabled in the picker. Assigning a new iterable takes effect the next time it opens."""
|
|
246
|
+
raw = self._internal._disabled_dates or []
|
|
247
|
+
coerce = self._internal._coerce_date
|
|
248
|
+
return tuple(sorted(d for d in (coerce(x) for x in raw) if d is not None))
|
|
249
|
+
|
|
250
|
+
@disabled_dates.setter
|
|
251
|
+
def disabled_dates(self, value: Iterable[date | str] | None) -> None:
|
|
252
|
+
self._internal.set_disabled_dates(value)
|
|
253
|
+
|
|
254
|
+
# ----- Methods -----
|
|
255
|
+
|
|
256
|
+
def validate(self) -> bool:
|
|
257
|
+
"""Run validation rules against the current value.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
`True` if all rules pass, `False` otherwise.
|
|
261
|
+
"""
|
|
262
|
+
entry = self._internal._entry
|
|
263
|
+
return entry.validate(entry._get_validation_value(), trigger="manual")
|
|
264
|
+
|
|
265
|
+
def focus(self) -> None:
|
|
266
|
+
"""Give keyboard focus to this field."""
|
|
267
|
+
self._entry_widget().focus_set()
|
|
268
|
+
|
|
269
|
+
def clear(self) -> None:
|
|
270
|
+
"""Clear the field, setting the value to `None`."""
|
|
271
|
+
self._internal.value = None
|
|
272
|
+
|
|
273
|
+
# ----- Event shorthands -----
|
|
274
|
+
|
|
275
|
+
@overload
|
|
276
|
+
def on_change(self) -> Stream: ...
|
|
277
|
+
@overload
|
|
278
|
+
def on_change(self, handler: Callable[[ChangeEvent], Any]) -> Subscription: ...
|
|
279
|
+
def on_change(self, handler: Callable[[ChangeEvent], Any] | None = None) -> Stream | Subscription:
|
|
280
|
+
"""Register a callback fired when the selected date changes.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
handler: Called with a :class:`~bootstack.events.ChangeEvent`. Omit to
|
|
284
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
288
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
289
|
+
"""
|
|
290
|
+
return self.on("change", handler)
|
|
291
|
+
|
|
292
|
+
@overload
|
|
293
|
+
def on_submit(self) -> Stream: ...
|
|
294
|
+
@overload
|
|
295
|
+
def on_submit(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
296
|
+
def on_submit(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
297
|
+
"""Register a callback fired when the user presses Return to confirm input.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
handler: Called with an :class:`~bootstack.events.Event`. Omit to
|
|
301
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
305
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
306
|
+
"""
|
|
307
|
+
return self.on("submit", handler)
|
|
308
|
+
|
|
309
|
+
@overload
|
|
310
|
+
def on_valid(self) -> Stream: ...
|
|
311
|
+
@overload
|
|
312
|
+
def on_valid(self, handler: Callable[[ValidationEvent], Any]) -> Subscription: ...
|
|
313
|
+
def on_valid(self, handler: Callable[[ValidationEvent], Any] | None = None) -> Stream | Subscription:
|
|
314
|
+
"""Register a callback fired when validation passes.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
handler: Called with a :class:`~bootstack.events.ValidationEvent`. Omit to
|
|
318
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
322
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
323
|
+
"""
|
|
324
|
+
return self.on("valid", handler)
|
|
325
|
+
|
|
326
|
+
@overload
|
|
327
|
+
def on_invalid(self) -> Stream: ...
|
|
328
|
+
@overload
|
|
329
|
+
def on_invalid(self, handler: Callable[[ValidationEvent], Any]) -> Subscription: ...
|
|
330
|
+
def on_invalid(self, handler: Callable[[ValidationEvent], Any] | None = None) -> Stream | Subscription:
|
|
331
|
+
"""Register a callback fired when validation fails.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
handler: Called with a :class:`~bootstack.events.ValidationEvent`. Omit to
|
|
335
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
339
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
340
|
+
"""
|
|
341
|
+
return self.on("invalid", handler)
|
|
342
|
+
|
|
343
|
+
@overload
|
|
344
|
+
def on_validate(self) -> Stream: ...
|
|
345
|
+
@overload
|
|
346
|
+
def on_validate(self, handler: Callable[[ValidationEvent], Any]) -> Subscription: ...
|
|
347
|
+
def on_validate(self, handler: Callable[[ValidationEvent], Any] | None = None) -> Stream | Subscription:
|
|
348
|
+
"""Register a callback fired when a validation check runs.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
handler: Called with a :class:`~bootstack.events.ValidationEvent`. Omit to
|
|
352
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
356
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
357
|
+
"""
|
|
358
|
+
return self.on("validate", handler)
|
|
359
|
+
|
|
360
|
+
@overload
|
|
361
|
+
def on_focus(self) -> Stream: ...
|
|
362
|
+
@overload
|
|
363
|
+
def on_focus(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
364
|
+
def on_focus(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
365
|
+
"""Register a callback fired when the field gains keyboard focus.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
handler: Called with an :class:`~bootstack.events.Event`. Omit to
|
|
369
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
373
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
374
|
+
"""
|
|
375
|
+
return self.on("focus", handler)
|
|
376
|
+
|
|
377
|
+
@overload
|
|
378
|
+
def on_blur(self) -> Stream: ...
|
|
379
|
+
@overload
|
|
380
|
+
def on_blur(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
381
|
+
def on_blur(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
382
|
+
"""Register a callback fired when the field loses keyboard focus.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
handler: Called with an :class:`~bootstack.events.Event`. Omit to
|
|
386
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
390
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
391
|
+
"""
|
|
392
|
+
return self.on("blur", handler)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
register_widget_events(DateField, _DATEFIELD_EVENTS)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from bootstack.widgets._impl.primitives.separator import Separator as _InternalSeparator
|
|
6
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
7
|
+
from bootstack.widgets._core.events import register_widget_events
|
|
8
|
+
from bootstack.widgets.types import AccentToken, Orient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Divider(PublicWidgetBase):
|
|
12
|
+
"""A horizontal or vertical dividing line.
|
|
13
|
+
|
|
14
|
+
Renders a thin themed line that can be used to visually divide sections
|
|
15
|
+
of a layout. The line color inherits from the active surface by default
|
|
16
|
+
and can be overridden with an accent token. (For invisible flexible space
|
|
17
|
+
between items, use :class:`Spacer <bootstack.Spacer>` instead.)
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
orient: Direction of the line. Defaults to `'horizontal'`.
|
|
21
|
+
accent: Color intent token applied to the line. When omitted, the
|
|
22
|
+
line color is derived from the active surface.
|
|
23
|
+
thickness: Line thickness in pixels. Defaults to the theme value
|
|
24
|
+
(typically 1 px).
|
|
25
|
+
length: Fixed length in pixels. When omitted the line stretches to
|
|
26
|
+
fill the available space along its axis.
|
|
27
|
+
parent: Override the context-stack parent widget.
|
|
28
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
29
|
+
`grow`, `horizontal`, `vertical`, `margin`, `row`, `column`.
|
|
30
|
+
See :doc:`/tasks/layout`.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
orient: Orient | str = "horizontal",
|
|
36
|
+
*,
|
|
37
|
+
accent: AccentToken | str | None = None,
|
|
38
|
+
thickness: int | None = None,
|
|
39
|
+
length: int | None = None,
|
|
40
|
+
parent: Any = None,
|
|
41
|
+
**kwargs: Any,
|
|
42
|
+
) -> None:
|
|
43
|
+
self._parent = self._resolve_parent(parent)
|
|
44
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
45
|
+
|
|
46
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
47
|
+
|
|
48
|
+
internal_kwargs: dict[str, Any] = {"orient": orient}
|
|
49
|
+
if accent is not None:
|
|
50
|
+
internal_kwargs["accent"] = accent
|
|
51
|
+
if thickness is not None:
|
|
52
|
+
internal_kwargs["thickness"] = thickness
|
|
53
|
+
if length is not None:
|
|
54
|
+
internal_kwargs["length"] = length
|
|
55
|
+
|
|
56
|
+
self._internal = _InternalSeparator(tk_master, **internal_kwargs)
|
|
57
|
+
self._attach_to_parent(layout_kw)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
register_widget_events(Divider, {})
|