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
bootstack/widgets/app.py
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence
|
|
5
|
+
|
|
6
|
+
from bootstack._runtime.app import App as _InternalApp, LocalizeMode
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from bootstack.images import AppIcon, Image
|
|
10
|
+
from bootstack.widgets._impl.primitives.flexframe import FlexFrame
|
|
11
|
+
from bootstack.widgets._core.app_config import AppConfigMixin, APP_CONFIG_KWARGS
|
|
12
|
+
from bootstack.widgets._core.container import FlexContainer
|
|
13
|
+
from bootstack.widgets._core.window_controls import WindowControlsMixin
|
|
14
|
+
from bootstack.widgets._core.window_menu import ChromeHostMixin
|
|
15
|
+
from bootstack.widgets.types import (
|
|
16
|
+
Padding, HAlign, VArrange, SurfaceToken, WindowStyle,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class App(AppConfigMixin, WindowControlsMixin, ChromeHostMixin, FlexContainer):
|
|
21
|
+
"""The application window. Behaves as an implicit Column from the user's
|
|
22
|
+
perspective: accepts `padding`, `gap`, `horizontal_items`, `vertical_items`,
|
|
23
|
+
and `grow_items` and applies them to its internal content frame.
|
|
24
|
+
|
|
25
|
+
Configuration is a single flat path: pass options as constructor kwargs and
|
|
26
|
+
read or change them through matching `app.*` properties (e.g. `app.theme`,
|
|
27
|
+
`app.locale`). Setting `app.theme` or `app.locale` takes effect live.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
title: Window title bar text and the app's display name.
|
|
31
|
+
size: Initial window size as `(width, height)`.
|
|
32
|
+
icon: Title-bar and taskbar icon — an icon file path, an `Image` handle,
|
|
33
|
+
or an `AppIcon`. Defaults to the bootstack icon.
|
|
34
|
+
theme: Theme name to apply on startup (e.g. `'bootstrap-dark'`).
|
|
35
|
+
light_theme: Theme used for the light end of system-appearance
|
|
36
|
+
tracking and `toggle_theme`.
|
|
37
|
+
dark_theme: Theme used for the dark end of system-appearance
|
|
38
|
+
tracking and `toggle_theme`.
|
|
39
|
+
follow_system_appearance: If True, switch between `light_theme` and
|
|
40
|
+
`dark_theme` to match the OS (currently effective on macOS).
|
|
41
|
+
available_themes: Theme names to expose to theme pickers. Empty means
|
|
42
|
+
all registered themes.
|
|
43
|
+
locale: Locale identifier (e.g. `'en_US'`, `'de_DE'`). Auto-detected
|
|
44
|
+
from the system when not given.
|
|
45
|
+
localize_mode: Localization behavior.
|
|
46
|
+
window_style: Windows-only window effect, or None to disable.
|
|
47
|
+
macos_quit_behavior: macOS close / Cmd+Q behavior. No-op on Win/Linux.
|
|
48
|
+
remember_window_state: If True, window geometry is saved on close and
|
|
49
|
+
restored on next launch.
|
|
50
|
+
state_path: Optional override for the persisted window-state file.
|
|
51
|
+
on_close: Handler invoked when the user clicks the window's close button.
|
|
52
|
+
Return `False` to veto the close; return `None` or `True` to allow
|
|
53
|
+
it. Not called by the programmatic `close()`.
|
|
54
|
+
position: Initial window position as `(x, y)`.
|
|
55
|
+
min_size: Minimum window size as `(width, height)`.
|
|
56
|
+
max_size: Maximum window size as `(width, height)`.
|
|
57
|
+
resizable: Whether the window can be resized as `(width, height)`.
|
|
58
|
+
scaling: Explicit UI scaling factor. When None, scaling is automatic.
|
|
59
|
+
hdpi: Enable high-DPI awareness for the application. Default `True`.
|
|
60
|
+
undecorated: Remove the OS title bar and border (borderless window).
|
|
61
|
+
Ignored on macOS. The app gets a built-in draggable title bar with
|
|
62
|
+
min/max/close so it stays movable and closeable; add your own with
|
|
63
|
+
`add_toolbar(show_window_controls=True)` to take over the chrome.
|
|
64
|
+
padding: Inner padding applied to the content frame.
|
|
65
|
+
gap: Spacing between stacked children. Default `0`.
|
|
66
|
+
horizontal_items: Horizontal alignment of children — `'left'`,
|
|
67
|
+
`'center'`, `'right'`, or `'stretch'` (fill the width). Default
|
|
68
|
+
`'center'`.
|
|
69
|
+
vertical_items: How children are arranged top to bottom — `'top'`,
|
|
70
|
+
`'center'`, `'bottom'`, or a `'space-*'` mode. Default `'top'`.
|
|
71
|
+
grow_items: When `True`, children grow equally to fill the height.
|
|
72
|
+
Default `False`.
|
|
73
|
+
surface: Background surface for the content frame.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
_auto_place = False # no parent
|
|
77
|
+
_dev_supports_inprocess = True # supports in-process hot reload (bootstack dev)
|
|
78
|
+
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
*,
|
|
82
|
+
title: str | None = None,
|
|
83
|
+
size: tuple[int, int] | None = None,
|
|
84
|
+
icon: "str | Image | AppIcon | None" = None,
|
|
85
|
+
theme: str | None = None,
|
|
86
|
+
# theme
|
|
87
|
+
light_theme: str = "bootstrap-light",
|
|
88
|
+
dark_theme: str = "bootstrap-dark",
|
|
89
|
+
follow_system_appearance: bool = False,
|
|
90
|
+
available_themes: Sequence[str] = (),
|
|
91
|
+
# localization
|
|
92
|
+
locale: str | None = None,
|
|
93
|
+
localize_mode: LocalizeMode = "auto",
|
|
94
|
+
# platform / window-state persistence
|
|
95
|
+
window_style: WindowStyle | str | None = "mica",
|
|
96
|
+
macos_quit_behavior: Literal['native', 'classic'] = "native",
|
|
97
|
+
remember_window_state: bool = False,
|
|
98
|
+
state_path: str | None = None,
|
|
99
|
+
on_close: Callable[[], bool | None] | None = None,
|
|
100
|
+
# window placement / display
|
|
101
|
+
position: tuple[int, int] | None = None,
|
|
102
|
+
min_size: tuple[int, int] | None = None,
|
|
103
|
+
max_size: tuple[int, int] | None = None,
|
|
104
|
+
resizable: tuple[bool, bool] | None = None,
|
|
105
|
+
scaling: float | None = None,
|
|
106
|
+
hdpi: bool = True,
|
|
107
|
+
undecorated: bool = False,
|
|
108
|
+
# Child-guidance (applied to the internal content frame)
|
|
109
|
+
padding: Padding | None = None,
|
|
110
|
+
gap: int = 0,
|
|
111
|
+
horizontal_items: HAlign = "center",
|
|
112
|
+
vertical_items: VArrange = "top",
|
|
113
|
+
grow_items: bool = False,
|
|
114
|
+
surface: SurfaceToken | str | None = None,
|
|
115
|
+
# Extra kwargs forwarded to the internal App (icon, position, etc.)
|
|
116
|
+
**app_kwargs: Any,
|
|
117
|
+
) -> None:
|
|
118
|
+
self._parent = None
|
|
119
|
+
self._dev_body = None # set in __enter__ under `bootstack dev`
|
|
120
|
+
|
|
121
|
+
# Under `bootstack dev`, persist window geometry by default so a
|
|
122
|
+
# process-restart reload re-opens the window where it was. Honors an
|
|
123
|
+
# explicit choice; uses a dev-scoped state file so it never clobbers the
|
|
124
|
+
# app's real saved state.
|
|
125
|
+
from bootstack.dev._env import DEV_MIN_SIZE, is_dev_mode
|
|
126
|
+
|
|
127
|
+
if is_dev_mode():
|
|
128
|
+
if not remember_window_state and state_path is None:
|
|
129
|
+
from bootstack._core.paths import app_config_file
|
|
130
|
+
|
|
131
|
+
remember_window_state = True
|
|
132
|
+
state_path = str(app_config_file("dev_window_state.json", title or "bootstack"))
|
|
133
|
+
# A usable floor so a reload window starts/stays a sensible size.
|
|
134
|
+
if min_size is None:
|
|
135
|
+
min_size = DEV_MIN_SIZE
|
|
136
|
+
|
|
137
|
+
init_kwargs: dict[str, Any] = {
|
|
138
|
+
"light_theme": light_theme,
|
|
139
|
+
"dark_theme": dark_theme,
|
|
140
|
+
"follow_system_appearance": follow_system_appearance,
|
|
141
|
+
"available_themes": available_themes,
|
|
142
|
+
"locale": locale,
|
|
143
|
+
"localize_mode": localize_mode,
|
|
144
|
+
"window_style": window_style,
|
|
145
|
+
"macos_quit_behavior": macos_quit_behavior,
|
|
146
|
+
"remember_window_state": remember_window_state,
|
|
147
|
+
"state_path": state_path,
|
|
148
|
+
"scaling": scaling,
|
|
149
|
+
"hdpi": hdpi,
|
|
150
|
+
"override_redirect": undecorated,
|
|
151
|
+
}
|
|
152
|
+
# overrideredirect has no effect on macOS — so the borderless treatment
|
|
153
|
+
# (custom border + title bar) is Windows/Linux only.
|
|
154
|
+
self._undecorated = undecorated and sys.platform != "darwin"
|
|
155
|
+
if title is not None:
|
|
156
|
+
init_kwargs["title"] = title
|
|
157
|
+
if size is not None:
|
|
158
|
+
init_kwargs["size"] = size
|
|
159
|
+
if theme is not None:
|
|
160
|
+
init_kwargs["theme"] = theme
|
|
161
|
+
if position is not None:
|
|
162
|
+
init_kwargs["position"] = position
|
|
163
|
+
if min_size is not None:
|
|
164
|
+
init_kwargs["minsize"] = min_size
|
|
165
|
+
if max_size is not None:
|
|
166
|
+
init_kwargs["maxsize"] = max_size
|
|
167
|
+
if resizable is not None:
|
|
168
|
+
init_kwargs["resizable"] = resizable
|
|
169
|
+
if on_close is not None:
|
|
170
|
+
init_kwargs["on_close"] = on_close
|
|
171
|
+
|
|
172
|
+
init_kwargs.update(app_kwargs)
|
|
173
|
+
|
|
174
|
+
self._tk_root = _InternalApp(**init_kwargs)
|
|
175
|
+
|
|
176
|
+
# Resolve the icon AFTER the root exists. An `AppIcon` may resolve theme
|
|
177
|
+
# color tokens (which need the style/root) and a deferred `Image` must be
|
|
178
|
+
# rendered against the root — doing either before the root would spin up
|
|
179
|
+
# a stray default root and bind the icon to the wrong interpreter.
|
|
180
|
+
self._app_icon_photo = None
|
|
181
|
+
if icon is not None:
|
|
182
|
+
from bootstack.widgets._core.image_binding import resolve_window_icon
|
|
183
|
+
|
|
184
|
+
icon_path, icon_image = resolve_window_icon(icon)
|
|
185
|
+
if icon_path is not None:
|
|
186
|
+
self._tk_root._setup_icon(icon_path)
|
|
187
|
+
elif icon_image is not None:
|
|
188
|
+
self._app_icon_photo = icon_image._materialize()
|
|
189
|
+
self._tk_root._setup_icon(self._app_icon_photo)
|
|
190
|
+
|
|
191
|
+
frame_kwargs: dict[str, Any] = {
|
|
192
|
+
"direction": "vertical",
|
|
193
|
+
"gap": gap,
|
|
194
|
+
"horizontal_items": horizontal_items,
|
|
195
|
+
"vertical_items": vertical_items,
|
|
196
|
+
"grow_items": grow_items,
|
|
197
|
+
}
|
|
198
|
+
if padding is not None:
|
|
199
|
+
frame_kwargs["padding"] = padding
|
|
200
|
+
if surface is not None:
|
|
201
|
+
frame_kwargs["surface"] = surface
|
|
202
|
+
|
|
203
|
+
# In undecorated mode the OS border is gone; a 1px themed border frame
|
|
204
|
+
# substitutes it and hosts both the chrome stack and the content.
|
|
205
|
+
if self._undecorated:
|
|
206
|
+
from bootstack.widgets._impl.primitives.frame import Frame
|
|
207
|
+
|
|
208
|
+
self._region_root = Frame(self._tk_root, show_border=True, padding=1)
|
|
209
|
+
self._region_root.pack(fill="both", expand=True)
|
|
210
|
+
else:
|
|
211
|
+
self._region_root = self._tk_root
|
|
212
|
+
|
|
213
|
+
# Stash the content-frame config so dev hot reload can rebuild a fresh
|
|
214
|
+
# content frame with identical guidance after tearing the old one down.
|
|
215
|
+
self._dev_frame_kwargs = dict(frame_kwargs)
|
|
216
|
+
self._content_frame = FlexFrame(self._region_root, **frame_kwargs)
|
|
217
|
+
self._content_frame.pack(fill="both", expand=True)
|
|
218
|
+
|
|
219
|
+
self._internal = self._tk_root
|
|
220
|
+
|
|
221
|
+
def _toolbar_stack_parent(self) -> Any:
|
|
222
|
+
# The chrome stack lives inside the (bordered) region root, above content.
|
|
223
|
+
return getattr(self, "_region_root", self._tk_root)
|
|
224
|
+
|
|
225
|
+
@classmethod
|
|
226
|
+
def from_store(cls, store: Any, **overrides: Any) -> "App":
|
|
227
|
+
"""Construct an `App` from a persisted `Store` (or plain dict).
|
|
228
|
+
|
|
229
|
+
Reads configuration from `store` and applies it as constructor kwargs,
|
|
230
|
+
tolerantly ignoring any keys that are not valid `App` configuration —
|
|
231
|
+
so a settings file written by an older or newer version (with renamed
|
|
232
|
+
or removed keys) still restores cleanly instead of raising. Explicit
|
|
233
|
+
keyword `overrides` win over stored values.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
store: A `Store` (anything with `as_dict()`) or a mapping of
|
|
237
|
+
configuration values.
|
|
238
|
+
**overrides: Configuration kwargs that take precedence over the
|
|
239
|
+
stored values.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
A new `App` configured from the store.
|
|
243
|
+
|
|
244
|
+
Example:
|
|
245
|
+
.. code-block:: python
|
|
246
|
+
|
|
247
|
+
from bootstack.store import Store
|
|
248
|
+
|
|
249
|
+
store = Store("settings")
|
|
250
|
+
app = bs.App.from_store(store)
|
|
251
|
+
app.on_theme_change(lambda t: store.update(theme=t))
|
|
252
|
+
"""
|
|
253
|
+
data = store.as_dict() if hasattr(store, "as_dict") else dict(store)
|
|
254
|
+
kwargs = {k: v for k, v in data.items() if k in APP_CONFIG_KWARGS}
|
|
255
|
+
kwargs.update(overrides)
|
|
256
|
+
return cls(**kwargs)
|
|
257
|
+
|
|
258
|
+
def _config_app(self) -> Any:
|
|
259
|
+
return self._tk_root
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def _flex_frame(self):
|
|
263
|
+
"""Children flow into the content frame, not the Tk root."""
|
|
264
|
+
return self._content_frame
|
|
265
|
+
|
|
266
|
+
def run(self) -> None:
|
|
267
|
+
"""Show the window and start the event loop."""
|
|
268
|
+
self._ensure_default_titlebar()
|
|
269
|
+
from bootstack.dev._env import is_dev_mode
|
|
270
|
+
|
|
271
|
+
if is_dev_mode():
|
|
272
|
+
from bootstack.dev._reloader import install_reloader
|
|
273
|
+
|
|
274
|
+
install_reloader(self)
|
|
275
|
+
# Let the internal mainloop center and *then* show the window — it
|
|
276
|
+
# flushes layout and applies the window style while still withdrawn, so
|
|
277
|
+
# the window is fully drawn and positioned before it becomes visible.
|
|
278
|
+
# (Deiconifying here first would map it uncentered, then jump on center.)
|
|
279
|
+
self._tk_root.mainloop()
|
|
280
|
+
|
|
281
|
+
def __enter__(self) -> "App":
|
|
282
|
+
result = super().__enter__()
|
|
283
|
+
# Under `bootstack dev`, capture where this `with` body lives so a save
|
|
284
|
+
# can re-exec it. No-op (and zero cost) outside dev mode.
|
|
285
|
+
from bootstack.dev._env import is_dev_mode
|
|
286
|
+
|
|
287
|
+
if is_dev_mode() and self._dev_body is None:
|
|
288
|
+
import sys as _sys
|
|
289
|
+
from bootstack.dev._capture import capture_from_frame
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
self._dev_body = capture_from_frame(_sys._getframe(1))
|
|
293
|
+
except Exception:
|
|
294
|
+
self._dev_body = None
|
|
295
|
+
return result
|
|
296
|
+
|
|
297
|
+
def __exit__(self, exc_type, exc, tb) -> None:
|
|
298
|
+
super().__exit__(exc_type, exc, tb)
|
|
299
|
+
try:
|
|
300
|
+
self._tk_root.update_idletasks()
|
|
301
|
+
except Exception:
|
|
302
|
+
pass
|
|
303
|
+
return None
|
|
304
|
+
|
|
305
|
+
# ----- dev hot-reload hooks ----------------------------------------------
|
|
306
|
+
# Used only under `bootstack dev`; see bootstack.dev. AppShell/Workbench
|
|
307
|
+
# override the route hooks to preserve the selected page across a reload.
|
|
308
|
+
|
|
309
|
+
def _dev_reset_region(self) -> None:
|
|
310
|
+
"""Tear down the chrome + content the `with` body built, keep the root."""
|
|
311
|
+
stack = getattr(self, "_toolbar_stack", None)
|
|
312
|
+
if stack is not None:
|
|
313
|
+
try:
|
|
314
|
+
stack.destroy()
|
|
315
|
+
except Exception:
|
|
316
|
+
pass
|
|
317
|
+
self._toolbar_stack = None
|
|
318
|
+
self._chrome_toolbars = []
|
|
319
|
+
self._native_menu_renderer = None
|
|
320
|
+
self._cancel_native_menu_pending()
|
|
321
|
+
# Clear the native menu bar (macOS) so a rebuild doesn't double it.
|
|
322
|
+
try:
|
|
323
|
+
root = self._menu_root()
|
|
324
|
+
if root is not None:
|
|
325
|
+
root["menu"] = ""
|
|
326
|
+
except Exception:
|
|
327
|
+
pass
|
|
328
|
+
# Replace the content frame wholesale — destroying the subtree fires
|
|
329
|
+
# <Destroy> on every descendant (the normal teardown path) and avoids
|
|
330
|
+
# carrying stale flex bookkeeping into the rebuild.
|
|
331
|
+
old = getattr(self, "_content_frame", None)
|
|
332
|
+
if old is not None:
|
|
333
|
+
try:
|
|
334
|
+
old.destroy()
|
|
335
|
+
except Exception:
|
|
336
|
+
pass
|
|
337
|
+
self._content_frame = FlexFrame(self._region_root, **self._dev_frame_kwargs)
|
|
338
|
+
self._content_frame.pack(fill="both", expand=True)
|
|
339
|
+
try:
|
|
340
|
+
from bootstack.dev import _registry
|
|
341
|
+
|
|
342
|
+
_registry.reset_mounts()
|
|
343
|
+
except Exception:
|
|
344
|
+
pass
|
|
345
|
+
|
|
346
|
+
def _dev_after_rebuild(self) -> None:
|
|
347
|
+
"""Re-apply window chrome that lives outside the body, then flush.
|
|
348
|
+
|
|
349
|
+
Grows the window to fit if the rebuilt layout needs more room than the
|
|
350
|
+
current geometry, but never shrinks it — so a reload that adds content
|
|
351
|
+
doesn't clip it, without the jarring shrink when content is removed.
|
|
352
|
+
"""
|
|
353
|
+
self._ensure_default_titlebar()
|
|
354
|
+
try:
|
|
355
|
+
root = self._tk_root
|
|
356
|
+
root.update_idletasks()
|
|
357
|
+
cur_w, cur_h = root.winfo_width(), root.winfo_height()
|
|
358
|
+
new_w = max(cur_w, root.winfo_reqwidth())
|
|
359
|
+
new_h = max(cur_h, root.winfo_reqheight())
|
|
360
|
+
if new_w > cur_w or new_h > cur_h:
|
|
361
|
+
root.geometry(f"{new_w}x{new_h}+{root.winfo_x()}+{root.winfo_y()}")
|
|
362
|
+
except Exception:
|
|
363
|
+
pass
|
|
364
|
+
|
|
365
|
+
def _dev_capture_route(self) -> Any:
|
|
366
|
+
"""Route to restore after a reload. Plain App has none."""
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
def _dev_restore_route(self, route: Any) -> None:
|
|
370
|
+
"""Restore a route captured before a reload. No-op for plain App."""
|
|
371
|
+
return None
|