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,369 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from bootstack.style.style_builder_ttk import StyleBuilderTtk
|
|
6
|
+
from bootstack.style.element import Element, ElementImage
|
|
7
|
+
from bootstack.style.utility import recolor_element_image
|
|
8
|
+
from bootstack.style.builders.utils import (
|
|
9
|
+
normalize_button_density,
|
|
10
|
+
button_font,
|
|
11
|
+
apply_icon_mapping,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _selection_wash(b: StyleBuilderTtk, accent: str, background: str, options: dict) -> str:
|
|
16
|
+
"""Row selection background — NEUTRAL by default; accent only when opted in.
|
|
17
|
+
|
|
18
|
+
Governs the row's background wash only. The selection control's glyph still
|
|
19
|
+
follows the accent (it reads as the accent indicator regardless). `wash=False`
|
|
20
|
+
drops the wash entirely (selection shown via the control); `accent_selection`
|
|
21
|
+
requests the old accent-tinted wash.
|
|
22
|
+
"""
|
|
23
|
+
if not options.get('wash', True):
|
|
24
|
+
return background
|
|
25
|
+
if options.get('accent_selection', False):
|
|
26
|
+
return b.subtle(accent or 'primary', background)
|
|
27
|
+
return b.active(background)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@StyleBuilderTtk.register_builder('container', 'ListView.TFrame')
|
|
31
|
+
def build_list_container_style(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
32
|
+
"""List container frame style - no hover state (only items should have hover)."""
|
|
33
|
+
surface_token = options.get('surface', 'content')
|
|
34
|
+
background = b.color(surface_token)
|
|
35
|
+
b.configure_style(ttk_style, background=background, relief='flat')
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@StyleBuilderTtk.register_builder('list', 'ListView.TFrame')
|
|
39
|
+
def build_list_frame_style(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
40
|
+
"""List internal frame style - has state mapping to sync with parent ListItem."""
|
|
41
|
+
hoverable = options.get('hoverable', True)
|
|
42
|
+
accent_token = accent or 'primary'
|
|
43
|
+
surface_token = options.get('surface', 'content')
|
|
44
|
+
base_token = surface_token.split('[')[0]
|
|
45
|
+
background = b.color(surface_token)
|
|
46
|
+
pressed = b.pressed(background)
|
|
47
|
+
selected = _selection_wash(b, accent, background, options)
|
|
48
|
+
b.configure_style(ttk_style, background=background, relief='flat')
|
|
49
|
+
|
|
50
|
+
# No hover wash and no 'focus' wash: rows show selection only (keyboard focus
|
|
51
|
+
# rides the row image's bar). Row hover was removed — it competed with the
|
|
52
|
+
# stripe and selection washes (several subtle colors at once) and is gone in
|
|
53
|
+
# DataTable too, so this keeps the data widgets consistent.
|
|
54
|
+
background_state_map = [
|
|
55
|
+
('selected', selected),
|
|
56
|
+
('', background)
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
b.map_style(ttk_style, background=[x for x in background_state_map if x is not None])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@StyleBuilderTtk.register_builder('item', 'ListView.TFrame')
|
|
63
|
+
def build_list_item_default_style(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
64
|
+
build_list_item_style(b, ttk_style, accent, 'list-item', **options)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@StyleBuilderTtk.register_builder('separated_item', 'ListView.TFrame')
|
|
68
|
+
def build_list_item_separated_style(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
69
|
+
build_list_item_style(b, ttk_style, accent, 'list-item-separated', **options)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def build_list_item_style(
|
|
73
|
+
b: StyleBuilderTtk,
|
|
74
|
+
ttk_style: str,
|
|
75
|
+
accent: Optional[str] = None,
|
|
76
|
+
variant: str = 'item',
|
|
77
|
+
**options
|
|
78
|
+
):
|
|
79
|
+
# TODO add density option
|
|
80
|
+
|
|
81
|
+
hoverable = options.get('hoverable', True)
|
|
82
|
+
surface_token = options.get('surface', 'content')
|
|
83
|
+
base_token = surface_token.split('[')[0]
|
|
84
|
+
accent_token = accent or 'primary'
|
|
85
|
+
|
|
86
|
+
background = b.color(surface_token)
|
|
87
|
+
pressed = b.pressed(background)
|
|
88
|
+
selected = _selection_wash(b, accent, background, options)
|
|
89
|
+
|
|
90
|
+
# Use separated image for separated variant, otherwise use standard list_item
|
|
91
|
+
is_separated = 'separated' in variant
|
|
92
|
+
image_key = 'listrow_default'
|
|
93
|
+
# An explicit `separator` color overrides the derived border — used to draw
|
|
94
|
+
# the divider in the stripe color so striped+separated rows read as one tone.
|
|
95
|
+
separator = options.get('separator')
|
|
96
|
+
if is_separated:
|
|
97
|
+
border_normal = b.color(separator) if separator else b.border(background)
|
|
98
|
+
else:
|
|
99
|
+
border_normal = background
|
|
100
|
+
|
|
101
|
+
def _bd(fill):
|
|
102
|
+
# Separated rows draw a real bottom separator (border_normal); otherwise
|
|
103
|
+
# the border tracks the fill so it stays invisible in every state. Without
|
|
104
|
+
# this, hover/selected rows showed a stray 1px frame (the border channel
|
|
105
|
+
# kept the base background while the fill changed).
|
|
106
|
+
return border_normal if is_separated else fill
|
|
107
|
+
|
|
108
|
+
# The magenta channel of the row image is the focus ring; paint it the
|
|
109
|
+
# foreground color but ONLY on the 'background focus' state (keyboard focus
|
|
110
|
+
# via visual_focus — see _runtime/visual_focus.py). Mouse focus has 'focus'
|
|
111
|
+
# but not 'background', so it shows no ring. Other (non-focus) images paint
|
|
112
|
+
# the ring channel = fill so it stays invisible.
|
|
113
|
+
focus_ring = b.color('foreground')
|
|
114
|
+
|
|
115
|
+
normal_img = recolor_element_image(image_key, background, _bd(background), background, None, border_normal)
|
|
116
|
+
# No left selection bar: the indicator channels match the selected fill so it
|
|
117
|
+
# stays invisible (selection reads via the row wash + accent checkbox, aligned
|
|
118
|
+
# with DataTable).
|
|
119
|
+
selected_img = recolor_element_image(image_key, selected, _bd(selected), selected, None, selected)
|
|
120
|
+
|
|
121
|
+
# Keyboard-focus bar images (bar on the current fill). Row hover was removed
|
|
122
|
+
# (it competed with stripe/selection washes), so there is no hover variant —
|
|
123
|
+
# the bar only needs a normal and a selected fill.
|
|
124
|
+
focus_ring_img = recolor_element_image(image_key, background, _bd(background), focus_ring, None, border_normal)
|
|
125
|
+
selected_focus_img = recolor_element_image(image_key, selected, _bd(selected), focus_ring, None, selected)
|
|
126
|
+
|
|
127
|
+
image_state_specs = [
|
|
128
|
+
('selected background focus', selected_focus_img.image),
|
|
129
|
+
('selected', selected_img.image),
|
|
130
|
+
('background focus', focus_ring_img.image),
|
|
131
|
+
('', normal_img.image),
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
b.create_style_element_image(
|
|
135
|
+
ElementImage(f'{ttk_style}.border', normal_img.image, sticky='nsew', border=normal_img.meta.border).state_specs(
|
|
136
|
+
[x for x in image_state_specs if x is not None]
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
b.create_style_layout(
|
|
141
|
+
ttk_style,
|
|
142
|
+
Element(f'{ttk_style}.border', sticky='nsew').children(
|
|
143
|
+
[
|
|
144
|
+
Element(f'{ttk_style}.padding', sticky='')
|
|
145
|
+
]
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
b.configure_style(ttk_style, background=background, relief='flat')
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@StyleBuilderTtk.register_builder('list', 'ListView.TButton')
|
|
152
|
+
def build_list_item_button_style(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
153
|
+
hoverable = options.get('hoverable', True)
|
|
154
|
+
surface_token = options.get('surface', 'content')
|
|
155
|
+
base_token = surface_token.split('[')[0]
|
|
156
|
+
density = normalize_button_density(options.get('density', 'default'))
|
|
157
|
+
|
|
158
|
+
background = b.color(surface_token)
|
|
159
|
+
pressed = b.pressed(background)
|
|
160
|
+
selected = _selection_wash(b, accent, background, options)
|
|
161
|
+
|
|
162
|
+
b.create_style_layout(
|
|
163
|
+
ttk_style,
|
|
164
|
+
Element('Label.border', sticky='nsew').children([
|
|
165
|
+
Element('Label.padding', sticky='nsew').children([
|
|
166
|
+
Element('Label.label', sticky='nsew')
|
|
167
|
+
])
|
|
168
|
+
])
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Selection + momentary press only — NO hover and NO plain-'focus' highlight.
|
|
172
|
+
# 'selected' keeps the button fill matching a selected row; 'pressed' gives a
|
|
173
|
+
# brief click feedback on the chevron. Row hover was removed (it competed with
|
|
174
|
+
# the stripe/selection washes and never cleared cleanly across recycling).
|
|
175
|
+
background_state_spec = [
|
|
176
|
+
('selected', selected),
|
|
177
|
+
('pressed', pressed),
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
b.configure_style(ttk_style, background=background, padding=0, relief='flat', stipple='gray12', font=button_font(density))
|
|
181
|
+
b.map_style(
|
|
182
|
+
ttk_style,
|
|
183
|
+
foreground=[],
|
|
184
|
+
background=[x for x in background_state_spec if x is not None]
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@StyleBuilderTtk.register_builder('radio', 'ListView.TLabel')
|
|
189
|
+
def build_list_item_radio_label(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
190
|
+
build_list_item_label(b, ttk_style, accent, 'list-radio', **options)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@StyleBuilderTtk.register_builder('check', 'ListView.TLabel')
|
|
194
|
+
def build_list_item_check_label(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
195
|
+
build_list_item_label(b, ttk_style, accent, 'list-checkbox', **options)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@StyleBuilderTtk.register_builder('list', 'ListView.TLabel')
|
|
199
|
+
def build_list_item_default_label(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
200
|
+
build_list_item_label(b, ttk_style, accent, 'list', **options)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _list_icon_size(b: StyleBuilderTtk, density: str) -> int:
|
|
204
|
+
"""Get icon size for list items based on density.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
b: The style builder instance.
|
|
208
|
+
density: The density ('default' or 'compact').
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Scaled icon size in pixels.
|
|
212
|
+
"""
|
|
213
|
+
return 16 if density == 'compact' else 18
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@StyleBuilderTtk.register_builder('icon', 'ListView.TButton')
|
|
217
|
+
@StyleBuilderTtk.register_builder('icon', 'ListView.TLabel')
|
|
218
|
+
def build_list_icon(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
219
|
+
hoverable = options.get('hoverable', True)
|
|
220
|
+
surface_token = options.get('surface', 'content')
|
|
221
|
+
base_token = surface_token.split('[')[0]
|
|
222
|
+
density = normalize_button_density(options.get('density', 'default'))
|
|
223
|
+
|
|
224
|
+
background = b.color(surface_token)
|
|
225
|
+
pressed = b.pressed(background)
|
|
226
|
+
selected = _selection_wash(b, accent, background, options)
|
|
227
|
+
on_background = b.on_color(background)
|
|
228
|
+
on_selected = b.on_color(selected)
|
|
229
|
+
on_disabled = b.disabled('text', background)
|
|
230
|
+
|
|
231
|
+
# Create layout (remove focus border)
|
|
232
|
+
b.create_style_layout(
|
|
233
|
+
ttk_style,
|
|
234
|
+
Element('Label.border', sticky='nsew').children([
|
|
235
|
+
Element('Label.padding', sticky='nsew').children([
|
|
236
|
+
Element('Label.label', sticky='nsew')
|
|
237
|
+
])
|
|
238
|
+
])
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Configure style
|
|
242
|
+
b.configure_style(
|
|
243
|
+
ttk_style,
|
|
244
|
+
background=background,
|
|
245
|
+
foreground=on_background,
|
|
246
|
+
padding=0,
|
|
247
|
+
relief='flat',
|
|
248
|
+
stipple='gray12',
|
|
249
|
+
font=button_font(density),
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
foreground_state_spec = [
|
|
253
|
+
('disabled', on_disabled),
|
|
254
|
+
('selected pressed', on_selected),
|
|
255
|
+
('selected', on_selected),
|
|
256
|
+
('', on_background)
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
# Selection only — no hover, no 'focus' wash. Row hover was removed (it
|
|
260
|
+
# competed with the stripe/selection washes); the icon/chevron fill just
|
|
261
|
+
# tracks the row's selected state so it stays consistent.
|
|
262
|
+
background_state_spec = [
|
|
263
|
+
('selected', selected),
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
# Prepare state spec
|
|
267
|
+
state_spec = dict(
|
|
268
|
+
foreground=[x for x in foreground_state_spec if x is not None],
|
|
269
|
+
background=[x for x in background_state_spec if x is not None]
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Apply icon mapping if icon is provided - use density-aware icon size
|
|
273
|
+
icon_size = _list_icon_size(b, density)
|
|
274
|
+
state_spec = apply_icon_mapping(b, options, state_spec, icon_size)
|
|
275
|
+
b.map_style(ttk_style, **state_spec)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@StyleBuilderTtk.register_builder('selection', 'ListView.TLabel')
|
|
279
|
+
def build_list_selection_icon(b: StyleBuilderTtk, ttk_style: str, accent: str = None, **options):
|
|
280
|
+
"""Selection checkbox/radio icon for list rows.
|
|
281
|
+
|
|
282
|
+
Mirrors the DataTable selection markers: the glyph is a muted outline when
|
|
283
|
+
unchecked and accent-filled when checked, so selection reads the same across
|
|
284
|
+
both data-bound widgets (unlike a generic row icon, which stays foreground).
|
|
285
|
+
"""
|
|
286
|
+
hoverable = options.get('hoverable', True)
|
|
287
|
+
surface_token = options.get('surface', 'content')
|
|
288
|
+
base_token = surface_token.split('[')[0]
|
|
289
|
+
density = normalize_button_density(options.get('density', 'default'))
|
|
290
|
+
|
|
291
|
+
background = b.color(surface_token)
|
|
292
|
+
pressed = b.pressed(background)
|
|
293
|
+
# Neutral row wash by default; the GLYPH foreground below stays accent so the
|
|
294
|
+
# checked control is the accent indicator regardless of the wash.
|
|
295
|
+
selected = _selection_wash(b, accent, background, options)
|
|
296
|
+
accent_color = b.color(accent or 'primary')
|
|
297
|
+
muted = b.color('muted')
|
|
298
|
+
on_disabled = b.disabled('text', background)
|
|
299
|
+
|
|
300
|
+
b.create_style_layout(
|
|
301
|
+
ttk_style,
|
|
302
|
+
Element('Label.border', sticky='nsew').children([
|
|
303
|
+
Element('Label.padding', sticky='nsew').children([
|
|
304
|
+
Element('Label.label', sticky='nsew')
|
|
305
|
+
])
|
|
306
|
+
])
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
b.configure_style(
|
|
310
|
+
ttk_style,
|
|
311
|
+
background=background,
|
|
312
|
+
foreground=muted,
|
|
313
|
+
padding=0,
|
|
314
|
+
relief='flat',
|
|
315
|
+
stipple='gray12',
|
|
316
|
+
font=button_font(density),
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
foreground_state_spec = [
|
|
320
|
+
('disabled', on_disabled),
|
|
321
|
+
('selected', accent_color), # accent-filled when checked
|
|
322
|
+
('alternate', accent_color), # partially-selected parent (mixed) -> accent dash
|
|
323
|
+
('', muted), # muted outline when unchecked
|
|
324
|
+
]
|
|
325
|
+
# Selection only — no hover, no 'focus' wash (row hover was removed).
|
|
326
|
+
background_state_spec = [
|
|
327
|
+
('selected', selected),
|
|
328
|
+
]
|
|
329
|
+
state_spec = dict(
|
|
330
|
+
foreground=[x for x in foreground_state_spec if x is not None],
|
|
331
|
+
background=[x for x in background_state_spec if x is not None],
|
|
332
|
+
)
|
|
333
|
+
# Fixed crisp size across densities so the control doesn't shrink/pixelate
|
|
334
|
+
# in compact mode (used by both ListView and Tree selection markers).
|
|
335
|
+
state_spec = apply_icon_mapping(b, options, state_spec, 18)
|
|
336
|
+
b.map_style(ttk_style, **state_spec)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def build_list_item_label(b: StyleBuilderTtk, ttk_style: str, accent: str = None, variant: str = None, **options):
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
Style Options
|
|
343
|
+
* surface
|
|
344
|
+
* hoverable
|
|
345
|
+
* foreground
|
|
346
|
+
"""
|
|
347
|
+
hoverable = options.get('hoverable', True)
|
|
348
|
+
surface_token = options.get('surface', 'content')
|
|
349
|
+
base_token = surface_token.split('[')[0]
|
|
350
|
+
foreground_token = options.get('foreground', None)
|
|
351
|
+
|
|
352
|
+
background = b.color(surface_token)
|
|
353
|
+
pressed = b.pressed(background)
|
|
354
|
+
selected = _selection_wash(b, accent, background, options)
|
|
355
|
+
on_background = b.color(foreground_token) if foreground_token else b.on_color(background)
|
|
356
|
+
on_selected = b.on_color(selected)
|
|
357
|
+
|
|
358
|
+
# Selection only — no hover wash, no 'focus' wash (keyboard focus = row bar).
|
|
359
|
+
# Row hover was removed (competed with stripe/selection washes).
|
|
360
|
+
background_state_spec = [
|
|
361
|
+
('selected', selected),
|
|
362
|
+
]
|
|
363
|
+
|
|
364
|
+
b.configure_style(ttk_style, background=background, foreground=on_background)
|
|
365
|
+
b.map_style(
|
|
366
|
+
ttk_style,
|
|
367
|
+
background=[x for x in background_state_spec if x is not None],
|
|
368
|
+
foreground=[('selected', on_selected)]
|
|
369
|
+
)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Menubutton widget style builders.
|
|
2
|
+
|
|
3
|
+
This module contains style builders for ttk.Menubutton widgets and variants.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from bootstack.style.style_builder_ttk import StyleBuilderTtk
|
|
9
|
+
from bootstack.style.element import Element, ElementImage
|
|
10
|
+
from bootstack.style.utility import recolor_element_image
|
|
11
|
+
from bootstack.style.builders.utils import (
|
|
12
|
+
button_font,
|
|
13
|
+
button_height,
|
|
14
|
+
button_padding,
|
|
15
|
+
normalize_button_density,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@StyleBuilderTtk.register_builder('menubar-item', 'TMenubutton')
|
|
20
|
+
@StyleBuilderTtk.register_builder('menubar-item', 'TButton')
|
|
21
|
+
def build_menubar_item(b: StyleBuilderTtk, ttk_style: str, color: str = None, **options):
|
|
22
|
+
# Default to the base content surface (so a menu trigger blends into a
|
|
23
|
+
# content-surfaced toolbar). The window menu bar passes surface='chrome'
|
|
24
|
+
# explicitly, so the chrome strip is unaffected. Note `'content'` is dropped
|
|
25
|
+
# before it reaches here, so a content toolbar arrives with no surface option
|
|
26
|
+
# and lands on this default.
|
|
27
|
+
surface_token = options.get('surface', 'content')
|
|
28
|
+
# Follow the host toolbar's density (sizing the trigger image, padding, and
|
|
29
|
+
# font like a button of the same density) so menu triggers match the buttons
|
|
30
|
+
# beside them — rather than being locked to a single compact size.
|
|
31
|
+
density = options.get('density', 'default')
|
|
32
|
+
icon_only = options.get('icon_only', False)
|
|
33
|
+
|
|
34
|
+
surface = b.color(surface_token)
|
|
35
|
+
active = b.active(surface)
|
|
36
|
+
pressed = b.pressed(surface)
|
|
37
|
+
|
|
38
|
+
foreground_normal = b.on_color(surface)
|
|
39
|
+
foreground_disabled = b.disabled('text', surface)
|
|
40
|
+
|
|
41
|
+
# The menu-bar look is a flat button — the normal state paints the surface on
|
|
42
|
+
# all four channels (no visible border); hover / pressed reveal the wash.
|
|
43
|
+
image_key = f'button_{normalize_button_density(density)}'
|
|
44
|
+
normal_img = recolor_element_image(image_key, surface, surface, surface, surface)
|
|
45
|
+
pressed_img = recolor_element_image(image_key, pressed, pressed, surface, surface)
|
|
46
|
+
active_img = recolor_element_image(image_key, active, active, surface, surface)
|
|
47
|
+
|
|
48
|
+
# button element
|
|
49
|
+
b.create_style_element_image(
|
|
50
|
+
ElementImage(f'{ttk_style}.Button.border', normal_img.image, sticky="nsew",
|
|
51
|
+
border=normal_img.meta.border, padding=normal_img.meta.border,
|
|
52
|
+
height=button_height(b, density)).state_specs([
|
|
53
|
+
('background focus pressed', pressed_img.image),
|
|
54
|
+
('background focus hover', active_img.image),
|
|
55
|
+
('background focus', pressed_img.image),
|
|
56
|
+
('pressed', pressed_img.image),
|
|
57
|
+
('hover', active_img.image)
|
|
58
|
+
]))
|
|
59
|
+
|
|
60
|
+
b.create_style_layout(
|
|
61
|
+
ttk_style, Element(f"{ttk_style}.Button.border", sticky="nsew").children([
|
|
62
|
+
Element("Button.padding", sticky="nsew").children([
|
|
63
|
+
Element("Button.label", sticky="nsew")
|
|
64
|
+
])
|
|
65
|
+
]))
|
|
66
|
+
|
|
67
|
+
b.configure_style(ttk_style, font=button_font(density), background=surface,
|
|
68
|
+
foreground=foreground_normal,
|
|
69
|
+
padding=button_padding(b, icon_only, density))
|
|
70
|
+
|
|
71
|
+
state_spec = dict(
|
|
72
|
+
foreground=[
|
|
73
|
+
('disabled', foreground_disabled),
|
|
74
|
+
('background focus', foreground_normal),
|
|
75
|
+
('', foreground_normal)
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
state_spec = _apply_icon_mapping(b, options, state_spec)
|
|
80
|
+
b.map_style(ttk_style, **state_spec)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _apply_icon_mapping(b: StyleBuilderTtk, options: dict, state_spec: dict) -> dict:
|
|
84
|
+
"""Apply icon mapping if an icon is provided in options."""
|
|
85
|
+
icon = options.get('icon')
|
|
86
|
+
if icon is None:
|
|
87
|
+
return state_spec
|
|
88
|
+
|
|
89
|
+
icon = b.normalize_icon_spec(icon, 20)
|
|
90
|
+
state_spec['image'] = b.map_stateful_icons(icon, state_spec['foreground'])
|
|
91
|
+
return state_spec
|