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,579 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import tkinter
|
|
4
|
+
from typing import overload, Any, Callable, Literal
|
|
5
|
+
|
|
6
|
+
from bootstack.widgets._impl.composites.expander import Expander as _InternalExpander
|
|
7
|
+
from bootstack.widgets._impl.composites.accordion import Accordion as _InternalAccordion
|
|
8
|
+
from bootstack.widgets._impl.primitives.flexframe import FlexFrame
|
|
9
|
+
from bootstack.widgets._impl.primitives.gridframe import GridFrame
|
|
10
|
+
from bootstack.widgets._core.container import (
|
|
11
|
+
PublicContainer, GRID_KEYS, grid_sticky, place_flex_child,
|
|
12
|
+
_reject_legacy_child_kwargs, _expand_margin,
|
|
13
|
+
)
|
|
14
|
+
from bootstack.widgets._core.base import PublicWidgetBase
|
|
15
|
+
from bootstack.widgets._core.context import push_container, pop_container
|
|
16
|
+
from bootstack.widgets._core.events import register_widget_events
|
|
17
|
+
from bootstack.events import AccordionChangeEvent, Subscription, ToggleEvent
|
|
18
|
+
from bootstack.streams import Stream
|
|
19
|
+
from bootstack.widgets.types import (
|
|
20
|
+
Event, AccentToken, Padding, LayoutKind, AutoFlow, AccordionVariant,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
_EXPANDER_EVENTS: dict[str, str] = {
|
|
24
|
+
"expand": "<<Toggle>>",
|
|
25
|
+
"collapse": "<<Toggle>>",
|
|
26
|
+
"toggle": "<<Toggle>>",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_ACCORDION_EVENTS: dict[str, str] = {
|
|
30
|
+
"change": "<<AccordionChange>>",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Expander(PublicContainer):
|
|
35
|
+
"""A collapsible container with a clickable header.
|
|
36
|
+
|
|
37
|
+
Children placed inside the context block go into the expandable body,
|
|
38
|
+
laid out according to `layout`.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
title: Header text shown in the clickable header bar.
|
|
42
|
+
layout: Internal layout for the body. One of `'column'` (default),
|
|
43
|
+
`'row'`, or `'grid'`.
|
|
44
|
+
padding: Space between the expander border and its body content, in
|
|
45
|
+
pixels. Accepts a single int or a `(x, y)` tuple.
|
|
46
|
+
gap: Space between body children in pixels. Default `0`.
|
|
47
|
+
horizontal_items: How body children sit on the horizontal axis — edge
|
|
48
|
+
values `'left'`/`'center'`/`'right'`/`'stretch'`, plus
|
|
49
|
+
`'space-*'` when horizontal is the stacking axis. Default
|
|
50
|
+
`'stretch'` for `'grid'`, else `'left'`.
|
|
51
|
+
vertical_items: How body children sit on the vertical axis — edge values
|
|
52
|
+
`'top'`/`'center'`/`'bottom'`/`'stretch'`, plus `'space-*'`
|
|
53
|
+
when vertical is the stacking axis. Default `'stretch'` for
|
|
54
|
+
`'grid'`, else `'top'`.
|
|
55
|
+
grow_items: For `'column'`/`'row'`, when `True` every body
|
|
56
|
+
child grows equally to share the main axis. Default `False`.
|
|
57
|
+
columns: Column size definitions for `'grid'` layout. An integer
|
|
58
|
+
creates that many equal-weight columns; a list of ints sets
|
|
59
|
+
per-column weights. Default `None`.
|
|
60
|
+
rows: Row size definitions for `'grid'` layout. Same format as
|
|
61
|
+
`columns`. Default `None`.
|
|
62
|
+
auto_flow: Grid placement direction — `'row'` (default) or
|
|
63
|
+
`'column'`.
|
|
64
|
+
expanded: If `True` (default), the body is visible on creation.
|
|
65
|
+
collapsible: If `True` (default), clicking the header toggles the
|
|
66
|
+
body. If `False`, the chevron is hidden and the body stays open.
|
|
67
|
+
show_border: If `True`, draws a border around the entire widget.
|
|
68
|
+
Default `False`.
|
|
69
|
+
variant: Header style. Defaults to `None` (the default header reads
|
|
70
|
+
as a ghost/transparent bar).
|
|
71
|
+
icon: Icon name or spec displayed to the left of the title.
|
|
72
|
+
icon_position: Side on which the collapse chevron appears —
|
|
73
|
+
`'after'` (default, right of title) or `'before'` (left).
|
|
74
|
+
highlight: If `True`, the header shows a selected visual state while
|
|
75
|
+
the body is expanded. Default `False`.
|
|
76
|
+
accent: Color intent token for the header. Defaults to `None`
|
|
77
|
+
(theme default).
|
|
78
|
+
parent: Explicit parent container. Omit to use the current context.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
title: str = "",
|
|
84
|
+
*,
|
|
85
|
+
layout: LayoutKind = "column",
|
|
86
|
+
padding: Padding | None = None,
|
|
87
|
+
gap: int = 0,
|
|
88
|
+
horizontal_items: str | None = None,
|
|
89
|
+
vertical_items: str | None = None,
|
|
90
|
+
grow_items: bool = False,
|
|
91
|
+
columns: int | list[int | str] | None = None,
|
|
92
|
+
rows: int | list[int | str] | None = None,
|
|
93
|
+
auto_flow: AutoFlow = "row",
|
|
94
|
+
expanded: bool = True,
|
|
95
|
+
collapsible: bool = True,
|
|
96
|
+
show_border: bool = False,
|
|
97
|
+
variant: AccordionVariant | None = None,
|
|
98
|
+
icon: str | None = None,
|
|
99
|
+
icon_position: Literal["before", "after"] = "after",
|
|
100
|
+
highlight: bool = False,
|
|
101
|
+
accent: AccentToken | str | None = None,
|
|
102
|
+
parent: Any = None,
|
|
103
|
+
**kwargs: Any,
|
|
104
|
+
) -> None:
|
|
105
|
+
self._parent = self._resolve_parent(parent)
|
|
106
|
+
self._layout = layout
|
|
107
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
108
|
+
layout_kw.setdefault("horizontal", "stretch")
|
|
109
|
+
|
|
110
|
+
if horizontal_items is None:
|
|
111
|
+
horizontal_items = (
|
|
112
|
+
"stretch" if layout == "grid"
|
|
113
|
+
else "center" if layout == "column" else "left"
|
|
114
|
+
)
|
|
115
|
+
if vertical_items is None:
|
|
116
|
+
vertical_items = (
|
|
117
|
+
"stretch" if layout == "grid"
|
|
118
|
+
else "center" if layout == "row" else "top"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
122
|
+
|
|
123
|
+
internal_kwargs: dict[str, Any] = {
|
|
124
|
+
"title": title,
|
|
125
|
+
"expanded": expanded,
|
|
126
|
+
"collapsible": collapsible,
|
|
127
|
+
"icon_position": icon_position,
|
|
128
|
+
"highlight": highlight,
|
|
129
|
+
}
|
|
130
|
+
if show_border:
|
|
131
|
+
internal_kwargs["show_border"] = True
|
|
132
|
+
if variant is not None:
|
|
133
|
+
internal_kwargs["variant"] = variant
|
|
134
|
+
if icon is not None:
|
|
135
|
+
internal_kwargs["icon"] = icon
|
|
136
|
+
if accent is not None:
|
|
137
|
+
internal_kwargs["accent"] = accent
|
|
138
|
+
|
|
139
|
+
self._internal = _InternalExpander(tk_master, **internal_kwargs)
|
|
140
|
+
|
|
141
|
+
content = self._internal._content_frame
|
|
142
|
+
if layout in ("column", "row"):
|
|
143
|
+
self._layout_frame = FlexFrame(
|
|
144
|
+
content,
|
|
145
|
+
direction="vertical" if layout == "column" else "horizontal",
|
|
146
|
+
padding=padding,
|
|
147
|
+
gap=gap,
|
|
148
|
+
horizontal_items=horizontal_items,
|
|
149
|
+
vertical_items=vertical_items,
|
|
150
|
+
grow_items=grow_items,
|
|
151
|
+
)
|
|
152
|
+
elif layout == "grid":
|
|
153
|
+
self._layout_frame = GridFrame(
|
|
154
|
+
content,
|
|
155
|
+
columns=columns,
|
|
156
|
+
rows=rows,
|
|
157
|
+
padding=padding,
|
|
158
|
+
gap=gap,
|
|
159
|
+
auto_flow=auto_flow,
|
|
160
|
+
)
|
|
161
|
+
else:
|
|
162
|
+
raise ValueError(
|
|
163
|
+
f"Expander layout must be 'column', 'row', or 'grid', got {layout!r}"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
self._horizontal_items = horizontal_items
|
|
167
|
+
self._vertical_items = vertical_items
|
|
168
|
+
self._layout_frame.pack(fill="both", expand=True)
|
|
169
|
+
self._attach_to_parent(layout_kw)
|
|
170
|
+
|
|
171
|
+
def _child_master(self) -> tkinter.Misc:
|
|
172
|
+
return self._layout_frame
|
|
173
|
+
|
|
174
|
+
def guide_layout(self, child: PublicWidgetBase, **layout_kw: Any) -> None:
|
|
175
|
+
if self._layout == "grid":
|
|
176
|
+
_reject_legacy_child_kwargs(layout_kw, "Expander")
|
|
177
|
+
_expand_margin(layout_kw)
|
|
178
|
+
options = {k: v for k, v in layout_kw.items() if k in GRID_KEYS}
|
|
179
|
+
h = layout_kw.get("horizontal") or self._horizontal_items
|
|
180
|
+
v = layout_kw.get("vertical") or self._vertical_items
|
|
181
|
+
options["sticky"] = grid_sticky(h, v)
|
|
182
|
+
child._internal.grid(in_=self._child_master(), **options)
|
|
183
|
+
return
|
|
184
|
+
place_flex_child(self._layout_frame, child, layout_kw, "Expander")
|
|
185
|
+
|
|
186
|
+
# ----- Properties -----
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def expanded(self) -> bool:
|
|
190
|
+
return self._internal._expanded
|
|
191
|
+
|
|
192
|
+
# ----- Methods -----
|
|
193
|
+
|
|
194
|
+
def expand(self) -> None:
|
|
195
|
+
"""Expand the body."""
|
|
196
|
+
self._internal.expand()
|
|
197
|
+
|
|
198
|
+
def collapse(self) -> None:
|
|
199
|
+
"""Collapse the body."""
|
|
200
|
+
self._internal.collapse()
|
|
201
|
+
|
|
202
|
+
def toggle(self) -> None:
|
|
203
|
+
"""Toggle between expanded and collapsed."""
|
|
204
|
+
self._internal.toggle()
|
|
205
|
+
|
|
206
|
+
# ----- Event shorthands -----
|
|
207
|
+
|
|
208
|
+
@overload
|
|
209
|
+
def on_toggle(self) -> Stream: ...
|
|
210
|
+
@overload
|
|
211
|
+
def on_toggle(self, handler: Callable[[ToggleEvent], Any]) -> Subscription: ...
|
|
212
|
+
def on_toggle(self, handler: Callable[[ToggleEvent], Any] | None = None) -> Stream | Subscription:
|
|
213
|
+
"""Register a callback fired when the expander is expanded or collapsed.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Subscription — call `.cancel()` to unsubscribe.
|
|
217
|
+
"""
|
|
218
|
+
return self.on("toggle", handler)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
register_widget_events(Expander, _EXPANDER_EVENTS)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class AccordionSection:
|
|
225
|
+
"""A handle for one accordion section — both a layout context and a live controller.
|
|
226
|
+
|
|
227
|
+
Returned by `Accordion.add()` and by `Accordion.item()` / `items()`. Use it
|
|
228
|
+
as a `with` block to place child widgets inside the section, and read or call
|
|
229
|
+
`key` / `title` / `expanded` / `expand()` / `collapse()` / `toggle()` to
|
|
230
|
+
inspect or drive the section afterward.
|
|
231
|
+
|
|
232
|
+
As a context manager it accepts the same layout kwargs as the standalone
|
|
233
|
+
layout containers — `layout=`, `gap=`, `horizontal_items=`, `vertical_items=`,
|
|
234
|
+
`grow_items=`, `columns=`, `rows=`, `auto_flow=`.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
def __init__(
|
|
238
|
+
self,
|
|
239
|
+
internal_expander: _InternalExpander,
|
|
240
|
+
*,
|
|
241
|
+
key: str,
|
|
242
|
+
layout: LayoutKind = "column",
|
|
243
|
+
padding: Padding | None = None,
|
|
244
|
+
gap: int = 0,
|
|
245
|
+
horizontal_items: str | None = None,
|
|
246
|
+
vertical_items: str | None = None,
|
|
247
|
+
grow_items: bool = False,
|
|
248
|
+
columns: int | list[int | str] | None = None,
|
|
249
|
+
rows: int | list[int | str] | None = None,
|
|
250
|
+
auto_flow: AutoFlow = "row",
|
|
251
|
+
) -> None:
|
|
252
|
+
self._expander = internal_expander
|
|
253
|
+
self._key = key
|
|
254
|
+
self._layout = layout
|
|
255
|
+
|
|
256
|
+
if horizontal_items is None:
|
|
257
|
+
horizontal_items = (
|
|
258
|
+
"stretch" if layout == "grid"
|
|
259
|
+
else "center" if layout == "column" else "left"
|
|
260
|
+
)
|
|
261
|
+
if vertical_items is None:
|
|
262
|
+
vertical_items = (
|
|
263
|
+
"stretch" if layout == "grid"
|
|
264
|
+
else "center" if layout == "row" else "top"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
content = internal_expander._content_frame
|
|
268
|
+
if layout in ("column", "row"):
|
|
269
|
+
self._layout_frame = FlexFrame(
|
|
270
|
+
content,
|
|
271
|
+
direction="vertical" if layout == "column" else "horizontal",
|
|
272
|
+
padding=padding,
|
|
273
|
+
gap=gap,
|
|
274
|
+
horizontal_items=horizontal_items,
|
|
275
|
+
vertical_items=vertical_items,
|
|
276
|
+
grow_items=grow_items,
|
|
277
|
+
)
|
|
278
|
+
elif layout == "grid":
|
|
279
|
+
self._layout_frame = GridFrame(
|
|
280
|
+
content,
|
|
281
|
+
columns=columns,
|
|
282
|
+
rows=rows,
|
|
283
|
+
padding=padding,
|
|
284
|
+
gap=gap,
|
|
285
|
+
auto_flow=auto_flow,
|
|
286
|
+
)
|
|
287
|
+
else:
|
|
288
|
+
raise ValueError(
|
|
289
|
+
f"AccordionSection layout must be 'column', 'row', or 'grid', got {layout!r}"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
self._horizontal_items = horizontal_items
|
|
293
|
+
self._vertical_items = vertical_items
|
|
294
|
+
self._layout_frame.pack(fill="both", expand=True)
|
|
295
|
+
|
|
296
|
+
def _child_master(self) -> tkinter.Misc:
|
|
297
|
+
return self._layout_frame
|
|
298
|
+
|
|
299
|
+
def guide_layout(self, child: PublicWidgetBase, **layout_kw: Any) -> None:
|
|
300
|
+
if self._layout == "grid":
|
|
301
|
+
_reject_legacy_child_kwargs(layout_kw, "AccordionSection")
|
|
302
|
+
_expand_margin(layout_kw)
|
|
303
|
+
options = {k: v for k, v in layout_kw.items() if k in GRID_KEYS}
|
|
304
|
+
h = layout_kw.get("horizontal") or self._horizontal_items
|
|
305
|
+
v = layout_kw.get("vertical") or self._vertical_items
|
|
306
|
+
options["sticky"] = grid_sticky(h, v)
|
|
307
|
+
child._internal.grid(in_=self._child_master(), **options)
|
|
308
|
+
return
|
|
309
|
+
place_flex_child(self._layout_frame, child, layout_kw, "AccordionSection")
|
|
310
|
+
|
|
311
|
+
# ----- Section identity, state, and control -----
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def key(self) -> str:
|
|
315
|
+
"""The section's unique key, used with `Accordion.item()`/`remove()`."""
|
|
316
|
+
return self._key
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def title(self) -> str:
|
|
320
|
+
"""The section header text. Assigning a new value relabels the header."""
|
|
321
|
+
return self._expander._title
|
|
322
|
+
|
|
323
|
+
@title.setter
|
|
324
|
+
def title(self, value: str) -> None:
|
|
325
|
+
self._expander.configure(title=value)
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
def expanded(self) -> bool:
|
|
329
|
+
"""Whether the section is currently expanded."""
|
|
330
|
+
return self._expander._expanded
|
|
331
|
+
|
|
332
|
+
def expand(self) -> None:
|
|
333
|
+
"""Expand this section."""
|
|
334
|
+
self._expander.expand()
|
|
335
|
+
|
|
336
|
+
def collapse(self) -> None:
|
|
337
|
+
"""Collapse this section."""
|
|
338
|
+
self._expander.collapse()
|
|
339
|
+
|
|
340
|
+
def toggle(self) -> None:
|
|
341
|
+
"""Toggle this section between expanded and collapsed."""
|
|
342
|
+
self._expander.toggle()
|
|
343
|
+
|
|
344
|
+
def __enter__(self) -> "AccordionSection":
|
|
345
|
+
push_container(self)
|
|
346
|
+
return self
|
|
347
|
+
|
|
348
|
+
def __exit__(self, exc_type, exc, tb) -> None:
|
|
349
|
+
pop_container(self)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class Accordion(PublicWidgetBase):
|
|
353
|
+
"""A list of collapsible sections, optionally limited to one open at a time.
|
|
354
|
+
|
|
355
|
+
Each section is added with `add()`, which returns an `AccordionSection`
|
|
356
|
+
context manager for placing child widgets inside that section.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
allow_multiple: If `True`, multiple sections can be expanded at
|
|
360
|
+
once. Defaults to `False` (only one section open at a time).
|
|
361
|
+
allow_collapse_all: If `True` (default), every section can be
|
|
362
|
+
collapsed. If `False`, at least one section stays open.
|
|
363
|
+
show_separators: If `True`, draws a separator line between sections.
|
|
364
|
+
Defaults to `True`.
|
|
365
|
+
show_border: If `True`, wraps the accordion in a bordered frame.
|
|
366
|
+
Defaults to `True`.
|
|
367
|
+
variant: Style variant applied to each section header. Defaults to
|
|
368
|
+
`None` (the default header reads as a ghost/transparent bar).
|
|
369
|
+
accent: Color intent token applied to all section headers. Defaults
|
|
370
|
+
to `None` (theme default).
|
|
371
|
+
padding: Space between the outer border and the sections, in pixels.
|
|
372
|
+
Defaults to `None`.
|
|
373
|
+
parent: Explicit parent container. Omit to use the current context.
|
|
374
|
+
**kwargs: Layout placement options applied by the parent container —
|
|
375
|
+
`fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
|
|
376
|
+
See :doc:`/tasks/layout`.
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
def __init__(
|
|
380
|
+
self,
|
|
381
|
+
*,
|
|
382
|
+
allow_multiple: bool = False,
|
|
383
|
+
allow_collapse_all: bool = True,
|
|
384
|
+
show_separators: bool = True,
|
|
385
|
+
show_border: bool = True,
|
|
386
|
+
variant: AccordionVariant | None = None,
|
|
387
|
+
accent: AccentToken | str | None = None,
|
|
388
|
+
padding: Padding | None = None,
|
|
389
|
+
parent: Any = None,
|
|
390
|
+
**kwargs: Any,
|
|
391
|
+
) -> None:
|
|
392
|
+
self._parent = self._resolve_parent(parent)
|
|
393
|
+
layout_kw = self._split_layout_kwargs(kwargs)
|
|
394
|
+
layout_kw.setdefault("horizontal", "stretch")
|
|
395
|
+
|
|
396
|
+
tk_master = self._parent._child_master() if self._parent else None
|
|
397
|
+
|
|
398
|
+
internal_kwargs: dict[str, Any] = {
|
|
399
|
+
"allow_multiple": allow_multiple,
|
|
400
|
+
"allow_collapse_all": allow_collapse_all,
|
|
401
|
+
"show_separators": show_separators,
|
|
402
|
+
}
|
|
403
|
+
if show_border:
|
|
404
|
+
internal_kwargs["show_border"] = True
|
|
405
|
+
if variant is not None:
|
|
406
|
+
internal_kwargs["variant"] = variant
|
|
407
|
+
if accent is not None:
|
|
408
|
+
internal_kwargs["accent"] = accent
|
|
409
|
+
if padding is not None:
|
|
410
|
+
internal_kwargs["padding"] = padding
|
|
411
|
+
|
|
412
|
+
self._sections: dict[str, AccordionSection] = {}
|
|
413
|
+
self._internal = _InternalAccordion(tk_master, **internal_kwargs)
|
|
414
|
+
self._attach_to_parent(layout_kw)
|
|
415
|
+
|
|
416
|
+
# ----- Section management -----
|
|
417
|
+
|
|
418
|
+
def remove(self, key: str) -> None:
|
|
419
|
+
"""Remove a section by key.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
key: The key assigned when the section was added.
|
|
423
|
+
"""
|
|
424
|
+
self._internal.remove(key)
|
|
425
|
+
self._sections.pop(key, None)
|
|
426
|
+
|
|
427
|
+
def item(self, key: str) -> AccordionSection:
|
|
428
|
+
"""Return the section handle for `key`.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
key: Section key.
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
The `AccordionSection` for that key — read `expanded`/`title` or call
|
|
435
|
+
`expand()`/`collapse()`/`toggle()` to drive it.
|
|
436
|
+
"""
|
|
437
|
+
return self._sections[key]
|
|
438
|
+
|
|
439
|
+
def items(self, expanded: bool | None = None) -> tuple[AccordionSection, ...]:
|
|
440
|
+
"""Return all section handles in insertion order, optionally filtered.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
expanded: If `True`, return only expanded sections. If `False`,
|
|
444
|
+
only collapsed. If `None` (default), return all.
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
A tuple of `AccordionSection` handles.
|
|
448
|
+
"""
|
|
449
|
+
sections = (self._sections[k] for k in self._internal.keys())
|
|
450
|
+
if expanded is None:
|
|
451
|
+
return tuple(sections)
|
|
452
|
+
return tuple(s for s in sections if s.expanded == expanded)
|
|
453
|
+
|
|
454
|
+
def keys(self) -> tuple[str, ...]:
|
|
455
|
+
"""Return all section keys in insertion order."""
|
|
456
|
+
return self._internal.keys()
|
|
457
|
+
|
|
458
|
+
def expand(self, key: str) -> None:
|
|
459
|
+
"""Expand the section identified by `key`.
|
|
460
|
+
|
|
461
|
+
Args:
|
|
462
|
+
key: Section key.
|
|
463
|
+
"""
|
|
464
|
+
self._internal.expand(key)
|
|
465
|
+
|
|
466
|
+
def collapse(self, key: str) -> None:
|
|
467
|
+
"""Collapse the section identified by `key`.
|
|
468
|
+
|
|
469
|
+
Args:
|
|
470
|
+
key: Section key.
|
|
471
|
+
"""
|
|
472
|
+
self._internal.collapse(key)
|
|
473
|
+
|
|
474
|
+
def expand_all(self) -> None:
|
|
475
|
+
"""Expand all sections."""
|
|
476
|
+
self._internal.expand_all()
|
|
477
|
+
|
|
478
|
+
def collapse_all(self) -> None:
|
|
479
|
+
"""Collapse all sections."""
|
|
480
|
+
self._internal.collapse_all()
|
|
481
|
+
|
|
482
|
+
# ----- Events -----
|
|
483
|
+
|
|
484
|
+
@overload
|
|
485
|
+
def on_change(self) -> Stream: ...
|
|
486
|
+
@overload
|
|
487
|
+
def on_change(self, handler: Callable[[AccordionChangeEvent], Any]) -> Subscription: ...
|
|
488
|
+
def on_change(self, handler: Callable[[AccordionChangeEvent], Any] | None = None) -> Stream | Subscription:
|
|
489
|
+
"""Register a callback fired when any section expands or collapses.
|
|
490
|
+
|
|
491
|
+
The handler receives an `AccordionChangeEvent`; `e.expanded` is the
|
|
492
|
+
tuple of currently expanded sections.
|
|
493
|
+
|
|
494
|
+
Returns:
|
|
495
|
+
`Subscription` (with handler) or `Stream` (without handler).
|
|
496
|
+
"""
|
|
497
|
+
return self.on("change", handler)
|
|
498
|
+
|
|
499
|
+
def add(
|
|
500
|
+
self,
|
|
501
|
+
title: str,
|
|
502
|
+
*,
|
|
503
|
+
key: str | None = None,
|
|
504
|
+
layout: LayoutKind = "column",
|
|
505
|
+
padding: Padding | None = 16,
|
|
506
|
+
gap: int = 0,
|
|
507
|
+
horizontal_items: str | None = None,
|
|
508
|
+
vertical_items: str | None = None,
|
|
509
|
+
grow_items: bool = False,
|
|
510
|
+
columns: int | list[int | str] | None = None,
|
|
511
|
+
rows: int | list[int | str] | None = None,
|
|
512
|
+
auto_flow: AutoFlow = "row",
|
|
513
|
+
expanded: bool | None = None,
|
|
514
|
+
icon: str | None = None,
|
|
515
|
+
) -> AccordionSection:
|
|
516
|
+
"""Add a section and return a context manager for placing its children.
|
|
517
|
+
|
|
518
|
+
Args:
|
|
519
|
+
title: Section header text.
|
|
520
|
+
key: Unique identifier used with `item()`, `expand()`, `collapse()`,
|
|
521
|
+
and `remove()`. Auto-generated if omitted.
|
|
522
|
+
layout: Body layout. Defaults to `'column'`.
|
|
523
|
+
padding: Space between the section border and its body, in pixels.
|
|
524
|
+
Defaults to `16`.
|
|
525
|
+
gap: Space between body children in pixels. Defaults to `0`.
|
|
526
|
+
horizontal_items: How body children sit on the horizontal axis — edge
|
|
527
|
+
values `'left'`/`'center'`/`'right'`/`'stretch'`, plus `'space-*'`
|
|
528
|
+
when horizontal is the stacking axis. Defaults to `'stretch'` in grid mode,
|
|
529
|
+
`'center'` in a column and `'left'` in a row.
|
|
530
|
+
vertical_items: How body children sit on the vertical axis — edge
|
|
531
|
+
values `'top'`/`'center'`/`'bottom'`/`'stretch'`, plus `'space-*'`
|
|
532
|
+
when vertical is the stacking axis. Defaults to `'stretch'` in grid mode,
|
|
533
|
+
`'center'` in a row and `'top'` in a column.
|
|
534
|
+
grow_items: For `'column'`/`'row'`, when `True` every body child
|
|
535
|
+
grows equally to share the main axis. Defaults to `False`.
|
|
536
|
+
columns: Column definitions for `'grid'` layout. An integer sets
|
|
537
|
+
the number of equal-weight columns; a list sets per-column
|
|
538
|
+
weights or sizes (e.g. `[1, 2, 'auto', '120px']`).
|
|
539
|
+
Defaults to `None`.
|
|
540
|
+
rows: Row definitions for `'grid'` layout. Defaults to `None`.
|
|
541
|
+
auto_flow: Grid placement direction. Defaults to `'row'`.
|
|
542
|
+
expanded: Whether the section starts expanded. Defaults to the
|
|
543
|
+
accordion's own default (collapsed when `allow_multiple=False`).
|
|
544
|
+
icon: Icon name or spec displayed in the section header.
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
`AccordionSection` — use as a context manager to place children.
|
|
548
|
+
"""
|
|
549
|
+
exp_kwargs: dict[str, Any] = {}
|
|
550
|
+
if key is not None:
|
|
551
|
+
exp_kwargs["key"] = key
|
|
552
|
+
if expanded is not None:
|
|
553
|
+
exp_kwargs["expanded"] = expanded
|
|
554
|
+
if icon is not None:
|
|
555
|
+
exp_kwargs["icon"] = icon
|
|
556
|
+
internal_exp = self._internal.add(title=title, **exp_kwargs)
|
|
557
|
+
# The internal accordion auto-generates a key when one is not supplied;
|
|
558
|
+
# recover the resolved key so the section handle can be looked up later.
|
|
559
|
+
resolved_key = next(
|
|
560
|
+
k for k, v in self._internal._expanders.items() if v is internal_exp
|
|
561
|
+
)
|
|
562
|
+
section = AccordionSection(
|
|
563
|
+
internal_exp,
|
|
564
|
+
key=resolved_key,
|
|
565
|
+
layout=layout,
|
|
566
|
+
padding=padding,
|
|
567
|
+
gap=gap,
|
|
568
|
+
horizontal_items=horizontal_items,
|
|
569
|
+
vertical_items=vertical_items,
|
|
570
|
+
grow_items=grow_items,
|
|
571
|
+
columns=columns,
|
|
572
|
+
rows=rows,
|
|
573
|
+
auto_flow=auto_flow,
|
|
574
|
+
)
|
|
575
|
+
self._sections[resolved_key] = section
|
|
576
|
+
return section
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
register_widget_events(Accordion, _ACCORDION_EVENTS)
|