bootstack 0.2.2__py3-none-any.whl → 0.2.3__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.
@@ -12,7 +12,9 @@ which are clean Python callables, not raw Tcl strings.
12
12
  from __future__ import annotations
13
13
 
14
14
  import tkinter as tk
15
- from idlelib.redirector import WidgetRedirector
15
+ from bootstack.widgets._impl.composites.textarea.redirector import (
16
+ WidgetRedirector,
17
+ )
16
18
  from typing import TYPE_CHECKING
17
19
 
18
20
  if TYPE_CHECKING:
@@ -0,0 +1,138 @@
1
+ """Tk command interception for the edit filter chain.
2
+
3
+ Port of IDLE's `idlelib/redirector.py`. The rest of this package already ports
4
+ that design rather than importing it — `filter.py` adapts Delegator and
5
+ Percolator, `undo.py` adapts UndoDelegator, `sidebar.py` and
6
+ `extensions/line_numbers.py` port the sidebar — and this was the one piece left
7
+ as a live import. `idlelib` is standard library, but not every Python build
8
+ ships it, so that import made the whole framework unimportable on those builds
9
+ rather than degrading the code editor.
10
+
11
+ A Tk widget is backed by a Tcl command named after the widget's path, and every
12
+ operation on the widget goes through it — including the ones Tk's own key
13
+ bindings perform, which never reach Python at all. Renaming that command and
14
+ putting a dispatcher in its place is what lets the filter chain see an insert
15
+ that came from a keystroke, which is the whole reason this exists.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import tkinter as tk
20
+ from typing import Any, Callable
21
+
22
+
23
+ class WidgetRedirector:
24
+ """Intercepts operations on a Tk widget, including the toolkit's own.
25
+
26
+ Renames the widget's Tcl command out of the way and installs a dispatcher
27
+ under the original name. Registered operations are routed to a Python
28
+ callable; everything else passes straight through to the renamed command.
29
+
30
+ Only one redirector can exist for a given widget — the rename fails once
31
+ the name it renames to is taken.
32
+
33
+ Args:
34
+ widget: The widget whose operations are to be intercepted.
35
+ """
36
+
37
+ def __init__(self, widget: tk.Misc) -> None:
38
+ self._operations: dict[str, Callable[..., Any]] = {}
39
+ self.widget = widget
40
+ self.tk = widget.tk
41
+ path = widget._w
42
+ self.orig = path + "_orig"
43
+ self.tk.call("rename", path, self.orig)
44
+ self.tk.createcommand(path, self.dispatch)
45
+
46
+ def register(
47
+ self, operation: str, function: Callable[..., Any]
48
+ ) -> OriginalCommand:
49
+ """Route `operation` to `function`, returning a way to call the original.
50
+
51
+ The function is also set on the widget, so a call written in Python —
52
+ `text.insert(...)` — is intercepted the same way a keystroke is.
53
+ Registering a second function for the same operation replaces the first
54
+ in both places.
55
+
56
+ Args:
57
+ operation: Name of the widget operation, such as `insert`.
58
+ function: What to call in its place. It receives the operation's
59
+ arguments, and is handed the returned callable to pass the call
60
+ on with.
61
+ """
62
+ self._operations[operation] = function
63
+ setattr(self.widget, operation, function)
64
+ return OriginalCommand(self, operation)
65
+
66
+ def unregister(self, operation: str) -> Callable[..., Any] | None:
67
+ """Stop routing `operation`, returning whatever was handling it.
68
+
69
+ Returns None if the operation was not registered. Dropping the widget
70
+ attribute that `register` set unmasks the widget's own method again.
71
+
72
+ Args:
73
+ operation: Name of the widget operation to stop intercepting.
74
+ """
75
+ function = self._operations.pop(operation, None)
76
+ if function is None:
77
+ return None
78
+ try:
79
+ delattr(self.widget, operation)
80
+ except AttributeError:
81
+ pass
82
+ return function
83
+
84
+ def dispatch(self, operation, *args):
85
+ """Handle one call to the widget, invoked from Tcl.
86
+
87
+ A registered operation goes to its function and does not continue on to
88
+ the widget — the function decides whether to pass the call along, using
89
+ the callable it was given at registration. Everything else goes
90
+ straight through.
91
+
92
+ Args:
93
+ operation: The operation being performed. Tcl may hand this over as
94
+ its own object type rather than a string.
95
+ args: The operation's arguments, exactly as Tcl passed them.
96
+ """
97
+ operation = str(operation)
98
+ function = self._operations.get(operation)
99
+ try:
100
+ if function is not None:
101
+ return function(*args)
102
+ return self.tk.call((self.orig, operation) + args)
103
+ except tk.TclError:
104
+ # What the toolkit itself does with a failed widget command. The
105
+ # caller here is Tcl, which has nowhere useful to put an exception.
106
+ return ""
107
+
108
+ def close(self) -> None:
109
+ """Undo the interception and restore the widget's own Tcl command."""
110
+ for operation in list(self._operations):
111
+ self.unregister(operation)
112
+ path = self.widget._w
113
+ self.tk.deletecommand(path)
114
+ self.tk.call("rename", self.orig, path)
115
+
116
+
117
+ class OriginalCommand:
118
+ """The widget operation a redirector displaced, as a plain callable.
119
+
120
+ Returned by `WidgetRedirector.register` so a registered function can pass
121
+ the call on to the widget after inspecting or changing it. Calling this
122
+ reaches the widget directly and does not re-enter the chain.
123
+
124
+ Args:
125
+ redirector: The redirector that displaced the operation.
126
+ operation: Name of the displaced operation.
127
+ """
128
+
129
+ def __init__(self, redirector: WidgetRedirector, operation: str) -> None:
130
+ self._operation = operation
131
+ self._call = redirector.tk.call
132
+ self._target = (redirector.orig, operation)
133
+
134
+ def __call__(self, *args):
135
+ return self._call(self._target + args)
136
+
137
+ def __repr__(self) -> str:
138
+ return f"OriginalCommand({self._operation!r})"
@@ -1,302 +1,302 @@
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
- ![bootstack](https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/banner-readme.png)
55
-
56
- ![](https://img.shields.io/github/release/israel-dryer/bootstack.svg)
57
- [![Downloads](https://pepy.tech/badge/bootstack)](https://pepy.tech/project/bootstack)
58
- [![Downloads](https://pepy.tech/badge/bootstack/month)](https://pepy.tech/project/bootstack)
59
- ![](https://img.shields.io/github/issues/israel-dryer/bootstack.svg)
60
- ![](https://img.shields.io/github/issues-closed/israel-dryer/bootstack.svg)
61
- ![](https://img.shields.io/github/license/israel-dryer/bootstack.svg)
62
- ![](https://img.shields.io/github/stars/israel-dryer/bootstack.svg)
63
- ![](https://img.shields.io/github/forks/israel-dryer/bootstack.svg)
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.3
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
+ ![bootstack](https://raw.githubusercontent.com/israel-dryer/bootstack/main/assets/banner-readme.png)
55
+
56
+ ![](https://img.shields.io/github/release/israel-dryer/bootstack.svg)
57
+ [![Downloads](https://pepy.tech/badge/bootstack)](https://pepy.tech/project/bootstack)
58
+ [![Downloads](https://pepy.tech/badge/bootstack/month)](https://pepy.tech/project/bootstack)
59
+ ![](https://img.shields.io/github/issues/israel-dryer/bootstack.svg)
60
+ ![](https://img.shields.io/github/issues-closed/israel-dryer/bootstack.svg)
61
+ ![](https://img.shields.io/github/license/israel-dryer/bootstack.svg)
62
+ ![](https://img.shields.io/github/stars/israel-dryer/bootstack.svg)
63
+ ![](https://img.shields.io/github/forks/israel-dryer/bootstack.svg)
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
@@ -414,7 +414,8 @@ bootstack/widgets/_impl/composites/textarea/codeeditor.py,sha256=SPLw3OoPxfhoKTr
414
414
  bootstack/widgets/_impl/composites/textarea/core.py,sha256=TA-eYPl929Fro11zPwB0FGoaTmsI_m0s54cNUkKQO8Y,20577
415
415
  bootstack/widgets/_impl/composites/textarea/decoration.py,sha256=OFMqDo7rqnvJoXqwhpg9w5m9A9LxTssYGeYQCQnFGAc,1077
416
416
  bootstack/widgets/_impl/composites/textarea/diff.py,sha256=AZ2xukMzUZBM9Nu-bCoQdsg4TU_FsmrJEF5K6CGssvY,4537
417
- bootstack/widgets/_impl/composites/textarea/filter.py,sha256=RRETrtw79giz6vHGfdXeImH8k6QRRTrgiqYs54ABw2k,6702
417
+ bootstack/widgets/_impl/composites/textarea/filter.py,sha256=GbkFVH9fEaoJorBQfPPT7JlK3wuS5KiPH5yYbk_wmBU,6749
418
+ bootstack/widgets/_impl/composites/textarea/redirector.py,sha256=vAL8Y3HuevC8Fab4kM9gV8Fh9Vt_DLQ74-zttrPQFd4,5713
418
419
  bootstack/widgets/_impl/composites/textarea/search_overlay.py,sha256=humVYBFN-EbfbIFC6IavtsNEFGHJtuYZCZ5W7SmZUeU,18669
419
420
  bootstack/widgets/_impl/composites/textarea/sidebar.py,sha256=X3LcIv-OMvymL3xTcNMEhP5ddzh53gxreDWmeMItXg8,3151
420
421
  bootstack/widgets/_impl/composites/textarea/style_registry.py,sha256=NOgBOGLJzYvw-Mf6O0YV7kwIoUc_yvOOWlqZDDzC6Qc,7678
@@ -465,10 +466,10 @@ bootstack/widgets/_impl/primitives/sizegrip.py,sha256=uwQRzOEHjNPXtUURhT6k2TNYdy
465
466
  bootstack/widgets/_impl/primitives/spinbox.py,sha256=5m0tZrqCw745nvIiBrJWnZ0q8fZ7bNEvopjROMbQolc,4526
466
467
  bootstack/widgets/_impl/primitives/switch.py,sha256=7dt43uE2P_WdkxZZsGtCFRAQ20nI2jx5VUqGSrWwEmA,2543
467
468
  bootstack/widgets/_impl/primitives/treeview.py,sha256=vnSowgzmtNEWst_i9ZgcacHjdvuheF9xmeTvTWE1bLg,2709
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,,
469
+ bootstack-0.2.3.dist-info/licenses/LICENSE,sha256=CUeTPUOM8Qc0yuqneJUwuUmDBooET5UfsHjMrkdBeCg,1097
470
+ bootstack-0.2.3.dist-info/licenses/NOTICE,sha256=c62TcygUKbXx1V3FEgziroDDry_NwmycqKEg_CRnYBU,1503
471
+ bootstack-0.2.3.dist-info/METADATA,sha256=t9_D7SfRbil4Yf9q4zipT3Q8padwc622bVtc5kltlVc,16107
472
+ bootstack-0.2.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
473
+ bootstack-0.2.3.dist-info/entry_points.txt,sha256=phOlfRy3Th86IYlNhQiUrTLLLzxie1IG-kMas_5iMdA,49
474
+ bootstack-0.2.3.dist-info/top_level.txt,sha256=IsKBAac2vRCegvRFSCzwcBr7TpHp4bLnLFgA75LOkXs,10
475
+ bootstack-0.2.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (83.0.0)
2
+ Generator: setuptools (84.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,30 @@
1
+ bootstack
2
+ Copyright (c) 2021 - 2026 Israel Dryer
3
+
4
+ This project is derived from ttkbootstrap
5
+ (https://github.com/israel-dryer/ttkbootstrap),
6
+ Copyright (c) 2021 - 2026 Israel Dryer and ttkbootstrap contributors,
7
+ licensed under the MIT License.
8
+
9
+ The original ttkbootstrap license and copyright notice are preserved above
10
+ in compliance with the MIT License terms.
11
+
12
+ This project also contains code derived from IDLE, part of the CPython
13
+ standard library (https://github.com/python/cpython),
14
+ Copyright (c) 2001-2023 Python Software Foundation; All Rights Reserved,
15
+ licensed under the Python Software Foundation License Agreement, Version 2.
16
+
17
+ src/bootstack/widgets/_impl/composites/textarea/redirector.py
18
+
19
+ is a port of idlelib/redirector.py, carrying its WidgetRedirector and
20
+ OriginalCommand classes and their dispatch logic. Summary of the changes made,
21
+ as the Python Software Foundation License Agreement asks for: the
22
+ OriginalCommand interface was narrowed to three private attributes,
23
+ WidgetRedirector.__repr__ was dropped, the operation name is coerced to a
24
+ string before lookup, the widget reference is retained after close() rather
25
+ than deleted, and type hints and rewritten documentation were added.
26
+
27
+ Other modules in the same package implement designs described in IDLE — the
28
+ Delegator and Percolator chain, UndoDelegator, the editor sidebar, and
29
+ parenmatch's flash-and-restore highlighting — but share no substantial code
30
+ with it and are original implementations.
@@ -1,10 +0,0 @@
1
- bootstack
2
- Copyright (c) 2021 - 2026 Israel Dryer
3
-
4
- This project is derived from ttkbootstrap
5
- (https://github.com/israel-dryer/ttkbootstrap),
6
- Copyright (c) 2021 - 2026 Israel Dryer and ttkbootstrap contributors,
7
- licensed under the MIT License.
8
-
9
- The original ttkbootstrap license and copyright notice are preserved above
10
- in compliance with the MIT License terms.