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,345 @@
|
|
|
1
|
+
"""The static navigation panel — single-select items, headers, separators, footer.
|
|
2
|
+
|
|
3
|
+
`NavPanel` renders a flat, single-select list into a sidebar region: items in a
|
|
4
|
+
scrolling main area plus a pinned footer area. Each item is a `RadioToggle`
|
|
5
|
+
sharing one `Signal`, so single-select is the radio machinery itself — no
|
|
6
|
+
hand-rolled selection state. The items are styled via a native Toolbutton
|
|
7
|
+
**variant** (`nav-quiet` under a rail; `nav-pill` standalone is added later), so
|
|
8
|
+
the look is driven by the style engine, not custom composite state.
|
|
9
|
+
|
|
10
|
+
Selection truth still lives in the shell's `NavModel`: clicking an item reports
|
|
11
|
+
the key via the `on_select` callback; the shell decides what becomes active and
|
|
12
|
+
calls `select()` back (setting the shared signal) to reflect it.
|
|
13
|
+
|
|
14
|
+
Section headers are plain, non-interactive labels (they chunk a flat list and
|
|
15
|
+
hide on compaction). There is no built-in collapsible section — hiding/revealing
|
|
16
|
+
a sub-list is a content concern (compose `bs.Accordion` in a custom panel).
|
|
17
|
+
Compaction to icon-only is a native `-compound` toggle on each item
|
|
18
|
+
(`'left'` <-> `'image'`); headers and separators hide while compact.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from typing import Callable
|
|
24
|
+
|
|
25
|
+
from bootstack.signals import Signal
|
|
26
|
+
from bootstack.style.style import get_style
|
|
27
|
+
from bootstack.widgets._impl.primitives.frame import Frame
|
|
28
|
+
from bootstack.widgets._impl.primitives.radiotoggle import RadioToggle
|
|
29
|
+
from bootstack.widgets._impl.composites.scrollview import ScrollView
|
|
30
|
+
from bootstack.widgets._impl.composites.sidenav.header import SideNavHeader
|
|
31
|
+
from bootstack.widgets._impl.composites.sidenav.separator import SideNavSeparator
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Container-controlled spacing (the button's own size is the style's job).
|
|
35
|
+
_ITEM_GAP = 3 # vertical gap between nav buttons
|
|
36
|
+
_COMPACT_INSET = 6 # horizontal inset of the compact (rail-width) sidebar
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class NavPanel(Frame):
|
|
40
|
+
"""A flat, single-select list of navigation items with a pinned footer.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
master: Parent widget (a sidebar region).
|
|
44
|
+
on_select: Called with an item key when that item is clicked.
|
|
45
|
+
accent: Accent token for the active item.
|
|
46
|
+
variant: Toolbutton style variant for the items (the tier treatment) —
|
|
47
|
+
`'nav-quiet'` under a rail, `'nav-pill'` standalone.
|
|
48
|
+
surface: Surface token the items sit on (the sidebar region surface).
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
master,
|
|
54
|
+
*,
|
|
55
|
+
on_select: Callable[[str], None],
|
|
56
|
+
accent: str | None = None,
|
|
57
|
+
variant: str = "nav-quiet",
|
|
58
|
+
surface: str = "card",
|
|
59
|
+
selection: str = "ghost",
|
|
60
|
+
) -> None:
|
|
61
|
+
super().__init__(master, surface=surface)
|
|
62
|
+
self._on_select = on_select
|
|
63
|
+
self._accent = accent
|
|
64
|
+
self._variant = variant
|
|
65
|
+
self._surface = surface
|
|
66
|
+
self._selection = selection
|
|
67
|
+
self._items: dict[str, RadioToggle] = {}
|
|
68
|
+
self._compact = False
|
|
69
|
+
# Shared selection signal: value is the selected item key (radio
|
|
70
|
+
# single-select). "" is the sentinel for "nothing selected" (a Signal is
|
|
71
|
+
# typed by its initial value, so it can't hold None here).
|
|
72
|
+
self._signal: Signal = Signal("")
|
|
73
|
+
# Insertion-ordered main-area children (items, headers, separators) so
|
|
74
|
+
# compaction can re-pack them in order; footer items tracked separately.
|
|
75
|
+
self._main_children: list = []
|
|
76
|
+
self._footer_items: list = []
|
|
77
|
+
|
|
78
|
+
# Pill items are inset from the sidebar edges (the rounded pill needs
|
|
79
|
+
# breathing room from the container); quiet rows run full-width.
|
|
80
|
+
self._inset = 8 if variant == "nav-pill" else 0
|
|
81
|
+
self._current_inset = self._inset
|
|
82
|
+
|
|
83
|
+
# Footer pinned to the bottom; the item area scrolls in the space above it
|
|
84
|
+
# (a wheel-scrollable canvas with an auto-hiding bar — the footer itself
|
|
85
|
+
# never scrolls). The canvas background is painted to the sidebar surface
|
|
86
|
+
# so the area below short content doesn't flash the default canvas color.
|
|
87
|
+
self._footer = Frame(self, surface=surface)
|
|
88
|
+
self._footer.pack(side="bottom", fill="x")
|
|
89
|
+
# A divider above the footer, shown ONLY when the item area scrolls — so a
|
|
90
|
+
# pinned footer reads as its own band instead of abutting a clipped row.
|
|
91
|
+
# When everything fits it stays hidden (no needless chrome). The vertical
|
|
92
|
+
# padding gives the line breathing room from the last scrolled row above
|
|
93
|
+
# and the footer item below (a flush line reads as cramped).
|
|
94
|
+
self._footer_divider = SideNavSeparator(self, surface=surface, padding=(0, 8, 0, 8))
|
|
95
|
+
# Start with no gutter/bar; overflow detection switches it on only when the
|
|
96
|
+
# content is actually tall enough to scroll (see _update_overflow_state).
|
|
97
|
+
self._scroll = ScrollView(
|
|
98
|
+
self,
|
|
99
|
+
scroll_direction="vertical",
|
|
100
|
+
scrollbar_visibility="never",
|
|
101
|
+
scrollbar_variant="thin",
|
|
102
|
+
surface=surface,
|
|
103
|
+
)
|
|
104
|
+
self._scroll.pack(side="top", fill="both", expand=True)
|
|
105
|
+
self._main = self._scroll.add(surface=surface)
|
|
106
|
+
self._updating_overflow = False
|
|
107
|
+
self._paint_canvas_surface()
|
|
108
|
+
# Re-evaluate the gutter/bar + footer divider whenever the content height
|
|
109
|
+
# or viewport changes (items added/removed, sidebar resized, compaction).
|
|
110
|
+
self._scroll.canvas.bind("<Configure>", lambda _e: self._update_overflow_state(), add="+")
|
|
111
|
+
self._main.bind("<Configure>", lambda _e: self._update_overflow_state(), add="+")
|
|
112
|
+
self._apply_inset(self._inset)
|
|
113
|
+
|
|
114
|
+
def add_item(self, key: str, *, text: str = "", icon=None) -> RadioToggle:
|
|
115
|
+
"""Add a selectable item to the main area; wire its click to `on_select`."""
|
|
116
|
+
return self._add_item(self._main, key, text=text, icon=icon, footer=False)
|
|
117
|
+
|
|
118
|
+
def add_footer_item(self, key: str, *, text: str = "", icon=None) -> RadioToggle:
|
|
119
|
+
"""Add a selectable item pinned to the footer."""
|
|
120
|
+
return self._add_item(self._footer, key, text=text, icon=icon, footer=True)
|
|
121
|
+
|
|
122
|
+
def _add_item(self, parent: Frame, key: str, *, text: str, icon, footer: bool) -> RadioToggle:
|
|
123
|
+
if key in self._items:
|
|
124
|
+
raise ValueError(f"duplicate nav item key: {key!r}")
|
|
125
|
+
item = RadioToggle(
|
|
126
|
+
parent,
|
|
127
|
+
value=key,
|
|
128
|
+
signal=self._signal,
|
|
129
|
+
text=text,
|
|
130
|
+
icon=icon,
|
|
131
|
+
compound="image" if self._compact else "left",
|
|
132
|
+
accent=self._accent,
|
|
133
|
+
surface=self._surface,
|
|
134
|
+
variant=self._item_variant(),
|
|
135
|
+
style_options={"selection_style": self._selection},
|
|
136
|
+
)
|
|
137
|
+
item.pack(fill="x", pady=(0, _ITEM_GAP))
|
|
138
|
+
# Click reports the key to the shell (which drives NavModel). The radio
|
|
139
|
+
# also updates the shared signal on click; the shell reconciles via select().
|
|
140
|
+
item.bind("<Button-1>", lambda _e, k=key: self._on_select(k), add="+")
|
|
141
|
+
self._items[key] = item
|
|
142
|
+
(self._footer_items if footer else self._main_children).append(item)
|
|
143
|
+
if footer:
|
|
144
|
+
# A footer item may appear after the content is laid out; the divider
|
|
145
|
+
# gate depends on footer presence, so re-evaluate now.
|
|
146
|
+
self._update_overflow_state()
|
|
147
|
+
return item
|
|
148
|
+
|
|
149
|
+
def remove_item(self, key: str) -> None:
|
|
150
|
+
"""Remove and destroy an item by key (no error if absent)."""
|
|
151
|
+
item = self._items.pop(key, None)
|
|
152
|
+
if item is not None:
|
|
153
|
+
for tracker in (self._main_children, self._footer_items):
|
|
154
|
+
if item in tracker:
|
|
155
|
+
tracker.remove(item)
|
|
156
|
+
item.destroy()
|
|
157
|
+
if self._signal() == key:
|
|
158
|
+
self._signal.set("")
|
|
159
|
+
self._update_overflow_state()
|
|
160
|
+
|
|
161
|
+
def update_item(self, key: str, *, text: str | None = None, icon=None) -> None:
|
|
162
|
+
"""Update an existing item's label and/or icon in place."""
|
|
163
|
+
item = self._items.get(key)
|
|
164
|
+
if item is None:
|
|
165
|
+
return
|
|
166
|
+
if text is not None:
|
|
167
|
+
item.configure(text=text)
|
|
168
|
+
if icon is not None:
|
|
169
|
+
item.configure(icon=icon)
|
|
170
|
+
|
|
171
|
+
def add_header(self, text: str) -> SideNavHeader:
|
|
172
|
+
"""Add a plain section-label header to the main area.
|
|
173
|
+
|
|
174
|
+
A header is a quiet, non-interactive label that chunks the flat list; it
|
|
175
|
+
hides while the panel is compacted. (There is no collapsible-header
|
|
176
|
+
primitive — a collapsible sub-list is a content concern.)
|
|
177
|
+
|
|
178
|
+
Uses a tighter top margin than the stock `SideNavHeader` default — the
|
|
179
|
+
header alone carries enough separation, so a roomy top gap reads as
|
|
180
|
+
excess (especially when it follows an item).
|
|
181
|
+
"""
|
|
182
|
+
# (left, top, right, bottom) — aligned to the item icon column. A roomier
|
|
183
|
+
# top gap separates the new group from the one above; the small bottom gap
|
|
184
|
+
# keeps the header bound to its own items.
|
|
185
|
+
header = SideNavHeader(self._main, text=text, padding=(12, 16, 12, 4))
|
|
186
|
+
if not self._compact:
|
|
187
|
+
header.pack(fill="x")
|
|
188
|
+
self._main_children.append(header)
|
|
189
|
+
return header
|
|
190
|
+
|
|
191
|
+
def add_divider(self) -> SideNavSeparator:
|
|
192
|
+
"""Add a divider to the main area."""
|
|
193
|
+
sep = SideNavSeparator(self._main)
|
|
194
|
+
if not self._compact:
|
|
195
|
+
sep.pack(fill="x")
|
|
196
|
+
self._main_children.append(sep)
|
|
197
|
+
return sep
|
|
198
|
+
|
|
199
|
+
def _relayout_main(self) -> None:
|
|
200
|
+
"""Re-pack the main area in insertion order, honoring compact.
|
|
201
|
+
|
|
202
|
+
Compact renders items icon-only (`-compound='image'`) and hides headers
|
|
203
|
+
and separators (a label-less icon strip); expanded shows everything.
|
|
204
|
+
"""
|
|
205
|
+
for child in self._main_children:
|
|
206
|
+
child.pack_forget()
|
|
207
|
+
for child in self._main_children:
|
|
208
|
+
if isinstance(child, (SideNavHeader, SideNavSeparator)):
|
|
209
|
+
if not self._compact:
|
|
210
|
+
child.pack(fill="x")
|
|
211
|
+
else: # RadioToggle nav item
|
|
212
|
+
child.pack(fill="x", pady=(0, _ITEM_GAP))
|
|
213
|
+
|
|
214
|
+
def _item_variant(self) -> str:
|
|
215
|
+
"""The Toolbutton style variant for items in the current mode."""
|
|
216
|
+
return f"{self._variant}-compact" if self._compact else self._variant
|
|
217
|
+
|
|
218
|
+
def _apply_inset(self, inset: int) -> None:
|
|
219
|
+
"""Inset the scrolled item area + footer from the sidebar edges.
|
|
220
|
+
|
|
221
|
+
Pills need breathing room; quiet rows run flush (inset 0). The item area
|
|
222
|
+
is a canvas window (not pack-managed), so its inset is its own padding.
|
|
223
|
+
"""
|
|
224
|
+
self._current_inset = inset
|
|
225
|
+
self._apply_insets()
|
|
226
|
+
|
|
227
|
+
def _gutter(self) -> int:
|
|
228
|
+
"""Width reserved for the scrollbar while the content overflows (else 0)."""
|
|
229
|
+
if not self._content_overflows():
|
|
230
|
+
return 0
|
|
231
|
+
try:
|
|
232
|
+
w = self._scroll.vertical_scrollbar.winfo_reqwidth()
|
|
233
|
+
return w if w > 1 else 0
|
|
234
|
+
except Exception:
|
|
235
|
+
return 0
|
|
236
|
+
|
|
237
|
+
def _apply_insets(self) -> None:
|
|
238
|
+
"""Apply the content + footer insets, accounting for the scrollbar gutter.
|
|
239
|
+
|
|
240
|
+
The gutter sits WITHIN the right inset rather than adding to it, so the
|
|
241
|
+
right margin stays about the left inset (not inset + gutter). The content's
|
|
242
|
+
right padding is reduced by the gutter; the footer (not scrolled) reserves
|
|
243
|
+
max(inset, gutter) so a footer item's right edge still lines up with the
|
|
244
|
+
scrolled rows.
|
|
245
|
+
"""
|
|
246
|
+
inset = self._current_inset
|
|
247
|
+
gutter = self._gutter()
|
|
248
|
+
self._main.configure(padding=(inset, inset, max(inset - gutter, 0), 0))
|
|
249
|
+
self._footer.pack_configure(padx=(inset, max(inset, gutter)), pady=(0, inset))
|
|
250
|
+
|
|
251
|
+
def _paint_canvas_surface(self) -> None:
|
|
252
|
+
"""Match the scroll canvas background to the sidebar surface token."""
|
|
253
|
+
try:
|
|
254
|
+
color = get_style().style_builder.color(self._surface)
|
|
255
|
+
self._scroll.canvas.configure(background=color)
|
|
256
|
+
except Exception:
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
# The unified theme walk re-applies the canvas surface on a theme change.
|
|
260
|
+
_bs_apply_theme = _paint_canvas_surface
|
|
261
|
+
|
|
262
|
+
def _content_overflows(self) -> bool:
|
|
263
|
+
"""Whether the item content is taller than the scroll viewport.
|
|
264
|
+
|
|
265
|
+
Uses a small epsilon so a 1–4px overhang doesn't toggle the gutter — and,
|
|
266
|
+
with the gutter's own width, gives stable hysteresis (no flicker).
|
|
267
|
+
"""
|
|
268
|
+
try:
|
|
269
|
+
bbox = self._scroll.canvas.bbox("all")
|
|
270
|
+
if not bbox:
|
|
271
|
+
return False
|
|
272
|
+
viewport_h = self._scroll.canvas.winfo_height()
|
|
273
|
+
return viewport_h > 1 and (bbox[3] - bbox[1]) > viewport_h + 4
|
|
274
|
+
except Exception:
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
def _update_overflow_state(self) -> None:
|
|
278
|
+
"""Reserve the scrollbar gutter + show the footer divider only on overflow.
|
|
279
|
+
|
|
280
|
+
When the content fits, the bar/gutter is off (`'never'`) so items run
|
|
281
|
+
full-width and there's no footer divider; when it overflows, the gutter +
|
|
282
|
+
auto-hiding bar turn on (`'scroll'`) and a divider separates the pinned
|
|
283
|
+
footer from the scrolling rows.
|
|
284
|
+
"""
|
|
285
|
+
if self._updating_overflow:
|
|
286
|
+
return
|
|
287
|
+
self._updating_overflow = True
|
|
288
|
+
try:
|
|
289
|
+
overflow = self._content_overflows()
|
|
290
|
+
desired = "scroll" if overflow else "never"
|
|
291
|
+
if self._scroll.cget("scrollbar_visibility") != desired:
|
|
292
|
+
self._scroll.configure(scrollbar_visibility=desired)
|
|
293
|
+
show_divider = overflow and bool(self._footer_items)
|
|
294
|
+
mapped = self._footer_divider.winfo_manager() != ""
|
|
295
|
+
if show_divider and not mapped:
|
|
296
|
+
# Pack the divider BEFORE the expanding scroll view in the pack
|
|
297
|
+
# order — otherwise, when the content overflows, the `expand=True`
|
|
298
|
+
# scroll claims the whole cavity first and the divider (last in
|
|
299
|
+
# order) is squeezed to zero height and never maps. `side="bottom"`
|
|
300
|
+
# still seats it just above the (earlier-packed) footer.
|
|
301
|
+
self._footer_divider.pack(side="bottom", fill="x", before=self._scroll)
|
|
302
|
+
elif not show_divider and mapped:
|
|
303
|
+
self._footer_divider.pack_forget()
|
|
304
|
+
# Keep the content + footer insets in sync with the gutter so the
|
|
305
|
+
# right margin stays even and footer items align with the scrolled rows.
|
|
306
|
+
self._apply_insets()
|
|
307
|
+
finally:
|
|
308
|
+
self._updating_overflow = False
|
|
309
|
+
|
|
310
|
+
def set_compact(self, compact: bool) -> None:
|
|
311
|
+
"""Render items icon-only (compact) or with labels (expanded).
|
|
312
|
+
|
|
313
|
+
Compaction swaps each item to the matching `-compact` style variant (a
|
|
314
|
+
centered icon-only layout) and flips `-compound` to hide the label — both
|
|
315
|
+
native, no custom composite state.
|
|
316
|
+
"""
|
|
317
|
+
if self._compact == compact:
|
|
318
|
+
return
|
|
319
|
+
self._compact = compact
|
|
320
|
+
# Compact shrinks the sidebar to the rail width; use a small inset so the
|
|
321
|
+
# pills don't touch the edges (the card pill is narrow enough to fit).
|
|
322
|
+
self._apply_inset(_COMPACT_INSET if compact else self._inset)
|
|
323
|
+
variant = self._item_variant()
|
|
324
|
+
compound = "image" if compact else "left"
|
|
325
|
+
for item in self._items.values():
|
|
326
|
+
item.configure(variant=variant, compound=compound)
|
|
327
|
+
self._relayout_main()
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def compact(self) -> bool:
|
|
331
|
+
"""Whether the panel is rendering items icon-only."""
|
|
332
|
+
return self._compact
|
|
333
|
+
|
|
334
|
+
def select(self, key: str | None) -> None:
|
|
335
|
+
"""Set the visual selection to `key` (or clear it with `None`)."""
|
|
336
|
+
self._signal.set(key if key is not None else "")
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
def selected(self) -> str | None:
|
|
340
|
+
"""The currently selected item key, or `None`."""
|
|
341
|
+
return self._signal() or None
|
|
342
|
+
|
|
343
|
+
def item_keys(self) -> tuple[str, ...]:
|
|
344
|
+
"""All item keys (main + footer) in insertion order."""
|
|
345
|
+
return tuple(self._items)
|