bootstack 0.2.1__py3-none-any.whl → 0.2.2__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/widgets/_core/base.py +3 -1
- bootstack/widgets/_impl/composites/tableview/tableview.py +50 -10
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/METADATA +302 -302
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/RECORD +9 -9
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/WHEEL +0 -0
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/entry_points.txt +0 -0
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/licenses/NOTICE +0 -0
- {bootstack-0.2.1.dist-info → bootstack-0.2.2.dist-info}/top_level.txt +0 -0
bootstack/widgets/_core/base.py
CHANGED
|
@@ -282,7 +282,9 @@ class PublicWidgetBase:
|
|
|
282
282
|
Example:
|
|
283
283
|
.. code-block:: python
|
|
284
284
|
|
|
285
|
-
|
|
285
|
+
from bootstack.events import ChangeEvent
|
|
286
|
+
|
|
287
|
+
field.emit("change", data=ChangeEvent(value=new_value))
|
|
286
288
|
"""
|
|
287
289
|
sequence = resolve_event(self, str(event))
|
|
288
290
|
|
|
@@ -29,7 +29,7 @@ from bootstack.style.style import get_style
|
|
|
29
29
|
from bootstack.data.sqlite_source import SqliteDataSource
|
|
30
30
|
from bootstack.data.query import col, any_of, all_of
|
|
31
31
|
from bootstack.widgets._impl.primitives.button import Button
|
|
32
|
-
from bootstack._runtime.utility import bind_right_click
|
|
32
|
+
from bootstack._runtime.utility import bind_right_click, debug_log_exception
|
|
33
33
|
from bootstack.widgets._impl.composites.contextmenu import ContextMenu
|
|
34
34
|
from bootstack.widgets._impl.composites.tooltip import ToolTip
|
|
35
35
|
from bootstack.widgets._impl.composites.dropdownbutton import DropdownButton
|
|
@@ -1148,8 +1148,8 @@ class TableView(Frame):
|
|
|
1148
1148
|
self._tree.bind("<Button-1>", self._on_header_click)
|
|
1149
1149
|
self._tree.bind("<<TreeviewSelect>>", self._on_selection_event)
|
|
1150
1150
|
# Keep group-header chevrons in sync with their open/closed state.
|
|
1151
|
-
self._tree.bind("<<TreeviewOpen>>", self.
|
|
1152
|
-
self._tree.bind("<<TreeviewClose>>", self.
|
|
1151
|
+
self._tree.bind("<<TreeviewOpen>>", self._refresh_group_chevrons_deferred, add="+")
|
|
1152
|
+
self._tree.bind("<<TreeviewClose>>", self._refresh_group_chevrons_deferred, add="+")
|
|
1153
1153
|
self._tree.bind("<ButtonRelease-1>", self._on_row_click_event)
|
|
1154
1154
|
# Escape clears the selection (also reachable in single-select mode, where
|
|
1155
1155
|
# clicking can't return to an empty selection). Bound on the tree widget
|
|
@@ -1158,8 +1158,10 @@ class TableView(Frame):
|
|
|
1158
1158
|
self._tree.bind("<Escape>", lambda _e: self.deselect_all(), add="+")
|
|
1159
1159
|
if self._context_menus != "none":
|
|
1160
1160
|
bind_right_click(self._tree, self._on_tree_context)
|
|
1161
|
-
|
|
1162
|
-
|
|
1161
|
+
# Bound unconditionally: `on_row_double_click` is public API and does not
|
|
1162
|
+
# depend on editing. The handler itself gates the built-in edit dialog on
|
|
1163
|
+
# `_editing['updating']`, so editing behavior is unchanged.
|
|
1164
|
+
self._tree.bind("<Double-1>", self._on_row_double_click)
|
|
1163
1165
|
# Track resize events to rebalance grouped layouts
|
|
1164
1166
|
self._tree.bind("<Configure>", self._on_tree_configure)
|
|
1165
1167
|
|
|
@@ -1690,9 +1692,12 @@ class TableView(Frame):
|
|
|
1690
1692
|
col_idx = 0
|
|
1691
1693
|
# Right-click does not alter the selection (left-click owns that); it
|
|
1692
1694
|
# only records which row the menu targets and opens the menu there.
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
+
# A group header is a real tree item but holds no record — it is absent
|
|
1696
|
+
# from `_row_map` — so it targets nothing, exactly like empty space.
|
|
1697
|
+
if not iid or iid not in self._row_map:
|
|
1698
|
+
self._context_iid = None
|
|
1695
1699
|
return # empty space or a group-header row — no row menu
|
|
1700
|
+
self._context_iid = iid
|
|
1696
1701
|
rec = self._row_map.get(iid, {})
|
|
1697
1702
|
self.event_generate("<<RowRightClick>>", data=RowEvent(record=self._public_record(rec), id=self._record_id(rec)))
|
|
1698
1703
|
self._row_menu_col = col_idx
|
|
@@ -1704,8 +1709,8 @@ class TableView(Frame):
|
|
|
1704
1709
|
if region == "heading":
|
|
1705
1710
|
return
|
|
1706
1711
|
iid = self._tree.identify_row(event.y)
|
|
1707
|
-
if not iid:
|
|
1708
|
-
return
|
|
1712
|
+
if not iid or iid not in self._row_map:
|
|
1713
|
+
return # empty space or a group-header row (no record)
|
|
1709
1714
|
rec = self._row_map.get(iid, {})
|
|
1710
1715
|
self.event_generate("<<RowDoubleClick>>", data=RowEvent(record=self._public_record(rec), id=self._record_id(rec)))
|
|
1711
1716
|
if self._editing['updating']:
|
|
@@ -2343,6 +2348,19 @@ class TableView(Frame):
|
|
|
2343
2348
|
except Exception:
|
|
2344
2349
|
pass
|
|
2345
2350
|
|
|
2351
|
+
def _refresh_group_chevrons_deferred(self, _event=None) -> None:
|
|
2352
|
+
"""Refresh chevrons once Tk has applied the item's new open state.
|
|
2353
|
+
|
|
2354
|
+
The toolkit reports an expand *before* it records it, so reading the
|
|
2355
|
+
state inside the notification paints the previous chevron. Deferring to
|
|
2356
|
+
the next idle point reads the settled state. Scheduled on the root so
|
|
2357
|
+
the pending callback outlives any widget being torn down.
|
|
2358
|
+
"""
|
|
2359
|
+
try:
|
|
2360
|
+
self._root().after_idle(self._refresh_group_chevrons)
|
|
2361
|
+
except Exception:
|
|
2362
|
+
pass
|
|
2363
|
+
|
|
2346
2364
|
def _refresh_group_chevrons(self, _event=None) -> None:
|
|
2347
2365
|
"""Sync every group header's chevron to its current open/closed state."""
|
|
2348
2366
|
if not self._group_by_key:
|
|
@@ -2845,6 +2863,23 @@ class TableView(Frame):
|
|
|
2845
2863
|
"""
|
|
2846
2864
|
return self._selection_markers_active()
|
|
2847
2865
|
|
|
2866
|
+
def _take_click_focus(self, iid) -> None:
|
|
2867
|
+
"""Give the body keyboard focus, and point it at the clicked row.
|
|
2868
|
+
|
|
2869
|
+
Both branches that call this answer the click themselves and stop it,
|
|
2870
|
+
which also stops the built-in handling that would otherwise have done
|
|
2871
|
+
this. Without it a click leaves the keyboard aimed somewhere else, so
|
|
2872
|
+
the row the user just clicked is not the row the arrow keys move from.
|
|
2873
|
+
"""
|
|
2874
|
+
try:
|
|
2875
|
+
self._tree.focus_set()
|
|
2876
|
+
if iid:
|
|
2877
|
+
self._tree.focus(iid)
|
|
2878
|
+
except Exception:
|
|
2879
|
+
# Silence here would restore the very bug this method exists to
|
|
2880
|
+
# fix, with nothing to show for it on any channel.
|
|
2881
|
+
debug_log_exception("could not move keyboard focus to the clicked row")
|
|
2882
|
+
|
|
2848
2883
|
def _on_header_click(self, event):
|
|
2849
2884
|
"""Handle left-click: header sorting, or toggle-select with checkboxes."""
|
|
2850
2885
|
# A left-click on the tree dismisses an open context menu. Do it
|
|
@@ -2873,20 +2908,25 @@ class TableView(Frame):
|
|
|
2873
2908
|
# fall through to normal selection below.
|
|
2874
2909
|
iid = self._tree.identify_row(event.y)
|
|
2875
2910
|
if iid and self._tree.get_children(iid):
|
|
2911
|
+
self._take_click_focus(iid)
|
|
2876
2912
|
self._toggle_group_open(iid)
|
|
2877
2913
|
return "break"
|
|
2878
2914
|
|
|
2879
2915
|
# Body click with checkboxes showing: treat the list like a checklist —
|
|
2880
2916
|
# a plain click toggles the row in/out of the selection (no modifier),
|
|
2881
2917
|
# and "break" suppresses ttk's default replace-the-selection behavior.
|
|
2918
|
+
# Only a click that lands on a row earns that "break" — a click on a
|
|
2919
|
+
# column separator reports no row, and stopping it there would kill the
|
|
2920
|
+
# drag that resizes the column.
|
|
2882
2921
|
if self._toggle_select_active():
|
|
2883
2922
|
iid = self._tree.identify_row(event.y)
|
|
2884
2923
|
if iid:
|
|
2924
|
+
self._take_click_focus(iid)
|
|
2885
2925
|
if iid in self._tree.selection():
|
|
2886
2926
|
self._tree.selection_remove(iid)
|
|
2887
2927
|
else:
|
|
2888
2928
|
self._tree.selection_add(iid)
|
|
2889
|
-
|
|
2929
|
+
return "break"
|
|
2890
2930
|
return None
|
|
2891
2931
|
|
|
2892
2932
|
def _filter_header_column(self) -> None:
|
|
@@ -1,302 +1,302 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: bootstack
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate.
|
|
5
|
-
Author-email: Israel Dryer <israel.dryer@gmail.com>
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/israel-dryer/bootstack
|
|
8
|
-
Project-URL: Documentation, https://bootstack.org/
|
|
9
|
-
Keywords: tkinter,ttk,gui,desktop,python3,ui,widgets,theming,cross-platform,modern,framework,application-framework,desktop-ui,python-gui
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Environment :: Win32 (MS Windows)
|
|
12
|
-
Classifier: Environment :: MacOS X
|
|
13
|
-
Classifier: Environment :: X11 Applications
|
|
14
|
-
Classifier: Intended Audience :: Developers
|
|
15
|
-
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
-
Classifier: Topic :: Software Development :: User Interfaces
|
|
20
|
-
Classifier: Operating System :: OS Independent
|
|
21
|
-
Requires-Python: >=3.12
|
|
22
|
-
Description-Content-Type: text/markdown
|
|
23
|
-
License-File: LICENSE
|
|
24
|
-
License-File: NOTICE
|
|
25
|
-
Requires-Dist: pillow<=12,>=10
|
|
26
|
-
Requires-Dist: pygments>=2.15
|
|
27
|
-
Requires-Dist: typing-extensions>=4.10
|
|
28
|
-
Requires-Dist: Babel>=2.12
|
|
29
|
-
Requires-Dist: python-dateutil>=2.9
|
|
30
|
-
Requires-Dist: dateparser>=1.1
|
|
31
|
-
Requires-Dist: pywinstyles>=1.8; sys_platform == "win32"
|
|
32
|
-
Requires-Dist: screeninfo>=0.8
|
|
33
|
-
Provides-Extra: excel
|
|
34
|
-
Requires-Dist: XlsxWriter>=3; extra == "excel"
|
|
35
|
-
Provides-Extra: parquet
|
|
36
|
-
Requires-Dist: pyarrow>=14; extra == "parquet"
|
|
37
|
-
Provides-Extra: hdf5
|
|
38
|
-
Requires-Dist: pandas>=2; extra == "hdf5"
|
|
39
|
-
Requires-Dist: tables>=3.8; extra == "hdf5"
|
|
40
|
-
Provides-Extra: viz
|
|
41
|
-
Requires-Dist: matplotlib>=3.8; extra == "viz"
|
|
42
|
-
Provides-Extra: viz-seaborn
|
|
43
|
-
Requires-Dist: matplotlib>=3.8; extra == "viz-seaborn"
|
|
44
|
-
Requires-Dist: seaborn>=0.13; extra == "viz-seaborn"
|
|
45
|
-
Provides-Extra: docs
|
|
46
|
-
Requires-Dist: sphinx>=7.2; extra == "docs"
|
|
47
|
-
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
48
|
-
Requires-Dist: sphinx-design; extra == "docs"
|
|
49
|
-
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
50
|
-
Requires-Dist: sphinx-autobuild; extra == "docs"
|
|
51
|
-
Requires-Dist: myst-parser; extra == "docs"
|
|
52
|
-
Dynamic: license-file
|
|
53
|
-
|
|
54
|
-

|
|
55
|
-
|
|
56
|
-

|
|
57
|
-
[](https://pepy.tech/project/bootstack)
|
|
58
|
-
[](https://pepy.tech/project/bootstack)
|
|
59
|
-

|
|
60
|
-

|
|
61
|
-

|
|
62
|
-

|
|
63
|
-

|
|
64
|
-
|
|
65
|
-
> Full documentation is at **[bootstack.org](https://bootstack.org)**.
|
|
66
|
-
|
|
67
|
-
### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
|
|
68
|
-
|
|
69
|
-
bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
|
|
70
|
-
write a `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
|
|
71
|
-
packages the whole thing.
|
|
72
|
-
|
|
73
|
-
<p align="center">
|
|
74
|
-
<picture>
|
|
75
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-dark.png">
|
|
76
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
|
|
77
|
-
<img alt="bootstack hero demo" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
|
|
78
|
-
</picture>
|
|
79
|
-
</p>
|
|
80
|
-
|
|
81
|
-
## Why bootstack?
|
|
82
|
-
|
|
83
|
-
Most Python desktop frameworks make you fight the framework. bootstack gets out of the way.
|
|
84
|
-
|
|
85
|
-
- **30% less code** — the declarative, context-manager layout eliminates geometry calls, explicit parenting, and most of the wiring boilerplate
|
|
86
|
-
- **Reads like Python** — nested `with` blocks mirror your UI structure; the code hierarchy *is* the layout
|
|
87
|
-
- **Modern layout system** — `Row`, `Column`, and `Grid` containers handle spacing, alignment, and growth automatically; a screen-axis vocabulary (`gap`, `padding`, `margin`, `horizontal`, `vertical`, `grow`) without writing CSS
|
|
88
|
-
- **60+ widgets out of the box** — primitives through full composites: tables, trees, calendars, date pickers, gauges, sliders, and more — including a full `CodeEditor` with syntax highlighting, line numbers, bracket matching, smart indent, and search; no external editor dependency required
|
|
89
|
-
- **Reactive signals** — observable state that flows between widgets; bind once, update everywhere
|
|
90
|
-
- **Event and stream pipelines** — compose, filter, debounce, and throttle UI events with a chainable stream API
|
|
91
|
-
- **Built-in icons** — the full Bootstrap Icons catalog, theme-aware and recolorable, bundled with the framework
|
|
92
|
-
- **Built-in localization** — 23 language catalogs, locale-aware number/date/time formatting, runtime language switching
|
|
93
|
-
- **Semantic styling** — `accent="primary"`, `variant="outline"` — no hard-coded colors; looks right across every theme automatically
|
|
94
|
-
- **10 paired light/dark themes** — popular dev color schemes plus Bootstrap, with a runtime switcher and a custom-theme API
|
|
95
|
-
- **Forms and validation** — field-level validators, inline error messages, and a `FormDialog` for quick modal forms
|
|
96
|
-
- **DataSource abstraction** — one interface over SQLite, in-memory, and file backends with filtering, sorting, pagination, and CRUD
|
|
97
|
-
- **Data visualization** — embed `matplotlib` (and `seaborn`) figures with `Chart`; they recolor with the theme and live-update from a `Signal` or `DataSource` (optional `viz` extra)
|
|
98
|
-
- **A real CLI** — scaffold, run, add pages/views/dialogs/themes, and package for distribution
|
|
99
|
-
- **Hot reload** — `bootstack dev app.py` updates the running app on save and keeps your place; module-level state and the active page survive the reload
|
|
100
|
-
- **PyInstaller packaging built in** — `bootstack build` produces a standalone executable; no separate toolchain required
|
|
101
|
-
|
|
102
|
-
## Hot reload
|
|
103
|
-
|
|
104
|
-
Edit and save — the running window updates in place. `bootstack dev app.py`
|
|
105
|
-
reloads the UI on every save while keeping your window position, module-level
|
|
106
|
-
state, and active page, so you never lose your spot.
|
|
107
|
-
|
|
108
|
-
<p align="center">
|
|
109
|
-
<video src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/docs/_static/examples/live-reload.mp4" controls muted loop playsinline></video>
|
|
110
|
-
</p>
|
|
111
|
-
|
|
112
|
-
## Installation
|
|
113
|
-
|
|
114
|
-
Requires Python 3.12+ and Tk/Tcl (bundled with most Python distributions).
|
|
115
|
-
Install with pip:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
python -m pip install bootstack
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
See the [installation guide](https://bootstack.org/getting-started/installation/)
|
|
122
|
-
for platform-specific Tk setup and the optional data-format extras.
|
|
123
|
-
|
|
124
|
-
## See it
|
|
125
|
-
|
|
126
|
-
The widget gallery is a single-window tour of everything bootstack ships — every widget, theme switcher, accent variants, and layout containers. Fastest way to see the framework in action without writing a line of code:
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
bootstack gallery
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
<p align="center">
|
|
133
|
-
<picture>
|
|
134
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-dark.png">
|
|
135
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
|
|
136
|
-
<img alt="bootstack widget gallery" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
|
|
137
|
-
</picture>
|
|
138
|
-
</p>
|
|
139
|
-
|
|
140
|
-
## Quick Start
|
|
141
|
-
|
|
142
|
-
```python
|
|
143
|
-
import bootstack as bs
|
|
144
|
-
|
|
145
|
-
with bs.App(title="Hello", padding=16, gap=16) as app:
|
|
146
|
-
bs.Label("Hello from bootstack!")
|
|
147
|
-
bs.Button("Primary", accent="primary")
|
|
148
|
-
bs.Button("Success", accent="success")
|
|
149
|
-
bs.Button("Danger Outline", accent="danger", variant="outline")
|
|
150
|
-
|
|
151
|
-
app.run()
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
<p align="center">
|
|
155
|
-
<picture>
|
|
156
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-dark.png">
|
|
157
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
|
|
158
|
-
<img alt="bootstack quick start example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
|
|
159
|
-
</picture>
|
|
160
|
-
</p>
|
|
161
|
-
|
|
162
|
-
For navigation-based apps, use `AppShell` — it gives you stacked toolbars, a sidebar, and a page stack in one call:
|
|
163
|
-
|
|
164
|
-
```python
|
|
165
|
-
import bootstack as bs
|
|
166
|
-
|
|
167
|
-
shell = bs.AppShell(title="My App", size=(1000, 650))
|
|
168
|
-
|
|
169
|
-
with shell.page_nav() as nav:
|
|
170
|
-
with nav.add_page("home", text="Home", icon="house"):
|
|
171
|
-
bs.Label("Welcome!")
|
|
172
|
-
with nav.add_page("docs", text="Documents", icon="file-earmark-text"):
|
|
173
|
-
bs.Label("Your documents.")
|
|
174
|
-
|
|
175
|
-
shell.run()
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## How it works
|
|
179
|
-
|
|
180
|
-
### Layout containers
|
|
181
|
-
|
|
182
|
-
`Column`, `Row`, and `Grid` let you describe a layout once instead of repeating geometry calls on each child:
|
|
183
|
-
|
|
184
|
-
```python
|
|
185
|
-
with bs.App(title="Sign In") as app:
|
|
186
|
-
with bs.Grid(columns=["auto", 1], gap=(12, 6), horizontal_items="stretch", padding=16):
|
|
187
|
-
bs.Label("Name:")
|
|
188
|
-
bs.TextField(placeholder="Full name")
|
|
189
|
-
bs.Label("Email:")
|
|
190
|
-
bs.TextField(placeholder="email@example.com")
|
|
191
|
-
bs.Label("Role:")
|
|
192
|
-
bs.Select(options=["Admin", "User", "Viewer"], value="User")
|
|
193
|
-
bs.Button("Submit", accent="primary", columnspan=2)
|
|
194
|
-
|
|
195
|
-
app.run()
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
<p align="center">
|
|
199
|
-
<picture>
|
|
200
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-dark.png">
|
|
201
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
|
|
202
|
-
<img alt="bootstack layout containers example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
|
|
203
|
-
</picture>
|
|
204
|
-
</p>
|
|
205
|
-
|
|
206
|
-
### Semantic styling
|
|
207
|
-
|
|
208
|
-
Widgets take an `accent` (color intent) and `variant` (visual weight) instead of hard-coded colors, so the same code looks right across themes and light/dark modes:
|
|
209
|
-
|
|
210
|
-
```python
|
|
211
|
-
bs.Button("Save", accent="primary")
|
|
212
|
-
bs.Button("Cancel", accent="secondary", variant="outline")
|
|
213
|
-
bs.Label("Heading", font="heading-lg")
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
<p align="center">
|
|
217
|
-
<picture>
|
|
218
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-dark.png">
|
|
219
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
|
|
220
|
-
<img alt="bootstack semantic styling example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
|
|
221
|
-
</picture>
|
|
222
|
-
</p>
|
|
223
|
-
|
|
224
|
-
### Signals (optional)
|
|
225
|
-
|
|
226
|
-
Plain callbacks work fine for most things. When state needs to flow between widgets, signals give you a small reactive primitive with two-way binding:
|
|
227
|
-
|
|
228
|
-
```python
|
|
229
|
-
with bs.App(title="Hello") as app:
|
|
230
|
-
name = bs.Signal("World")
|
|
231
|
-
bs.Label(textsignal=name) # updates automatically when name changes
|
|
232
|
-
bs.TextField(textsignal=name) # two-way binding to the same state
|
|
233
|
-
|
|
234
|
-
app.run()
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## Features
|
|
238
|
-
|
|
239
|
-
- **Application scaffolding** — `App` for blank windows, `AppShell` for toolbar + sidebar + page-stack apps, `Workbench` for two-tier workspace apps, `Splash` for a startup intro screen, undecorated windows with custom chrome
|
|
240
|
-
- **60+ themed widgets** — primitives plus higher-level composites (DataTable, Tree, ListView, Calendar, DateField, Form, Gauge, ToggleGroup, PageStack, Carousel, Tooltip, and more)
|
|
241
|
-
- **Dialogs and messages** — `alert()` / `confirm()` / `ask_*()` prompts and `FormDialog` / `FontDialog` / `FilterDialog`, plus non-blocking `toast()`, `Notification`, and `Snackbar` surfaces
|
|
242
|
-
- **Layout containers** — `Column`, `Row`, `Grid`, and `Spacer` for declarative layouts; `Card`, `GroupBox`, `ScrollView`, `SplitView`, `Accordion`, `Divider`
|
|
243
|
-
- **Design system** — semantic `accent` colors (primary, secondary, success, danger, warning, info) and `variant` tokens (solid, outline, ghost), consistent across widgets
|
|
244
|
-
- **Built-in themes** — 10 paired light/dark variants (bootstrap, catppuccin, dracula, everforest, gruvbox, nord, one, pydata, solarized, tokyo-night) with runtime theme switching and a custom-theme API
|
|
245
|
-
- **Reactive signals** — observable state with subscribe/set, integrates with widgets via `signal=` / `textsignal=`
|
|
246
|
-
- **Forms & validation** — `Form` with built-in field-level validators and inline error messages
|
|
247
|
-
- **DataSource** — common interface over in-memory, SQLite, and file backends, with pagination, filtering, sorting, CRUD, and CSV/TSV/Excel export
|
|
248
|
-
- **Data visualization** — `Chart` embeds `matplotlib`/`seaborn` figures that theme themselves and live-update from a `Signal` or `DataSource`; managed render, blitting animation, and a themed navigation toolbar (optional `viz` / `viz-seaborn` extras)
|
|
249
|
-
- **Localization (i18n)** — 23 bundled message catalogs, locale-aware number/date/time formatting via Babel, runtime language switching
|
|
250
|
-
- **Icons & images** — Bootstrap Icons catalog with theme-aware recoloring and caching
|
|
251
|
-
- **Platform support** — DPI awareness, multi-monitor centering, mica/acrylic effects on Windows
|
|
252
|
-
- **CLI (`bootstack`)** — project scaffolding, run, add components, theme/i18n setup, doctor, build/package
|
|
253
|
-
|
|
254
|
-
## Widget Categories
|
|
255
|
-
|
|
256
|
-
| Category | Widgets |
|
|
257
|
-
|----------|---------|
|
|
258
|
-
| **Actions** | Button, ButtonGroup, MenuButton, ContextMenu, Toolbar, ThemeToggle |
|
|
259
|
-
| **Inputs** | TextField, PasswordField, PathField, NumberField, SpinnerField, Slider, RangeSlider, TextArea, CodeEditor, DateField, TimeField |
|
|
260
|
-
| **Selection** | Checkbox, Switch, ToggleButton, Radio, RadioGroup, ToggleGroup, Select, SelectButton, Calendar |
|
|
261
|
-
| **Data Display** | Label, Badge, ListView, Tree, DataTable, ProgressBar, Gauge |
|
|
262
|
-
| **Media** | Avatar, Picture, Gallery, Carousel |
|
|
263
|
-
| **Layout** | Column, Row, Grid, Spacer, Card, GroupBox, SplitView, ScrollView, Accordion, Divider |
|
|
264
|
-
| **Navigation** | AppShell, Workbench, Window, Splash, StatusBar, Tabs, PageStack |
|
|
265
|
-
| **Dialogs** | `alert()`, `confirm()`, `ask_*()` prompts, FormDialog, FontDialog, FilterDialog |
|
|
266
|
-
| **Overlays** | `toast()`, Notification, Snackbar, Tooltip |
|
|
267
|
-
| **Forms** | Form, with field-level validation |
|
|
268
|
-
|
|
269
|
-
## CLI
|
|
270
|
-
|
|
271
|
-
bootstack ships with an optional CLI for scaffolding, running, and packaging applications:
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
bootstack gallery # Launch the interactive widget gallery
|
|
275
|
-
bootstack icons # Browse the built-in icon catalog
|
|
276
|
-
bootstack appicon # Design an app icon and export it
|
|
277
|
-
bootstack start MyApp # Create a new project (basic template)
|
|
278
|
-
bootstack start MyApp --template appshell # ...or with sidebar navigation
|
|
279
|
-
bootstack run # Run the app defined in the project config
|
|
280
|
-
bootstack dev app.py # Run with hot reload (live edit-and-save)
|
|
281
|
-
bootstack add page Dashboard # Add a new page (appshell)
|
|
282
|
-
bootstack add view Settings # Add a new view (basic)
|
|
283
|
-
bootstack add dialog Preferences # Add a new dialog
|
|
284
|
-
bootstack doctor # Diagnose project & environment
|
|
285
|
-
bootstack promote # Make the project packaging-ready
|
|
286
|
-
bootstack build # Package for distribution
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## Documentation
|
|
290
|
-
|
|
291
|
-
Full documentation — guides, the widget catalog, and the API reference — lives at
|
|
292
|
-
**[bootstack.org](https://bootstack.org)**.
|
|
293
|
-
|
|
294
|
-
## Contributing
|
|
295
|
-
|
|
296
|
-
Contributions are welcome — code, bug reports, and especially **translations**.
|
|
297
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, the pull-request
|
|
298
|
-
workflow, and how to review the bundled language catalogs.
|
|
299
|
-
|
|
300
|
-
## Links
|
|
301
|
-
|
|
302
|
-
- **GitHub**: https://github.com/israel-dryer/bootstack
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bootstack
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate.
|
|
5
|
+
Author-email: Israel Dryer <israel.dryer@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/israel-dryer/bootstack
|
|
8
|
+
Project-URL: Documentation, https://bootstack.org/
|
|
9
|
+
Keywords: tkinter,ttk,gui,desktop,python3,ui,widgets,theming,cross-platform,modern,framework,application-framework,desktop-ui,python-gui
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
12
|
+
Classifier: Environment :: MacOS X
|
|
13
|
+
Classifier: Environment :: X11 Applications
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
License-File: NOTICE
|
|
25
|
+
Requires-Dist: pillow<=12,>=10
|
|
26
|
+
Requires-Dist: pygments>=2.15
|
|
27
|
+
Requires-Dist: typing-extensions>=4.10
|
|
28
|
+
Requires-Dist: Babel>=2.12
|
|
29
|
+
Requires-Dist: python-dateutil>=2.9
|
|
30
|
+
Requires-Dist: dateparser>=1.1
|
|
31
|
+
Requires-Dist: pywinstyles>=1.8; sys_platform == "win32"
|
|
32
|
+
Requires-Dist: screeninfo>=0.8
|
|
33
|
+
Provides-Extra: excel
|
|
34
|
+
Requires-Dist: XlsxWriter>=3; extra == "excel"
|
|
35
|
+
Provides-Extra: parquet
|
|
36
|
+
Requires-Dist: pyarrow>=14; extra == "parquet"
|
|
37
|
+
Provides-Extra: hdf5
|
|
38
|
+
Requires-Dist: pandas>=2; extra == "hdf5"
|
|
39
|
+
Requires-Dist: tables>=3.8; extra == "hdf5"
|
|
40
|
+
Provides-Extra: viz
|
|
41
|
+
Requires-Dist: matplotlib>=3.8; extra == "viz"
|
|
42
|
+
Provides-Extra: viz-seaborn
|
|
43
|
+
Requires-Dist: matplotlib>=3.8; extra == "viz-seaborn"
|
|
44
|
+
Requires-Dist: seaborn>=0.13; extra == "viz-seaborn"
|
|
45
|
+
Provides-Extra: docs
|
|
46
|
+
Requires-Dist: sphinx>=7.2; extra == "docs"
|
|
47
|
+
Requires-Dist: pydata-sphinx-theme; extra == "docs"
|
|
48
|
+
Requires-Dist: sphinx-design; extra == "docs"
|
|
49
|
+
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
50
|
+
Requires-Dist: sphinx-autobuild; extra == "docs"
|
|
51
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
[](https://pepy.tech/project/bootstack)
|
|
58
|
+
[](https://pepy.tech/project/bootstack)
|
|
59
|
+

|
|
60
|
+

|
|
61
|
+

|
|
62
|
+

|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
> Full documentation is at **[bootstack.org](https://bootstack.org)**.
|
|
66
|
+
|
|
67
|
+
### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
|
|
68
|
+
|
|
69
|
+
bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
|
|
70
|
+
write a `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
|
|
71
|
+
packages the whole thing.
|
|
72
|
+
|
|
73
|
+
<p align="center">
|
|
74
|
+
<picture>
|
|
75
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-dark.png">
|
|
76
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
|
|
77
|
+
<img alt="bootstack hero demo" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/hero-light.png">
|
|
78
|
+
</picture>
|
|
79
|
+
</p>
|
|
80
|
+
|
|
81
|
+
## Why bootstack?
|
|
82
|
+
|
|
83
|
+
Most Python desktop frameworks make you fight the framework. bootstack gets out of the way.
|
|
84
|
+
|
|
85
|
+
- **30% less code** — the declarative, context-manager layout eliminates geometry calls, explicit parenting, and most of the wiring boilerplate
|
|
86
|
+
- **Reads like Python** — nested `with` blocks mirror your UI structure; the code hierarchy *is* the layout
|
|
87
|
+
- **Modern layout system** — `Row`, `Column`, and `Grid` containers handle spacing, alignment, and growth automatically; a screen-axis vocabulary (`gap`, `padding`, `margin`, `horizontal`, `vertical`, `grow`) without writing CSS
|
|
88
|
+
- **60+ widgets out of the box** — primitives through full composites: tables, trees, calendars, date pickers, gauges, sliders, and more — including a full `CodeEditor` with syntax highlighting, line numbers, bracket matching, smart indent, and search; no external editor dependency required
|
|
89
|
+
- **Reactive signals** — observable state that flows between widgets; bind once, update everywhere
|
|
90
|
+
- **Event and stream pipelines** — compose, filter, debounce, and throttle UI events with a chainable stream API
|
|
91
|
+
- **Built-in icons** — the full Bootstrap Icons catalog, theme-aware and recolorable, bundled with the framework
|
|
92
|
+
- **Built-in localization** — 23 language catalogs, locale-aware number/date/time formatting, runtime language switching
|
|
93
|
+
- **Semantic styling** — `accent="primary"`, `variant="outline"` — no hard-coded colors; looks right across every theme automatically
|
|
94
|
+
- **10 paired light/dark themes** — popular dev color schemes plus Bootstrap, with a runtime switcher and a custom-theme API
|
|
95
|
+
- **Forms and validation** — field-level validators, inline error messages, and a `FormDialog` for quick modal forms
|
|
96
|
+
- **DataSource abstraction** — one interface over SQLite, in-memory, and file backends with filtering, sorting, pagination, and CRUD
|
|
97
|
+
- **Data visualization** — embed `matplotlib` (and `seaborn`) figures with `Chart`; they recolor with the theme and live-update from a `Signal` or `DataSource` (optional `viz` extra)
|
|
98
|
+
- **A real CLI** — scaffold, run, add pages/views/dialogs/themes, and package for distribution
|
|
99
|
+
- **Hot reload** — `bootstack dev app.py` updates the running app on save and keeps your place; module-level state and the active page survive the reload
|
|
100
|
+
- **PyInstaller packaging built in** — `bootstack build` produces a standalone executable; no separate toolchain required
|
|
101
|
+
|
|
102
|
+
## Hot reload
|
|
103
|
+
|
|
104
|
+
Edit and save — the running window updates in place. `bootstack dev app.py`
|
|
105
|
+
reloads the UI on every save while keeping your window position, module-level
|
|
106
|
+
state, and active page, so you never lose your spot.
|
|
107
|
+
|
|
108
|
+
<p align="center">
|
|
109
|
+
<video src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/docs/_static/examples/live-reload.mp4" controls muted loop playsinline></video>
|
|
110
|
+
</p>
|
|
111
|
+
|
|
112
|
+
## Installation
|
|
113
|
+
|
|
114
|
+
Requires Python 3.12+ and Tk/Tcl (bundled with most Python distributions).
|
|
115
|
+
Install with pip:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
python -m pip install bootstack
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
See the [installation guide](https://bootstack.org/getting-started/installation/)
|
|
122
|
+
for platform-specific Tk setup and the optional data-format extras.
|
|
123
|
+
|
|
124
|
+
## See it
|
|
125
|
+
|
|
126
|
+
The widget gallery is a single-window tour of everything bootstack ships — every widget, theme switcher, accent variants, and layout containers. Fastest way to see the framework in action without writing a line of code:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
bootstack gallery
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
<p align="center">
|
|
133
|
+
<picture>
|
|
134
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-dark.png">
|
|
135
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
|
|
136
|
+
<img alt="bootstack widget gallery" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/gallery-light.png">
|
|
137
|
+
</picture>
|
|
138
|
+
</p>
|
|
139
|
+
|
|
140
|
+
## Quick Start
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
import bootstack as bs
|
|
144
|
+
|
|
145
|
+
with bs.App(title="Hello", padding=16, gap=16) as app:
|
|
146
|
+
bs.Label("Hello from bootstack!")
|
|
147
|
+
bs.Button("Primary", accent="primary")
|
|
148
|
+
bs.Button("Success", accent="success")
|
|
149
|
+
bs.Button("Danger Outline", accent="danger", variant="outline")
|
|
150
|
+
|
|
151
|
+
app.run()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
<p align="center">
|
|
155
|
+
<picture>
|
|
156
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-dark.png">
|
|
157
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
|
|
158
|
+
<img alt="bootstack quick start example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-quickstart-light.png">
|
|
159
|
+
</picture>
|
|
160
|
+
</p>
|
|
161
|
+
|
|
162
|
+
For navigation-based apps, use `AppShell` — it gives you stacked toolbars, a sidebar, and a page stack in one call:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
import bootstack as bs
|
|
166
|
+
|
|
167
|
+
shell = bs.AppShell(title="My App", size=(1000, 650))
|
|
168
|
+
|
|
169
|
+
with shell.page_nav() as nav:
|
|
170
|
+
with nav.add_page("home", text="Home", icon="house"):
|
|
171
|
+
bs.Label("Welcome!")
|
|
172
|
+
with nav.add_page("docs", text="Documents", icon="file-earmark-text"):
|
|
173
|
+
bs.Label("Your documents.")
|
|
174
|
+
|
|
175
|
+
shell.run()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## How it works
|
|
179
|
+
|
|
180
|
+
### Layout containers
|
|
181
|
+
|
|
182
|
+
`Column`, `Row`, and `Grid` let you describe a layout once instead of repeating geometry calls on each child:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
with bs.App(title="Sign In") as app:
|
|
186
|
+
with bs.Grid(columns=["auto", 1], gap=(12, 6), horizontal_items="stretch", padding=16):
|
|
187
|
+
bs.Label("Name:")
|
|
188
|
+
bs.TextField(placeholder="Full name")
|
|
189
|
+
bs.Label("Email:")
|
|
190
|
+
bs.TextField(placeholder="email@example.com")
|
|
191
|
+
bs.Label("Role:")
|
|
192
|
+
bs.Select(options=["Admin", "User", "Viewer"], value="User")
|
|
193
|
+
bs.Button("Submit", accent="primary", columnspan=2)
|
|
194
|
+
|
|
195
|
+
app.run()
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
<p align="center">
|
|
199
|
+
<picture>
|
|
200
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-dark.png">
|
|
201
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
|
|
202
|
+
<img alt="bootstack layout containers example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-layout-light.png">
|
|
203
|
+
</picture>
|
|
204
|
+
</p>
|
|
205
|
+
|
|
206
|
+
### Semantic styling
|
|
207
|
+
|
|
208
|
+
Widgets take an `accent` (color intent) and `variant` (visual weight) instead of hard-coded colors, so the same code looks right across themes and light/dark modes:
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
bs.Button("Save", accent="primary")
|
|
212
|
+
bs.Button("Cancel", accent="secondary", variant="outline")
|
|
213
|
+
bs.Label("Heading", font="heading-lg")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
<p align="center">
|
|
217
|
+
<picture>
|
|
218
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-dark.png">
|
|
219
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
|
|
220
|
+
<img alt="bootstack semantic styling example" src="https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/readme/ex-semantic-styling-light.png">
|
|
221
|
+
</picture>
|
|
222
|
+
</p>
|
|
223
|
+
|
|
224
|
+
### Signals (optional)
|
|
225
|
+
|
|
226
|
+
Plain callbacks work fine for most things. When state needs to flow between widgets, signals give you a small reactive primitive with two-way binding:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
with bs.App(title="Hello") as app:
|
|
230
|
+
name = bs.Signal("World")
|
|
231
|
+
bs.Label(textsignal=name) # updates automatically when name changes
|
|
232
|
+
bs.TextField(textsignal=name) # two-way binding to the same state
|
|
233
|
+
|
|
234
|
+
app.run()
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Features
|
|
238
|
+
|
|
239
|
+
- **Application scaffolding** — `App` for blank windows, `AppShell` for toolbar + sidebar + page-stack apps, `Workbench` for two-tier workspace apps, `Splash` for a startup intro screen, undecorated windows with custom chrome
|
|
240
|
+
- **60+ themed widgets** — primitives plus higher-level composites (DataTable, Tree, ListView, Calendar, DateField, Form, Gauge, ToggleGroup, PageStack, Carousel, Tooltip, and more)
|
|
241
|
+
- **Dialogs and messages** — `alert()` / `confirm()` / `ask_*()` prompts and `FormDialog` / `FontDialog` / `FilterDialog`, plus non-blocking `toast()`, `Notification`, and `Snackbar` surfaces
|
|
242
|
+
- **Layout containers** — `Column`, `Row`, `Grid`, and `Spacer` for declarative layouts; `Card`, `GroupBox`, `ScrollView`, `SplitView`, `Accordion`, `Divider`
|
|
243
|
+
- **Design system** — semantic `accent` colors (primary, secondary, success, danger, warning, info) and `variant` tokens (solid, outline, ghost), consistent across widgets
|
|
244
|
+
- **Built-in themes** — 10 paired light/dark variants (bootstrap, catppuccin, dracula, everforest, gruvbox, nord, one, pydata, solarized, tokyo-night) with runtime theme switching and a custom-theme API
|
|
245
|
+
- **Reactive signals** — observable state with subscribe/set, integrates with widgets via `signal=` / `textsignal=`
|
|
246
|
+
- **Forms & validation** — `Form` with built-in field-level validators and inline error messages
|
|
247
|
+
- **DataSource** — common interface over in-memory, SQLite, and file backends, with pagination, filtering, sorting, CRUD, and CSV/TSV/Excel export
|
|
248
|
+
- **Data visualization** — `Chart` embeds `matplotlib`/`seaborn` figures that theme themselves and live-update from a `Signal` or `DataSource`; managed render, blitting animation, and a themed navigation toolbar (optional `viz` / `viz-seaborn` extras)
|
|
249
|
+
- **Localization (i18n)** — 23 bundled message catalogs, locale-aware number/date/time formatting via Babel, runtime language switching
|
|
250
|
+
- **Icons & images** — Bootstrap Icons catalog with theme-aware recoloring and caching
|
|
251
|
+
- **Platform support** — DPI awareness, multi-monitor centering, mica/acrylic effects on Windows
|
|
252
|
+
- **CLI (`bootstack`)** — project scaffolding, run, add components, theme/i18n setup, doctor, build/package
|
|
253
|
+
|
|
254
|
+
## Widget Categories
|
|
255
|
+
|
|
256
|
+
| Category | Widgets |
|
|
257
|
+
|----------|---------|
|
|
258
|
+
| **Actions** | Button, ButtonGroup, MenuButton, ContextMenu, Toolbar, ThemeToggle |
|
|
259
|
+
| **Inputs** | TextField, PasswordField, PathField, NumberField, SpinnerField, Slider, RangeSlider, TextArea, CodeEditor, DateField, TimeField |
|
|
260
|
+
| **Selection** | Checkbox, Switch, ToggleButton, Radio, RadioGroup, ToggleGroup, Select, SelectButton, Calendar |
|
|
261
|
+
| **Data Display** | Label, Badge, ListView, Tree, DataTable, ProgressBar, Gauge |
|
|
262
|
+
| **Media** | Avatar, Picture, Gallery, Carousel |
|
|
263
|
+
| **Layout** | Column, Row, Grid, Spacer, Card, GroupBox, SplitView, ScrollView, Accordion, Divider |
|
|
264
|
+
| **Navigation** | AppShell, Workbench, Window, Splash, StatusBar, Tabs, PageStack |
|
|
265
|
+
| **Dialogs** | `alert()`, `confirm()`, `ask_*()` prompts, FormDialog, FontDialog, FilterDialog |
|
|
266
|
+
| **Overlays** | `toast()`, Notification, Snackbar, Tooltip |
|
|
267
|
+
| **Forms** | Form, with field-level validation |
|
|
268
|
+
|
|
269
|
+
## CLI
|
|
270
|
+
|
|
271
|
+
bootstack ships with an optional CLI for scaffolding, running, and packaging applications:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
bootstack gallery # Launch the interactive widget gallery
|
|
275
|
+
bootstack icons # Browse the built-in icon catalog
|
|
276
|
+
bootstack appicon # Design an app icon and export it
|
|
277
|
+
bootstack start MyApp # Create a new project (basic template)
|
|
278
|
+
bootstack start MyApp --template appshell # ...or with sidebar navigation
|
|
279
|
+
bootstack run # Run the app defined in the project config
|
|
280
|
+
bootstack dev app.py # Run with hot reload (live edit-and-save)
|
|
281
|
+
bootstack add page Dashboard # Add a new page (appshell)
|
|
282
|
+
bootstack add view Settings # Add a new view (basic)
|
|
283
|
+
bootstack add dialog Preferences # Add a new dialog
|
|
284
|
+
bootstack doctor # Diagnose project & environment
|
|
285
|
+
bootstack promote # Make the project packaging-ready
|
|
286
|
+
bootstack build # Package for distribution
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Documentation
|
|
290
|
+
|
|
291
|
+
Full documentation — guides, the widget catalog, and the API reference — lives at
|
|
292
|
+
**[bootstack.org](https://bootstack.org)**.
|
|
293
|
+
|
|
294
|
+
## Contributing
|
|
295
|
+
|
|
296
|
+
Contributions are welcome — code, bug reports, and especially **translations**.
|
|
297
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, the pull-request
|
|
298
|
+
workflow, and how to review the bundled language catalogs.
|
|
299
|
+
|
|
300
|
+
## Links
|
|
301
|
+
|
|
302
|
+
- **GitHub**: https://github.com/israel-dryer/bootstack
|
|
@@ -322,7 +322,7 @@ bootstack/widgets/types.py,sha256=_86PwJ20gim0hGnCdPYSn1YVrrsTfZhyQ1zWDwHqQTY,13
|
|
|
322
322
|
bootstack/widgets/window.py,sha256=lwzYO6uAeXM_lSMXES911OsX8aVrJPKQHJu1u30bAIo,12921
|
|
323
323
|
bootstack/widgets/_core/__init__.py,sha256=rJPvvI3eOV9M5cICBD2XPZFokThf_tQyTeZhLPaqukU,1106
|
|
324
324
|
bootstack/widgets/_core/app_config.py,sha256=h_OaJ0jSif1eJeHWErpsXNyhtfCcmYQCcq0VriM48uk,9771
|
|
325
|
-
bootstack/widgets/_core/base.py,sha256=
|
|
325
|
+
bootstack/widgets/_core/base.py,sha256=LOLzA-m3NpcFi05b-W77r5W73efR5mgceq6xIsZJ4Ps,22739
|
|
326
326
|
bootstack/widgets/_core/choices.py,sha256=IGm4NspPJQgnGOxfuXWsqs4nSk7HSkdH0P60Cd1gnjo,2369
|
|
327
327
|
bootstack/widgets/_core/container.py,sha256=zrMadhoswXERiY4jjzeot2dnqpus-PKmG_vHESiuoqM,16051
|
|
328
328
|
bootstack/widgets/_core/context.py,sha256=laL75HYr7kIx3KbZqtT_rO1wWRjV4pehNzWgcZUkw_I,764
|
|
@@ -402,7 +402,7 @@ bootstack/widgets/_impl/composites/slider/_shared.py,sha256=xbwghVe-mKno5gDJsQNX
|
|
|
402
402
|
bootstack/widgets/_impl/composites/slider/rangeslider.py,sha256=xhzv68hhSx2iImtPdXBzuk9p41tdOJxzdl8APnGAnhY,43770
|
|
403
403
|
bootstack/widgets/_impl/composites/slider/slider.py,sha256=OWdhzahCDsXP1xNtDoHb82iQMbtYyzR895CePBbEQP0,38996
|
|
404
404
|
bootstack/widgets/_impl/composites/tableview/__init__.py,sha256=ccQKtGH53tGj7K1ezfsbY2iEyIH1wRgd1qEQ0Glqra4,127
|
|
405
|
-
bootstack/widgets/_impl/composites/tableview/tableview.py,sha256=
|
|
405
|
+
bootstack/widgets/_impl/composites/tableview/tableview.py,sha256=Qr7UwHxRB6p9mG6WDD5rZblEi3TvxuYwnk6TJXKgA1Q,150713
|
|
406
406
|
bootstack/widgets/_impl/composites/tableview/types.py,sha256=oDmJco19M42Zv_lUEpsfeM7kjjuHHsNBMVZoWRe-QDs,4906
|
|
407
407
|
bootstack/widgets/_impl/composites/tabs/__init__.py,sha256=yRRJCO9egzFCDNN7xDyQcH8KqCQx6AgGE-eVtpn4KSc,427
|
|
408
408
|
bootstack/widgets/_impl/composites/tabs/tabitem.py,sha256=WGCxBU2ObqFVLVa5p4KfBLp7QvJ-Y8sLfUkJjXP4820,14754
|
|
@@ -465,10 +465,10 @@ bootstack/widgets/_impl/primitives/sizegrip.py,sha256=uwQRzOEHjNPXtUURhT6k2TNYdy
|
|
|
465
465
|
bootstack/widgets/_impl/primitives/spinbox.py,sha256=5m0tZrqCw745nvIiBrJWnZ0q8fZ7bNEvopjROMbQolc,4526
|
|
466
466
|
bootstack/widgets/_impl/primitives/switch.py,sha256=7dt43uE2P_WdkxZZsGtCFRAQ20nI2jx5VUqGSrWwEmA,2543
|
|
467
467
|
bootstack/widgets/_impl/primitives/treeview.py,sha256=vnSowgzmtNEWst_i9ZgcacHjdvuheF9xmeTvTWE1bLg,2709
|
|
468
|
-
bootstack-0.2.
|
|
469
|
-
bootstack-0.2.
|
|
470
|
-
bootstack-0.2.
|
|
471
|
-
bootstack-0.2.
|
|
472
|
-
bootstack-0.2.
|
|
473
|
-
bootstack-0.2.
|
|
474
|
-
bootstack-0.2.
|
|
468
|
+
bootstack-0.2.2.dist-info/licenses/LICENSE,sha256=CUeTPUOM8Qc0yuqneJUwuUmDBooET5UfsHjMrkdBeCg,1097
|
|
469
|
+
bootstack-0.2.2.dist-info/licenses/NOTICE,sha256=-wgrIMRWBeNKGVXd48W43hf2xv9zDLzRyemn5tkgZIE,370
|
|
470
|
+
bootstack-0.2.2.dist-info/METADATA,sha256=yefZeA7n_PxLWN5n6WhxoVNMD45CZZbSHbG9ecBLkkc,16409
|
|
471
|
+
bootstack-0.2.2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
472
|
+
bootstack-0.2.2.dist-info/entry_points.txt,sha256=phOlfRy3Th86IYlNhQiUrTLLLzxie1IG-kMas_5iMdA,49
|
|
473
|
+
bootstack-0.2.2.dist-info/top_level.txt,sha256=IsKBAac2vRCegvRFSCzwcBr7TpHp4bLnLFgA75LOkXs,10
|
|
474
|
+
bootstack-0.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|