bootstack 0.1.0a1__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 +249 -0
- bootstack/__main__.py +5 -0
- bootstack/api/__init__.py +127 -0
- bootstack/api/app.py +30 -0
- bootstack/api/constants.py +3 -0
- bootstack/api/data.py +23 -0
- bootstack/api/dialogs.py +44 -0
- bootstack/api/i18n.py +17 -0
- bootstack/api/localization.py +16 -0
- bootstack/api/menu.py +7 -0
- bootstack/api/style.py +23 -0
- bootstack/api/utils.py +24 -0
- bootstack/api/widgets.py +137 -0
- bootstack/assets/__init__.py +24 -0
- bootstack/assets/bootstack-transparent.png +0 -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/border.png +0 -0
- bootstack/assets/elements/button-compact.png +0 -0
- bootstack/assets/elements/button-default.png +0 -0
- bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
- bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
- bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
- bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
- bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
- bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
- bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
- bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
- bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
- bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
- bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
- bootstack/assets/elements/button-group-vertical-center-default.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-after-compact.png +0 -0
- bootstack/assets/elements/input-after-default.png +0 -0
- bootstack/assets/elements/input-before-compact.png +0 -0
- bootstack/assets/elements/input-before-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/manifest.toml +480 -0
- bootstack/assets/elements/menu-item.png +0 -0
- bootstack/assets/elements/nav-button-compact.png +0 -0
- bootstack/assets/elements/nav-button-default.png +0 -0
- bootstack/assets/elements/nav-icon-button-compact.png +0 -0
- bootstack/assets/elements/nav-icon-button-default.png +0 -0
- bootstack/assets/elements/notebook-client-border.png +0 -0
- bootstack/assets/elements/notebook-tab-active.png +0 -0
- bootstack/assets/elements/notebook-tab-bar.png +0 -0
- bootstack/assets/elements/notebook-tab-normal.png +0 -0
- bootstack/assets/elements/notebook-tab-pill.png +0 -0
- bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
- bootstack/assets/elements/progress-bar-solid.png +0 -0
- bootstack/assets/elements/progress-bar-thin.png +0 -0
- bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
- bootstack/assets/elements/radio-selected.png +0 -0
- bootstack/assets/elements/radio-unselected.png +0 -0
- bootstack/assets/elements/scrollbar-horizontal.png +0 -0
- bootstack/assets/elements/scrollbar-vertical.png +0 -0
- bootstack/assets/elements/slider-handle-focus.png +0 -0
- bootstack/assets/elements/slider-handle.png +0 -0
- bootstack/assets/elements/slider-track-horizontal.png +0 -0
- bootstack/assets/elements/slider-track-vertical.png +0 -0
- bootstack/assets/elements/switch-off.png +0 -0
- bootstack/assets/elements/switch-on.png +0 -0
- bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
- bootstack/assets/elements/tabs-bar-vertical.png +0 -0
- bootstack/assets/elements/tabs-pill.png +0 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
- bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
- bootstack/assets/themes/__init__.py +0 -0
- bootstack/assets/themes/amber-dark.json +32 -0
- bootstack/assets/themes/amber-light.json +32 -0
- bootstack/assets/themes/aurora-dark.json +32 -0
- bootstack/assets/themes/aurora-light.json +32 -0
- bootstack/assets/themes/bootstrap-dark.json +32 -0
- bootstack/assets/themes/bootstrap-light.json +32 -0
- bootstack/assets/themes/classic-dark.json +32 -0
- bootstack/assets/themes/classic-light.json +32 -0
- bootstack/assets/themes/docs-dark.json +32 -0
- bootstack/assets/themes/docs-light.json +32 -0
- bootstack/assets/themes/forest-dark.json +32 -0
- bootstack/assets/themes/forest-light.json +32 -0
- bootstack/assets/themes/ocean-dark.json +32 -0
- bootstack/assets/themes/ocean-light.json +32 -0
- bootstack/assets/themes/rose-dark.json +32 -0
- bootstack/assets/themes/rose-light.json +32 -0
- bootstack/assets/widgets/__init__.py +0 -0
- bootstack/assets/widgets/badge-default.png +0 -0
- bootstack/assets/widgets/badge-pill.png +0 -0
- bootstack/assets/widgets/border.png +0 -0
- bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
- bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
- bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
- bootstack/assets/widgets/button-group-vertical-after.png +0 -0
- bootstack/assets/widgets/button-group-vertical-before.png +0 -0
- bootstack/assets/widgets/button-group-vertical-center.png +0 -0
- bootstack/assets/widgets/button.png +0 -0
- bootstack/assets/widgets/checkbox-checked.png +0 -0
- bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
- bootstack/assets/widgets/checkbox-unchecked.png +0 -0
- bootstack/assets/widgets/field.png +0 -0
- bootstack/assets/widgets/icon-button.png +0 -0
- bootstack/assets/widgets/input-inner.png +0 -0
- bootstack/assets/widgets/input-prefix.png +0 -0
- bootstack/assets/widgets/input-suffix.png +0 -0
- bootstack/assets/widgets/input.png +0 -0
- bootstack/assets/widgets/list-item-focus.png +0 -0
- bootstack/assets/widgets/list-item-separated.png +0 -0
- bootstack/assets/widgets/menu-item-separated.png +0 -0
- bootstack/assets/widgets/notebook-client-border.png +0 -0
- bootstack/assets/widgets/notebook-pill-active.png +0 -0
- bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
- bootstack/assets/widgets/notebook-tab-active.png +0 -0
- bootstack/assets/widgets/notebook-tab-border.png +0 -0
- bootstack/assets/widgets/notebook-tab-normal.png +0 -0
- bootstack/assets/widgets/notebook-underline.png +0 -0
- bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
- bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
- bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
- bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
- bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
- bootstack/assets/widgets/progress-trough-vertical.png +0 -0
- bootstack/assets/widgets/radio-selected.png +0 -0
- bootstack/assets/widgets/radio-unselected.png +0 -0
- bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
- bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
- bootstack/assets/widgets/separator-horizontal.png +0 -0
- bootstack/assets/widgets/separator-vertical.png +0 -0
- bootstack/assets/widgets/slider-handle-focus.png +0 -0
- bootstack/assets/widgets/slider-handle.png +0 -0
- bootstack/assets/widgets/slider-track-horizontal.png +0 -0
- bootstack/assets/widgets/slider-track-vertical.png +0 -0
- bootstack/assets/widgets/switch-off.png +0 -0
- bootstack/assets/widgets/switch-on.png +0 -0
- bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
- bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
- bootstack/assets/widgets/tabs-pill.png +0 -0
- bootstack/cli/__init__.py +124 -0
- bootstack/cli/__main__.py +6 -0
- bootstack/cli/add.py +439 -0
- bootstack/cli/build.py +115 -0
- bootstack/cli/config.py +287 -0
- bootstack/cli/demo.py +1267 -0
- bootstack/cli/doctor.py +195 -0
- bootstack/cli/list_cmd.py +71 -0
- bootstack/cli/promote.py +120 -0
- bootstack/cli/pyinstaller.py +246 -0
- bootstack/cli/run.py +99 -0
- bootstack/cli/start.py +105 -0
- bootstack/cli/templates/__init__.py +861 -0
- bootstack/constants.py +325 -0
- bootstack/core/__init__.py +34 -0
- bootstack/core/capabilities/__init__.py +45 -0
- bootstack/core/capabilities/after.py +103 -0
- bootstack/core/capabilities/bind.py +154 -0
- bootstack/core/capabilities/bindtags.py +112 -0
- bootstack/core/capabilities/busy.py +61 -0
- bootstack/core/capabilities/clipboard.py +88 -0
- bootstack/core/capabilities/focus.py +118 -0
- bootstack/core/capabilities/grab.py +65 -0
- bootstack/core/capabilities/grid.py +188 -0
- bootstack/core/capabilities/localization.py +231 -0
- bootstack/core/capabilities/pack.py +119 -0
- bootstack/core/capabilities/place.py +92 -0
- bootstack/core/capabilities/selection.py +136 -0
- bootstack/core/capabilities/signals.py +242 -0
- bootstack/core/capabilities/winfo.py +315 -0
- bootstack/core/colorutils.py +234 -0
- bootstack/core/exceptions.py +95 -0
- bootstack/core/images.py +283 -0
- bootstack/core/localization/README.md +90 -0
- bootstack/core/localization/__init__.py +13 -0
- bootstack/core/localization/intl_format.py +580 -0
- bootstack/core/localization/msgcat.py +425 -0
- bootstack/core/localization/specs.py +143 -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/publisher.py +147 -0
- bootstack/core/signals/README.md +112 -0
- bootstack/core/signals/__init__.py +8 -0
- bootstack/core/signals/integration.py +100 -0
- bootstack/core/signals/signal.py +317 -0
- bootstack/core/signals/types.py +4 -0
- bootstack/core/validation/__init__.py +5 -0
- bootstack/core/validation/types.py +13 -0
- bootstack/core/validation/validation_result.py +17 -0
- bootstack/core/validation/validation_rules.py +112 -0
- bootstack/core/variables.py +62 -0
- bootstack/datasource/README.md +607 -0
- bootstack/datasource/__init__.py +51 -0
- bootstack/datasource/base.py +474 -0
- bootstack/datasource/file_source.py +541 -0
- bootstack/datasource/memory_source.py +482 -0
- bootstack/datasource/sqlite_source.py +453 -0
- bootstack/datasource/types.py +259 -0
- bootstack/dialogs/__init__.py +56 -0
- bootstack/dialogs/colorchooser.py +674 -0
- bootstack/dialogs/colordropper.py +257 -0
- bootstack/dialogs/datedialog.py +404 -0
- bootstack/dialogs/dialog.py +514 -0
- bootstack/dialogs/filterdialog.py +358 -0
- bootstack/dialogs/fontdialog.py +339 -0
- bootstack/dialogs/formdialog.py +541 -0
- bootstack/dialogs/message.py +489 -0
- bootstack/dialogs/query.py +561 -0
- bootstack/py.typed +1 -0
- bootstack/runtime/__init__.py +3 -0
- bootstack/runtime/app.py +879 -0
- bootstack/runtime/base_window.py +786 -0
- bootstack/runtime/events.py +399 -0
- bootstack/runtime/menu.py +510 -0
- bootstack/runtime/shortcuts.py +423 -0
- bootstack/runtime/tk_patch.py +31 -0
- bootstack/runtime/toplevel.py +131 -0
- bootstack/runtime/utility.py +371 -0
- bootstack/runtime/visual_focus.py +228 -0
- bootstack/runtime/window_utilities.py +1043 -0
- bootstack/style/__init__.py +5498 -0
- bootstack/style/bootstyle.py +507 -0
- bootstack/style/bootstyle_builder_base.py +752 -0
- bootstack/style/bootstyle_builder_mixed.py +93 -0
- bootstack/style/bootstyle_builder_tk.py +109 -0
- bootstack/style/bootstyle_builder_ttk.py +354 -0
- bootstack/style/builders/__init__.py +51 -0
- bootstack/style/builders/badge.py +44 -0
- bootstack/style/builders/button.py +453 -0
- bootstack/style/builders/buttongroup.py +344 -0
- bootstack/style/builders/calendar.py +271 -0
- bootstack/style/builders/checkbutton.py +95 -0
- bootstack/style/builders/combobox.py +112 -0
- bootstack/style/builders/contextmenu.py +268 -0
- bootstack/style/builders/entry.py +83 -0
- bootstack/style/builders/expander.py +171 -0
- bootstack/style/builders/field.py +312 -0
- bootstack/style/builders/frame.py +27 -0
- bootstack/style/builders/label.py +28 -0
- bootstack/style/builders/labelframe.py +41 -0
- bootstack/style/builders/listview.py +267 -0
- bootstack/style/builders/menubar.py +74 -0
- bootstack/style/builders/menubutton.py +408 -0
- bootstack/style/builders/notebook.py +316 -0
- bootstack/style/builders/panedwindow.py +25 -0
- bootstack/style/builders/progressbar.py +71 -0
- bootstack/style/builders/radiobutton.py +68 -0
- bootstack/style/builders/scale.py +66 -0
- bootstack/style/builders/scrollbar.py +360 -0
- bootstack/style/builders/separator.py +45 -0
- bootstack/style/builders/sidenav.py +313 -0
- bootstack/style/builders/sizegrip.py +15 -0
- bootstack/style/builders/spinbox.py +119 -0
- bootstack/style/builders/switch.py +67 -0
- bootstack/style/builders/tabitem.py +205 -0
- bootstack/style/builders/toolbutton.py +260 -0
- bootstack/style/builders/tooltip.py +26 -0
- bootstack/style/builders/treeview.py +269 -0
- bootstack/style/builders/utils.py +404 -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/style.py +499 -0
- bootstack/style/theme_provider.py +449 -0
- bootstack/style/tk_patch.py +5 -0
- bootstack/style/token_maps.py +42 -0
- bootstack/style/types.py +32 -0
- bootstack/style/typography.py +527 -0
- bootstack/style/utility.py +696 -0
- bootstack/themes/__init__.py +12 -0
- bootstack/themes/standard.py +415 -0
- bootstack/themes/user.py +45 -0
- bootstack/widgets/__init__.py +53 -0
- bootstack/widgets/composites/__init__.py +38 -0
- bootstack/widgets/composites/accordion.py +385 -0
- bootstack/widgets/composites/appshell.py +445 -0
- bootstack/widgets/composites/buttongroup.py +391 -0
- bootstack/widgets/composites/calendar.py +914 -0
- bootstack/widgets/composites/compositeframe.py +282 -0
- bootstack/widgets/composites/contextmenu.py +1754 -0
- bootstack/widgets/composites/dateentry.py +261 -0
- bootstack/widgets/composites/dropdownbutton.py +190 -0
- bootstack/widgets/composites/expander.py +508 -0
- bootstack/widgets/composites/field.py +448 -0
- bootstack/widgets/composites/floodgauge.py +434 -0
- bootstack/widgets/composites/form.py +983 -0
- bootstack/widgets/composites/labeledscale.py +209 -0
- bootstack/widgets/composites/list/__init__.py +15 -0
- bootstack/widgets/composites/list/listitem.py +733 -0
- bootstack/widgets/composites/list/listview.py +1507 -0
- bootstack/widgets/composites/menubar.py +303 -0
- bootstack/widgets/composites/meter.py +882 -0
- bootstack/widgets/composites/numericentry.py +183 -0
- bootstack/widgets/composites/pagestack.py +330 -0
- bootstack/widgets/composites/passwordentry.py +149 -0
- bootstack/widgets/composites/pathentry.py +223 -0
- bootstack/widgets/composites/radiogroup.py +466 -0
- bootstack/widgets/composites/scrolledtext.py +388 -0
- bootstack/widgets/composites/scrolledtext.pyi +186 -0
- bootstack/widgets/composites/scrollview.py +675 -0
- bootstack/widgets/composites/selectbox.py +544 -0
- bootstack/widgets/composites/sidenav/__init__.py +24 -0
- bootstack/widgets/composites/sidenav/group.py +485 -0
- bootstack/widgets/composites/sidenav/header.py +83 -0
- bootstack/widgets/composites/sidenav/item.py +413 -0
- bootstack/widgets/composites/sidenav/separator.py +51 -0
- bootstack/widgets/composites/sidenav/view.py +919 -0
- bootstack/widgets/composites/spinnerentry.py +232 -0
- bootstack/widgets/composites/tableview/__init__.py +5 -0
- bootstack/widgets/composites/tableview/tableview.py +2254 -0
- bootstack/widgets/composites/tableview/types.py +169 -0
- bootstack/widgets/composites/tabs/__init__.py +6 -0
- bootstack/widgets/composites/tabs/tabitem.py +372 -0
- bootstack/widgets/composites/tabs/tabs.py +478 -0
- bootstack/widgets/composites/tabs/tabview.py +352 -0
- bootstack/widgets/composites/textentry.py +90 -0
- bootstack/widgets/composites/timeentry.py +189 -0
- bootstack/widgets/composites/toast.py +364 -0
- bootstack/widgets/composites/togglegroup.py +382 -0
- bootstack/widgets/composites/toolbar.py +393 -0
- bootstack/widgets/composites/tooltip.py +404 -0
- bootstack/widgets/internal/__init__.py +0 -0
- bootstack/widgets/internal/wrapper_base.py +304 -0
- bootstack/widgets/mixins/__init__.py +25 -0
- bootstack/widgets/mixins/configure_mixin.py +186 -0
- bootstack/widgets/mixins/entry_mixin.py +70 -0
- bootstack/widgets/mixins/font_mixin.py +346 -0
- bootstack/widgets/mixins/icon_mixin.py +38 -0
- bootstack/widgets/mixins/localization_mixin.py +255 -0
- bootstack/widgets/mixins/signal_mixin.py +272 -0
- bootstack/widgets/mixins/validation_mixin.py +204 -0
- bootstack/widgets/parts/__init__.py +11 -0
- bootstack/widgets/parts/numberentry_part.py +345 -0
- bootstack/widgets/parts/spinnerentry_part.py +394 -0
- bootstack/widgets/parts/textentry_part.py +344 -0
- bootstack/widgets/primitives/__init__.py +55 -0
- bootstack/widgets/primitives/badge.py +44 -0
- bootstack/widgets/primitives/button.py +89 -0
- bootstack/widgets/primitives/card.py +66 -0
- bootstack/widgets/primitives/checkbutton.py +124 -0
- bootstack/widgets/primitives/checktoggle.py +53 -0
- bootstack/widgets/primitives/combobox.py +165 -0
- bootstack/widgets/primitives/entry.py +98 -0
- bootstack/widgets/primitives/frame.py +206 -0
- bootstack/widgets/primitives/gridframe.py +479 -0
- bootstack/widgets/primitives/label.py +95 -0
- bootstack/widgets/primitives/labelframe.py +63 -0
- bootstack/widgets/primitives/menubutton.py +118 -0
- bootstack/widgets/primitives/notebook.py +551 -0
- bootstack/widgets/primitives/optionmenu.py +248 -0
- bootstack/widgets/primitives/packframe.py +228 -0
- bootstack/widgets/primitives/panedwindow.py +58 -0
- bootstack/widgets/primitives/progressbar.py +95 -0
- bootstack/widgets/primitives/radiobutton.py +115 -0
- bootstack/widgets/primitives/radiotoggle.py +50 -0
- bootstack/widgets/primitives/scale.py +85 -0
- bootstack/widgets/primitives/scrollbar.py +56 -0
- bootstack/widgets/primitives/separator.py +56 -0
- bootstack/widgets/primitives/sizegrip.py +47 -0
- bootstack/widgets/primitives/spinbox.py +91 -0
- bootstack/widgets/primitives/switch.py +41 -0
- bootstack/widgets/primitives/treeview.py +77 -0
- bootstack/widgets/types.py +20 -0
- bootstack-0.1.0a1.dist-info/METADATA +196 -0
- bootstack-0.1.0a1.dist-info/RECORD +419 -0
- bootstack-0.1.0a1.dist-info/WHEEL +5 -0
- bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
- bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
- bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
- bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,861 @@
|
|
|
1
|
+
"""Project templates for bootstack start command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
ContainerType = Literal["grid", "pack"]
|
|
9
|
+
TemplateType = Literal["basic", "appshell"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# =============================================================================
|
|
13
|
+
# Main entry point template
|
|
14
|
+
# =============================================================================
|
|
15
|
+
|
|
16
|
+
MAIN_PY_TEMPLATE = '''\
|
|
17
|
+
"""
|
|
18
|
+
{app_name} - A bootstack application.
|
|
19
|
+
|
|
20
|
+
Run with: python -m {module_name}
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import os
|
|
24
|
+
|
|
25
|
+
import bootstack as bs
|
|
26
|
+
|
|
27
|
+
from {module_name}.views.main_view import MainView
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def main() -> None:
|
|
31
|
+
"""Application entry point."""
|
|
32
|
+
app = bs.App(
|
|
33
|
+
title="{app_name}",
|
|
34
|
+
theme=os.environ.get("BOOTSTACK_THEME", "{theme}"),
|
|
35
|
+
size=(800, 600),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Create and display main view
|
|
39
|
+
MainView(app).pack(fill="both", expand=True)
|
|
40
|
+
|
|
41
|
+
app.mainloop()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
main()
|
|
46
|
+
'''
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# =============================================================================
|
|
50
|
+
# View templates (GridFrame vs PackFrame)
|
|
51
|
+
# =============================================================================
|
|
52
|
+
|
|
53
|
+
MAIN_VIEW_GRID_TEMPLATE = '''\
|
|
54
|
+
"""Main application view."""
|
|
55
|
+
|
|
56
|
+
import bootstack as bs
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MainView(bs.GridFrame):
|
|
60
|
+
"""Main view using GridFrame layout."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, master, **kwargs):
|
|
63
|
+
super().__init__(
|
|
64
|
+
master,
|
|
65
|
+
columns=["auto", 1],
|
|
66
|
+
gap=10,
|
|
67
|
+
padding=20,
|
|
68
|
+
**kwargs,
|
|
69
|
+
)
|
|
70
|
+
self._create_widgets()
|
|
71
|
+
|
|
72
|
+
def _create_widgets(self) -> None:
|
|
73
|
+
"""Create and layout widgets."""
|
|
74
|
+
# Header
|
|
75
|
+
bs.Label(
|
|
76
|
+
self,
|
|
77
|
+
text="Welcome to {app_name}",
|
|
78
|
+
font=("TkDefaultFont", 18, "bold"),
|
|
79
|
+
).grid(row=0, column=0, columnspan=2, sticky="w", pady=(0, 20))
|
|
80
|
+
|
|
81
|
+
# Example form layout
|
|
82
|
+
bs.Label(self, text="Name:").grid(row=1, column=0, sticky="e")
|
|
83
|
+
self.name_entry = bs.Entry(self)
|
|
84
|
+
self.name_entry.grid(row=1, column=1, sticky="ew")
|
|
85
|
+
|
|
86
|
+
bs.Label(self, text="Email:").grid(row=2, column=0, sticky="e")
|
|
87
|
+
self.email_entry = bs.Entry(self)
|
|
88
|
+
self.email_entry.grid(row=2, column=1, sticky="ew")
|
|
89
|
+
|
|
90
|
+
# Action button
|
|
91
|
+
bs.Button(
|
|
92
|
+
self,
|
|
93
|
+
text="Get Started",
|
|
94
|
+
accent="primary",
|
|
95
|
+
command=self._on_submit,
|
|
96
|
+
).grid(row=3, column=0, columnspan=2, pady=(20, 0))
|
|
97
|
+
|
|
98
|
+
def _on_submit(self) -> None:
|
|
99
|
+
"""Handle form submission."""
|
|
100
|
+
name = self.name_entry.get()
|
|
101
|
+
email = self.email_entry.get()
|
|
102
|
+
print(f"Name: {{name}}, Email: {{email}}")
|
|
103
|
+
'''
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
MAIN_VIEW_PACK_TEMPLATE = '''\
|
|
107
|
+
"""Main application view."""
|
|
108
|
+
|
|
109
|
+
import bootstack as bs
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class MainView(bs.PackFrame):
|
|
113
|
+
"""Main view using PackFrame layout."""
|
|
114
|
+
|
|
115
|
+
def __init__(self, master, **kwargs):
|
|
116
|
+
super().__init__(
|
|
117
|
+
master,
|
|
118
|
+
direction="vertical",
|
|
119
|
+
gap=10,
|
|
120
|
+
padding=20,
|
|
121
|
+
**kwargs,
|
|
122
|
+
)
|
|
123
|
+
self._create_widgets()
|
|
124
|
+
|
|
125
|
+
def _create_widgets(self) -> None:
|
|
126
|
+
"""Create and layout widgets."""
|
|
127
|
+
# Header
|
|
128
|
+
header = bs.Label(
|
|
129
|
+
self,
|
|
130
|
+
text="Welcome to {app_name}",
|
|
131
|
+
font=("TkDefaultFont", 18, "bold"),
|
|
132
|
+
)
|
|
133
|
+
self.add(header)
|
|
134
|
+
|
|
135
|
+
# Spacer
|
|
136
|
+
self.add(bs.Frame(self, height=10))
|
|
137
|
+
|
|
138
|
+
# Name field
|
|
139
|
+
name_frame = bs.PackFrame(self, direction="horizontal", gap=10)
|
|
140
|
+
bs.Label(name_frame, text="Name:", width=10).pack(side="left")
|
|
141
|
+
self.name_entry = bs.Entry(name_frame)
|
|
142
|
+
self.name_entry.pack(side="left", fill="x", expand=True)
|
|
143
|
+
self.add(name_frame, fill_items="x")
|
|
144
|
+
|
|
145
|
+
# Email field
|
|
146
|
+
email_frame = bs.PackFrame(self, direction="horizontal", gap=10)
|
|
147
|
+
bs.Label(email_frame, text="Email:", width=10).pack(side="left")
|
|
148
|
+
self.email_entry = bs.Entry(email_frame)
|
|
149
|
+
self.email_entry.pack(side="left", fill="x", expand=True)
|
|
150
|
+
self.add(email_frame, fill_items="x")
|
|
151
|
+
|
|
152
|
+
# Action button
|
|
153
|
+
self.add(bs.Frame(self, height=10))
|
|
154
|
+
btn = bs.Button(
|
|
155
|
+
self,
|
|
156
|
+
text="Get Started",
|
|
157
|
+
accent="primary",
|
|
158
|
+
command=self._on_submit,
|
|
159
|
+
)
|
|
160
|
+
self.add(btn)
|
|
161
|
+
|
|
162
|
+
def _on_submit(self) -> None:
|
|
163
|
+
"""Handle form submission."""
|
|
164
|
+
name = self.name_entry.get()
|
|
165
|
+
email = self.email_entry.get()
|
|
166
|
+
print(f"Name: {{name}}, Email: {{email}}")
|
|
167
|
+
'''
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# =============================================================================
|
|
171
|
+
# View/Dialog add templates
|
|
172
|
+
# =============================================================================
|
|
173
|
+
|
|
174
|
+
VIEW_GRID_TEMPLATE = '''\
|
|
175
|
+
"""
|
|
176
|
+
{class_name} view.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
import bootstack as bs
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class {class_name}(bs.GridFrame):
|
|
183
|
+
"""{class_name} using GridFrame layout."""
|
|
184
|
+
|
|
185
|
+
def __init__(self, master, **kwargs):
|
|
186
|
+
super().__init__(
|
|
187
|
+
master,
|
|
188
|
+
columns=["auto", 1],
|
|
189
|
+
gap=10,
|
|
190
|
+
padding=20,
|
|
191
|
+
**kwargs,
|
|
192
|
+
)
|
|
193
|
+
self._create_widgets()
|
|
194
|
+
|
|
195
|
+
def _create_widgets(self) -> None:
|
|
196
|
+
"""Create and layout widgets."""
|
|
197
|
+
bs.Label(
|
|
198
|
+
self,
|
|
199
|
+
text="{class_name}",
|
|
200
|
+
font=("TkDefaultFont", 14, "bold"),
|
|
201
|
+
).grid(row=0, column=0, columnspan=2, sticky="w")
|
|
202
|
+
|
|
203
|
+
# Add your widgets here
|
|
204
|
+
'''
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
VIEW_PACK_TEMPLATE = '''\
|
|
208
|
+
"""
|
|
209
|
+
{class_name} view.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
import bootstack as bs
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class {class_name}(bs.PackFrame):
|
|
216
|
+
"""{class_name} using PackFrame layout."""
|
|
217
|
+
|
|
218
|
+
def __init__(self, master, **kwargs):
|
|
219
|
+
super().__init__(
|
|
220
|
+
master,
|
|
221
|
+
direction="vertical",
|
|
222
|
+
gap=10,
|
|
223
|
+
padding=20,
|
|
224
|
+
**kwargs,
|
|
225
|
+
)
|
|
226
|
+
self._create_widgets()
|
|
227
|
+
|
|
228
|
+
def _create_widgets(self) -> None:
|
|
229
|
+
"""Create and layout widgets."""
|
|
230
|
+
header = bs.Label(
|
|
231
|
+
self,
|
|
232
|
+
text="{class_name}",
|
|
233
|
+
font=("TkDefaultFont", 14, "bold"),
|
|
234
|
+
)
|
|
235
|
+
self.add(header)
|
|
236
|
+
|
|
237
|
+
# Add your widgets here
|
|
238
|
+
'''
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
DIALOG_TEMPLATE = '''\
|
|
242
|
+
"""
|
|
243
|
+
{class_name} dialog.
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
import bootstack as bs
|
|
247
|
+
from bootstack.dialogs import Dialog
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class {class_name}(Dialog):
|
|
251
|
+
"""{class_name} modal dialog."""
|
|
252
|
+
|
|
253
|
+
def __init__(self, parent, title: str = "{class_name}", **kwargs):
|
|
254
|
+
super().__init__(parent, title=title, **kwargs)
|
|
255
|
+
|
|
256
|
+
def create_body(self, master) -> bs.Frame:
|
|
257
|
+
"""Create the dialog body."""
|
|
258
|
+
body = bs.Frame(master, padding=20)
|
|
259
|
+
|
|
260
|
+
bs.Label(
|
|
261
|
+
body,
|
|
262
|
+
text="Dialog content goes here",
|
|
263
|
+
).pack(pady=10)
|
|
264
|
+
|
|
265
|
+
return body
|
|
266
|
+
|
|
267
|
+
def create_buttonbox(self, master) -> bs.Frame:
|
|
268
|
+
"""Create the dialog buttons."""
|
|
269
|
+
box = bs.Frame(master, padding=(20, 10))
|
|
270
|
+
|
|
271
|
+
bs.Button(
|
|
272
|
+
box,
|
|
273
|
+
text="Cancel",
|
|
274
|
+
command=self.cancel,
|
|
275
|
+
).pack(side="right", padx=5)
|
|
276
|
+
|
|
277
|
+
bs.Button(
|
|
278
|
+
box,
|
|
279
|
+
text="OK",
|
|
280
|
+
accent="primary",
|
|
281
|
+
command=self.ok,
|
|
282
|
+
).pack(side="right")
|
|
283
|
+
|
|
284
|
+
return box
|
|
285
|
+
|
|
286
|
+
def validate(self) -> bool:
|
|
287
|
+
"""Validate dialog input before closing."""
|
|
288
|
+
return True
|
|
289
|
+
|
|
290
|
+
def apply(self) -> None:
|
|
291
|
+
"""Process dialog input after OK is clicked."""
|
|
292
|
+
self.result = True
|
|
293
|
+
'''
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
# =============================================================================
|
|
297
|
+
# Package init template
|
|
298
|
+
# =============================================================================
|
|
299
|
+
|
|
300
|
+
INIT_PY_TEMPLATE = '''\
|
|
301
|
+
"""{app_name} package."""
|
|
302
|
+
|
|
303
|
+
__version__ = "0.1.0"
|
|
304
|
+
'''
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
# =============================================================================
|
|
308
|
+
# README template
|
|
309
|
+
# =============================================================================
|
|
310
|
+
|
|
311
|
+
README_TEMPLATE = '''\
|
|
312
|
+
# {app_name}
|
|
313
|
+
|
|
314
|
+
A bootstack application.
|
|
315
|
+
|
|
316
|
+
## Getting Started
|
|
317
|
+
|
|
318
|
+
### Development
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# Run the application
|
|
322
|
+
python -m {module_name}
|
|
323
|
+
|
|
324
|
+
# Or use the CLI
|
|
325
|
+
bootstack run
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Building for Distribution
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Promote to packaging-ready (adds PyInstaller support)
|
|
332
|
+
bootstack promote --pyinstaller
|
|
333
|
+
|
|
334
|
+
# Build the executable
|
|
335
|
+
bootstack build
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Project Structure
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
{project_dir}/
|
|
342
|
+
├── src/{module_name}/
|
|
343
|
+
│ ├── __init__.py
|
|
344
|
+
│ ├── main.py
|
|
345
|
+
│ └── views/
|
|
346
|
+
│ └── main_view.py
|
|
347
|
+
├── assets/
|
|
348
|
+
├── bootstack.toml
|
|
349
|
+
└── README.md
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Configuration
|
|
353
|
+
|
|
354
|
+
Application settings are defined in `bootstack.toml`:
|
|
355
|
+
|
|
356
|
+
- `[app]` - Application metadata
|
|
357
|
+
- `[settings]` - Runtime settings (theme, language)
|
|
358
|
+
- `[layout]` - Default layout preferences
|
|
359
|
+
- `[build]` - Build/packaging configuration (after `bootstack promote`)
|
|
360
|
+
'''
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
# =============================================================================
|
|
364
|
+
# AppShell templates
|
|
365
|
+
# =============================================================================
|
|
366
|
+
|
|
367
|
+
APPSHELL_MAIN_PY_TEMPLATE = '''\
|
|
368
|
+
"""
|
|
369
|
+
{app_name} - A bootstack application.
|
|
370
|
+
|
|
371
|
+
Run with: python -m {module_name}
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
import os
|
|
375
|
+
|
|
376
|
+
import bootstack as bs
|
|
377
|
+
|
|
378
|
+
from {module_name}.pages.home_page import HomePage
|
|
379
|
+
from {module_name}.pages.settings_page import SettingsPage
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def main() -> None:
|
|
383
|
+
"""Application entry point."""
|
|
384
|
+
shell = bs.AppShell(
|
|
385
|
+
title="{app_name}",
|
|
386
|
+
theme=os.environ.get("BOOTSTACK_THEME", "{theme}"),
|
|
387
|
+
size=(1000, 650),
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# Add a theme toggle button to the toolbar
|
|
391
|
+
shell.toolbar.add_button(icon="sun", command=bs.toggle_theme)
|
|
392
|
+
|
|
393
|
+
# Navigation pages
|
|
394
|
+
home = shell.add_page("home", text="Home", icon="house")
|
|
395
|
+
HomePage(home)
|
|
396
|
+
|
|
397
|
+
shell.add_separator()
|
|
398
|
+
|
|
399
|
+
# Footer pages
|
|
400
|
+
settings = shell.add_page("settings", text="Settings", icon="gear", is_footer=True)
|
|
401
|
+
SettingsPage(settings)
|
|
402
|
+
|
|
403
|
+
# Start on the home page
|
|
404
|
+
shell.navigate("home")
|
|
405
|
+
shell.mainloop()
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
if __name__ == "__main__":
|
|
409
|
+
main()
|
|
410
|
+
'''
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
APPSHELL_HOME_PAGE_TEMPLATE = '''\
|
|
414
|
+
"""Home page."""
|
|
415
|
+
|
|
416
|
+
import bootstack as bs
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class HomePage:
|
|
420
|
+
"""Home page content.
|
|
421
|
+
|
|
422
|
+
Pages in an AppShell are not widget subclasses. The `parent` frame
|
|
423
|
+
is created by `shell.add_page()` and this class populates it.
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
def __init__(self, parent):
|
|
427
|
+
self.parent = parent
|
|
428
|
+
self._build()
|
|
429
|
+
|
|
430
|
+
def _build(self):
|
|
431
|
+
bs.Label(
|
|
432
|
+
self.parent,
|
|
433
|
+
text="Welcome to {app_name}",
|
|
434
|
+
font="heading-xl",
|
|
435
|
+
).pack(anchor="w", padx=20, pady=(20, 10))
|
|
436
|
+
|
|
437
|
+
bs.Label(
|
|
438
|
+
self.parent,
|
|
439
|
+
text="This is your home page. Edit this file to get started.",
|
|
440
|
+
wraplength=500,
|
|
441
|
+
).pack(anchor="w", padx=20, pady=(0, 20))
|
|
442
|
+
|
|
443
|
+
content = bs.LabelFrame(self.parent, text="Getting Started", padding=20)
|
|
444
|
+
content.pack(fill="both", expand=True, padx=20, pady=(0, 20))
|
|
445
|
+
|
|
446
|
+
bs.Label(
|
|
447
|
+
content,
|
|
448
|
+
text=(
|
|
449
|
+
"Add your widgets here.\\n\\n"
|
|
450
|
+
"To add another page:\\n"
|
|
451
|
+
" 1. Run 'bootstack add page <Name>' to generate the file under pages/.\\n"
|
|
452
|
+
" 2. In main.py, import it, call shell.add_page(...), and pass\\n"
|
|
453
|
+
" the returned frame to your page class. The CLI prints the\\n"
|
|
454
|
+
" exact lines to paste."
|
|
455
|
+
),
|
|
456
|
+
).pack(expand=True)
|
|
457
|
+
'''
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
APPSHELL_SETTINGS_PAGE_TEMPLATE = '''\
|
|
461
|
+
"""Settings page."""
|
|
462
|
+
|
|
463
|
+
import bootstack as bs
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
class SettingsPage:
|
|
467
|
+
"""Settings page content.
|
|
468
|
+
|
|
469
|
+
Pages in an AppShell are not widget subclasses. The `parent` frame
|
|
470
|
+
is created by `shell.add_page()` and this class populates it.
|
|
471
|
+
"""
|
|
472
|
+
|
|
473
|
+
def __init__(self, parent):
|
|
474
|
+
self.parent = parent
|
|
475
|
+
self._build()
|
|
476
|
+
|
|
477
|
+
def _build(self):
|
|
478
|
+
bs.Label(
|
|
479
|
+
self.parent,
|
|
480
|
+
text="Settings",
|
|
481
|
+
font="heading-xl",
|
|
482
|
+
).pack(anchor="w", padx=20, pady=(20, 10))
|
|
483
|
+
|
|
484
|
+
bs.Label(
|
|
485
|
+
self.parent,
|
|
486
|
+
text="Configure your application preferences.",
|
|
487
|
+
wraplength=500,
|
|
488
|
+
).pack(anchor="w", padx=20, pady=(0, 20))
|
|
489
|
+
|
|
490
|
+
content = bs.LabelFrame(self.parent, text="Preferences", padding=20)
|
|
491
|
+
content.pack(fill="both", expand=True, padx=20, pady=(0, 20))
|
|
492
|
+
|
|
493
|
+
# Example settings
|
|
494
|
+
theme_frame = bs.Frame(content)
|
|
495
|
+
theme_frame.pack(fill="x", pady=(0, 10))
|
|
496
|
+
bs.Label(theme_frame, text="Theme:", width=15).pack(side="left")
|
|
497
|
+
bs.Button(
|
|
498
|
+
theme_frame,
|
|
499
|
+
text="Toggle Light/Dark",
|
|
500
|
+
command=bs.toggle_theme,
|
|
501
|
+
).pack(side="left")
|
|
502
|
+
'''
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
APPSHELL_PAGE_TEMPLATE = '''\
|
|
506
|
+
"""{page_title} page."""
|
|
507
|
+
|
|
508
|
+
import bootstack as bs
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
class {class_name}:
|
|
512
|
+
"""{page_title} page content.
|
|
513
|
+
|
|
514
|
+
Pages in an AppShell are not widget subclasses. The `parent` frame
|
|
515
|
+
is created by `shell.add_page()` and this class populates it.
|
|
516
|
+
"""
|
|
517
|
+
|
|
518
|
+
def __init__(self, parent):
|
|
519
|
+
self.parent = parent
|
|
520
|
+
self._build()
|
|
521
|
+
|
|
522
|
+
def _build(self):
|
|
523
|
+
bs.Label(
|
|
524
|
+
self.parent,
|
|
525
|
+
text="{page_title}",
|
|
526
|
+
font="heading-xl",
|
|
527
|
+
).pack(anchor="w", padx=20, pady=(20, 10))
|
|
528
|
+
|
|
529
|
+
content = bs.LabelFrame(self.parent, text="Content", padding=20)
|
|
530
|
+
content.pack(fill="both", expand=True, padx=20, pady=(0, 20))
|
|
531
|
+
|
|
532
|
+
# Add your widgets here
|
|
533
|
+
'''
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
APPSHELL_README_TEMPLATE = '''\
|
|
537
|
+
# {app_name}
|
|
538
|
+
|
|
539
|
+
A bootstack application using AppShell navigation.
|
|
540
|
+
|
|
541
|
+
## Getting Started
|
|
542
|
+
|
|
543
|
+
### Development
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
# Run the application
|
|
547
|
+
python -m {module_name}
|
|
548
|
+
|
|
549
|
+
# Or use the CLI
|
|
550
|
+
bootstack run
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Adding Pages
|
|
554
|
+
|
|
555
|
+
```bash
|
|
556
|
+
# Scaffold a new page
|
|
557
|
+
bootstack add page DashboardPage
|
|
558
|
+
|
|
559
|
+
# Then wire it up in main.py:
|
|
560
|
+
# from {module_name}.pages.dashboard_page import DashboardPage
|
|
561
|
+
# page = shell.add_page("dashboard", text="Dashboard", icon="speedometer2")
|
|
562
|
+
# DashboardPage(page)
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Building for Distribution
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
# Promote to packaging-ready (adds PyInstaller support)
|
|
569
|
+
bootstack promote --pyinstaller
|
|
570
|
+
|
|
571
|
+
# Build the executable
|
|
572
|
+
bootstack build
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
## Project Structure
|
|
576
|
+
|
|
577
|
+
```
|
|
578
|
+
{project_dir}/
|
|
579
|
+
\u251c\u2500\u2500 src/{module_name}/
|
|
580
|
+
\u2502 \u251c\u2500\u2500 __init__.py
|
|
581
|
+
\u2502 \u251c\u2500\u2500 main.py
|
|
582
|
+
\u2502 \u2514\u2500\u2500 pages/
|
|
583
|
+
\u2502 \u251c\u2500\u2500 __init__.py
|
|
584
|
+
\u2502 \u251c\u2500\u2500 home_page.py
|
|
585
|
+
\u2502 \u2514\u2500\u2500 settings_page.py
|
|
586
|
+
\u251c\u2500\u2500 assets/
|
|
587
|
+
\u251c\u2500\u2500 bootstack.toml
|
|
588
|
+
\u2514\u2500\u2500 README.md
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Configuration
|
|
592
|
+
|
|
593
|
+
Application settings are defined in `bootstack.toml`:
|
|
594
|
+
|
|
595
|
+
- `[app]` - Application metadata
|
|
596
|
+
- `[settings]` - Runtime settings (theme, language)
|
|
597
|
+
- `[layout]` - Default layout preferences
|
|
598
|
+
- `[build]` - Build/packaging configuration (after `bootstack promote`)
|
|
599
|
+
'''
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
def create_page(
|
|
603
|
+
class_name: str,
|
|
604
|
+
target_dir: Path,
|
|
605
|
+
scrollable: bool = False,
|
|
606
|
+
) -> Path:
|
|
607
|
+
"""Create a new AppShell page file.
|
|
608
|
+
|
|
609
|
+
Args:
|
|
610
|
+
class_name: Page class name (CamelCase).
|
|
611
|
+
target_dir: Directory to create the page in.
|
|
612
|
+
scrollable: If True, the page template notes that
|
|
613
|
+
`scrollable=True` should be passed to `add_page()`.
|
|
614
|
+
|
|
615
|
+
Returns:
|
|
616
|
+
Path to the created file.
|
|
617
|
+
"""
|
|
618
|
+
file_name = _camel_to_snake(class_name) + ".py"
|
|
619
|
+
|
|
620
|
+
# Derive a readable title from the class name (e.g. "DashboardPage" -> "Dashboard")
|
|
621
|
+
page_title = class_name
|
|
622
|
+
if page_title.endswith("Page"):
|
|
623
|
+
page_title = page_title[:-4]
|
|
624
|
+
# Insert spaces before uppercase letters
|
|
625
|
+
import re
|
|
626
|
+
page_title = re.sub(r"([a-z])([A-Z])", r"\1 \2", page_title)
|
|
627
|
+
|
|
628
|
+
content = APPSHELL_PAGE_TEMPLATE.format(
|
|
629
|
+
class_name=class_name,
|
|
630
|
+
page_title=page_title,
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
file_path = target_dir / file_name
|
|
634
|
+
file_path.write_text(content, encoding="utf-8")
|
|
635
|
+
|
|
636
|
+
return file_path
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
def create_project(
|
|
640
|
+
name: str,
|
|
641
|
+
target_dir: Path,
|
|
642
|
+
container: ContainerType = "grid",
|
|
643
|
+
theme: str = "bootstrap-light",
|
|
644
|
+
template: TemplateType = "basic",
|
|
645
|
+
simple: bool = False,
|
|
646
|
+
) -> None:
|
|
647
|
+
"""Create a new bootstack project.
|
|
648
|
+
|
|
649
|
+
Args:
|
|
650
|
+
name: Application name.
|
|
651
|
+
target_dir: Target directory for the project.
|
|
652
|
+
container: Default container type ('grid' or 'pack').
|
|
653
|
+
theme: Theme name for the application.
|
|
654
|
+
template: Project template ('basic' or 'appshell').
|
|
655
|
+
simple: If True, create minimal project without build config.
|
|
656
|
+
"""
|
|
657
|
+
if template == "appshell":
|
|
658
|
+
_create_appshell_project(name, target_dir, theme, simple)
|
|
659
|
+
else:
|
|
660
|
+
_create_basic_project(name, target_dir, container, theme, simple)
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
def _create_basic_project(
|
|
664
|
+
name: str,
|
|
665
|
+
target_dir: Path,
|
|
666
|
+
container: ContainerType,
|
|
667
|
+
theme: str,
|
|
668
|
+
simple: bool,
|
|
669
|
+
) -> None:
|
|
670
|
+
"""Create a basic single-view project."""
|
|
671
|
+
from bootstack.cli.config import write_config
|
|
672
|
+
|
|
673
|
+
# Normalize names
|
|
674
|
+
name_lower = name.lower().replace(" ", "_").replace("-", "_")
|
|
675
|
+
module_name = name_lower
|
|
676
|
+
|
|
677
|
+
# Create directory structure
|
|
678
|
+
src_dir = target_dir / "src" / module_name
|
|
679
|
+
views_dir = src_dir / "views"
|
|
680
|
+
assets_dir = target_dir / "assets"
|
|
681
|
+
|
|
682
|
+
src_dir.mkdir(parents=True, exist_ok=True)
|
|
683
|
+
views_dir.mkdir(parents=True, exist_ok=True)
|
|
684
|
+
if not simple:
|
|
685
|
+
assets_dir.mkdir(parents=True, exist_ok=True)
|
|
686
|
+
|
|
687
|
+
# Write main.py
|
|
688
|
+
main_content = MAIN_PY_TEMPLATE.format(
|
|
689
|
+
app_name=name,
|
|
690
|
+
module_name=module_name,
|
|
691
|
+
theme=theme,
|
|
692
|
+
)
|
|
693
|
+
(src_dir / "main.py").write_text(main_content, encoding="utf-8")
|
|
694
|
+
|
|
695
|
+
# Write __init__.py
|
|
696
|
+
init_content = INIT_PY_TEMPLATE.format(app_name=name)
|
|
697
|
+
(src_dir / "__init__.py").write_text(init_content, encoding="utf-8")
|
|
698
|
+
|
|
699
|
+
# Write views/__init__.py
|
|
700
|
+
(views_dir / "__init__.py").write_text(
|
|
701
|
+
'"""Views package."""\n', encoding="utf-8"
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
# Write main_view.py
|
|
705
|
+
if container == "grid":
|
|
706
|
+
view_template = MAIN_VIEW_GRID_TEMPLATE
|
|
707
|
+
else:
|
|
708
|
+
view_template = MAIN_VIEW_PACK_TEMPLATE
|
|
709
|
+
|
|
710
|
+
view_content = view_template.format(app_name=name)
|
|
711
|
+
(views_dir / "main_view.py").write_text(view_content, encoding="utf-8")
|
|
712
|
+
|
|
713
|
+
# Write bootstack.toml
|
|
714
|
+
write_config(
|
|
715
|
+
path=target_dir / "bootstack.toml",
|
|
716
|
+
name=name,
|
|
717
|
+
entry=f"src/{module_name}/main.py",
|
|
718
|
+
theme=theme,
|
|
719
|
+
template="basic",
|
|
720
|
+
include_build=False,
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
# Write README.md
|
|
724
|
+
if not simple:
|
|
725
|
+
readme_content = README_TEMPLATE.format(
|
|
726
|
+
app_name=name,
|
|
727
|
+
module_name=module_name,
|
|
728
|
+
project_dir=target_dir.name,
|
|
729
|
+
)
|
|
730
|
+
(target_dir / "README.md").write_text(readme_content, encoding="utf-8")
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
def _create_appshell_project(
|
|
734
|
+
name: str,
|
|
735
|
+
target_dir: Path,
|
|
736
|
+
theme: str,
|
|
737
|
+
simple: bool,
|
|
738
|
+
) -> None:
|
|
739
|
+
"""Create an AppShell project with sidebar navigation and pages."""
|
|
740
|
+
from bootstack.cli.config import write_config
|
|
741
|
+
|
|
742
|
+
# Normalize names
|
|
743
|
+
name_lower = name.lower().replace(" ", "_").replace("-", "_")
|
|
744
|
+
module_name = name_lower
|
|
745
|
+
|
|
746
|
+
# Create directory structure
|
|
747
|
+
src_dir = target_dir / "src" / module_name
|
|
748
|
+
pages_dir = src_dir / "pages"
|
|
749
|
+
assets_dir = target_dir / "assets"
|
|
750
|
+
|
|
751
|
+
src_dir.mkdir(parents=True, exist_ok=True)
|
|
752
|
+
pages_dir.mkdir(parents=True, exist_ok=True)
|
|
753
|
+
if not simple:
|
|
754
|
+
assets_dir.mkdir(parents=True, exist_ok=True)
|
|
755
|
+
|
|
756
|
+
# Write main.py
|
|
757
|
+
main_content = APPSHELL_MAIN_PY_TEMPLATE.format(
|
|
758
|
+
app_name=name,
|
|
759
|
+
module_name=module_name,
|
|
760
|
+
theme=theme,
|
|
761
|
+
)
|
|
762
|
+
(src_dir / "main.py").write_text(main_content, encoding="utf-8")
|
|
763
|
+
|
|
764
|
+
# Write __init__.py
|
|
765
|
+
init_content = INIT_PY_TEMPLATE.format(app_name=name)
|
|
766
|
+
(src_dir / "__init__.py").write_text(init_content, encoding="utf-8")
|
|
767
|
+
|
|
768
|
+
# Write pages/__init__.py
|
|
769
|
+
(pages_dir / "__init__.py").write_text(
|
|
770
|
+
'"""Pages package."""\n', encoding="utf-8"
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
# Write home_page.py
|
|
774
|
+
home_content = APPSHELL_HOME_PAGE_TEMPLATE.format(app_name=name)
|
|
775
|
+
(pages_dir / "home_page.py").write_text(home_content, encoding="utf-8")
|
|
776
|
+
|
|
777
|
+
# Write settings_page.py
|
|
778
|
+
(pages_dir / "settings_page.py").write_text(
|
|
779
|
+
APPSHELL_SETTINGS_PAGE_TEMPLATE, encoding="utf-8"
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
# Write bootstack.toml
|
|
783
|
+
write_config(
|
|
784
|
+
path=target_dir / "bootstack.toml",
|
|
785
|
+
name=name,
|
|
786
|
+
entry=f"src/{module_name}/main.py",
|
|
787
|
+
theme=theme,
|
|
788
|
+
template="appshell",
|
|
789
|
+
include_build=False,
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
# Write README.md
|
|
793
|
+
if not simple:
|
|
794
|
+
readme_content = APPSHELL_README_TEMPLATE.format(
|
|
795
|
+
app_name=name,
|
|
796
|
+
module_name=module_name,
|
|
797
|
+
project_dir=target_dir.name,
|
|
798
|
+
)
|
|
799
|
+
(target_dir / "README.md").write_text(readme_content, encoding="utf-8")
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def create_view(
|
|
803
|
+
class_name: str,
|
|
804
|
+
target_dir: Path,
|
|
805
|
+
container: ContainerType = "grid",
|
|
806
|
+
) -> Path:
|
|
807
|
+
"""Create a new view file.
|
|
808
|
+
|
|
809
|
+
Args:
|
|
810
|
+
class_name: View class name (CamelCase).
|
|
811
|
+
target_dir: Directory to create the view in.
|
|
812
|
+
container: Container type ('grid' or 'pack').
|
|
813
|
+
|
|
814
|
+
Returns:
|
|
815
|
+
Path to the created file.
|
|
816
|
+
"""
|
|
817
|
+
# Convert CamelCase to snake_case
|
|
818
|
+
file_name = _camel_to_snake(class_name) + ".py"
|
|
819
|
+
|
|
820
|
+
if container == "grid":
|
|
821
|
+
template = VIEW_GRID_TEMPLATE
|
|
822
|
+
else:
|
|
823
|
+
template = VIEW_PACK_TEMPLATE
|
|
824
|
+
|
|
825
|
+
content = template.format(class_name=class_name)
|
|
826
|
+
|
|
827
|
+
file_path = target_dir / file_name
|
|
828
|
+
file_path.write_text(content, encoding="utf-8")
|
|
829
|
+
|
|
830
|
+
return file_path
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
def create_dialog(
|
|
834
|
+
class_name: str,
|
|
835
|
+
target_dir: Path,
|
|
836
|
+
) -> Path:
|
|
837
|
+
"""Create a new dialog file.
|
|
838
|
+
|
|
839
|
+
Args:
|
|
840
|
+
class_name: Dialog class name (CamelCase).
|
|
841
|
+
target_dir: Directory to create the dialog in.
|
|
842
|
+
|
|
843
|
+
Returns:
|
|
844
|
+
Path to the created file.
|
|
845
|
+
"""
|
|
846
|
+
file_name = _camel_to_snake(class_name) + ".py"
|
|
847
|
+
content = DIALOG_TEMPLATE.format(class_name=class_name)
|
|
848
|
+
|
|
849
|
+
file_path = target_dir / file_name
|
|
850
|
+
file_path.write_text(content, encoding="utf-8")
|
|
851
|
+
|
|
852
|
+
return file_path
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
def _camel_to_snake(name: str) -> str:
|
|
856
|
+
"""Convert CamelCase to snake_case."""
|
|
857
|
+
import re
|
|
858
|
+
|
|
859
|
+
# Insert underscore before uppercase letters and lowercase
|
|
860
|
+
s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
|
|
861
|
+
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()
|