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,455 @@
|
|
|
1
|
+
"""Utility functions for style builders.
|
|
2
|
+
|
|
3
|
+
This module provides common utilities used across builder functions,
|
|
4
|
+
including accent extraction, variant parsing, and style name manipulation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
10
|
+
|
|
11
|
+
from bootstack.style.element import Element
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from bootstack.style.style_builder_ttk import StyleBuilderTtk
|
|
15
|
+
|
|
16
|
+
# Standard bootstack color tokens
|
|
17
|
+
COLORS = {
|
|
18
|
+
'primary', 'success', 'warning', 'danger', 'blue'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def extract_accent_from_style(ttk_style: str, default: str = 'primary') -> str:
|
|
23
|
+
"""Extract accent token from TTK style name.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
ttk_style: Full TTK style name (e.g., "custom_abc.success.Outline.TButton")
|
|
27
|
+
default: Default accent if none found
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Accent token name (e.g., "success")
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
>>> extract_accent_from_style("success.Outline.TButton")
|
|
34
|
+
'success'
|
|
35
|
+
>>> extract_accent_from_style("custom_abc.danger.TLabel")
|
|
36
|
+
'danger'
|
|
37
|
+
>>> extract_accent_from_style("TButton")
|
|
38
|
+
'primary'
|
|
39
|
+
"""
|
|
40
|
+
# Remove custom prefix if present
|
|
41
|
+
parts = ttk_style.split('.')
|
|
42
|
+
if parts and parts[0].startswith('custom_'):
|
|
43
|
+
parts = parts[1:]
|
|
44
|
+
|
|
45
|
+
# Find accent in parts
|
|
46
|
+
for part in parts:
|
|
47
|
+
if part.lower() in COLORS:
|
|
48
|
+
return part.lower()
|
|
49
|
+
|
|
50
|
+
return default
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def extract_variant_from_style(ttk_style: str) -> Optional[str]:
|
|
54
|
+
"""Extract variant name from TTK style name.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
ttk_style: Full TTK style name (e.g., "success.Outline.TButton")
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Variant name (lowercase) or None
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
>>> extract_variant_from_style("success.Outline.TButton")
|
|
64
|
+
'outline'
|
|
65
|
+
>>> extract_variant_from_style("primary.TLabel") is None
|
|
66
|
+
True
|
|
67
|
+
"""
|
|
68
|
+
parts = ttk_style.split('.')
|
|
69
|
+
|
|
70
|
+
# Remove custom prefix if present
|
|
71
|
+
if parts and parts[0].startswith('custom_'):
|
|
72
|
+
parts = parts[1:]
|
|
73
|
+
|
|
74
|
+
# Find variant (not accent, not widget class)
|
|
75
|
+
for part in parts:
|
|
76
|
+
part_lower = part.lower()
|
|
77
|
+
if part_lower not in COLORS and not part.startswith('T'):
|
|
78
|
+
return part_lower
|
|
79
|
+
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def extract_widget_class_from_style(ttk_style: str) -> Optional[str]:
|
|
84
|
+
"""Extract widget class from TTK style name.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
ttk_style: Full TTK style name (e.g., "success.Outline.TButton")
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Widget class name or None
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
>>> extract_widget_class_from_style("success.Outline.TButton")
|
|
94
|
+
'TButton'
|
|
95
|
+
>>> extract_widget_class_from_style("primary.TLabel")
|
|
96
|
+
'TLabel'
|
|
97
|
+
"""
|
|
98
|
+
parts = ttk_style.split('.')
|
|
99
|
+
|
|
100
|
+
# Find widget class (starts with 'T')
|
|
101
|
+
for part in parts:
|
|
102
|
+
if part.startswith('T'):
|
|
103
|
+
return part
|
|
104
|
+
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def parse_style_components(ttk_style: str) -> dict:
|
|
109
|
+
"""Parse TTK style name into all components.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
ttk_style: Full TTK style name
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Dictionary with parsed components:
|
|
116
|
+
{
|
|
117
|
+
'custom_prefix': 'custom_abc123' or None,
|
|
118
|
+
'accent': 'success' or default,
|
|
119
|
+
'variant': 'outline' or None,
|
|
120
|
+
'widget_class': 'TButton'
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
>>> parse_style_components("custom_abc.success.Outline.TButton")
|
|
125
|
+
{'custom_prefix': 'custom_abc', 'accent': 'success', 'variant': 'outline', 'widget_class': 'TButton'}
|
|
126
|
+
>>> parse_style_components("danger.TLabel")
|
|
127
|
+
{'custom_prefix': None, 'accent': 'danger', 'variant': None, 'widget_class': 'TLabel'}
|
|
128
|
+
"""
|
|
129
|
+
parts = ttk_style.split('.')
|
|
130
|
+
|
|
131
|
+
# Check for custom prefix
|
|
132
|
+
custom_prefix = None
|
|
133
|
+
if parts and parts[0].startswith('custom_'):
|
|
134
|
+
custom_prefix = parts[0]
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
'custom_prefix': custom_prefix,
|
|
138
|
+
'accent': extract_accent_from_style(ttk_style),
|
|
139
|
+
'variant': extract_variant_from_style(ttk_style),
|
|
140
|
+
'widget_class': extract_widget_class_from_style(ttk_style),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# Button utilities
|
|
145
|
+
# These utilities are used by button style builders and can be reused by other widgets.
|
|
146
|
+
|
|
147
|
+
# Valid button densities: 'default' (normal) and 'compact' (smaller/tighter)
|
|
148
|
+
BUTTON_DENSITIES = {'default', 'compact'}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def normalize_button_density(density: str) -> str:
|
|
152
|
+
"""Normalize button density to valid values ('default' or 'compact').
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
density: The requested button density.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
'compact' for compact buttons, 'default' for all other densities.
|
|
159
|
+
"""
|
|
160
|
+
return 'compact' if density == 'compact' else 'default'
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def button_layout(ttk_style: str) -> Element:
|
|
164
|
+
"""Create the standard button element layout.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
ttk_style: The TTK style name prefix for the button.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Element tree representing the button layout.
|
|
171
|
+
"""
|
|
172
|
+
return Element(f"{ttk_style}.Button.border", sticky="nsew").children(
|
|
173
|
+
[
|
|
174
|
+
Element("Button.padding", sticky="nsew").children(
|
|
175
|
+
[
|
|
176
|
+
Element("Button.label", sticky="nsew")
|
|
177
|
+
])
|
|
178
|
+
])
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def toolbutton_layout(ttk_style: str) -> Element:
|
|
182
|
+
"""Create the standard toolbutton element layout.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
ttk_style: The TTK style name prefix for the toolbutton.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Element tree representing the toolbutton layout.
|
|
189
|
+
"""
|
|
190
|
+
return Element(f"{ttk_style}.border", sticky="nsew").children(
|
|
191
|
+
[
|
|
192
|
+
Element("Toolbutton.padding", sticky="nsew").children(
|
|
193
|
+
[
|
|
194
|
+
Element("Toolbutton.label", sticky="nsew")
|
|
195
|
+
])
|
|
196
|
+
])
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def icon_size(icon_only: bool, density: str) -> int:
|
|
200
|
+
"""Determine icon size based on button density and icon_only flag.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
icon_only: Whether the button displays only an icon (no text).
|
|
204
|
+
density: The button density ('default' or 'compact').
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
The icon size in pixels.
|
|
208
|
+
"""
|
|
209
|
+
from tkinter import font
|
|
210
|
+
|
|
211
|
+
if icon_only:
|
|
212
|
+
return 20 if density != 'compact' else 17
|
|
213
|
+
|
|
214
|
+
# Size the icon to the label's cap height (font ascent) for alignment.
|
|
215
|
+
# Different buffers compensate for y_bias effect per density.
|
|
216
|
+
font_name = 'caption' if density == 'compact' else 'body'
|
|
217
|
+
f = font.nametofont(font_name)
|
|
218
|
+
buffer = 4 if density == 'compact' else 3
|
|
219
|
+
ascent = f.metrics()['ascent'] + buffer
|
|
220
|
+
|
|
221
|
+
# The ascent is already in physical pixels (named Tk fonts render at the
|
|
222
|
+
# current scaling), but this value is handed to normalize_icon_spec, which
|
|
223
|
+
# re-applies DPI scaling. Return the logical size (divide the scaling back
|
|
224
|
+
# out) so the icon is scaled exactly once and tracks the cap height at any
|
|
225
|
+
# DPI, instead of double-scaling to ~ui_scale x too large (#305).
|
|
226
|
+
from bootstack._runtime.utility import _ScalingState
|
|
227
|
+
ui_scale = _ScalingState.get_ui_scale() or 1.0
|
|
228
|
+
return round(ascent / ui_scale)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def button_font(density: str) -> str:
|
|
232
|
+
"""Get the font token for a button based on its density.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
density: The button density ('default' or 'compact').
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
The font token name.
|
|
239
|
+
"""
|
|
240
|
+
return 'caption' if density == 'compact' else 'body'
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def button_height(b: StyleBuilderTtk, density: str) -> int:
|
|
244
|
+
"""Get button height based on density, matching the total height of input fields.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
b: The style builder instance.
|
|
248
|
+
density: The button density ('default' or 'compact').
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Scaled height in pixels.
|
|
252
|
+
"""
|
|
253
|
+
return b.scale(37) if density == 'compact' else b.scale(43)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def button_padding(b: StyleBuilderTtk, icon_only: bool, density: Any) -> int | tuple[int, ...]:
|
|
257
|
+
"""Calculate button padding based on options.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
b: The style builder instance.
|
|
261
|
+
icon_only: Whether the button displays only an icon.
|
|
262
|
+
density: The button density ('default' or 'compact').
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Padding value (0 for icon_only, scaled tuple otherwise).
|
|
266
|
+
"""
|
|
267
|
+
if icon_only:
|
|
268
|
+
return b.scale((2, 3, 2, 3)) if density == 'compact' else 0
|
|
269
|
+
if density == 'compact':
|
|
270
|
+
# (left, top, right, bottom) - extra top padding to center text
|
|
271
|
+
return b.scale((6, 5, 6, 3))
|
|
272
|
+
return b.scale((8, 0))
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def resolve_icon_spec(options: dict) -> 'str | dict | None':
|
|
276
|
+
"""Resolve on_icon/off_icon/icon kwargs into a unified icon spec.
|
|
277
|
+
|
|
278
|
+
Handles the three icon kwargs accepted by toggle-style widgets:
|
|
279
|
+
- icon: base icon for all states (color changes with state)
|
|
280
|
+
- off_icon: icon for the unselected/off state
|
|
281
|
+
- on_icon: icon for the selected/on state
|
|
282
|
+
|
|
283
|
+
Returns an IconSpec dict (or plain name string) suitable for passing
|
|
284
|
+
to normalize_icon_spec, or None if no icon was provided.
|
|
285
|
+
"""
|
|
286
|
+
on_icon = options.get('on_icon')
|
|
287
|
+
off_icon = options.get('off_icon')
|
|
288
|
+
icon = options.get('icon')
|
|
289
|
+
|
|
290
|
+
if not on_icon and not off_icon:
|
|
291
|
+
return icon # None, str, or full IconSpec dict
|
|
292
|
+
|
|
293
|
+
base = off_icon or icon or on_icon
|
|
294
|
+
spec: dict = {'name': base}
|
|
295
|
+
if on_icon:
|
|
296
|
+
spec['state'] = [('selected', on_icon)]
|
|
297
|
+
return spec
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def apply_icon_mapping(
|
|
301
|
+
b: StyleBuilderTtk,
|
|
302
|
+
options: dict,
|
|
303
|
+
state_spec: dict,
|
|
304
|
+
default_size: int | None = None
|
|
305
|
+
) -> dict:
|
|
306
|
+
"""Apply icon mapping to a state specification dictionary.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
b: The style builder instance.
|
|
310
|
+
options: Style options dictionary containing 'icon', 'on_icon', 'off_icon',
|
|
311
|
+
and 'icon_only' keys.
|
|
312
|
+
state_spec: The state specification dictionary to update.
|
|
313
|
+
default_size: Default icon size, or None to use normalize_icon_spec defaults.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Updated state_spec with icon mappings applied.
|
|
317
|
+
"""
|
|
318
|
+
icon = resolve_icon_spec(options)
|
|
319
|
+
if icon is None:
|
|
320
|
+
return state_spec
|
|
321
|
+
|
|
322
|
+
if default_size is None:
|
|
323
|
+
icon = b.normalize_icon_spec(icon)
|
|
324
|
+
else:
|
|
325
|
+
icon = b.normalize_icon_spec(icon, default_size)
|
|
326
|
+
|
|
327
|
+
state_spec['image'] = b.map_stateful_icons(icon, state_spec['foreground'])
|
|
328
|
+
# Set compound to 'left' so text is visible alongside the icon
|
|
329
|
+
icon_only = options.get('icon_only', False)
|
|
330
|
+
if not icon_only:
|
|
331
|
+
state_spec['compound'] = 'left'
|
|
332
|
+
return state_spec
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
# Entry/Field utilities
|
|
336
|
+
# These utilities are used by entry-type style builders (Entry, Combobox, Spinbox, Field).
|
|
337
|
+
|
|
338
|
+
def entry_font(density: str) -> str:
|
|
339
|
+
"""Get the font for an entry widget based on its density.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
density: The entry density ('default' or 'compact').
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
The Tk font name.
|
|
346
|
+
"""
|
|
347
|
+
from bootstack.style.typography import get_font
|
|
348
|
+
font_token = 'caption' if density == 'compact' else 'body'
|
|
349
|
+
return str(get_font(font_token))
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def entry_padding(b: StyleBuilderTtk, density: str) -> tuple:
|
|
353
|
+
"""Get entry padding based on density.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
b: The style builder instance.
|
|
357
|
+
density: The entry density ('default' or 'compact').
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
Scaled padding tuple (horizontal, vertical).
|
|
361
|
+
"""
|
|
362
|
+
if density == 'compact':
|
|
363
|
+
return b.scale((6, 0))
|
|
364
|
+
return b.scale((6, 0))
|
|
365
|
+
|
|
366
|
+
def field_height(b: StyleBuilderTtk, density: str) -> int:
|
|
367
|
+
"""Get entry element height based on density.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
b: The style builder instance.
|
|
371
|
+
density: The entry density ('default' or 'compact').
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
Scaled height in pixels.
|
|
375
|
+
"""
|
|
376
|
+
return b.scale(26) if density == 'compact' else b.scale(33)
|
|
377
|
+
|
|
378
|
+
def entry_height(b: StyleBuilderTtk, density: str) -> int:
|
|
379
|
+
"""Get entry element height based on density.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
b: The style builder instance.
|
|
383
|
+
density: The entry density ('default' or 'compact').
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
Scaled height in pixels.
|
|
387
|
+
"""
|
|
388
|
+
return b.scale(25) if density == 'compact' else b.scale(31)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _snap_even(v: int) -> int:
|
|
392
|
+
return v if v % 2 == 0 else v + 1
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def entry_icon_size(b: StyleBuilderTtk, density: str) -> int:
|
|
396
|
+
"""Get icon size for entry widgets (chevrons, spinner arrows).
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
b: The style builder instance.
|
|
400
|
+
density: The entry density ('default' or 'compact').
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
Scaled icon size in pixels, snapped to an even number.
|
|
404
|
+
"""
|
|
405
|
+
return _snap_even(b.scale(12) if density == 'compact' else b.scale(14))
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def entry_image_key(base: str, density: str) -> str:
|
|
409
|
+
"""Get density-aware manifest key for entry elements.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
base: Base key name (e.g., 'input', 'input_before', 'input_after').
|
|
413
|
+
density: The entry density ('default' or 'compact').
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
Full manifest key with density suffix (e.g., 'input_default', 'input_compact').
|
|
417
|
+
"""
|
|
418
|
+
return f'{base}_{density}'
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def spinner_arrow_height(b: StyleBuilderTtk, density: str) -> int:
|
|
422
|
+
"""Get height for spinner arrow elements based on density.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
b: The style builder instance.
|
|
426
|
+
density: The entry density ('default' or 'compact').
|
|
427
|
+
|
|
428
|
+
Returns:
|
|
429
|
+
Scaled arrow height in pixels, snapped to an even number.
|
|
430
|
+
"""
|
|
431
|
+
return _snap_even(b.scale(10) if density == 'compact' else b.scale(13))
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def spinner_arrow_width(b: StyleBuilderTtk) -> int:
|
|
435
|
+
"""Get width for spinner arrow elements.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
b: The style builder instance.
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
Scaled arrow width in pixels, snapped to an even number.
|
|
442
|
+
"""
|
|
443
|
+
return _snap_even(b.scale(16))
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def chevron_width(b: StyleBuilderTtk) -> int:
|
|
447
|
+
"""Get width for combobox chevron element.
|
|
448
|
+
|
|
449
|
+
Args:
|
|
450
|
+
b: The style builder instance.
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
Scaled chevron width in pixels, snapped to an even number.
|
|
454
|
+
"""
|
|
455
|
+
return _snap_even(b.scale(16))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Tk (legacy tkinter) widget builders for bootstack.
|
|
2
|
+
|
|
3
|
+
Importing this package registers default builder functions for common Tk
|
|
4
|
+
widgets using the StyleBuilderTk registry. Builders receive the actual
|
|
5
|
+
widget instance, plus theme/color utilities via the builder object.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
# Import defaults to trigger registration
|
|
11
|
+
from . import defaults # noqa: F401
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'defaults',
|
|
15
|
+
]
|
|
16
|
+
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing_extensions import Any
|
|
4
|
+
|
|
5
|
+
from bootstack.style.style_builder_tk import StyleBuilderTk
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@StyleBuilderTk.register_builder('Tk')
|
|
9
|
+
def build_tk_root(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
10
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
11
|
+
widget.configure(background=bg)
|
|
12
|
+
widget.option_add('*Text*Font', 'TkDefaultFont')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@StyleBuilderTk.register_builder('Toplevel')
|
|
16
|
+
def build_tk_toplevel(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
17
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
18
|
+
widget.configure(background=bg)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@StyleBuilderTk.register_builder('Frame')
|
|
22
|
+
def build_tk_frame(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
23
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
24
|
+
widget.configure(background=bg)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@StyleBuilderTk.register_builder('Label')
|
|
28
|
+
def build_tk_label(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
29
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
30
|
+
fg = builder.on_color(bg)
|
|
31
|
+
widget.configure(background=bg, foreground=fg)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@StyleBuilderTk.register_builder('Button')
|
|
35
|
+
def build_tk_button(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
36
|
+
bg = builder.color('primary')
|
|
37
|
+
fg = builder.on_color(bg)
|
|
38
|
+
widget.configure(
|
|
39
|
+
relief='flat',
|
|
40
|
+
background=bg,
|
|
41
|
+
activebackground=bg,
|
|
42
|
+
foreground=fg,
|
|
43
|
+
activeforeground=fg,
|
|
44
|
+
highlightbackground=bg,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@StyleBuilderTk.register_builder('Entry')
|
|
49
|
+
def build_tk_entry(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
50
|
+
bg = builder.color('background')
|
|
51
|
+
fg = builder.colors.get('foreground')
|
|
52
|
+
accent = builder.color('primary')
|
|
53
|
+
border = builder.border(bg)
|
|
54
|
+
widget.configure(
|
|
55
|
+
relief='flat',
|
|
56
|
+
highlightthickness=1,
|
|
57
|
+
highlightbackground=border,
|
|
58
|
+
highlightcolor=accent,
|
|
59
|
+
foreground=fg,
|
|
60
|
+
background=bg,
|
|
61
|
+
insertbackground=accent,
|
|
62
|
+
insertwidth=1
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@StyleBuilderTk.register_builder('Text')
|
|
67
|
+
def build_tk_text(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
68
|
+
bg = builder.color('background')
|
|
69
|
+
fg = builder.colors.get('foreground')
|
|
70
|
+
border = builder.border(bg)
|
|
71
|
+
accent = builder.color('primary')
|
|
72
|
+
accent_fg = builder.on_color(accent)
|
|
73
|
+
widget.configure(
|
|
74
|
+
background=bg,
|
|
75
|
+
foreground=fg,
|
|
76
|
+
highlightcolor=accent,
|
|
77
|
+
highlightbackground=border,
|
|
78
|
+
highlightthickness=0,
|
|
79
|
+
insertbackground=fg,
|
|
80
|
+
selectbackground=accent,
|
|
81
|
+
selectforeground=accent_fg,
|
|
82
|
+
insertwidth=1,
|
|
83
|
+
relief='flat',
|
|
84
|
+
padx=5,
|
|
85
|
+
pady=5
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@StyleBuilderTk.register_builder('Canvas')
|
|
90
|
+
def build_tk_canvas(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
91
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
92
|
+
widget.configure(background=bg, highlightthickness=0)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@StyleBuilderTk.register_builder('Checkbutton')
|
|
96
|
+
def build_tk_checkbutton(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
97
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
98
|
+
fg = builder.colors.get('foreground')
|
|
99
|
+
accent = builder.color('primary')
|
|
100
|
+
widget.configure(
|
|
101
|
+
activebackground=bg,
|
|
102
|
+
activeforeground=accent,
|
|
103
|
+
background=bg,
|
|
104
|
+
foreground=fg,
|
|
105
|
+
selectcolor=bg
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@StyleBuilderTk.register_builder('Radiobutton')
|
|
110
|
+
def build_tk_radiobutton(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
111
|
+
accent = builder.color('primary')
|
|
112
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
113
|
+
fg = builder.colors.get('foreground')
|
|
114
|
+
widget.configure(
|
|
115
|
+
background=bg,
|
|
116
|
+
foreground=fg,
|
|
117
|
+
activebackground=bg,
|
|
118
|
+
activeforeground=accent,
|
|
119
|
+
highlightbackground=bg,
|
|
120
|
+
selectcolor=bg
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@StyleBuilderTk.register_builder('Scale')
|
|
125
|
+
def build_tk_scale(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
126
|
+
accent = builder.color('primary')
|
|
127
|
+
hover = builder.active(accent)
|
|
128
|
+
border = builder.color('border')
|
|
129
|
+
widget.configure(
|
|
130
|
+
background=accent,
|
|
131
|
+
showvalue=False,
|
|
132
|
+
sliderrelief='flat',
|
|
133
|
+
borderwidth=0,
|
|
134
|
+
activebackground=hover,
|
|
135
|
+
highlightthickness=1,
|
|
136
|
+
highlightcolor=border,
|
|
137
|
+
highlightbackground=border,
|
|
138
|
+
troughcolor=border
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@StyleBuilderTk.register_builder('Listbox')
|
|
143
|
+
def build_tk_listbox(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
144
|
+
bg = builder.color('background')
|
|
145
|
+
fg = builder.color('foreground')
|
|
146
|
+
accent = builder.subtle('primary', bg)
|
|
147
|
+
on_accent = builder.on_color(accent)
|
|
148
|
+
border = builder.border(bg)
|
|
149
|
+
widget.configure(
|
|
150
|
+
foreground=fg,
|
|
151
|
+
background=bg,
|
|
152
|
+
selectbackground=accent,
|
|
153
|
+
selectforeground=on_accent,
|
|
154
|
+
highlightbackground=border,
|
|
155
|
+
highlightcolor=accent,
|
|
156
|
+
highlightthickness=1,
|
|
157
|
+
activestyle="none",
|
|
158
|
+
relief='flat'
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@StyleBuilderTk.register_builder('Menu')
|
|
163
|
+
def build_tk_menu(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
164
|
+
bg = builder.color('background')
|
|
165
|
+
fg = builder.color('foreground')
|
|
166
|
+
accent = builder.elevate(bg, 2)
|
|
167
|
+
on_accent = builder.on_color(accent)
|
|
168
|
+
|
|
169
|
+
widget.configure(
|
|
170
|
+
tearoff=False,
|
|
171
|
+
borderwidth=1,
|
|
172
|
+
foreground=fg,
|
|
173
|
+
activeforeground=on_accent,
|
|
174
|
+
selectcolor=fg,
|
|
175
|
+
activebackground=accent,
|
|
176
|
+
background=bg,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@StyleBuilderTk.register_builder('Menubutton')
|
|
181
|
+
def build_tk_menubutton(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
182
|
+
bg = builder.color('primary')
|
|
183
|
+
fg = builder.on_color(bg)
|
|
184
|
+
hover = builder.active(bg)
|
|
185
|
+
|
|
186
|
+
widget.configure(
|
|
187
|
+
background=bg,
|
|
188
|
+
foreground=fg,
|
|
189
|
+
activebackground=hover,
|
|
190
|
+
activeforeground=fg,
|
|
191
|
+
borderwidth=0
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@StyleBuilderTk.register_builder('Labelframe')
|
|
196
|
+
def build_tk_labelframe(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
197
|
+
bg = builder.color(options.get('surface', 'content'))
|
|
198
|
+
fg = builder.on_color(bg)
|
|
199
|
+
border = builder.border(bg)
|
|
200
|
+
widget.configure(
|
|
201
|
+
background=bg,
|
|
202
|
+
foreground=fg, # does not work on Aqua or Windows
|
|
203
|
+
borderwidth=1,
|
|
204
|
+
highlightthickness=0,
|
|
205
|
+
highlightcolor=border,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@StyleBuilderTk.register_builder('Spinbox')
|
|
210
|
+
def build_tk_spinbox(builder: StyleBuilderTk, widget: Any, **options: Any) -> None:
|
|
211
|
+
bg = builder.color('background')
|
|
212
|
+
fg = builder.color('foreground')
|
|
213
|
+
border = builder.border(bg)
|
|
214
|
+
accent = builder.subtle('primary', bg)
|
|
215
|
+
insert_background = builder.color('primary')
|
|
216
|
+
|
|
217
|
+
widget.configure(
|
|
218
|
+
relief='flat',
|
|
219
|
+
foreground=fg,
|
|
220
|
+
background=bg,
|
|
221
|
+
insertbackground=insert_background,
|
|
222
|
+
insertwidth=1,
|
|
223
|
+
highlightcolor=accent,
|
|
224
|
+
highlightthickness=1,
|
|
225
|
+
highlightbackground=border,
|
|
226
|
+
# button relief ignored by Windows and macOS
|
|
227
|
+
buttonuprelief='flat',
|
|
228
|
+
buttondownrelief='flat',
|
|
229
|
+
)
|