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,408 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import overload, Any, Callable, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from bootstack.widgets._impl.composites.slider.slider import Slider as _InternalSlider
|
|
6
|
+
from bootstack.widgets._impl.composites.slider.rangeslider import RangeSlider as _InternalRangeSlider
|
|
7
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
8
|
+
from bootstack.widgets._core.events import register_widget_events
|
|
9
|
+
from bootstack.events import RangeSliderCommitEvent, RangeSliderEvent, SliderCommitEvent, SliderEvent, Subscription
|
|
10
|
+
from bootstack.streams import Stream
|
|
11
|
+
from bootstack.widgets.types import AccentToken, Event, Orient
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from bootstack.signals import Signal
|
|
15
|
+
|
|
16
|
+
_SLIDER_EVENTS: dict[str, str] = {
|
|
17
|
+
"change": "<<Change>>",
|
|
18
|
+
"commit": "<<Commit>>",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Slider(PublicWidgetBase):
|
|
23
|
+
"""A single-handle slider for selecting a numeric value within a range.
|
|
24
|
+
|
|
25
|
+
The initial value is the first positional argument. All options are
|
|
26
|
+
keyword-only.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
value: Initial value. Defaults to `0`.
|
|
30
|
+
min_value: Minimum of the range. Defaults to `0`.
|
|
31
|
+
max_value: Maximum of the range. Defaults to `100`.
|
|
32
|
+
signal: Reactive `Signal[float]` linked to the slider value. The
|
|
33
|
+
slider and signal stay in sync automatically.
|
|
34
|
+
orient: Track orientation. Default `'horizontal'`.
|
|
35
|
+
show_value: If `True`, shows a floating badge with the current
|
|
36
|
+
value above the handle. Defaults to `False`.
|
|
37
|
+
show_minmax: If `True`, shows min/max labels at the track ends.
|
|
38
|
+
Defaults to `False`.
|
|
39
|
+
tick_step: Spacing between major tick marks. `None` disables
|
|
40
|
+
ticks entirely.
|
|
41
|
+
minor_ticks: Number of minor tick marks between each major tick.
|
|
42
|
+
Defaults to `0`.
|
|
43
|
+
tick_labels: If `True`, shows numeric labels at major tick
|
|
44
|
+
positions. Defaults to `True`.
|
|
45
|
+
tick_format: Python format string applied to tick and badge labels.
|
|
46
|
+
Defaults to `'{:.0f}'`.
|
|
47
|
+
step: Snap increment. When set, click/drag values snap to multiples of
|
|
48
|
+
`step` (measured from `min_value`) and the arrow keys move by `step`.
|
|
49
|
+
`None` (the default) leaves the value continuous. Independent of
|
|
50
|
+
`tick_step`, which only places tick marks.
|
|
51
|
+
accent: Accent token controlling the fill, handle, and focus ring
|
|
52
|
+
color. Defaults to `'primary'`.
|
|
53
|
+
disabled: If `True`, slider is non-interactive. Defaults to
|
|
54
|
+
`False`.
|
|
55
|
+
parent: Explicit parent widget. If omitted, the current
|
|
56
|
+
context-stack container is used.
|
|
57
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
58
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
59
|
+
See :doc:`/tasks/layout`.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
value: float = 0,
|
|
65
|
+
*,
|
|
66
|
+
min_value: float = 0,
|
|
67
|
+
max_value: float = 100,
|
|
68
|
+
signal: "Signal[float] | None" = None,
|
|
69
|
+
orient: Orient = "horizontal",
|
|
70
|
+
show_value: bool = False,
|
|
71
|
+
show_minmax: bool = False,
|
|
72
|
+
tick_step: float | None = None,
|
|
73
|
+
minor_ticks: int = 0,
|
|
74
|
+
tick_labels: bool = True,
|
|
75
|
+
tick_format: str = "{:.0f}",
|
|
76
|
+
step: float | None = None,
|
|
77
|
+
accent: AccentToken | str | None = None,
|
|
78
|
+
disabled: bool = False,
|
|
79
|
+
parent: Any = None,
|
|
80
|
+
**kwargs: Any,
|
|
81
|
+
) -> None:
|
|
82
|
+
self._parent = self._resolve_parent(parent)
|
|
83
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
84
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
85
|
+
|
|
86
|
+
internal_kwargs: dict[str, Any] = {
|
|
87
|
+
"value": value,
|
|
88
|
+
"minvalue": min_value,
|
|
89
|
+
"maxvalue": max_value,
|
|
90
|
+
"orient": orient,
|
|
91
|
+
"show_value": show_value,
|
|
92
|
+
"show_minmax": show_minmax,
|
|
93
|
+
"tick_interval": tick_step,
|
|
94
|
+
"minor_ticks": minor_ticks,
|
|
95
|
+
"tick_labels": tick_labels,
|
|
96
|
+
"tick_format": tick_format,
|
|
97
|
+
"step": step,
|
|
98
|
+
}
|
|
99
|
+
if signal is not None:
|
|
100
|
+
internal_kwargs["signal"] = signal
|
|
101
|
+
if accent is not None:
|
|
102
|
+
internal_kwargs["accent"] = accent
|
|
103
|
+
if disabled:
|
|
104
|
+
internal_kwargs["state"] = "disabled"
|
|
105
|
+
|
|
106
|
+
self._internal = _InternalSlider(tk_master, **internal_kwargs)
|
|
107
|
+
self._attach_to_parent(layout_kw)
|
|
108
|
+
|
|
109
|
+
# ----- Properties -----
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def value(self) -> float:
|
|
113
|
+
"""The current slider value."""
|
|
114
|
+
return self._internal.value
|
|
115
|
+
|
|
116
|
+
@value.setter
|
|
117
|
+
def value(self, v: float) -> None:
|
|
118
|
+
# Route through set() so the value is clamped to [min, max] — a bare
|
|
119
|
+
# signal write would store an out-of-range value the getter reads back.
|
|
120
|
+
self._internal.set(float(v))
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def signal(self) -> "Signal[float]":
|
|
124
|
+
"""The reactive `Signal[float]` linked to this slider."""
|
|
125
|
+
return self._internal.signal
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def min_value(self) -> float:
|
|
129
|
+
"""The minimum value of the slider range."""
|
|
130
|
+
return self._internal._minvalue
|
|
131
|
+
|
|
132
|
+
@min_value.setter
|
|
133
|
+
def min_value(self, v: float) -> None:
|
|
134
|
+
self._internal.configure(minvalue=float(v))
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def max_value(self) -> float:
|
|
138
|
+
"""The maximum value of the slider range."""
|
|
139
|
+
return self._internal._maxvalue
|
|
140
|
+
|
|
141
|
+
@max_value.setter
|
|
142
|
+
def max_value(self, v: float) -> None:
|
|
143
|
+
self._internal.configure(maxvalue=float(v))
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def step(self) -> float | None:
|
|
147
|
+
"""Snap increment, or `None` when the value is continuous."""
|
|
148
|
+
return self._internal._step_size
|
|
149
|
+
|
|
150
|
+
@step.setter
|
|
151
|
+
def step(self, v: float | None) -> None:
|
|
152
|
+
self._internal.configure(step=v)
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def disabled(self) -> bool:
|
|
156
|
+
"""Whether the slider is non-interactive."""
|
|
157
|
+
return self._internal._state == "disabled"
|
|
158
|
+
|
|
159
|
+
@disabled.setter
|
|
160
|
+
def disabled(self, v: bool) -> None:
|
|
161
|
+
self._internal.configure(state="disabled" if v else "normal")
|
|
162
|
+
|
|
163
|
+
# ----- Event shorthands -----
|
|
164
|
+
|
|
165
|
+
@overload
|
|
166
|
+
def on_change(self) -> Stream: ...
|
|
167
|
+
@overload
|
|
168
|
+
def on_change(self, handler: Callable[[SliderEvent], Any]) -> Subscription: ...
|
|
169
|
+
def on_change(self, handler: Callable[[SliderEvent], Any] | None = None) -> Stream | Subscription:
|
|
170
|
+
"""Register a callback fired continuously as the handle moves.
|
|
171
|
+
|
|
172
|
+
The current value is available via `slider.value` inside the handler.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
handler: Called with a :class:`~bootstack.events.SliderEvent`. Omit to
|
|
176
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
180
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
181
|
+
"""
|
|
182
|
+
return self.on("change", handler)
|
|
183
|
+
|
|
184
|
+
@overload
|
|
185
|
+
def on_commit(self) -> Stream: ...
|
|
186
|
+
@overload
|
|
187
|
+
def on_commit(self, handler: Callable[[SliderCommitEvent], Any]) -> Subscription: ...
|
|
188
|
+
def on_commit(self, handler: Callable[[SliderCommitEvent], Any] | None = None) -> Stream | Subscription:
|
|
189
|
+
"""Register a callback fired when the handle is released.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
handler: Called with a :class:`~bootstack.events.SliderCommitEvent`. Omit to
|
|
193
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
197
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
198
|
+
"""
|
|
199
|
+
return self.on("commit", handler)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
register_widget_events(Slider, _SLIDER_EVENTS)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class RangeSlider(PublicWidgetBase):
|
|
206
|
+
"""A two-handle slider for selecting a low/high value range.
|
|
207
|
+
|
|
208
|
+
The initial handle positions are the first two positional arguments.
|
|
209
|
+
All options are keyword-only.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
low_value: Initial low-handle value. Defaults to `0`.
|
|
213
|
+
high_value: Initial high-handle value. Defaults to `100`.
|
|
214
|
+
min_value: Minimum of the range. Defaults to `0`.
|
|
215
|
+
max_value: Maximum of the range. Defaults to `100`.
|
|
216
|
+
low_signal: Reactive `Signal[float]` linked to the low handle.
|
|
217
|
+
high_signal: Reactive `Signal[float]` linked to the high handle.
|
|
218
|
+
orient: Track orientation. Default `'horizontal'`.
|
|
219
|
+
show_value: If `True`, shows floating badges on both handles.
|
|
220
|
+
Defaults to `False`.
|
|
221
|
+
tick_step: Spacing between major tick marks. `None` disables
|
|
222
|
+
ticks entirely.
|
|
223
|
+
minor_ticks: Number of minor tick marks between each major tick.
|
|
224
|
+
Defaults to `0`.
|
|
225
|
+
tick_labels: If `True`, shows numeric labels at major tick
|
|
226
|
+
positions. Defaults to `True`.
|
|
227
|
+
tick_format: Python format string applied to tick and badge labels.
|
|
228
|
+
Defaults to `'{:.0f}'`.
|
|
229
|
+
step: Snap increment. When set, handle values snap to multiples of
|
|
230
|
+
`step` (measured from `min_value`) and the arrow keys move by `step`.
|
|
231
|
+
`None` (the default) leaves the values continuous. Independent of
|
|
232
|
+
`tick_step`, which only places tick marks.
|
|
233
|
+
accent: Accent token controlling the fill, handles, and focus ring
|
|
234
|
+
color. Defaults to `'primary'`.
|
|
235
|
+
disabled: If `True`, slider is non-interactive. Defaults to
|
|
236
|
+
`False`.
|
|
237
|
+
parent: Explicit parent widget. If omitted, the current
|
|
238
|
+
context-stack container is used.
|
|
239
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
240
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
241
|
+
See :doc:`/tasks/layout`.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def __init__(
|
|
245
|
+
self,
|
|
246
|
+
low_value: float = 0,
|
|
247
|
+
high_value: float = 100,
|
|
248
|
+
*,
|
|
249
|
+
min_value: float = 0,
|
|
250
|
+
max_value: float = 100,
|
|
251
|
+
low_signal: "Signal[float] | None" = None,
|
|
252
|
+
high_signal: "Signal[float] | None" = None,
|
|
253
|
+
orient: Orient = "horizontal",
|
|
254
|
+
show_value: bool = False,
|
|
255
|
+
tick_step: float | None = None,
|
|
256
|
+
minor_ticks: int = 0,
|
|
257
|
+
tick_labels: bool = True,
|
|
258
|
+
tick_format: str = "{:.0f}",
|
|
259
|
+
step: float | None = None,
|
|
260
|
+
accent: AccentToken | str | None = None,
|
|
261
|
+
disabled: bool = False,
|
|
262
|
+
parent: Any = None,
|
|
263
|
+
**kwargs: Any,
|
|
264
|
+
) -> None:
|
|
265
|
+
self._parent = self._resolve_parent(parent)
|
|
266
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
267
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
268
|
+
|
|
269
|
+
internal_kwargs: dict[str, Any] = {
|
|
270
|
+
"lovalue": low_value,
|
|
271
|
+
"hivalue": high_value,
|
|
272
|
+
"minvalue": min_value,
|
|
273
|
+
"maxvalue": max_value,
|
|
274
|
+
"orient": orient,
|
|
275
|
+
"show_value": show_value,
|
|
276
|
+
"tick_interval": tick_step,
|
|
277
|
+
"minor_ticks": minor_ticks,
|
|
278
|
+
"tick_labels": tick_labels,
|
|
279
|
+
"tick_format": tick_format,
|
|
280
|
+
"step": step,
|
|
281
|
+
}
|
|
282
|
+
if low_signal is not None:
|
|
283
|
+
internal_kwargs["lo_signal"] = low_signal
|
|
284
|
+
if high_signal is not None:
|
|
285
|
+
internal_kwargs["hi_signal"] = high_signal
|
|
286
|
+
if accent is not None:
|
|
287
|
+
internal_kwargs["accent"] = accent
|
|
288
|
+
if disabled:
|
|
289
|
+
internal_kwargs["state"] = "disabled"
|
|
290
|
+
|
|
291
|
+
self._internal = _InternalRangeSlider(tk_master, **internal_kwargs)
|
|
292
|
+
self._attach_to_parent(layout_kw)
|
|
293
|
+
|
|
294
|
+
# ----- Properties -----
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
def low_value(self) -> float:
|
|
298
|
+
"""The current low-handle value."""
|
|
299
|
+
return self._internal.lovalue
|
|
300
|
+
|
|
301
|
+
@low_value.setter
|
|
302
|
+
def low_value(self, v: float) -> None:
|
|
303
|
+
# Route through set_lo so the value is clamped to [min, high] — a bare
|
|
304
|
+
# signal write would let the low handle cross above the high handle.
|
|
305
|
+
self._internal.set_lo(float(v))
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
def high_value(self) -> float:
|
|
309
|
+
"""The current high-handle value."""
|
|
310
|
+
return self._internal.hivalue
|
|
311
|
+
|
|
312
|
+
@high_value.setter
|
|
313
|
+
def high_value(self, v: float) -> None:
|
|
314
|
+
# Route through set_hi so the value is clamped to [low, max].
|
|
315
|
+
self._internal.set_hi(float(v))
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def value(self) -> tuple[float, float]:
|
|
319
|
+
"""Current `(low, high)` values as a tuple."""
|
|
320
|
+
return (self._internal.lovalue, self._internal.hivalue)
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
def low_signal(self) -> "Signal[float]":
|
|
324
|
+
"""The reactive `Signal[float]` linked to the low handle."""
|
|
325
|
+
return self._internal._lo_signal
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def high_signal(self) -> "Signal[float]":
|
|
329
|
+
"""The reactive `Signal[float]` linked to the high handle."""
|
|
330
|
+
return self._internal._hi_signal
|
|
331
|
+
|
|
332
|
+
@property
|
|
333
|
+
def min_value(self) -> float:
|
|
334
|
+
"""The minimum value of the slider range."""
|
|
335
|
+
return self._internal._minvalue
|
|
336
|
+
|
|
337
|
+
@min_value.setter
|
|
338
|
+
def min_value(self, v: float) -> None:
|
|
339
|
+
self._internal.configure(minvalue=float(v))
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def max_value(self) -> float:
|
|
343
|
+
"""The maximum value of the slider range."""
|
|
344
|
+
return self._internal._maxvalue
|
|
345
|
+
|
|
346
|
+
@max_value.setter
|
|
347
|
+
def max_value(self, v: float) -> None:
|
|
348
|
+
self._internal.configure(maxvalue=float(v))
|
|
349
|
+
|
|
350
|
+
@property
|
|
351
|
+
def step(self) -> float | None:
|
|
352
|
+
"""Snap increment, or `None` when the values are continuous."""
|
|
353
|
+
return self._internal._step_size
|
|
354
|
+
|
|
355
|
+
@step.setter
|
|
356
|
+
def step(self, v: float | None) -> None:
|
|
357
|
+
self._internal.configure(step=v)
|
|
358
|
+
|
|
359
|
+
@property
|
|
360
|
+
def disabled(self) -> bool:
|
|
361
|
+
"""Whether the slider is non-interactive."""
|
|
362
|
+
return self._internal._state == "disabled"
|
|
363
|
+
|
|
364
|
+
@disabled.setter
|
|
365
|
+
def disabled(self, v: bool) -> None:
|
|
366
|
+
self._internal.configure(state="disabled" if v else "normal")
|
|
367
|
+
|
|
368
|
+
# ----- Event shorthands -----
|
|
369
|
+
|
|
370
|
+
@overload
|
|
371
|
+
def on_change(self) -> Stream: ...
|
|
372
|
+
@overload
|
|
373
|
+
def on_change(self, handler: Callable[[RangeSliderEvent], Any]) -> Subscription: ...
|
|
374
|
+
def on_change(self, handler: Callable[[RangeSliderEvent], Any] | None = None) -> Stream | Subscription:
|
|
375
|
+
"""Register a callback fired continuously as either handle moves.
|
|
376
|
+
|
|
377
|
+
The current values are available via `slider.low_value` and
|
|
378
|
+
`slider.high_value` inside the handler.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
handler: Called with a :class:`~bootstack.events.RangeSliderEvent`. Omit to
|
|
382
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
383
|
+
|
|
384
|
+
Returns:
|
|
385
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
386
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
387
|
+
"""
|
|
388
|
+
return self.on("change", handler)
|
|
389
|
+
|
|
390
|
+
@overload
|
|
391
|
+
def on_commit(self) -> Stream: ...
|
|
392
|
+
@overload
|
|
393
|
+
def on_commit(self, handler: Callable[[RangeSliderCommitEvent], Any]) -> Subscription: ...
|
|
394
|
+
def on_commit(self, handler: Callable[[RangeSliderCommitEvent], Any] | None = None) -> Stream | Subscription:
|
|
395
|
+
"""Register a callback fired when a handle is released.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
handler: Called with a :class:`~bootstack.events.RangeSliderCommitEvent`. Omit to
|
|
399
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
403
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
404
|
+
"""
|
|
405
|
+
return self.on("commit", handler)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
register_widget_events(RangeSlider, _SLIDER_EVENTS)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import overload, Any, Callable, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from bootstack.widgets._impl.primitives.spinbox import Spinbox as _InternalSpinbox
|
|
6
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
7
|
+
from bootstack.widgets._core.events import register_widget_events
|
|
8
|
+
from bootstack.events import ChangeEvent, Subscription
|
|
9
|
+
from bootstack.streams import Stream
|
|
10
|
+
from bootstack.widgets.types import Event, AccentToken, WidgetDensity
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from bootstack.signals import Signal
|
|
14
|
+
|
|
15
|
+
_SPINBOX_EVENTS: dict[str, str] = {
|
|
16
|
+
"change": "<KeyRelease>",
|
|
17
|
+
"submit": "<Return>",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Spinbox(PublicWidgetBase):
|
|
22
|
+
"""A spin-box that cycles through a fixed list or numeric range.
|
|
23
|
+
|
|
24
|
+
Pass either `options=` for a discrete list, or `min_value=`/`max_value=`
|
|
25
|
+
for a numeric range. `options=` takes precedence if both are provided.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
value: Initial display value.
|
|
29
|
+
options: Fixed list of values to cycle through.
|
|
30
|
+
min_value: Minimum numeric value (used when `options=` is not set).
|
|
31
|
+
max_value: Maximum numeric value.
|
|
32
|
+
step: Increment between values. Default `1`.
|
|
33
|
+
wrap: If True, wraps from max back to min and vice versa.
|
|
34
|
+
value_format: Display format string (e.g. `'%.2f'`).
|
|
35
|
+
textsignal: Reactive `Signal` linked to the displayed text.
|
|
36
|
+
width: Width in character cells.
|
|
37
|
+
disabled: If True, widget is non-interactive.
|
|
38
|
+
density: Padding density.
|
|
39
|
+
accent: Accent token applied to the focus ring.
|
|
40
|
+
parent: Override the context-stack parent.
|
|
41
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
42
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
43
|
+
See :doc:`/tasks/layout`.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
value: Any = "",
|
|
49
|
+
*,
|
|
50
|
+
options: list[Any] | None = None,
|
|
51
|
+
min_value: float | None = None,
|
|
52
|
+
max_value: float | None = None,
|
|
53
|
+
step: float = 1,
|
|
54
|
+
wrap: bool = False,
|
|
55
|
+
value_format: str | None = None,
|
|
56
|
+
textsignal: "Signal | None" = None,
|
|
57
|
+
width: int | None = None,
|
|
58
|
+
disabled: bool = False,
|
|
59
|
+
density: WidgetDensity | None = None,
|
|
60
|
+
accent: AccentToken | str | None = None,
|
|
61
|
+
parent: Any = None,
|
|
62
|
+
**kwargs: Any,
|
|
63
|
+
) -> None:
|
|
64
|
+
self._parent = self._resolve_parent(parent)
|
|
65
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
66
|
+
|
|
67
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
68
|
+
|
|
69
|
+
internal_kwargs: dict[str, Any] = {"wrap": wrap}
|
|
70
|
+
if options is not None:
|
|
71
|
+
internal_kwargs["values"] = [str(o) for o in options]
|
|
72
|
+
elif min_value is not None or max_value is not None:
|
|
73
|
+
if min_value is not None:
|
|
74
|
+
internal_kwargs["from_"] = min_value
|
|
75
|
+
if max_value is not None:
|
|
76
|
+
internal_kwargs["to"] = max_value
|
|
77
|
+
internal_kwargs["increment"] = step
|
|
78
|
+
if value_format is not None:
|
|
79
|
+
internal_kwargs["format"] = value_format
|
|
80
|
+
if textsignal is not None:
|
|
81
|
+
internal_kwargs["textsignal"] = textsignal
|
|
82
|
+
if width is not None:
|
|
83
|
+
internal_kwargs["width"] = width
|
|
84
|
+
if disabled:
|
|
85
|
+
internal_kwargs["state"] = "disabled"
|
|
86
|
+
if density is not None:
|
|
87
|
+
internal_kwargs["density"] = density
|
|
88
|
+
if accent is not None:
|
|
89
|
+
internal_kwargs["accent"] = accent
|
|
90
|
+
# Clean up any None values accidentally set. (**kwargs is layout-only —
|
|
91
|
+
# already split out above — so it is NOT forwarded to the internal widget.)
|
|
92
|
+
internal_kwargs = {k: v for k, v in internal_kwargs.items() if v is not None}
|
|
93
|
+
|
|
94
|
+
self._internal = _InternalSpinbox(tk_master, **internal_kwargs)
|
|
95
|
+
|
|
96
|
+
# Seed the display value after construction in all cases.
|
|
97
|
+
if value != "":
|
|
98
|
+
self._internal.set(str(value))
|
|
99
|
+
|
|
100
|
+
self._attach_to_parent(layout_kw)
|
|
101
|
+
|
|
102
|
+
# ----- Properties -----
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def value(self) -> str:
|
|
106
|
+
return self._internal.get()
|
|
107
|
+
|
|
108
|
+
@value.setter
|
|
109
|
+
def value(self, v: Any) -> None:
|
|
110
|
+
self._internal.set(str(v))
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def disabled(self) -> bool:
|
|
114
|
+
return str(self._internal.cget("state")) == "disabled"
|
|
115
|
+
|
|
116
|
+
@disabled.setter
|
|
117
|
+
def disabled(self, v: bool) -> None:
|
|
118
|
+
self._internal.configure(state="disabled" if v else "normal")
|
|
119
|
+
|
|
120
|
+
# ----- Event shorthands -----
|
|
121
|
+
|
|
122
|
+
@overload
|
|
123
|
+
def on_change(self) -> Stream: ...
|
|
124
|
+
@overload
|
|
125
|
+
def on_change(self, handler: Callable[[ChangeEvent], Any]) -> Subscription: ...
|
|
126
|
+
def on_change(self, handler: Callable[[ChangeEvent], Any] | None = None) -> Stream | Subscription:
|
|
127
|
+
"""Register a callback fired on each keystroke or spin-button click.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Subscription — call `.cancel()` to unsubscribe.
|
|
131
|
+
"""
|
|
132
|
+
return self.on("change", handler)
|
|
133
|
+
|
|
134
|
+
@overload
|
|
135
|
+
def on_submit(self) -> Stream: ...
|
|
136
|
+
@overload
|
|
137
|
+
def on_submit(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
138
|
+
def on_submit(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
139
|
+
"""Register a callback fired on Enter key.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Subscription — call `.cancel()` to unsubscribe.
|
|
143
|
+
"""
|
|
144
|
+
return self.on("submit", handler)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
register_widget_events(Spinbox, _SPINBOX_EVENTS)
|