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
bootstack/cli/demo.py
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Widget Gallery
|
|
3
|
+
|
|
4
|
+
A hero-first showcase of bootstack widgets, organized by category. Each sidebar
|
|
5
|
+
page shows one representative instance of each widget — variants and colors only
|
|
6
|
+
where they're meaningful (accent palettes, key modes) rather than an exhaustive
|
|
7
|
+
matrix. Kept deliberately lean.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import bootstack as bs
|
|
11
|
+
from bootstack.signals import Signal
|
|
12
|
+
from bootstack.dialogs import FormDialog
|
|
13
|
+
from bootstack.style.style import get_style
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# =============================================================================
|
|
17
|
+
# Page builders — one hero page per category
|
|
18
|
+
# =============================================================================
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _heading(title, subtitle):
|
|
22
|
+
bs.Label(title, font="heading-xl")
|
|
23
|
+
bs.Label(subtitle, accent="secondary")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _build_home_page():
|
|
27
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
28
|
+
bs.Label("bootstack", font="display-lg[bold]")
|
|
29
|
+
bs.Label("A batteries-included desktop UI framework for Python.",
|
|
30
|
+
font="body-lg", accent="secondary")
|
|
31
|
+
|
|
32
|
+
with bs.Row(gap=16, grow_items=True):
|
|
33
|
+
for title, body, icon, color in [
|
|
34
|
+
("Widgets", "50+ composable widgets", "grid-3x3-gap", "primary"),
|
|
35
|
+
("Theming", "Live light/dark themes", "palette", "success"),
|
|
36
|
+
("Data", "Tables, trees, sources", "table", "info"),
|
|
37
|
+
]:
|
|
38
|
+
with bs.Card(accent=color, gap=6):
|
|
39
|
+
bs.Label(title, icon=icon, accent=color, font="body[bold]")
|
|
40
|
+
bs.Label(body, accent="secondary", font="caption")
|
|
41
|
+
|
|
42
|
+
with bs.GroupBox("About this gallery"):
|
|
43
|
+
bs.Label(
|
|
44
|
+
"Browse the sidebar to explore widgets by category. Each page shows "
|
|
45
|
+
"a representative example — switch the theme from the toolbar to see "
|
|
46
|
+
"everything update live."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _build_actions_page():
|
|
51
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
52
|
+
_heading("Actions", "Buttons and action triggers.")
|
|
53
|
+
|
|
54
|
+
with bs.GroupBox("Button — accents", grow_items=True, gap=4, layout="row"):
|
|
55
|
+
for color in ("default", "primary", "success", "warning", "danger"):
|
|
56
|
+
bs.Button(color.title(), accent=color)
|
|
57
|
+
|
|
58
|
+
with bs.GroupBox("Button — variants", layout="row", gap=4, grow_items=True):
|
|
59
|
+
for variant in ("solid", "outline", "ghost"):
|
|
60
|
+
bs.Button(variant.title(), accent="primary", variant=variant)
|
|
61
|
+
bs.Button("Disabled", accent="primary", disabled=True)
|
|
62
|
+
|
|
63
|
+
with bs.GroupBox("ButtonGroup, MenuButton", layout="row", gap=16):
|
|
64
|
+
bg = bs.ButtonGroup(accent="primary", variant="outline")
|
|
65
|
+
bg.add("Cut", icon="scissors")
|
|
66
|
+
bg.add("Copy", icon="copy")
|
|
67
|
+
bg.add("Paste", icon="clipboard")
|
|
68
|
+
|
|
69
|
+
mb = bs.MenuButton("Actions", icon="three-dots", accent="primary")
|
|
70
|
+
mb.add_item("New file", icon="file-earmark")
|
|
71
|
+
mb.add_item("Open…", icon="folder2-open")
|
|
72
|
+
mb.add_divider()
|
|
73
|
+
mb.add_item("Delete", icon="trash")
|
|
74
|
+
|
|
75
|
+
with bs.GroupBox("ThemeToggle", layout="row", gap=8, vertical_items="center"):
|
|
76
|
+
bs.Label("Light / dark switch:")
|
|
77
|
+
bs.ThemeToggle()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _build_inputs_page():
|
|
81
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
82
|
+
_heading("Inputs", "Text, numeric, path, and date/time entry fields.")
|
|
83
|
+
|
|
84
|
+
with bs.GroupBox("Text", horizontal_items="stretch", gap=6):
|
|
85
|
+
bs.TextField(label="Name", message="Enter your full name")
|
|
86
|
+
bs.PasswordField(label="Password", message="Click the eye to reveal")
|
|
87
|
+
bs.PathField(label="File", mode="open", message="Select a file")
|
|
88
|
+
|
|
89
|
+
with bs.GroupBox("Numeric", gap=8, layout="row", grow_items=True):
|
|
90
|
+
bs.NumberField(label="Quantity", value=42, min_value=0, max_value=100)
|
|
91
|
+
bs.SpinnerField(
|
|
92
|
+
label="Month",
|
|
93
|
+
options=["Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
94
|
+
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
|
95
|
+
value="Jan",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
with bs.GroupBox("Date & time", gap=8, layout="row", grow_items=True):
|
|
99
|
+
bs.DateField(label="Date")
|
|
100
|
+
bs.TimeField(label="Time")
|
|
101
|
+
|
|
102
|
+
with bs.GroupBox("Sliders", horizontal_items="stretch", gap=12):
|
|
103
|
+
bs.Slider(value=65, show_value=True, tick_step=25)
|
|
104
|
+
bs.RangeSlider(low_value=25, high_value=75, min_value=0, max_value=100,
|
|
105
|
+
show_value=True, accent="primary")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
_DEMO_PYTHON = '''\
|
|
109
|
+
def greet(name: str) -> str:
|
|
110
|
+
"""Return a friendly greeting."""
|
|
111
|
+
return f"Hello, {name}!"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
print(greet("bootstack"))
|
|
116
|
+
'''
|
|
117
|
+
|
|
118
|
+
_DEMO_JSON = '''\
|
|
119
|
+
{
|
|
120
|
+
"name": "bootstack",
|
|
121
|
+
"version": "1.0.0",
|
|
122
|
+
"description": "Modern UI framework for Python"
|
|
123
|
+
}
|
|
124
|
+
'''
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _build_editing_page():
|
|
128
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
129
|
+
_heading("Text editing", "Multi-line text and a syntax-highlighting editor.")
|
|
130
|
+
|
|
131
|
+
with bs.GroupBox("TextArea", horizontal_items="stretch"):
|
|
132
|
+
bs.TextArea(
|
|
133
|
+
value="Multi-line input with scrollbars, undo/redo, and signal "
|
|
134
|
+
"binding.\n\nTry typing more to see it scroll.",
|
|
135
|
+
height=5,
|
|
136
|
+
grow=True,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
with bs.GroupBox("CodeEditor — Python", horizontal_items="stretch", gap=6):
|
|
140
|
+
editor = bs.CodeEditor(_DEMO_PYTHON, language="python", height=10)
|
|
141
|
+
with bs.Row(gap=6, vertical_items="center"):
|
|
142
|
+
bs.Button("Undo", variant="outline", on_click=editor.undo)
|
|
143
|
+
bs.Button("Redo", variant="outline", on_click=editor.redo)
|
|
144
|
+
bs.Button("Find", variant="outline", icon="search",
|
|
145
|
+
on_click=editor.show_search)
|
|
146
|
+
|
|
147
|
+
with bs.GroupBox("CodeEditor — JSON (read-only)", horizontal_items="stretch"):
|
|
148
|
+
bs.CodeEditor(_DEMO_JSON, language="json", read_only=True, height=6)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _build_selection_page():
|
|
152
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
153
|
+
_heading("Selection", "Checkboxes, switches, radios, toggles, and pickers.")
|
|
154
|
+
|
|
155
|
+
with bs.GroupBox("Checkbox & Switch", gap=8, layout="row"):
|
|
156
|
+
bs.Checkbox("Enabled", accent="primary", value=True)
|
|
157
|
+
bs.Switch("Notifications", accent="success", value=True)
|
|
158
|
+
|
|
159
|
+
with bs.GroupBox("RadioGroup, ToggleGroup", gap=16, layout="row"):
|
|
160
|
+
rg = bs.RadioGroup(value="opt1", accent="primary")
|
|
161
|
+
rg.add("Option 1", value="opt1")
|
|
162
|
+
rg.add("Option 2", value="opt2")
|
|
163
|
+
rg.add("Option 3", value="opt3")
|
|
164
|
+
|
|
165
|
+
with bs.Column(gap=4):
|
|
166
|
+
bs.Label("Multi-select:", font="caption", accent="secondary")
|
|
167
|
+
tg = bs.ToggleGroup(mode="multi", accent="success", variant="outline")
|
|
168
|
+
tg.add("Bold", value="B")
|
|
169
|
+
tg.add("Italic", value="I")
|
|
170
|
+
tg.add("Underline", value="U")
|
|
171
|
+
|
|
172
|
+
with bs.GroupBox("Select & SelectButton", horizontal_items="stretch", gap=8):
|
|
173
|
+
bs.Select(label="Size", options=["Small", "Medium", "Large"], value="Medium")
|
|
174
|
+
bs.SelectButton(options=["Day", "Week", "Month"], value="Week", accent="primary")
|
|
175
|
+
|
|
176
|
+
with bs.GroupBox("Calendar", layout="row", gap=16):
|
|
177
|
+
bs.Calendar(accent="primary")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _build_data_page():
|
|
181
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
182
|
+
_heading("Data display", "Labels, badges, progress bars, and gauges.")
|
|
183
|
+
|
|
184
|
+
with bs.GroupBox("Badges — accents", gap=12, layout="row"):
|
|
185
|
+
for color in ("primary", "success", "warning", "danger"):
|
|
186
|
+
bs.Badge(color.title(), accent=color)
|
|
187
|
+
bs.Badge("99+", accent="danger", variant="pill")
|
|
188
|
+
|
|
189
|
+
with bs.GroupBox("ProgressBar", horizontal_items="stretch", gap=8):
|
|
190
|
+
bs.ProgressBar(value=70, max_value=100, accent="primary")
|
|
191
|
+
bs.ProgressBar(value=45, max_value=100, accent="success")
|
|
192
|
+
|
|
193
|
+
with bs.GroupBox("Gauge", layout="row", gap=16, vertical_items="center"):
|
|
194
|
+
for amount, label, color in [
|
|
195
|
+
(45, "CPU", "primary"),
|
|
196
|
+
(78, "Memory", "warning"),
|
|
197
|
+
(92, "Disk", "danger"),
|
|
198
|
+
]:
|
|
199
|
+
bs.Gauge(value=amount, max_value=100, subtitle=label,
|
|
200
|
+
accent=color, interactive=True)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _build_tables_page():
|
|
204
|
+
employees = [
|
|
205
|
+
{"name": "Ada Lovelace", "role": "Staff Engineer", "dept": "Engineering", "salary": 185000},
|
|
206
|
+
{"name": "Alan Turing", "role": "Software Engineer", "dept": "Engineering", "salary": 162000},
|
|
207
|
+
{"name": "Grace Hopper", "role": "Engineering Lead", "dept": "Engineering", "salary": 198000},
|
|
208
|
+
{"name": "Carol Williams", "role": "Product Designer", "dept": "Design", "salary": 142000},
|
|
209
|
+
{"name": "Eva Martinez", "role": "Account Executive", "dept": "Sales", "salary": 129000},
|
|
210
|
+
{"name": "Iris Chen", "role": "Content Strategist", "dept": "Marketing", "salary": 112000},
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
214
|
+
_heading("Data tables", "List, table, and tree views over records.")
|
|
215
|
+
|
|
216
|
+
with bs.GroupBox("ListView"):
|
|
217
|
+
bs.ListView(
|
|
218
|
+
items=[
|
|
219
|
+
{"id": 1, "title": "Inbox", "text": "12 unread", "icon": "inbox", "badge": "12"},
|
|
220
|
+
{"id": 2, "title": "Starred", "text": "Flagged items", "icon": "star-fill"},
|
|
221
|
+
{"id": 3, "title": "Sent", "text": "Your sent mail", "icon": "send"},
|
|
222
|
+
],
|
|
223
|
+
selection_mode="single",
|
|
224
|
+
height=150,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
with bs.GroupBox("DataTable", horizontal_items="stretch", grow=True):
|
|
228
|
+
bs.DataTable(
|
|
229
|
+
columns=[
|
|
230
|
+
{"text": "Name", "key": "name", "width": 200},
|
|
231
|
+
{"text": "Role", "key": "role", "width": 180},
|
|
232
|
+
{"text": "Department", "key": "dept", "width": 140},
|
|
233
|
+
{"text": "Salary", "key": "salary", "width": 120, "anchor": "e", "format": "${:,.0f}"},
|
|
234
|
+
],
|
|
235
|
+
rows=employees,
|
|
236
|
+
selection_mode="multi",
|
|
237
|
+
show_selection_controls=True,
|
|
238
|
+
allow_filter=True,
|
|
239
|
+
allow_group=True,
|
|
240
|
+
grow=True,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
with bs.GroupBox("Tree"):
|
|
244
|
+
bs.Tree(
|
|
245
|
+
nodes=[
|
|
246
|
+
{"label": "Engineering", "open_icon": "folder2-open",
|
|
247
|
+
"closed_icon": "folder-fill", "expanded": True, "children": [
|
|
248
|
+
{"label": "Ada Lovelace", "icon": "person-fill"},
|
|
249
|
+
{"label": "Grace Hopper", "icon": "person-fill"},
|
|
250
|
+
]},
|
|
251
|
+
{"label": "Design", "open_icon": "folder2-open",
|
|
252
|
+
"closed_icon": "folder-fill", "children": [
|
|
253
|
+
{"label": "Carol Williams", "icon": "person-fill"},
|
|
254
|
+
]},
|
|
255
|
+
],
|
|
256
|
+
height=200,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _demo_photos():
|
|
261
|
+
"""A few solid-color tiles as `Image` handles, for the media widgets."""
|
|
262
|
+
from PIL import Image as _PILImage
|
|
263
|
+
from bootstack.images import Image
|
|
264
|
+
|
|
265
|
+
swatches = [
|
|
266
|
+
("Sunset", (244, 114, 82)), ("Ocean", (56, 132, 222)),
|
|
267
|
+
("Forest", (71, 159, 118)), ("Berry", (176, 42, 88)),
|
|
268
|
+
("Amber", (240, 180, 41)), ("Slate", (90, 99, 110)),
|
|
269
|
+
]
|
|
270
|
+
return [
|
|
271
|
+
{"title": name, "image": Image.from_pil(_PILImage.new("RGB", (320, 320), rgb))}
|
|
272
|
+
for name, rgb in swatches
|
|
273
|
+
]
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _build_media_page():
|
|
277
|
+
from bootstack.images import get_icon
|
|
278
|
+
|
|
279
|
+
photos = _demo_photos()
|
|
280
|
+
|
|
281
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
282
|
+
_heading("Media", "Avatars, images, carousels, and thumbnail grids.")
|
|
283
|
+
|
|
284
|
+
with bs.GroupBox("Avatar", layout="row", gap=12):
|
|
285
|
+
bs.Avatar(name="Ada Lovelace")
|
|
286
|
+
bs.Avatar(name="Grace Hopper", shape="rounded")
|
|
287
|
+
bs.Avatar(initials="JS", shape="square")
|
|
288
|
+
bs.Avatar(image=get_icon("person-fill", size=40))
|
|
289
|
+
|
|
290
|
+
with bs.GroupBox("Picture", layout="row", gap=16):
|
|
291
|
+
bs.Picture(photos[0]["image"], width=180, height=120, fit="cover", corner_radius=8)
|
|
292
|
+
bs.Picture(photos[1]["image"], width=120, height=120, fit="cover", corner_radius=60)
|
|
293
|
+
|
|
294
|
+
with bs.GroupBox("Carousel", horizontal_items="stretch"):
|
|
295
|
+
bs.Carousel(items=photos, image_field="image", caption_field="title", fit="cover")
|
|
296
|
+
|
|
297
|
+
with bs.GroupBox("Gallery", horizontal_items="stretch", grow=True):
|
|
298
|
+
bs.Gallery(items=photos, image_field="image", caption_field="title",
|
|
299
|
+
tile_size=(120, 120), grow=True)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _build_layout_page():
|
|
303
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
304
|
+
_heading("Layout", "Cards, panels, dividers, and split panes.")
|
|
305
|
+
|
|
306
|
+
with bs.GroupBox("Card", layout="row", grow_items=True, gap=16):
|
|
307
|
+
for title, body, color in [
|
|
308
|
+
("Users", "1,234 active", "primary"),
|
|
309
|
+
("Revenue", "$45,678", "success"),
|
|
310
|
+
("Errors", "12 today", "danger"),
|
|
311
|
+
]:
|
|
312
|
+
with bs.Card(accent=color):
|
|
313
|
+
bs.Label(title, accent=color, font="body[bold]")
|
|
314
|
+
bs.Label(body, font="heading-lg")
|
|
315
|
+
|
|
316
|
+
with bs.GroupBox("Accordion"):
|
|
317
|
+
acc = bs.Accordion(accent="primary")
|
|
318
|
+
with acc.add("Section 1", expanded=True):
|
|
319
|
+
bs.Label("Content for section one.")
|
|
320
|
+
with acc.add("Section 2"):
|
|
321
|
+
bs.Label("Content for section two.")
|
|
322
|
+
|
|
323
|
+
with bs.GroupBox("SplitView", horizontal_items="stretch", grow=True):
|
|
324
|
+
sv = bs.SplitView(orient="horizontal", grow=True)
|
|
325
|
+
with sv.add(padding=10, horizontal_items="center"):
|
|
326
|
+
bs.Label("Left pane")
|
|
327
|
+
bs.Label("Drag the sash to resize", accent="secondary", font="caption")
|
|
328
|
+
with sv.add(padding=10, horizontal_items="center"):
|
|
329
|
+
bs.Label("Right pane")
|
|
330
|
+
|
|
331
|
+
with bs.GroupBox("ScrollView", horizontal_items="stretch"):
|
|
332
|
+
with bs.ScrollView(height=120, show_border=True, padding=8):
|
|
333
|
+
for i in range(20):
|
|
334
|
+
bs.Label(f"Scrollable row {i + 1}")
|
|
335
|
+
|
|
336
|
+
with bs.GroupBox("Divider — accents", horizontal_items="stretch", gap=8):
|
|
337
|
+
bs.Divider()
|
|
338
|
+
bs.Divider(accent="primary")
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _build_navigation_page():
|
|
342
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
343
|
+
_heading("Navigation & overlays", "Tabs, page stacks, tooltips, toasts, menus.")
|
|
344
|
+
|
|
345
|
+
with bs.GroupBox("Tabs", horizontal_items="stretch", grow=True):
|
|
346
|
+
tabs = bs.Tabs(grow=True)
|
|
347
|
+
with tabs.add("dashboard", label="Dashboard", icon="house"):
|
|
348
|
+
bs.Label("Dashboard content.", padding=20)
|
|
349
|
+
with tabs.add("files", label="Files", icon="folder2"):
|
|
350
|
+
bs.Label("Browse your files.", padding=20)
|
|
351
|
+
with tabs.add("settings", label="Settings", icon="gear"):
|
|
352
|
+
bs.Label("Configure settings.", padding=20)
|
|
353
|
+
|
|
354
|
+
with bs.GroupBox("PageStack", horizontal_items="stretch", grow=True):
|
|
355
|
+
ps = bs.PageStack(grow=True)
|
|
356
|
+
with ps.add("welcome"):
|
|
357
|
+
bs.Label("Welcome page", font="heading-md", padding=20)
|
|
358
|
+
with ps.add("details"):
|
|
359
|
+
bs.Label("Details page", font="heading-md", padding=20)
|
|
360
|
+
with bs.Row(gap=8):
|
|
361
|
+
bs.Button("Welcome", on_click=lambda: ps.navigate("welcome"))
|
|
362
|
+
bs.Button("Details", on_click=lambda: ps.navigate("details"))
|
|
363
|
+
|
|
364
|
+
with bs.GroupBox("Tooltip & Toast", layout="row", gap=8):
|
|
365
|
+
tip = bs.Button("Hover for a tip", accent="primary")
|
|
366
|
+
bs.Tooltip(tip, "Tooltips can carry accent colors.", accent="primary")
|
|
367
|
+
bs.Button("Show toast", accent="success",
|
|
368
|
+
on_click=lambda: bs.toast("Operation completed.",
|
|
369
|
+
title="Success", accent="success", duration=3000))
|
|
370
|
+
|
|
371
|
+
with bs.GroupBox("ContextMenu", horizontal_items="stretch"):
|
|
372
|
+
target = bs.Card(padding=24, horizontal_items="center")
|
|
373
|
+
with target:
|
|
374
|
+
bs.Label("Right-click me", accent="secondary")
|
|
375
|
+
menu = bs.ContextMenu(target=target)
|
|
376
|
+
menu.add_item("Cut", icon="scissors")
|
|
377
|
+
menu.add_item("Copy", icon="copy")
|
|
378
|
+
menu.add_divider()
|
|
379
|
+
menu.add_item("Delete", icon="trash")
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def _build_dialogs_page():
|
|
383
|
+
def _ask(fn, *args, **kw):
|
|
384
|
+
result = fn(*args, **kw)
|
|
385
|
+
if result is not None:
|
|
386
|
+
bs.toast(str(result), title="Result", duration=2000)
|
|
387
|
+
|
|
388
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
389
|
+
_heading("Dialogs & forms", "Prompt for input and edit structured data.")
|
|
390
|
+
|
|
391
|
+
with bs.GroupBox("Message & input", layout="row", gap=8):
|
|
392
|
+
bs.Button("alert()", on_click=lambda: bs.alert("Operation complete."))
|
|
393
|
+
bs.Button("confirm()", accent="warning",
|
|
394
|
+
on_click=lambda: _ask(lambda: bs.confirm("Continue?")))
|
|
395
|
+
bs.Button("ask_string()", on_click=lambda: _ask(bs.ask_string, "Enter your name:"))
|
|
396
|
+
bs.Button("ask_integer()",
|
|
397
|
+
on_click=lambda: _ask(bs.ask_integer, "Enter age:", min_value=0, max_value=120))
|
|
398
|
+
|
|
399
|
+
with bs.GroupBox("Pickers", layout="row", gap=8):
|
|
400
|
+
bs.Button("ask_date()", on_click=lambda: _ask(bs.ask_date, title="Pick a date"))
|
|
401
|
+
bs.Button("ask_color()", on_click=lambda: _ask(bs.ask_color, title="Pick a color"))
|
|
402
|
+
bs.Button("ask_font()", on_click=lambda: _ask(bs.ask_font, title="Pick a font"))
|
|
403
|
+
bs.Button("ask_filter()",
|
|
404
|
+
on_click=lambda: _ask(bs.ask_filter,
|
|
405
|
+
[f"Option {i:02d}" for i in range(20)],
|
|
406
|
+
title="Filter", enable_search=True,
|
|
407
|
+
enable_select_all=True))
|
|
408
|
+
|
|
409
|
+
with bs.GroupBox("Form & FormDialog", horizontal_items="stretch", gap=8):
|
|
410
|
+
bs.Form(
|
|
411
|
+
data={"first_name": "Jane", "last_name": "Doe",
|
|
412
|
+
"email": "jane@example.com", "active": True},
|
|
413
|
+
col_count=2, min_col_width=220,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
def _show_form():
|
|
417
|
+
dlg = FormDialog(
|
|
418
|
+
title="Settings",
|
|
419
|
+
data={"name": "", "email": ""},
|
|
420
|
+
items=[
|
|
421
|
+
{"key": "name", "label": "Name"},
|
|
422
|
+
{"key": "email", "label": "Email"},
|
|
423
|
+
],
|
|
424
|
+
)
|
|
425
|
+
dlg.show()
|
|
426
|
+
if dlg.result:
|
|
427
|
+
bs.toast(str(dlg.result), title="Form Result", duration=3000)
|
|
428
|
+
|
|
429
|
+
bs.Button("Open FormDialog", accent="primary", on_click=_show_form)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _build_design_page():
|
|
433
|
+
with bs.Column(padding=24, gap=16, grow=True, horizontal_items="stretch"):
|
|
434
|
+
_heading("Design system", "Font tokens, icons, themes, and surfaces.")
|
|
435
|
+
|
|
436
|
+
with bs.GroupBox("Font tokens", layout="grid", columns=['200px', 1],
|
|
437
|
+
horizontal_items="left"):
|
|
438
|
+
for token, desc in [
|
|
439
|
+
("heading-lg", "Heading LG"),
|
|
440
|
+
("body", "Body (default)"),
|
|
441
|
+
("caption", "Caption"),
|
|
442
|
+
("code", "Code"),
|
|
443
|
+
]:
|
|
444
|
+
bs.Label(desc, font=token)
|
|
445
|
+
bs.Label(f'font="{token}"', font="code", accent="secondary")
|
|
446
|
+
|
|
447
|
+
with bs.GroupBox("Icons", layout="row", gap=16, vertical_items="center"):
|
|
448
|
+
for size in (16, 20, 24, 32, 48):
|
|
449
|
+
bs.Label(f"{size}px", icon={"name": "star-fill", "size": size})
|
|
450
|
+
|
|
451
|
+
with bs.GroupBox("Theme", horizontal_items="stretch", gap=8):
|
|
452
|
+
style = get_style()
|
|
453
|
+
theme_names = sorted(s["name"] for s in style.theme_provider.list_themes())
|
|
454
|
+
with bs.Row(gap=8, vertical_items="center"):
|
|
455
|
+
bs.Label("Theme:")
|
|
456
|
+
sel = bs.Select(options=theme_names, value=style.current_theme, grow=True)
|
|
457
|
+
sel.on_change(lambda e: sel._internal.after(0, lambda: bs.set_theme(sel.value)))
|
|
458
|
+
bs.ThemeToggle()
|
|
459
|
+
|
|
460
|
+
with bs.GroupBox("Surfaces", layout="row", grow_items=True, gap=8):
|
|
461
|
+
for surface in ("chrome", "content", "card", "overlay"):
|
|
462
|
+
with bs.Column(padding=12, horizontal_items="center", surface=surface):
|
|
463
|
+
bs.Label(surface.title(), surface=surface)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
# =============================================================================
|
|
467
|
+
# Gallery app
|
|
468
|
+
# =============================================================================
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def build_gallery_shell(shell) -> None:
|
|
472
|
+
"""Populate a Widget Gallery `AppShell` (toolbar, status bar, and pages).
|
|
473
|
+
|
|
474
|
+
Shared by `run_demo()` and the docs gallery screenshot so the captured
|
|
475
|
+
gallery always matches the live demo. Pages are lazy-built on first visit.
|
|
476
|
+
"""
|
|
477
|
+
with shell.add_toolbar() as bar:
|
|
478
|
+
with bar.add_menu("File") as file_menu:
|
|
479
|
+
file_menu.add_action("Quit", shortcut="Mod+Q", on_click=shell.close)
|
|
480
|
+
with bar.add_menu("View") as view_menu:
|
|
481
|
+
view_menu.add_action("Toggle theme", on_click=bs.toggle_theme)
|
|
482
|
+
bar.add_spacer()
|
|
483
|
+
bar.add_theme_toggle()
|
|
484
|
+
|
|
485
|
+
shell.statusbar.add_text("Ready")
|
|
486
|
+
shell.statusbar.add_spacer()
|
|
487
|
+
shell.statusbar.add_text(f"bootstack v{bs.__version__}")
|
|
488
|
+
|
|
489
|
+
# Page registry: key → (page_frame, builder)
|
|
490
|
+
_pages: dict[str, tuple[object, object]] = {}
|
|
491
|
+
|
|
492
|
+
# A single-tier page nav with the higher-emphasis solid selection.
|
|
493
|
+
nav = shell.page_nav(variant="solid")
|
|
494
|
+
|
|
495
|
+
def _register(key, builder, *, text, icon, scrollable=False):
|
|
496
|
+
page = nav.add_page(key, text=text, icon=icon, scrollable=scrollable)
|
|
497
|
+
_pages[key] = (page, builder)
|
|
498
|
+
|
|
499
|
+
_register("home", _build_home_page, text="Home", icon="house")
|
|
500
|
+
|
|
501
|
+
nav.add_divider()
|
|
502
|
+
nav.add_header("Widgets")
|
|
503
|
+
_register("actions", _build_actions_page, text="Actions", icon="hand-index-thumb", scrollable=True)
|
|
504
|
+
_register("inputs", _build_inputs_page, text="Inputs", icon="input-cursor-text", scrollable=True)
|
|
505
|
+
_register("editing", _build_editing_page, text="Text Editing", icon="code-slash", scrollable=True)
|
|
506
|
+
_register("selection", _build_selection_page, text="Selection", icon="ui-checks", scrollable=True)
|
|
507
|
+
|
|
508
|
+
nav.add_divider()
|
|
509
|
+
nav.add_header("Data")
|
|
510
|
+
_register("data", _build_data_page, text="Data Display", icon="speedometer2", scrollable=True)
|
|
511
|
+
_register("tables", _build_tables_page, text="Data Tables", icon="table", scrollable=True)
|
|
512
|
+
_register("media", _build_media_page, text="Media", icon="images", scrollable=True)
|
|
513
|
+
|
|
514
|
+
nav.add_divider()
|
|
515
|
+
nav.add_header("Structure")
|
|
516
|
+
_register("layout", _build_layout_page, text="Layout", icon="layout-wtf", scrollable=True)
|
|
517
|
+
_register("navigation", _build_navigation_page, text="Navigation", icon="window-stack", scrollable=True)
|
|
518
|
+
_register("dialogs", _build_dialogs_page, text="Dialogs & Forms", icon="chat-square-text", scrollable=True)
|
|
519
|
+
|
|
520
|
+
nav.add_divider()
|
|
521
|
+
nav.add_header("Design System")
|
|
522
|
+
_register("design", _build_design_page, text="Design", icon="palette", scrollable=True)
|
|
523
|
+
|
|
524
|
+
# Lazy-build: construct page content only on first visit
|
|
525
|
+
_built: set[str] = set()
|
|
526
|
+
|
|
527
|
+
def _build_page(key: str) -> None:
|
|
528
|
+
if key in _built or key not in _pages:
|
|
529
|
+
return
|
|
530
|
+
page, builder = _pages[key]
|
|
531
|
+
with page:
|
|
532
|
+
builder()
|
|
533
|
+
_built.add(key)
|
|
534
|
+
|
|
535
|
+
_build_page("home")
|
|
536
|
+
|
|
537
|
+
def _on_page_change(event) -> None:
|
|
538
|
+
# on_page_change delivers a PageChangeEvent (unpacked); .page is the key.
|
|
539
|
+
key = getattr(event, "page", None)
|
|
540
|
+
if key:
|
|
541
|
+
_build_page(key)
|
|
542
|
+
|
|
543
|
+
shell.on_page_change(_on_page_change)
|
|
544
|
+
shell.navigate("home")
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def run_demo():
|
|
548
|
+
"""Run the bootstack widget gallery as an AppShell application."""
|
|
549
|
+
with bs.AppShell(
|
|
550
|
+
title="Widget Gallery",
|
|
551
|
+
theme="bootstrap-light",
|
|
552
|
+
size=(1100, 750),
|
|
553
|
+
) as shell:
|
|
554
|
+
build_gallery_shell(shell)
|
|
555
|
+
shell.run()
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
def setup_demo(master):
|
|
559
|
+
"""Legacy entry point — the gallery now uses AppShell."""
|
|
560
|
+
with bs.Column(parent=master, grow=True, horizontal_items="stretch", padding=40):
|
|
561
|
+
bs.Label(
|
|
562
|
+
"Use 'bootstack gallery' to launch the Widget Gallery.",
|
|
563
|
+
font="heading-lg",
|
|
564
|
+
)
|