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,302 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable
|
|
4
|
+
|
|
5
|
+
from bootstack.errors import BootstackError
|
|
6
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
7
|
+
from bootstack.widgets._impl.composites.chart import Chart as _InternalChart
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _require_matplotlib() -> None:
|
|
11
|
+
"""Raise a friendly error if the optional matplotlib dependency is missing."""
|
|
12
|
+
try:
|
|
13
|
+
import matplotlib # noqa: F401
|
|
14
|
+
except ImportError as exc:
|
|
15
|
+
raise BootstackError(
|
|
16
|
+
"Chart requires matplotlib, which is not installed. Install the "
|
|
17
|
+
"optional visualization extra with:\n\n pip install bootstack[viz]"
|
|
18
|
+
) from exc
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Chart(PublicWidgetBase):
|
|
22
|
+
"""Embed a matplotlib figure in a bootstack app, themed to match.
|
|
23
|
+
|
|
24
|
+
`Chart` is the bridge between bootstack and the scientific Python plotting
|
|
25
|
+
stack. You build a plot with matplotlib (or seaborn, which draws onto the
|
|
26
|
+
same axes) and hand the figure to a `Chart`; it embeds the figure as a
|
|
27
|
+
first-class widget that fills its space and recolors its chrome — figure and
|
|
28
|
+
axes backgrounds, spines, ticks, and text — to match the active theme,
|
|
29
|
+
flipping with light/dark like everything else in the app.
|
|
30
|
+
|
|
31
|
+
`Chart` is deliberately not a plotting API: it does not wrap matplotlib's
|
|
32
|
+
drawing calls. You keep the full expressive power of matplotlib/seaborn and
|
|
33
|
+
bootstack owns only the embedding, theming, and redraw.
|
|
34
|
+
|
|
35
|
+
matplotlib is an optional dependency. Install it with the visualization
|
|
36
|
+
extra: ``pip install bootstack[viz]`` (or ``bootstack[viz-seaborn]`` to add
|
|
37
|
+
seaborn). Constructing a `Chart` without matplotlib installed raises a
|
|
38
|
+
`bootstack.errors.BootstackError` explaining how to install it.
|
|
39
|
+
|
|
40
|
+
Build the figure with matplotlib's object API (``matplotlib.figure.Figure``)
|
|
41
|
+
rather than ``pyplot`` — an embedded figure must be a standalone object, and
|
|
42
|
+
``pyplot`` would also open a separate window.
|
|
43
|
+
|
|
44
|
+
There are two ways to use it:
|
|
45
|
+
|
|
46
|
+
- **Figure host** — pass a ``figure`` you built. The chart embeds it and
|
|
47
|
+
recolors its chrome to the theme. You own the figure; theming the data
|
|
48
|
+
series is up to you.
|
|
49
|
+
- **Managed render** — pass a ``render`` callback and a reactive source: one
|
|
50
|
+
or more ``signal`` objects, or a ``data_source``. The chart owns the figure
|
|
51
|
+
and redraws for you: each redraw clears the axes, applies the theme as
|
|
52
|
+
matplotlib settings — including a semantic accent color cycle so multiple
|
|
53
|
+
series are on-brand — then calls your ``render``. It re-renders when the
|
|
54
|
+
theme changes or the bound signal / data source updates::
|
|
55
|
+
|
|
56
|
+
count = bs.Signal(20)
|
|
57
|
+
def render(ax, n):
|
|
58
|
+
ax.plot(range(n), [i * i for i in range(n)])
|
|
59
|
+
bs.Chart(render=render, signal=count) # redraws when `count` changes
|
|
60
|
+
|
|
61
|
+
With ``data_source=``, ``render`` receives the source's records (a list of
|
|
62
|
+
dicts) and the chart re-renders whenever the source changes — so a chart
|
|
63
|
+
and a `DataTable` can share one source and stay in sync.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
figure: The matplotlib `Figure` to display (figure-host mode). Omit to
|
|
67
|
+
start empty, or when using ``render``.
|
|
68
|
+
render: A drawing callback for managed mode, called as ``render(ax)`` or
|
|
69
|
+
``render(ax, data)`` where `data` is the bound signal value(s). The
|
|
70
|
+
chart clears and re-themes the axes before each call, so just draw.
|
|
71
|
+
signal: A `bootstack.Signal` (or a list of them) whose value is passed to
|
|
72
|
+
``render`` as `data`; the chart re-renders when it changes. Requires
|
|
73
|
+
``render``. Mutually exclusive with ``data_source``.
|
|
74
|
+
data_source: A data source (any `bootstack.data` source) to plot. Its
|
|
75
|
+
records are passed to ``render`` as `data` (a list of dicts), and the
|
|
76
|
+
chart re-renders whenever the source changes — so a chart and a
|
|
77
|
+
`DataTable` can share one source and stay in sync. Reads all rows
|
|
78
|
+
matching the source's current ``where``/``order``, so filter or sort
|
|
79
|
+
the source to scope or shape what is plotted. Requires ``render``;
|
|
80
|
+
mutually exclusive with ``signal``.
|
|
81
|
+
debounce: Milliseconds to coalesce rapid signal changes before
|
|
82
|
+
re-rendering. ``0`` (default) re-renders on every change.
|
|
83
|
+
toolbar: Show a themed navigation toolbar above the chart. ``True``
|
|
84
|
+
includes all standard tools — ``home``, ``back``, ``forward``,
|
|
85
|
+
``pan``, ``zoom``, ``save``; pass a list to choose a subset in order
|
|
86
|
+
(for example ``["pan", "zoom", "save"]``), or ``[]`` for an empty bar
|
|
87
|
+
you fill yourself. Defaults to ``False`` (no toolbar). The toolbar
|
|
88
|
+
drives matplotlib's own navigation, so pan and zoom work on any
|
|
89
|
+
embedded figure; save routes through bootstack's file dialog. Add
|
|
90
|
+
your own buttons through the :attr:`toolbar` property.
|
|
91
|
+
themed: Whether bootstack colors your data series. ``True`` (default)
|
|
92
|
+
applies the semantic accent color cycle (and seaborn palette) so
|
|
93
|
+
multiple series are on-brand. Pass ``False`` to keep your own series
|
|
94
|
+
colors — the chart's *chrome* (background, axes, text, ticks, grid)
|
|
95
|
+
still tracks the theme so it fits the app, but the accent cycle and
|
|
96
|
+
seaborn seeding are not imposed, leaving data colors to you (or to
|
|
97
|
+
your own matplotlib style). Per-series colors you set explicitly
|
|
98
|
+
always win regardless of this flag.
|
|
99
|
+
seaborn_desat: How much to soften the accent colors when seeding
|
|
100
|
+
seaborn's palette, in ``[0, 1]`` (seaborn's own ``desat``). Defaults
|
|
101
|
+
to ``0.75`` — seaborn plots are usually area-filled, where the full
|
|
102
|
+
accent saturation reads heavy, so the seeded palette is muted to suit
|
|
103
|
+
its aesthetic while staying on-brand. ``1.0`` keeps the accents fully
|
|
104
|
+
saturated. Only affects seaborn (the matplotlib line cycle stays
|
|
105
|
+
vivid) and only when ``themed=True``.
|
|
106
|
+
parent: Explicit parent widget. If omitted, the current context-stack
|
|
107
|
+
container is used.
|
|
108
|
+
**kwargs: Layout placement options applied by the parent container
|
|
109
|
+
(e.g. `grow`, `horizontal`, `row`, `column`), plus container styling
|
|
110
|
+
such as `surface` and `padding`. See :doc:`/tasks/layout`.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
_internal_class = _InternalChart
|
|
114
|
+
|
|
115
|
+
def __init__(
|
|
116
|
+
self,
|
|
117
|
+
figure: Any = None,
|
|
118
|
+
*,
|
|
119
|
+
render: Callable | None = None,
|
|
120
|
+
signal: Any = None,
|
|
121
|
+
data_source: Any = None,
|
|
122
|
+
debounce: int = 0,
|
|
123
|
+
toolbar: bool | list[str] = False,
|
|
124
|
+
themed: bool = True,
|
|
125
|
+
seaborn_desat: float = 0.75,
|
|
126
|
+
parent: Any = None,
|
|
127
|
+
**kwargs: Any,
|
|
128
|
+
) -> None:
|
|
129
|
+
_require_matplotlib()
|
|
130
|
+
|
|
131
|
+
if signal is None:
|
|
132
|
+
signals: list[Any] = []
|
|
133
|
+
elif isinstance(signal, (list, tuple)):
|
|
134
|
+
signals = list(signal)
|
|
135
|
+
else:
|
|
136
|
+
signals = [signal]
|
|
137
|
+
if signals and render is None:
|
|
138
|
+
raise BootstackError("Chart(signal=...) requires render= to draw the signal value.")
|
|
139
|
+
if data_source is not None and render is None:
|
|
140
|
+
raise BootstackError("Chart(data_source=...) requires render= to plot the rows.")
|
|
141
|
+
if data_source is not None and signals:
|
|
142
|
+
raise BootstackError("Chart accepts either data_source= or signal=, not both.")
|
|
143
|
+
|
|
144
|
+
self._parent = self._resolve_parent(parent)
|
|
145
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
146
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
147
|
+
|
|
148
|
+
internal_kwargs: dict[str, Any] = {
|
|
149
|
+
"figure": figure,
|
|
150
|
+
"render": render,
|
|
151
|
+
"signals": signals,
|
|
152
|
+
"data_source": data_source,
|
|
153
|
+
"debounce": debounce,
|
|
154
|
+
"toolbar": toolbar,
|
|
155
|
+
"themed": themed,
|
|
156
|
+
"seaborn_desat": seaborn_desat,
|
|
157
|
+
}
|
|
158
|
+
internal_kwargs.update(kwargs)
|
|
159
|
+
self._internal = self._internal_class(tk_master, **internal_kwargs)
|
|
160
|
+
self._toolbar_wrapper: Any = None
|
|
161
|
+
self._attach_to_parent(layout_kw)
|
|
162
|
+
|
|
163
|
+
# ----- Properties -----
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def figure(self) -> Any:
|
|
167
|
+
"""The embedded matplotlib `Figure`.
|
|
168
|
+
|
|
169
|
+
Assign a new `Figure` to swap what is displayed; the old canvas is torn
|
|
170
|
+
down and the new figure is themed and drawn.
|
|
171
|
+
"""
|
|
172
|
+
return self._internal._figure
|
|
173
|
+
|
|
174
|
+
@figure.setter
|
|
175
|
+
def figure(self, value: Any) -> None:
|
|
176
|
+
self._internal.set_figure(value)
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def toolbar(self) -> Any:
|
|
180
|
+
"""The navigation toolbar, for adding your own buttons.
|
|
181
|
+
|
|
182
|
+
Available only when the chart was created with ``toolbar=True``. Returns a
|
|
183
|
+
`bootstack.Toolbar` whose built-in navigation buttons (home, back,
|
|
184
|
+
forward, pan, zoom, save) sit on the left and the coordinate readout on
|
|
185
|
+
the right; anything you add lands beside the built-in tools::
|
|
186
|
+
|
|
187
|
+
chart = bs.Chart(render=render, signal=sig, toolbar=True)
|
|
188
|
+
chart.toolbar.add_divider()
|
|
189
|
+
chart.toolbar.add_button(icon="arrow-clockwise", on_click=refresh)
|
|
190
|
+
chart.toolbar.add_widget(bs.ThemeToggle)
|
|
191
|
+
|
|
192
|
+
It is the full `Toolbar` surface — ``add_button``, ``add_divider``,
|
|
193
|
+
``add_widget``, and the rest all work.
|
|
194
|
+
|
|
195
|
+
Raises:
|
|
196
|
+
BootstackError: if the chart was created without ``toolbar=True``.
|
|
197
|
+
"""
|
|
198
|
+
navbar = self._internal._navbar
|
|
199
|
+
if navbar is None:
|
|
200
|
+
raise BootstackError(
|
|
201
|
+
"Chart.toolbar requires toolbar=True; this chart has no toolbar."
|
|
202
|
+
)
|
|
203
|
+
# Re-wrap if a figure swap rebuilt the underlying bar.
|
|
204
|
+
wrapper = self._toolbar_wrapper
|
|
205
|
+
if wrapper is None or wrapper._internal is not navbar:
|
|
206
|
+
from bootstack.widgets.toolbar import Toolbar
|
|
207
|
+
|
|
208
|
+
wrapper = Toolbar(_toolbar=navbar)
|
|
209
|
+
self._toolbar_wrapper = wrapper
|
|
210
|
+
return wrapper
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def ax(self) -> Any:
|
|
214
|
+
"""The figure's primary `Axes`, creating one if the figure is empty.
|
|
215
|
+
|
|
216
|
+
A convenience for the common single-plot case::
|
|
217
|
+
|
|
218
|
+
chart = bs.Chart()
|
|
219
|
+
chart.ax.plot([1, 2, 3])
|
|
220
|
+
chart.draw()
|
|
221
|
+
"""
|
|
222
|
+
fig = self._internal._figure
|
|
223
|
+
return fig.axes[0] if fig.axes else fig.add_subplot(111)
|
|
224
|
+
|
|
225
|
+
# ----- Methods -----
|
|
226
|
+
|
|
227
|
+
def draw(self) -> None:
|
|
228
|
+
"""Redraw the figure after mutating it in place.
|
|
229
|
+
|
|
230
|
+
Call this after drawing onto `ax` (or the figure) so the change appears.
|
|
231
|
+
Theme changes redraw automatically — this is for your own updates.
|
|
232
|
+
"""
|
|
233
|
+
self._internal.draw()
|
|
234
|
+
|
|
235
|
+
def animate(
|
|
236
|
+
self,
|
|
237
|
+
setup: Callable,
|
|
238
|
+
update: Callable,
|
|
239
|
+
*,
|
|
240
|
+
interval: int = 30,
|
|
241
|
+
frames: Any = None,
|
|
242
|
+
) -> "ChartAnimation":
|
|
243
|
+
"""Drive a smooth, high-performance animation via blitting.
|
|
244
|
+
|
|
245
|
+
Unlike the managed ``render=`` path (which rebuilds the whole figure on
|
|
246
|
+
each update — right for occasional data changes, but limited to ~30 fps),
|
|
247
|
+
animation updates artists in place and redraws only them over a cached
|
|
248
|
+
background, sustaining high frame rates.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
setup: Called once with the themed `Axes`. Create your artists with
|
|
252
|
+
initial or empty data and set FIXED axis limits — blitting needs
|
|
253
|
+
stable axes — then return the artist, or a list of artists, to
|
|
254
|
+
animate.
|
|
255
|
+
update: Called every frame as ``update(value, artist)`` (or
|
|
256
|
+
``update(value)``), where `artist` is whatever `setup` returned.
|
|
257
|
+
For a continuous animation (the default) `value` is the elapsed
|
|
258
|
+
time in **seconds** since the animation started — drive motion by
|
|
259
|
+
this and the apparent speed stays constant even when frame timing
|
|
260
|
+
jitters. If you pass `frames`, `value` is the current frame value
|
|
261
|
+
instead. Mutate the artist's data in place; do not create new
|
|
262
|
+
artists or rescale the axes.
|
|
263
|
+
interval: Target milliseconds between frames. Default 30 (~33 fps).
|
|
264
|
+
frames: An iterable of frame values to step through fixed data, or
|
|
265
|
+
None (default) for a continuous, time-driven animation.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
A `ChartAnimation` handle — call `stop()` / `start()` to control it.
|
|
269
|
+
The animation stops automatically when the widget is destroyed.
|
|
270
|
+
"""
|
|
271
|
+
self._internal.animate(setup, update, interval=interval, frames=frames)
|
|
272
|
+
return ChartAnimation(self._internal)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class ChartAnimation:
|
|
276
|
+
"""Handle for a running `Chart` animation.
|
|
277
|
+
|
|
278
|
+
Returned by `Chart.animate`. Use it to pause and resume the animation or
|
|
279
|
+
query whether it is playing.
|
|
280
|
+
|
|
281
|
+
The animation is also gated on visibility: it pauses automatically when the
|
|
282
|
+
chart is hidden (a switched-away tab, a scrolled-off region, a minimized
|
|
283
|
+
window) or fully covered by another window, and resumes when shown — so an
|
|
284
|
+
off-screen chart on a dashboard costs nothing. `stop` / `start` set your
|
|
285
|
+
intent on top of that gate.
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
def __init__(self, chart: Any) -> None:
|
|
289
|
+
self._chart = chart
|
|
290
|
+
|
|
291
|
+
def stop(self) -> None:
|
|
292
|
+
"""Pause the animation; the last drawn frame stays on screen."""
|
|
293
|
+
self._chart._set_anim_wanted(False)
|
|
294
|
+
|
|
295
|
+
def start(self) -> None:
|
|
296
|
+
"""Resume the animation (subject to the chart being visible)."""
|
|
297
|
+
self._chart._set_anim_wanted(True)
|
|
298
|
+
|
|
299
|
+
@property
|
|
300
|
+
def running(self) -> bool:
|
|
301
|
+
"""Whether the animation is currently playing (wanted and visible)."""
|
|
302
|
+
return bool(self._chart._anim_wanted and self._chart._anim_visible())
|