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,140 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Callable, Literal, overload, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from bootstack.events import Event, Subscription
|
|
7
|
+
from bootstack.streams import Stream
|
|
8
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
9
|
+
from bootstack.widgets._core.events import register_widget_events
|
|
10
|
+
from bootstack.widgets._impl.composites.avatar import Avatar as _InternalAvatar
|
|
11
|
+
from bootstack.widgets.types import AccentToken
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from bootstack.images import Image
|
|
15
|
+
|
|
16
|
+
AvatarShape = Literal["circle", "rounded", "square"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Avatar(PublicWidgetBase):
|
|
20
|
+
"""A small identity badge — a picture or initials on a filled tile.
|
|
21
|
+
|
|
22
|
+
Shows `image` cover-fit and clipped to the avatar shape; when no image is
|
|
23
|
+
given (or one fails to load), it falls back to initials on a `background`
|
|
24
|
+
tile. Initials come from `initials` if given, otherwise from `name` (the
|
|
25
|
+
first letters of the first and last words).
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
image: The picture to show — an `Image` handle, a file path, or a PIL
|
|
29
|
+
image. Omit to show initials instead.
|
|
30
|
+
name: A name to derive initials from, e.g. `'Ada Lovelace'` → `'AL'`.
|
|
31
|
+
Used when `image` is absent and `initials` is not given.
|
|
32
|
+
initials: Explicit initials (1–2 characters), overriding `name`.
|
|
33
|
+
size: The avatar's edge length in pixels (it is square). Default `40`.
|
|
34
|
+
shape: `'circle'` (default), `'rounded'`, or `'square'`.
|
|
35
|
+
background: Tile color behind initials (and the fallback when an image
|
|
36
|
+
can't load) — a theme color token or a hex string. Default
|
|
37
|
+
`'primary'`.
|
|
38
|
+
foreground: Initials text color — a theme color token or hex string.
|
|
39
|
+
Default `'white'`.
|
|
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
|
+
image: "Image | str | Path | None" = None,
|
|
49
|
+
*,
|
|
50
|
+
name: str | None = None,
|
|
51
|
+
initials: str | None = None,
|
|
52
|
+
size: int = 40,
|
|
53
|
+
shape: AvatarShape = "circle",
|
|
54
|
+
background: AccentToken | str = "primary",
|
|
55
|
+
foreground: str = "white",
|
|
56
|
+
parent: Any = None,
|
|
57
|
+
**kwargs: Any,
|
|
58
|
+
) -> None:
|
|
59
|
+
self._parent = self._resolve_parent(parent)
|
|
60
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
61
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
62
|
+
|
|
63
|
+
self._source = self._coerce_image(image)
|
|
64
|
+
self._internal = _InternalAvatar(
|
|
65
|
+
tk_master, source=self._source, name=name, initials=initials,
|
|
66
|
+
size=size, shape=shape, background=background, foreground=foreground,
|
|
67
|
+
)
|
|
68
|
+
self._attach_to_parent(layout_kw)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def _coerce_image(image: "Image | str | Path | None") -> Any:
|
|
72
|
+
if image is None:
|
|
73
|
+
return None
|
|
74
|
+
from bootstack.images import Image as _ImageHandle
|
|
75
|
+
|
|
76
|
+
if isinstance(image, _ImageHandle):
|
|
77
|
+
return image
|
|
78
|
+
if isinstance(image, (str, Path)):
|
|
79
|
+
return _ImageHandle.open(image)
|
|
80
|
+
try:
|
|
81
|
+
from PIL.Image import Image as _PILImage
|
|
82
|
+
|
|
83
|
+
if isinstance(image, _PILImage):
|
|
84
|
+
return _ImageHandle.from_pil(image)
|
|
85
|
+
except Exception:
|
|
86
|
+
pass
|
|
87
|
+
raise TypeError(
|
|
88
|
+
"Avatar image must be an Image handle, a file path, or a PIL image; "
|
|
89
|
+
f"got {type(image).__name__}"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# ----- Properties -----
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def image(self) -> "Image | None":
|
|
96
|
+
"""The displayed image handle, or `None` when showing initials.
|
|
97
|
+
|
|
98
|
+
Assign an `Image`, a file path, or `None` to change what is shown.
|
|
99
|
+
"""
|
|
100
|
+
return self._source
|
|
101
|
+
|
|
102
|
+
@image.setter
|
|
103
|
+
def image(self, value: "Image | str | Path | None") -> None:
|
|
104
|
+
self._source = self._coerce_image(value)
|
|
105
|
+
self._internal.set_source(self._source)
|
|
106
|
+
|
|
107
|
+
def set_initials(self, *, name: str | None = None, initials: str | None = None) -> None:
|
|
108
|
+
"""Update the initials shown (when no image is set).
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
name: A name to derive initials from.
|
|
112
|
+
initials: Explicit initials, overriding `name`.
|
|
113
|
+
"""
|
|
114
|
+
self._internal.set_text(name=name, initials=initials)
|
|
115
|
+
|
|
116
|
+
# ----- Events -----
|
|
117
|
+
|
|
118
|
+
@overload
|
|
119
|
+
def on_click(self) -> Stream: ...
|
|
120
|
+
@overload
|
|
121
|
+
def on_click(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
122
|
+
def on_click(
|
|
123
|
+
self, handler: Callable[[Event], Any] | None = None
|
|
124
|
+
) -> Stream | Subscription:
|
|
125
|
+
"""Register a callback for clicks on the avatar.
|
|
126
|
+
|
|
127
|
+
The handler receives a curated :class:`~bootstack.events.Event`.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
handler: Called with the click `Event`. Omit to get a composable
|
|
131
|
+
:class:`~bootstack.streams.Stream`.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
A cancellable :class:`~bootstack.events.Subscription` when a handler
|
|
135
|
+
is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
136
|
+
"""
|
|
137
|
+
return self.on("click", handler)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
register_widget_events(Avatar, {"click": "<<AvatarClick>>"})
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import overload, Any, Callable, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from bootstack.widgets._impl.primitives.checkbutton import CheckButton as _InternalCheckButton
|
|
6
|
+
from bootstack.widgets._impl.primitives.switch import Switch as _InternalSwitch
|
|
7
|
+
from bootstack.widgets._impl.primitives.checktoggle import CheckToggle as _InternalCheckToggle
|
|
8
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
9
|
+
from bootstack.widgets._core.events import register_widget_events
|
|
10
|
+
from bootstack.events import Subscription, ChangeEvent
|
|
11
|
+
from bootstack.streams import Stream
|
|
12
|
+
from bootstack.widgets.types import AccentToken, Event, WidgetDensity, ButtonVariant, LocalizeMode
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from bootstack.signals import Signal
|
|
16
|
+
|
|
17
|
+
_BOOLEAN_EVENTS: dict[str, str] = {
|
|
18
|
+
"change": "<<Change>>",
|
|
19
|
+
"check": "<<ToggleOn>>",
|
|
20
|
+
"uncheck": "<<ToggleOff>>",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class _BooleanControlBase(PublicWidgetBase):
|
|
25
|
+
"""Shared base for Checkbox, Switch, and ToggleButton."""
|
|
26
|
+
|
|
27
|
+
_internal_class: type # set by subclass
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
label: str = "",
|
|
32
|
+
*,
|
|
33
|
+
signal: "Signal | None" = None,
|
|
34
|
+
value: Any = None,
|
|
35
|
+
checked_value: Any = True,
|
|
36
|
+
unchecked_value: Any = False,
|
|
37
|
+
on_change: Callable[[], Any] | None = None,
|
|
38
|
+
disabled: bool = False,
|
|
39
|
+
accent: AccentToken | str | None = None,
|
|
40
|
+
localize: LocalizeMode | None = None,
|
|
41
|
+
_tristate: bool = False,
|
|
42
|
+
_internal_options: dict[str, Any] | None = None,
|
|
43
|
+
parent: Any = None,
|
|
44
|
+
**kwargs: Any,
|
|
45
|
+
) -> None:
|
|
46
|
+
self._parent = self._resolve_parent(parent)
|
|
47
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
48
|
+
if kwargs:
|
|
49
|
+
raise TypeError(
|
|
50
|
+
f"{type(self).__name__}() got unexpected keyword argument(s): "
|
|
51
|
+
f"{', '.join(sorted(kwargs))}"
|
|
52
|
+
)
|
|
53
|
+
self._checked_value = checked_value
|
|
54
|
+
self._unchecked_value = unchecked_value
|
|
55
|
+
self._tristate = _tristate
|
|
56
|
+
|
|
57
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
58
|
+
|
|
59
|
+
# Ctor on_change callback — stored so the command wrapper can call it.
|
|
60
|
+
_ctor_callback = on_change
|
|
61
|
+
|
|
62
|
+
internal_kwargs: dict[str, Any] = {}
|
|
63
|
+
if label:
|
|
64
|
+
internal_kwargs["text"] = label
|
|
65
|
+
if signal is not None:
|
|
66
|
+
internal_kwargs["signal"] = signal
|
|
67
|
+
if checked_value is not True:
|
|
68
|
+
internal_kwargs["onvalue"] = checked_value
|
|
69
|
+
if unchecked_value is not False:
|
|
70
|
+
internal_kwargs["offvalue"] = unchecked_value
|
|
71
|
+
if disabled:
|
|
72
|
+
internal_kwargs["state"] = "disabled"
|
|
73
|
+
if accent is not None:
|
|
74
|
+
internal_kwargs["accent"] = accent
|
|
75
|
+
if localize is not None:
|
|
76
|
+
internal_kwargs["localize"] = localize
|
|
77
|
+
# Per-subclass styling options (icons, variant, density, …) — only the
|
|
78
|
+
# ones a given control actually supports are passed in by the subclass.
|
|
79
|
+
if _internal_options:
|
|
80
|
+
internal_kwargs.update(_internal_options)
|
|
81
|
+
|
|
82
|
+
self._internal = self._internal_class(tk_master, **internal_kwargs)
|
|
83
|
+
|
|
84
|
+
# Seed initial value when no signal was passed.
|
|
85
|
+
# tristate=False: default to unchecked_value so the box never shows the
|
|
86
|
+
# indeterminate dash unexpectedly. tristate=True: leave unseeded so the
|
|
87
|
+
# initial state is None (indeterminate) unless value= was explicitly given.
|
|
88
|
+
if signal is None:
|
|
89
|
+
if value is not None:
|
|
90
|
+
self._internal.set(value)
|
|
91
|
+
elif not _tristate:
|
|
92
|
+
self._internal.set(unchecked_value)
|
|
93
|
+
|
|
94
|
+
# Track the previous value so on_change can report it. The control may be
|
|
95
|
+
# tristate (checked / unchecked / indeterminate), so prev cannot be derived
|
|
96
|
+
# from the new value alone — and the command fires after Tk updates the var.
|
|
97
|
+
self._prev_value = self._internal.get()
|
|
98
|
+
|
|
99
|
+
# Wire command → virtual events so on_change() / on_check() subscriptions work.
|
|
100
|
+
def _command():
|
|
101
|
+
v = self._internal.get()
|
|
102
|
+
prev, self._prev_value = self._prev_value, v
|
|
103
|
+
self._internal.event_generate(
|
|
104
|
+
"<<Change>>", data=ChangeEvent(value=v, prev_value=prev)
|
|
105
|
+
)
|
|
106
|
+
if v == self._checked_value:
|
|
107
|
+
self._internal.event_generate("<<ToggleOn>>")
|
|
108
|
+
else:
|
|
109
|
+
self._internal.event_generate("<<ToggleOff>>")
|
|
110
|
+
if _ctor_callback is not None:
|
|
111
|
+
_ctor_callback()
|
|
112
|
+
|
|
113
|
+
self._internal.configure(command=_command)
|
|
114
|
+
self._attach_to_parent(layout_kw)
|
|
115
|
+
|
|
116
|
+
# ----- Properties -----
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def value(self) -> Any:
|
|
120
|
+
"""The current value.
|
|
121
|
+
|
|
122
|
+
Returns `checked_value` when checked, `unchecked_value` when
|
|
123
|
+
unchecked, or `None` when in the indeterminate state (only possible
|
|
124
|
+
when `tristate=True`).
|
|
125
|
+
"""
|
|
126
|
+
v = self._internal.get()
|
|
127
|
+
if v == self._checked_value:
|
|
128
|
+
return self._checked_value
|
|
129
|
+
if v == self._unchecked_value:
|
|
130
|
+
return self._unchecked_value
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
@value.setter
|
|
134
|
+
def value(self, v: Any) -> None:
|
|
135
|
+
self._internal.set(v)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def checked(self) -> bool:
|
|
139
|
+
"""Whether the control is in the checked/on state."""
|
|
140
|
+
return self._internal.get() == self._checked_value
|
|
141
|
+
|
|
142
|
+
@checked.setter
|
|
143
|
+
def checked(self, v: bool) -> None:
|
|
144
|
+
self._internal.set(self._checked_value if v else self._internal.cget("offvalue"))
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def signal(self) -> "Signal | None":
|
|
148
|
+
"""The reactive `Signal` linked to this control, or `None`."""
|
|
149
|
+
return getattr(self._internal, 'signal', None)
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def disabled(self) -> bool:
|
|
153
|
+
"""Whether the control is non-interactive."""
|
|
154
|
+
return str(self._internal.cget("state")) == "disabled"
|
|
155
|
+
|
|
156
|
+
@disabled.setter
|
|
157
|
+
def disabled(self, v: bool) -> None:
|
|
158
|
+
self._internal.configure(state="disabled" if v else "normal")
|
|
159
|
+
|
|
160
|
+
# ----- Methods -----
|
|
161
|
+
|
|
162
|
+
def toggle(self) -> None:
|
|
163
|
+
"""Toggle the control's state programmatically."""
|
|
164
|
+
self._internal.invoke()
|
|
165
|
+
|
|
166
|
+
# ----- Event shorthands -----
|
|
167
|
+
|
|
168
|
+
@overload
|
|
169
|
+
def on_change(self) -> Stream: ...
|
|
170
|
+
@overload
|
|
171
|
+
def on_change(self, handler: Callable[[ChangeEvent], Any]) -> Subscription: ...
|
|
172
|
+
def on_change(self, handler: Callable[[ChangeEvent], Any] | None = None) -> Stream | Subscription:
|
|
173
|
+
"""Register a callback fired whenever the value changes.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
handler: Called with a :class:`~bootstack.events.ChangeEvent`
|
|
177
|
+
carrying the new `value` and the `prev_value` (useful for
|
|
178
|
+
tristate controls). Omit to get a composable
|
|
179
|
+
:class:`~bootstack.streams.Stream` instead.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
183
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
184
|
+
"""
|
|
185
|
+
return self.on("change", handler)
|
|
186
|
+
|
|
187
|
+
@overload
|
|
188
|
+
def on_check(self) -> Stream: ...
|
|
189
|
+
@overload
|
|
190
|
+
def on_check(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
191
|
+
def on_check(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
192
|
+
"""Register a callback fired when the control becomes checked/selected.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
handler: Called with the :class:`~bootstack.events.Event`. Omit to
|
|
196
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
200
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
201
|
+
"""
|
|
202
|
+
return self.on("check", handler)
|
|
203
|
+
|
|
204
|
+
@overload
|
|
205
|
+
def on_uncheck(self) -> Stream: ...
|
|
206
|
+
@overload
|
|
207
|
+
def on_uncheck(self, handler: Callable[[Event], Any]) -> Subscription: ...
|
|
208
|
+
def on_uncheck(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
|
|
209
|
+
"""Register a callback fired when the control becomes unchecked/deselected.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
handler: Called with the :class:`~bootstack.events.Event`. Omit to
|
|
213
|
+
get a composable :class:`~bootstack.streams.Stream` instead.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
A cancellable :class:`~bootstack.events.Subscription` when a
|
|
217
|
+
handler is given, otherwise a :class:`~bootstack.streams.Stream`.
|
|
218
|
+
"""
|
|
219
|
+
return self.on("uncheck", handler)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Checkbox(_BooleanControlBase):
|
|
223
|
+
"""A labeled checkbox — checked or unchecked.
|
|
224
|
+
|
|
225
|
+
The label is the first positional argument. All options are keyword-only.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
label: Label text displayed beside the checkbox.
|
|
229
|
+
signal: Reactive `Signal` controlling the checked state. When
|
|
230
|
+
provided, `value=` is ignored — seed the Signal directly.
|
|
231
|
+
value: Initial value. Ignored when `signal=` is passed.
|
|
232
|
+
checked_value: Value representing the checked state. Defaults to
|
|
233
|
+
`True`.
|
|
234
|
+
unchecked_value: Value representing the unchecked state. Defaults
|
|
235
|
+
to `False`.
|
|
236
|
+
tristate: If `True`, enables a third indeterminate state. When
|
|
237
|
+
indeterminate the box shows a dash indicator and `value`
|
|
238
|
+
returns `None`. If no `value=` or `signal=` is provided,
|
|
239
|
+
the checkbox starts in the indeterminate state. Defaults to
|
|
240
|
+
`False`.
|
|
241
|
+
on_change: Shorthand callback fired on every toggle. Equivalent to
|
|
242
|
+
`checkbox.on_change(fn)`.
|
|
243
|
+
on_icon: Bootstrap Icons name shown when the checkbox is checked.
|
|
244
|
+
Pair with `off_icon=` to display different icons per state,
|
|
245
|
+
e.g. `on_icon="check-circle-fill", off_icon="circle"`.
|
|
246
|
+
off_icon: Bootstrap Icons name shown when the checkbox is unchecked.
|
|
247
|
+
icon_only: If `True`, hides the label text and shows only the icon.
|
|
248
|
+
Combine with `on_icon=`/`off_icon=` and
|
|
249
|
+
`show_indicator=False` for fully icon-driven checkboxes.
|
|
250
|
+
show_indicator: If `False`, hides the checkbox box indicator.
|
|
251
|
+
Useful when `on_icon=`/`off_icon=` serve as the visual cue.
|
|
252
|
+
disabled: If `True`, widget is non-interactive and dimmed.
|
|
253
|
+
Defaults to `False`.
|
|
254
|
+
accent: Accent token applied to the box and check mark.
|
|
255
|
+
parent: Explicit parent widget. If omitted, the current
|
|
256
|
+
context-stack container is used.
|
|
257
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
258
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
259
|
+
See :doc:`/tasks/layout`.
|
|
260
|
+
"""
|
|
261
|
+
_internal_class = _InternalCheckButton
|
|
262
|
+
|
|
263
|
+
def __init__(
|
|
264
|
+
self,
|
|
265
|
+
label: str = "",
|
|
266
|
+
*,
|
|
267
|
+
signal: "Signal | None" = None,
|
|
268
|
+
value: Any = None,
|
|
269
|
+
checked_value: Any = True,
|
|
270
|
+
unchecked_value: Any = False,
|
|
271
|
+
tristate: bool = False,
|
|
272
|
+
on_change: Callable[[], Any] | None = None,
|
|
273
|
+
on_icon: str | None = None,
|
|
274
|
+
off_icon: str | None = None,
|
|
275
|
+
icon_only: bool = False,
|
|
276
|
+
show_indicator: bool = True,
|
|
277
|
+
disabled: bool = False,
|
|
278
|
+
accent: AccentToken | str | None = None,
|
|
279
|
+
parent: Any = None,
|
|
280
|
+
**kwargs: Any,
|
|
281
|
+
) -> None:
|
|
282
|
+
options: dict[str, Any] = {}
|
|
283
|
+
if on_icon is not None:
|
|
284
|
+
options["on_icon"] = on_icon
|
|
285
|
+
if off_icon is not None:
|
|
286
|
+
options["off_icon"] = off_icon
|
|
287
|
+
if icon_only:
|
|
288
|
+
options["icon_only"] = True
|
|
289
|
+
if not show_indicator:
|
|
290
|
+
options["show_indicator"] = False
|
|
291
|
+
super().__init__(
|
|
292
|
+
label,
|
|
293
|
+
signal=signal,
|
|
294
|
+
value=value,
|
|
295
|
+
checked_value=checked_value,
|
|
296
|
+
unchecked_value=unchecked_value,
|
|
297
|
+
_tristate=tristate,
|
|
298
|
+
on_change=on_change,
|
|
299
|
+
disabled=disabled,
|
|
300
|
+
accent=accent,
|
|
301
|
+
_internal_options=options,
|
|
302
|
+
parent=parent,
|
|
303
|
+
**kwargs,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class Switch(_BooleanControlBase):
|
|
308
|
+
"""A toggle switch — on or off.
|
|
309
|
+
|
|
310
|
+
Renders as a sliding track-and-thumb control. Use in place of a checkbox
|
|
311
|
+
when the action takes effect immediately (e.g. enable/disable a setting).
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
label: Label text displayed beside the switch.
|
|
315
|
+
signal: Reactive `Signal` controlling the on/off state. When
|
|
316
|
+
provided, `value=` is ignored — seed the Signal directly.
|
|
317
|
+
value: Initial value. Ignored when `signal=` is passed.
|
|
318
|
+
checked_value: Value representing the on state. Defaults to
|
|
319
|
+
`True`.
|
|
320
|
+
unchecked_value: Value representing the off state. Defaults to
|
|
321
|
+
`False`.
|
|
322
|
+
on_change: Shorthand callback fired on every toggle. Equivalent to
|
|
323
|
+
`switch.on_change(fn)`.
|
|
324
|
+
disabled: If `True`, widget is non-interactive and dimmed.
|
|
325
|
+
Defaults to `False`.
|
|
326
|
+
accent: Accent token applied to the track when on.
|
|
327
|
+
parent: Explicit parent widget. If omitted, the current
|
|
328
|
+
context-stack container is used.
|
|
329
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
330
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
331
|
+
See :doc:`/tasks/layout`.
|
|
332
|
+
"""
|
|
333
|
+
_internal_class = _InternalSwitch
|
|
334
|
+
|
|
335
|
+
def __init__(
|
|
336
|
+
self,
|
|
337
|
+
label: str = "",
|
|
338
|
+
*,
|
|
339
|
+
signal: "Signal | None" = None,
|
|
340
|
+
value: Any = None,
|
|
341
|
+
checked_value: Any = True,
|
|
342
|
+
unchecked_value: Any = False,
|
|
343
|
+
on_change: Callable[[], Any] | None = None,
|
|
344
|
+
disabled: bool = False,
|
|
345
|
+
accent: AccentToken | str | None = None,
|
|
346
|
+
parent: Any = None,
|
|
347
|
+
**kwargs: Any,
|
|
348
|
+
) -> None:
|
|
349
|
+
super().__init__(
|
|
350
|
+
label,
|
|
351
|
+
signal=signal,
|
|
352
|
+
value=value,
|
|
353
|
+
checked_value=checked_value,
|
|
354
|
+
unchecked_value=unchecked_value,
|
|
355
|
+
on_change=on_change,
|
|
356
|
+
disabled=disabled,
|
|
357
|
+
accent=accent,
|
|
358
|
+
parent=parent,
|
|
359
|
+
**kwargs,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
class ToggleButton(_BooleanControlBase):
|
|
364
|
+
"""A button that stays pressed when active — toolbar-style toggle.
|
|
365
|
+
|
|
366
|
+
Renders as a depressed button rather than a checkbox or switch. Commonly
|
|
367
|
+
used in toolbars and button groups to represent a persistent on/off state.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
text: Button text.
|
|
371
|
+
signal: Reactive `Signal` controlling the pressed state. When
|
|
372
|
+
provided, `value=` is ignored — seed the Signal directly.
|
|
373
|
+
value: Initial value. Ignored when `signal=` is passed.
|
|
374
|
+
checked_value: Value representing the pressed/active state. Defaults
|
|
375
|
+
to `True`.
|
|
376
|
+
unchecked_value: Value representing the unpressed/inactive state.
|
|
377
|
+
Defaults to `False`.
|
|
378
|
+
on_change: Shorthand callback fired on every toggle. Equivalent to
|
|
379
|
+
`btn.on_change(fn)`.
|
|
380
|
+
icon: Bootstrap Icons name shown in both states — the fallback for
|
|
381
|
+
`on_icon`/`off_icon` when those are not given. Pass `on_icon`/
|
|
382
|
+
`off_icon` to override the icon per state.
|
|
383
|
+
on_icon: Bootstrap Icons name shown when the button is active/pressed.
|
|
384
|
+
Use alone to swap icon on activation, or pair with `off_icon=`
|
|
385
|
+
to show different icons per state,
|
|
386
|
+
e.g. `on_icon="star-fill", off_icon="star"`. Falls back to `icon`.
|
|
387
|
+
off_icon: Bootstrap Icons name shown when the button is inactive.
|
|
388
|
+
Can be used alone or paired with `on_icon=`. Falls back to `icon`.
|
|
389
|
+
icon_only: If `True`, shows only the icon with no label text.
|
|
390
|
+
Requires `icon=`, `on_icon=`, or `off_icon=` to be set.
|
|
391
|
+
disabled: If `True`, widget is non-interactive and dimmed.
|
|
392
|
+
Defaults to `False`.
|
|
393
|
+
accent: Accent token applied to the button when active.
|
|
394
|
+
variant: Button style variant. Default `'solid'`.
|
|
395
|
+
density: Padding density.
|
|
396
|
+
parent: Explicit parent widget. If omitted, the current
|
|
397
|
+
context-stack container is used.
|
|
398
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
399
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
400
|
+
See :doc:`/tasks/layout`.
|
|
401
|
+
"""
|
|
402
|
+
_internal_class = _InternalCheckToggle
|
|
403
|
+
|
|
404
|
+
def __init__(
|
|
405
|
+
self,
|
|
406
|
+
text: str = "",
|
|
407
|
+
*,
|
|
408
|
+
signal: "Signal | None" = None,
|
|
409
|
+
value: Any = None,
|
|
410
|
+
checked_value: Any = True,
|
|
411
|
+
unchecked_value: Any = False,
|
|
412
|
+
on_change: Callable[[], Any] | None = None,
|
|
413
|
+
icon: str | None = None,
|
|
414
|
+
on_icon: str | None = None,
|
|
415
|
+
off_icon: str | None = None,
|
|
416
|
+
icon_only: bool = False,
|
|
417
|
+
disabled: bool = False,
|
|
418
|
+
accent: AccentToken | str | None = None,
|
|
419
|
+
variant: ButtonVariant = "default",
|
|
420
|
+
density: WidgetDensity | None = None,
|
|
421
|
+
parent: Any = None,
|
|
422
|
+
**kwargs: Any,
|
|
423
|
+
) -> None:
|
|
424
|
+
options: dict[str, Any] = {}
|
|
425
|
+
# `icon` is the fallback for both states; on_icon/off_icon override it.
|
|
426
|
+
resolved_on = on_icon if on_icon is not None else icon
|
|
427
|
+
resolved_off = off_icon if off_icon is not None else icon
|
|
428
|
+
if resolved_on is not None:
|
|
429
|
+
options["on_icon"] = resolved_on
|
|
430
|
+
if resolved_off is not None:
|
|
431
|
+
options["off_icon"] = resolved_off
|
|
432
|
+
if icon_only:
|
|
433
|
+
options["icon_only"] = True
|
|
434
|
+
if variant is not None:
|
|
435
|
+
options["variant"] = variant
|
|
436
|
+
if density is not None:
|
|
437
|
+
options["density"] = density
|
|
438
|
+
super().__init__(
|
|
439
|
+
text,
|
|
440
|
+
signal=signal,
|
|
441
|
+
value=value,
|
|
442
|
+
checked_value=checked_value,
|
|
443
|
+
unchecked_value=unchecked_value,
|
|
444
|
+
on_change=on_change,
|
|
445
|
+
disabled=disabled,
|
|
446
|
+
accent=accent,
|
|
447
|
+
_internal_options=options,
|
|
448
|
+
parent=parent,
|
|
449
|
+
**kwargs,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
register_widget_events(Checkbox, _BOOLEAN_EVENTS)
|
|
454
|
+
register_widget_events(Switch, _BOOLEAN_EVENTS)
|
|
455
|
+
register_widget_events(ToggleButton, _BOOLEAN_EVENTS)
|