bootstack 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (471) hide show
  1. bootstack/__init__.py +157 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/_core/__init__.py +21 -0
  4. bootstack/_core/capabilities/__init__.py +45 -0
  5. bootstack/_core/capabilities/after.py +103 -0
  6. bootstack/_core/capabilities/bind.py +192 -0
  7. bootstack/_core/capabilities/bindtags.py +112 -0
  8. bootstack/_core/capabilities/busy.py +72 -0
  9. bootstack/_core/capabilities/clipboard.py +89 -0
  10. bootstack/_core/capabilities/focus.py +118 -0
  11. bootstack/_core/capabilities/grab.py +65 -0
  12. bootstack/_core/capabilities/grid.py +211 -0
  13. bootstack/_core/capabilities/localization.py +231 -0
  14. bootstack/_core/capabilities/pack.py +140 -0
  15. bootstack/_core/capabilities/place.py +113 -0
  16. bootstack/_core/capabilities/selection.py +136 -0
  17. bootstack/_core/capabilities/signals.py +244 -0
  18. bootstack/_core/capabilities/winfo.py +315 -0
  19. bootstack/_core/colorutils.py +234 -0
  20. bootstack/_core/exceptions.py +25 -0
  21. bootstack/_core/images.py +463 -0
  22. bootstack/_core/mixins/__init__.py +1 -0
  23. bootstack/_core/mixins/ttk_state.py +35 -0
  24. bootstack/_core/mixins/widget.py +132 -0
  25. bootstack/_core/paths.py +49 -0
  26. bootstack/_core/publisher.py +149 -0
  27. bootstack/_core/variables.py +62 -0
  28. bootstack/_runtime/__init__.py +3 -0
  29. bootstack/_runtime/app.py +930 -0
  30. bootstack/_runtime/base_window.py +945 -0
  31. bootstack/_runtime/events.py +399 -0
  32. bootstack/_runtime/shortcuts.py +496 -0
  33. bootstack/_runtime/tk_patch.py +43 -0
  34. bootstack/_runtime/toplevel.py +276 -0
  35. bootstack/_runtime/utility.py +457 -0
  36. bootstack/_runtime/visual_focus.py +240 -0
  37. bootstack/_runtime/window_utilities.py +1123 -0
  38. bootstack/assets/__init__.py +21 -0
  39. bootstack/assets/bootstack.ico +0 -0
  40. bootstack/assets/bootstack.png +0 -0
  41. bootstack/assets/elements/__init__.py +0 -0
  42. bootstack/assets/elements/badge-pill.png +0 -0
  43. bootstack/assets/elements/badge-square.png +0 -0
  44. bootstack/assets/elements/button-compact.png +0 -0
  45. bootstack/assets/elements/button-default.png +0 -0
  46. bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
  47. bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
  48. bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
  49. bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
  50. bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
  51. bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
  52. bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
  53. bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
  54. bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
  55. bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
  56. bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
  57. bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
  58. bootstack/assets/elements/card.png +0 -0
  59. bootstack/assets/elements/checkbox-checked.png +0 -0
  60. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  61. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  62. bootstack/assets/elements/field.png +0 -0
  63. bootstack/assets/elements/input-addon-compact.png +0 -0
  64. bootstack/assets/elements/input-addon-default.png +0 -0
  65. bootstack/assets/elements/input-compact.png +0 -0
  66. bootstack/assets/elements/input-default.png +0 -0
  67. bootstack/assets/elements/list-item-separated.png +0 -0
  68. bootstack/assets/elements/list-item.png +0 -0
  69. bootstack/assets/elements/listrow-compact.png +0 -0
  70. bootstack/assets/elements/listrow-default.png +0 -0
  71. bootstack/assets/elements/manifest.toml +361 -0
  72. bootstack/assets/elements/menu-item.png +0 -0
  73. bootstack/assets/elements/navitem-compact.png +0 -0
  74. bootstack/assets/elements/navitem-default.png +0 -0
  75. bootstack/assets/elements/progressbar-h-compact.png +0 -0
  76. bootstack/assets/elements/progressbar-h-default.png +0 -0
  77. bootstack/assets/elements/progressbar-v-compact.png +0 -0
  78. bootstack/assets/elements/progressbar-v-default.png +0 -0
  79. bootstack/assets/elements/radiobutton.png +0 -0
  80. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  81. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  82. bootstack/assets/elements/slider-handle.png +0 -0
  83. bootstack/assets/elements/slider-track-h.png +0 -0
  84. bootstack/assets/elements/slider-track-v.png +0 -0
  85. bootstack/assets/elements/switch-off.png +0 -0
  86. bootstack/assets/elements/switch-on.png +0 -0
  87. bootstack/assets/elements/tab-h.png +0 -0
  88. bootstack/assets/elements/tab-v.png +0 -0
  89. bootstack/assets/icons/bootstrap.ttf +0 -0
  90. bootstack/assets/icons/glyphmap.json +2080 -0
  91. bootstack/assets/icons/icon_metrics.json +12470 -0
  92. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  93. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +856 -0
  94. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
  95. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +878 -0
  96. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  97. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +856 -0
  98. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  99. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +856 -0
  100. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  101. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +856 -0
  102. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  103. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +878 -0
  104. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  105. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +856 -0
  106. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  107. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +856 -0
  108. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  109. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +854 -0
  110. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  111. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +845 -0
  112. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  113. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +844 -0
  114. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  115. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +917 -0
  116. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  117. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +845 -0
  118. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  119. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +844 -0
  120. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  121. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +844 -0
  122. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  123. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +845 -0
  124. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  125. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +845 -0
  126. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  127. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +845 -0
  128. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  129. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +845 -0
  130. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  131. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +845 -0
  132. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  133. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +845 -0
  134. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  135. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +845 -0
  136. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  137. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +845 -0
  138. bootstack/cli/__init__.py +133 -0
  139. bootstack/cli/__main__.py +6 -0
  140. bootstack/cli/add.py +395 -0
  141. bootstack/cli/appicon.py +285 -0
  142. bootstack/cli/build.py +115 -0
  143. bootstack/cli/config.py +313 -0
  144. bootstack/cli/demo.py +564 -0
  145. bootstack/cli/dev.py +153 -0
  146. bootstack/cli/doctor.py +195 -0
  147. bootstack/cli/icons.py +98 -0
  148. bootstack/cli/promote.py +120 -0
  149. bootstack/cli/pyinstaller.py +268 -0
  150. bootstack/cli/run.py +95 -0
  151. bootstack/cli/start.py +117 -0
  152. bootstack/cli/templates/__init__.py +931 -0
  153. bootstack/clipboard.py +48 -0
  154. bootstack/constants.py +318 -0
  155. bootstack/data/README.md +615 -0
  156. bootstack/data/__init__.py +78 -0
  157. bootstack/data/_observable.py +276 -0
  158. bootstack/data/base.py +780 -0
  159. bootstack/data/file_source.py +367 -0
  160. bootstack/data/memory_source.py +450 -0
  161. bootstack/data/query.py +367 -0
  162. bootstack/data/readers.py +289 -0
  163. bootstack/data/sqlite_source.py +869 -0
  164. bootstack/data/types.py +354 -0
  165. bootstack/data/writers.py +232 -0
  166. bootstack/dev/__init__.py +36 -0
  167. bootstack/dev/_capture.py +141 -0
  168. bootstack/dev/_env.py +43 -0
  169. bootstack/dev/_registry.py +140 -0
  170. bootstack/dev/_reloader.py +351 -0
  171. bootstack/dev/_reset.py +50 -0
  172. bootstack/dev/_watcher.py +91 -0
  173. bootstack/dialogs/__init__.py +948 -0
  174. bootstack/dialogs/_impl/__init__.py +47 -0
  175. bootstack/dialogs/_impl/colorchooser.py +588 -0
  176. bootstack/dialogs/_impl/datedialog.py +450 -0
  177. bootstack/dialogs/_impl/dialog.py +594 -0
  178. bootstack/dialogs/_impl/filterdialog.py +358 -0
  179. bootstack/dialogs/_impl/fontdialog.py +364 -0
  180. bootstack/dialogs/_impl/formdialog.py +564 -0
  181. bootstack/dialogs/_impl/message.py +486 -0
  182. bootstack/dialogs/_impl/query.py +570 -0
  183. bootstack/errors.py +67 -0
  184. bootstack/events/__init__.py +111 -0
  185. bootstack/events/_event.py +135 -0
  186. bootstack/events/_payloads.py +539 -0
  187. bootstack/events/_subscription.py +38 -0
  188. bootstack/i18n/README.md +77 -0
  189. bootstack/i18n/__init__.py +23 -0
  190. bootstack/i18n/catalog.py +121 -0
  191. bootstack/i18n/intl_format.py +584 -0
  192. bootstack/i18n/msgcat.py +425 -0
  193. bootstack/i18n/specs.py +156 -0
  194. bootstack/images.py +563 -0
  195. bootstack/py.typed +1 -0
  196. bootstack/scheduling/__init__.py +11 -0
  197. bootstack/scheduling/_schedule.py +218 -0
  198. bootstack/shortcuts.py +21 -0
  199. bootstack/signals/README.md +98 -0
  200. bootstack/signals/__init__.py +10 -0
  201. bootstack/signals/integration.py +100 -0
  202. bootstack/signals/signal.py +353 -0
  203. bootstack/signals/types.py +6 -0
  204. bootstack/store.py +286 -0
  205. bootstack/streams/__init__.py +12 -0
  206. bootstack/streams/_stream.py +321 -0
  207. bootstack/style/__init__.py +38 -0
  208. bootstack/style/builders/__init__.py +51 -0
  209. bootstack/style/builders/badge.py +46 -0
  210. bootstack/style/builders/button.py +339 -0
  211. bootstack/style/builders/buttongroup.py +311 -0
  212. bootstack/style/builders/calendar.py +271 -0
  213. bootstack/style/builders/checkbutton.py +110 -0
  214. bootstack/style/builders/combobox.py +113 -0
  215. bootstack/style/builders/contextmenu.py +268 -0
  216. bootstack/style/builders/entry.py +82 -0
  217. bootstack/style/builders/expander.py +148 -0
  218. bootstack/style/builders/field.py +335 -0
  219. bootstack/style/builders/frame.py +50 -0
  220. bootstack/style/builders/label.py +28 -0
  221. bootstack/style/builders/labelframe.py +34 -0
  222. bootstack/style/builders/listview.py +369 -0
  223. bootstack/style/builders/menubar.py +91 -0
  224. bootstack/style/builders/menubutton.py +359 -0
  225. bootstack/style/builders/panedwindow.py +25 -0
  226. bootstack/style/builders/progressbar.py +67 -0
  227. bootstack/style/builders/radiobutton.py +99 -0
  228. bootstack/style/builders/scale.py +64 -0
  229. bootstack/style/builders/scrollbar.py +225 -0
  230. bootstack/style/builders/separator.py +49 -0
  231. bootstack/style/builders/sidenav.py +643 -0
  232. bootstack/style/builders/sizegrip.py +15 -0
  233. bootstack/style/builders/spinbox.py +119 -0
  234. bootstack/style/builders/switch.py +70 -0
  235. bootstack/style/builders/tabitem.py +204 -0
  236. bootstack/style/builders/togglegroup.py +294 -0
  237. bootstack/style/builders/toolbutton.py +275 -0
  238. bootstack/style/builders/tooltip.py +26 -0
  239. bootstack/style/builders/treeview.py +193 -0
  240. bootstack/style/builders/utils.py +455 -0
  241. bootstack/style/builders_tk/__init__.py +16 -0
  242. bootstack/style/builders_tk/defaults.py +229 -0
  243. bootstack/style/element.py +173 -0
  244. bootstack/style/fonts.py +123 -0
  245. bootstack/style/style.py +609 -0
  246. bootstack/style/style_builder_base.py +716 -0
  247. bootstack/style/style_builder_mixed.py +93 -0
  248. bootstack/style/style_builder_tk.py +109 -0
  249. bootstack/style/style_builder_ttk.py +353 -0
  250. bootstack/style/style_resolver.py +447 -0
  251. bootstack/style/theme.py +245 -0
  252. bootstack/style/theme_provider.py +471 -0
  253. bootstack/style/themes/__init__.py +128 -0
  254. bootstack/style/tk_patch.py +5 -0
  255. bootstack/style/token_maps.py +41 -0
  256. bootstack/style/types.py +32 -0
  257. bootstack/style/typography.py +523 -0
  258. bootstack/style/utility.py +746 -0
  259. bootstack/types.py +39 -0
  260. bootstack/validation/__init__.py +6 -0
  261. bootstack/validation/types.py +15 -0
  262. bootstack/validation/validation_result.py +17 -0
  263. bootstack/validation/validation_rules.py +205 -0
  264. bootstack/widgets/__init__.py +74 -0
  265. bootstack/widgets/_core/__init__.py +31 -0
  266. bootstack/widgets/_core/app_config.py +266 -0
  267. bootstack/widgets/_core/base.py +461 -0
  268. bootstack/widgets/_core/container.py +334 -0
  269. bootstack/widgets/_core/context.py +35 -0
  270. bootstack/widgets/_core/events.py +130 -0
  271. bootstack/widgets/_core/field_mixin.py +353 -0
  272. bootstack/widgets/_core/icon_image_props.py +72 -0
  273. bootstack/widgets/_core/image_binding.py +93 -0
  274. bootstack/widgets/_core/navmodel.py +345 -0
  275. bootstack/widgets/_core/options.py +210 -0
  276. bootstack/widgets/_core/selection_group.py +130 -0
  277. bootstack/widgets/_core/window_controls.py +96 -0
  278. bootstack/widgets/_core/window_menu.py +246 -0
  279. bootstack/widgets/_impl/__init__.py +1 -0
  280. bootstack/widgets/_impl/_internal/__init__.py +0 -0
  281. bootstack/widgets/_impl/_internal/wrapper_base.py +307 -0
  282. bootstack/widgets/_impl/_parts/__init__.py +11 -0
  283. bootstack/widgets/_impl/_parts/numberentry_part.py +385 -0
  284. bootstack/widgets/_impl/_parts/spinnerentry_part.py +434 -0
  285. bootstack/widgets/_impl/_parts/textentry_part.py +406 -0
  286. bootstack/widgets/_impl/composites/__init__.py +33 -0
  287. bootstack/widgets/_impl/composites/_dateutils.py +33 -0
  288. bootstack/widgets/_impl/composites/_image_fit.py +105 -0
  289. bootstack/widgets/_impl/composites/accordion.py +381 -0
  290. bootstack/widgets/_impl/composites/avatar.py +191 -0
  291. bootstack/widgets/_impl/composites/buttongroup.py +371 -0
  292. bootstack/widgets/_impl/composites/calendar.py +972 -0
  293. bootstack/widgets/_impl/composites/carousel.py +567 -0
  294. bootstack/widgets/_impl/composites/chart.py +882 -0
  295. bootstack/widgets/_impl/composites/compositeframe.py +298 -0
  296. bootstack/widgets/_impl/composites/contextmenu.py +1951 -0
  297. bootstack/widgets/_impl/composites/dateentry.py +404 -0
  298. bootstack/widgets/_impl/composites/dropdownbutton.py +325 -0
  299. bootstack/widgets/_impl/composites/expander.py +515 -0
  300. bootstack/widgets/_impl/composites/field.py +670 -0
  301. bootstack/widgets/_impl/composites/form.py +1066 -0
  302. bootstack/widgets/_impl/composites/gallery.py +551 -0
  303. bootstack/widgets/_impl/composites/list/__init__.py +15 -0
  304. bootstack/widgets/_impl/composites/list/listitem.py +802 -0
  305. bootstack/widgets/_impl/composites/list/listview.py +1433 -0
  306. bootstack/widgets/_impl/composites/menu/__init__.py +18 -0
  307. bootstack/widgets/_impl/composites/menu/model.py +358 -0
  308. bootstack/widgets/_impl/composites/menu/render_native.py +134 -0
  309. bootstack/widgets/_impl/composites/menu/render_themed.py +134 -0
  310. bootstack/widgets/_impl/composites/meter.py +860 -0
  311. bootstack/widgets/_impl/composites/numericentry.py +201 -0
  312. bootstack/widgets/_impl/composites/pagestack.py +395 -0
  313. bootstack/widgets/_impl/composites/passwordentry.py +142 -0
  314. bootstack/widgets/_impl/composites/pathentry.py +168 -0
  315. bootstack/widgets/_impl/composites/picture.py +289 -0
  316. bootstack/widgets/_impl/composites/radiogroup.py +511 -0
  317. bootstack/widgets/_impl/composites/scrolledtext.py +375 -0
  318. bootstack/widgets/_impl/composites/scrolledtext.pyi +186 -0
  319. bootstack/widgets/_impl/composites/scrollview.py +764 -0
  320. bootstack/widgets/_impl/composites/selectbox.py +1026 -0
  321. bootstack/widgets/_impl/composites/shell/__init__.py +40 -0
  322. bootstack/widgets/_impl/composites/shell/content_host.py +52 -0
  323. bootstack/widgets/_impl/composites/shell/layout.py +335 -0
  324. bootstack/widgets/_impl/composites/shell/nav_panel.py +345 -0
  325. bootstack/widgets/_impl/composites/shell/providers.py +558 -0
  326. bootstack/widgets/_impl/composites/shell/rail.py +117 -0
  327. bootstack/widgets/_impl/composites/shell/shell.py +581 -0
  328. bootstack/widgets/_impl/composites/shell/workspace.py +273 -0
  329. bootstack/widgets/_impl/composites/sidenav/__init__.py +16 -0
  330. bootstack/widgets/_impl/composites/sidenav/header.py +81 -0
  331. bootstack/widgets/_impl/composites/sidenav/separator.py +44 -0
  332. bootstack/widgets/_impl/composites/slider/__init__.py +7 -0
  333. bootstack/widgets/_impl/composites/slider/_shared.py +195 -0
  334. bootstack/widgets/_impl/composites/slider/rangeslider.py +982 -0
  335. bootstack/widgets/_impl/composites/slider/slider.py +851 -0
  336. bootstack/widgets/_impl/composites/spinnerentry.py +185 -0
  337. bootstack/widgets/_impl/composites/tableview/__init__.py +5 -0
  338. bootstack/widgets/_impl/composites/tableview/tableview.py +3388 -0
  339. bootstack/widgets/_impl/composites/tableview/types.py +169 -0
  340. bootstack/widgets/_impl/composites/tabs/__init__.py +23 -0
  341. bootstack/widgets/_impl/composites/tabs/tabitem.py +389 -0
  342. bootstack/widgets/_impl/composites/tabs/tabs.py +974 -0
  343. bootstack/widgets/_impl/composites/tabs/tabview.py +650 -0
  344. bootstack/widgets/_impl/composites/textarea/__init__.py +26 -0
  345. bootstack/widgets/_impl/composites/textarea/change.py +46 -0
  346. bootstack/widgets/_impl/composites/textarea/codeeditor.py +526 -0
  347. bootstack/widgets/_impl/composites/textarea/core.py +495 -0
  348. bootstack/widgets/_impl/composites/textarea/decoration.py +42 -0
  349. bootstack/widgets/_impl/composites/textarea/diff.py +127 -0
  350. bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +1 -0
  351. bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +138 -0
  352. bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +158 -0
  353. bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +138 -0
  354. bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +312 -0
  355. bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +177 -0
  356. bootstack/widgets/_impl/composites/textarea/filter.py +171 -0
  357. bootstack/widgets/_impl/composites/textarea/search_overlay.py +459 -0
  358. bootstack/widgets/_impl/composites/textarea/sidebar.py +88 -0
  359. bootstack/widgets/_impl/composites/textarea/style_registry.py +178 -0
  360. bootstack/widgets/_impl/composites/textarea/textarea.py +606 -0
  361. bootstack/widgets/_impl/composites/textarea/undo.py +217 -0
  362. bootstack/widgets/_impl/composites/textentry.py +57 -0
  363. bootstack/widgets/_impl/composites/timeentry.py +176 -0
  364. bootstack/widgets/_impl/composites/toast.py +390 -0
  365. bootstack/widgets/_impl/composites/toast_stack.py +156 -0
  366. bootstack/widgets/_impl/composites/togglegroup.py +418 -0
  367. bootstack/widgets/_impl/composites/toolbar.py +608 -0
  368. bootstack/widgets/_impl/composites/tooltip.py +491 -0
  369. bootstack/widgets/_impl/composites/tree/__init__.py +7 -0
  370. bootstack/widgets/_impl/composites/tree/source_binding.py +136 -0
  371. bootstack/widgets/_impl/composites/tree/treeitem.py +393 -0
  372. bootstack/widgets/_impl/composites/tree/treenode.py +174 -0
  373. bootstack/widgets/_impl/composites/tree/treeview.py +841 -0
  374. bootstack/widgets/_impl/mixins/__init__.py +24 -0
  375. bootstack/widgets/_impl/mixins/configure_mixin.py +216 -0
  376. bootstack/widgets/_impl/mixins/entry_mixin.py +134 -0
  377. bootstack/widgets/_impl/mixins/font_mixin.py +368 -0
  378. bootstack/widgets/_impl/mixins/icon_mixin.py +61 -0
  379. bootstack/widgets/_impl/mixins/localization_mixin.py +253 -0
  380. bootstack/widgets/_impl/mixins/signal_mixin.py +268 -0
  381. bootstack/widgets/_impl/mixins/validation_mixin.py +226 -0
  382. bootstack/widgets/_impl/primitives/__init__.py +49 -0
  383. bootstack/widgets/_impl/primitives/_menubutton.py +107 -0
  384. bootstack/widgets/_impl/primitives/badge.py +45 -0
  385. bootstack/widgets/_impl/primitives/button.py +76 -0
  386. bootstack/widgets/_impl/primitives/card.py +45 -0
  387. bootstack/widgets/_impl/primitives/checkbutton.py +124 -0
  388. bootstack/widgets/_impl/primitives/checktoggle.py +62 -0
  389. bootstack/widgets/_impl/primitives/combobox.py +156 -0
  390. bootstack/widgets/_impl/primitives/entry.py +87 -0
  391. bootstack/widgets/_impl/primitives/flexframe.py +448 -0
  392. bootstack/widgets/_impl/primitives/frame.py +185 -0
  393. bootstack/widgets/_impl/primitives/gridframe.py +546 -0
  394. bootstack/widgets/_impl/primitives/label.py +84 -0
  395. bootstack/widgets/_impl/primitives/labelframe.py +54 -0
  396. bootstack/widgets/_impl/primitives/optionmenu.py +387 -0
  397. bootstack/widgets/_impl/primitives/packframe.py +227 -0
  398. bootstack/widgets/_impl/primitives/panedwindow.py +45 -0
  399. bootstack/widgets/_impl/primitives/progressbar.py +83 -0
  400. bootstack/widgets/_impl/primitives/radiobutton.py +115 -0
  401. bootstack/widgets/_impl/primitives/radiotoggle.py +54 -0
  402. bootstack/widgets/_impl/primitives/scrollbar.py +42 -0
  403. bootstack/widgets/_impl/primitives/separator.py +43 -0
  404. bootstack/widgets/_impl/primitives/sizegrip.py +33 -0
  405. bootstack/widgets/_impl/primitives/spinbox.py +95 -0
  406. bootstack/widgets/_impl/primitives/switch.py +44 -0
  407. bootstack/widgets/_impl/primitives/treeview.py +69 -0
  408. bootstack/widgets/app.py +371 -0
  409. bootstack/widgets/appshell.py +1179 -0
  410. bootstack/widgets/avatar.py +140 -0
  411. bootstack/widgets/boolean_controls.py +455 -0
  412. bootstack/widgets/button.py +224 -0
  413. bootstack/widgets/buttongroup.py +239 -0
  414. bootstack/widgets/calendar.py +195 -0
  415. bootstack/widgets/card.py +159 -0
  416. bootstack/widgets/carousel.py +241 -0
  417. bootstack/widgets/chart.py +302 -0
  418. bootstack/widgets/codeeditor.py +675 -0
  419. bootstack/widgets/contextmenu.py +371 -0
  420. bootstack/widgets/datatable.py +688 -0
  421. bootstack/widgets/datefield.py +395 -0
  422. bootstack/widgets/divider.py +60 -0
  423. bootstack/widgets/expander.py +579 -0
  424. bootstack/widgets/form.py +200 -0
  425. bootstack/widgets/gallery.py +250 -0
  426. bootstack/widgets/gauge.py +168 -0
  427. bootstack/widgets/grid.py +121 -0
  428. bootstack/widgets/groupbox.py +162 -0
  429. bootstack/widgets/label.py +229 -0
  430. bootstack/widgets/listview.py +354 -0
  431. bootstack/widgets/menubutton.py +419 -0
  432. bootstack/widgets/numberfield.py +431 -0
  433. bootstack/widgets/pagestack.py +345 -0
  434. bootstack/widgets/passwordfield.py +383 -0
  435. bootstack/widgets/pathfield.py +454 -0
  436. bootstack/widgets/picture.py +251 -0
  437. bootstack/widgets/progressbar.py +106 -0
  438. bootstack/widgets/radio_variants.py +271 -0
  439. bootstack/widgets/radiogroup.py +228 -0
  440. bootstack/widgets/scrollbar.py +64 -0
  441. bootstack/widgets/scrollview.py +186 -0
  442. bootstack/widgets/select.py +302 -0
  443. bootstack/widgets/selectbutton.py +182 -0
  444. bootstack/widgets/sidebar_toggle.py +130 -0
  445. bootstack/widgets/sizegrip.py +42 -0
  446. bootstack/widgets/slider.py +408 -0
  447. bootstack/widgets/spinbox.py +147 -0
  448. bootstack/widgets/spinnerfield.py +413 -0
  449. bootstack/widgets/splash.py +367 -0
  450. bootstack/widgets/splitview.py +482 -0
  451. bootstack/widgets/stacks.py +249 -0
  452. bootstack/widgets/statusbar.py +189 -0
  453. bootstack/widgets/tabs.py +425 -0
  454. bootstack/widgets/textarea.py +459 -0
  455. bootstack/widgets/textfield.py +410 -0
  456. bootstack/widgets/theme_toggle.py +92 -0
  457. bootstack/widgets/timefield.py +340 -0
  458. bootstack/widgets/toast.py +314 -0
  459. bootstack/widgets/togglegroup.py +231 -0
  460. bootstack/widgets/toolbar.py +347 -0
  461. bootstack/widgets/tooltip.py +94 -0
  462. bootstack/widgets/tree.py +648 -0
  463. bootstack/widgets/types.py +305 -0
  464. bootstack/widgets/window.py +307 -0
  465. bootstack-0.1.0.dist-info/METADATA +301 -0
  466. bootstack-0.1.0.dist-info/RECORD +471 -0
  467. bootstack-0.1.0.dist-info/WHEEL +5 -0
  468. bootstack-0.1.0.dist-info/entry_points.txt +2 -0
  469. bootstack-0.1.0.dist-info/licenses/LICENSE +21 -0
  470. bootstack-0.1.0.dist-info/licenses/NOTICE +10 -0
  471. bootstack-0.1.0.dist-info/top_level.txt +1 -0
bootstack/__init__.py ADDED
@@ -0,0 +1,157 @@
1
+ """bootstack — a Python desktop UI framework.
2
+
3
+ Build modern desktop apps with a clean, Pythonic API. No Tkinter knowledge required.
4
+
5
+ Example:
6
+ ```python
7
+ import bootstack as bs
8
+
9
+ with bs.App(title="Hello") as app:
10
+ bs.Label("Hello, world!")
11
+ app.run()
12
+ ```
13
+
14
+ The top-level `bootstack` namespace holds what you *compose a UI* with: every
15
+ widget, `App`/`AppShell`/`Window`, `Signal`, the dialog verbs
16
+ (`alert`/`confirm`/`ask_*`/`toast`), and `set_theme`/`toggle_theme`.
17
+ Framework primitives you reference *by type to configure behavior* live in
18
+ submodules — for example::
19
+
20
+ from bootstack.data import SqliteDataSource, col
21
+ from bootstack.i18n import L, LV
22
+ from bootstack.validation import ValidationRule
23
+ from bootstack.style import Theme, get_theme_color
24
+ from bootstack.events import Event, Subscription
25
+ from bootstack.images import Image, get_icon, AppIcon
26
+ from bootstack.types import AccentToken
27
+
28
+ See the "API overview" in the documentation for the full map.
29
+ """
30
+ try:
31
+ from importlib.metadata import version as _pkg_version
32
+ __version__ = _pkg_version("bootstack")
33
+ except Exception:
34
+ __version__ = "unknown"
35
+
36
+ # ── Runtime patches — must run before widgets are created ─────────────────────
37
+ from bootstack._runtime.tk_patch import install_tk_autostyle as _install_autostyle
38
+ from bootstack._runtime.events import install_enhanced_events as _install_events
39
+ from bootstack._runtime.visual_focus import install_visual_focus as _install_focus
40
+
41
+ _install_autostyle()
42
+ _install_events()
43
+ _install_focus()
44
+
45
+ # ── Reactive state ────────────────────────────────────────────────────────────
46
+ from bootstack.signals import Signal
47
+
48
+ # ── Theme switching (full theming API lives in `bootstack.style`) ─────────────
49
+ from bootstack.style import set_theme, toggle_theme
50
+
51
+ # ── Dialog verbs (dialog classes live in `bootstack.dialogs`) ─────────────────
52
+ from bootstack.dialogs import (
53
+ alert, confirm, ask_string, ask_integer, ask_float,
54
+ ask_date, ask_date_range, ask_item,
55
+ ask_color, ask_font, ask_filter,
56
+ ask_save_file, ask_open_file, ask_open_files, ask_directory,
57
+ )
58
+
59
+ # ── Application & windows ─────────────────────────────────────────────────────
60
+ from bootstack.widgets.app import App
61
+ from bootstack.widgets.appshell import AppShell, Workbench
62
+ from bootstack.widgets.window import Window
63
+ from bootstack.widgets.splash import Splash
64
+
65
+ # ── Public widget layer ───────────────────────────────────────────────────────
66
+ from bootstack.widgets.stacks import Row, Column, Spacer
67
+ from bootstack.widgets.grid import Grid
68
+ from bootstack.widgets.boolean_controls import Checkbox, Switch, ToggleButton
69
+ from bootstack.widgets.theme_toggle import ThemeToggle
70
+ from bootstack.widgets.button import Button
71
+ from bootstack.widgets.card import Card
72
+ from bootstack.widgets.buttongroup import ButtonGroup
73
+ from bootstack.widgets.codeeditor import CodeEditor
74
+ from bootstack.widgets.contextmenu import ContextMenu, ContextMenuItem
75
+ from bootstack.widgets.datefield import DateField
76
+ from bootstack.widgets.expander import Accordion, AccordionSection
77
+ from bootstack.widgets.gauge import Gauge
78
+ from bootstack.widgets.groupbox import GroupBox
79
+ from bootstack.widgets.label import Badge, Label
80
+ from bootstack.widgets.listview import ListView
81
+ from bootstack.widgets.menubutton import MenuButton
82
+ from bootstack.widgets.numberfield import NumberField
83
+ from bootstack.widgets.pagestack import PageStack, StackPage
84
+ from bootstack.widgets.pathfield import PathField
85
+ from bootstack.widgets.avatar import Avatar
86
+ from bootstack.widgets.carousel import Carousel
87
+ from bootstack.widgets.chart import Chart
88
+ from bootstack.widgets.gallery import Gallery
89
+ from bootstack.widgets.passwordfield import PasswordField
90
+ from bootstack.widgets.picture import Picture
91
+ from bootstack.widgets.progressbar import ProgressBar
92
+ from bootstack.widgets.radio_variants import Radio, RadioToggleButton
93
+ from bootstack.widgets.radiogroup import RadioGroup
94
+ from bootstack.widgets.scrollview import ScrollView
95
+ from bootstack.widgets.select import Select
96
+ from bootstack.widgets.selectbutton import SelectButton
97
+ from bootstack.widgets.divider import Divider
98
+ from bootstack.widgets.splitview import SplitView, SplitPane
99
+ from bootstack.widgets.slider import RangeSlider, Slider
100
+ from bootstack.widgets.spinnerfield import SpinnerField
101
+ from bootstack.widgets.datatable import DataTable
102
+ from bootstack.widgets.tabs import TabPage, Tabs
103
+ from bootstack.widgets.textarea import TextArea
104
+ from bootstack.widgets.timefield import TimeField
105
+ from bootstack.widgets.tree import Tree, TreeNode
106
+ from bootstack.widgets.textfield import TextField
107
+ from bootstack.widgets.toast import toast, Notification, Snackbar, snackbar
108
+ from bootstack.widgets.togglegroup import ToggleGroup
109
+ from bootstack.widgets.toolbar import Toolbar
110
+ from bootstack.widgets.statusbar import StatusBar
111
+ from bootstack.widgets.tooltip import Tooltip
112
+
113
+ from bootstack.widgets.calendar import Calendar
114
+ from bootstack.widgets.form import Form
115
+ from bootstack.widgets.form import FormItem, FieldItem, GroupItem, TabsItem, TabItem
116
+
117
+
118
+ # ── Public API surface ────────────────────────────────────────────────────────
119
+ # The curated top-level namespace: things you compose a UI with. Framework
120
+ # primitives (data, i18n, validation, events, streams, scheduling, shortcuts,
121
+ # style, errors, store, types) live in their own submodules — see the docs'
122
+ # "API overview". This list is kept in sync with tests/test_public_surface.py.
123
+ __all__ = [
124
+ "__version__",
125
+ # Reactive state
126
+ "Signal",
127
+ # Theme switching
128
+ "set_theme", "toggle_theme",
129
+ # Dialog verbs
130
+ "alert", "confirm", "ask_string", "ask_integer", "ask_float", "ask_date",
131
+ "ask_date_range", "ask_item", "ask_color", "ask_font", "ask_filter",
132
+ "ask_save_file", "ask_open_file", "ask_open_files", "ask_directory",
133
+ # Application & windows
134
+ "App", "AppShell", "Workbench", "Window", "Splash",
135
+ # Layout
136
+ "Row", "Column", "Spacer", "Grid", "Card", "GroupBox", "Divider", "ScrollView",
137
+ "SplitView", "SplitPane", "Accordion", "AccordionSection",
138
+ # Actions
139
+ "Button", "ButtonGroup", "ThemeToggle", "MenuButton", "Toolbar", "StatusBar",
140
+ "ContextMenu", "ContextMenuItem",
141
+ # Inputs
142
+ "TextField", "PasswordField", "NumberField", "PathField", "SpinnerField",
143
+ "TextArea", "CodeEditor", "DateField", "TimeField", "Slider", "RangeSlider",
144
+ # Selection
145
+ "Checkbox", "Switch", "ToggleButton", "ToggleGroup", "Radio",
146
+ "RadioToggleButton", "RadioGroup", "Select", "SelectButton", "Calendar",
147
+ # Data display
148
+ "Label", "Badge", "ProgressBar", "Gauge", "ListView", "DataTable", "Tree", "TreeNode",
149
+ # Media
150
+ "Picture", "Gallery", "Carousel", "Avatar", "Chart",
151
+ # Navigation
152
+ "PageStack", "StackPage", "Tabs", "TabPage",
153
+ # Overlays
154
+ "Tooltip", "toast", "Notification", "Snackbar", "snackbar",
155
+ # Forms
156
+ "Form", "FormItem", "FieldItem", "GroupItem", "TabsItem", "TabItem",
157
+ ]
bootstack/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ """CLI entry point — invoked as `python -m bootstack` to launch the bootstack CLI."""
2
+ from bootstack.cli import main
3
+
4
+ if __name__ == "__main__":
5
+ main()
@@ -0,0 +1,21 @@
1
+ """Core utilities and error types."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from . import colorutils, publisher, capabilities
6
+ from bootstack._core.exceptions import (
7
+ ThemeError,
8
+ NavigationError,
9
+ StyleBuilderError,
10
+ ConfigurationWarning,
11
+ )
12
+
13
+ __all__ = [
14
+ "colorutils",
15
+ "publisher",
16
+ "capabilities",
17
+ "ThemeError",
18
+ "NavigationError",
19
+ "StyleBuilderError",
20
+ "ConfigurationWarning",
21
+ ]
@@ -0,0 +1,45 @@
1
+ """Core widget capabilities for bootstack.
2
+
3
+ This package provides framework services that can be used by widget mixins
4
+ and other parts of the library. Each capability module contains reusable
5
+ logic that mixins delegate to, keeping the mixins themselves as thin glue.
6
+
7
+ Capabilities:
8
+ signals: Signal/Variable binding and normalization
9
+ localization: Text translation and value formatting
10
+ """
11
+
12
+ from bootstack._core.capabilities.signals import (
13
+ SignalBinding,
14
+ is_signal,
15
+ is_variable,
16
+ normalize_signal,
17
+ create_signal,
18
+ infer_default_value_for_widget,
19
+ query_binding,
20
+ )
21
+
22
+ from bootstack._core.capabilities.localization import (
23
+ resolve_text,
24
+ resolve_variable_text,
25
+ apply_spec,
26
+ get_current_locale,
27
+ create_formatted_signal,
28
+ )
29
+
30
+ __all__ = [
31
+ # Signals capability
32
+ "SignalBinding",
33
+ "is_signal",
34
+ "is_variable",
35
+ "normalize_signal",
36
+ "create_signal",
37
+ "infer_default_value_for_widget",
38
+ "query_binding",
39
+ # Localization capability
40
+ "resolve_text",
41
+ "resolve_variable_text",
42
+ "apply_spec",
43
+ "get_current_locale",
44
+ "create_formatted_signal",
45
+ ]
@@ -0,0 +1,103 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable
4
+
5
+
6
+ class AfterMixin:
7
+ """Scheduling helpers (after).
8
+
9
+ Tk’s `after` family lets you schedule callbacks to run later on the Tk event loop.
10
+
11
+ Common uses:
12
+ - Debounce user input (schedule a callback and cancel previous ones).
13
+ - Run periodic UI updates (schedule, then reschedule from inside the callback).
14
+ - Defer work until the UI is idle (`after_idle`) so layout/paint can complete.
15
+
16
+ Notes:
17
+ - Callbacks run on the Tk thread/event loop. If you have long-running work,
18
+ run it off-thread/process and schedule UI updates back onto Tk using `after`.
19
+ - `after` returns an identifier that can be canceled with `after_cancel`.
20
+ """
21
+
22
+ def after(self, ms: int, func: Callable[..., Any] | None = None, *args: Any) -> str:
23
+ """Schedule a callback to run after a delay.
24
+
25
+ Args:
26
+ ms: Delay in milliseconds.
27
+ func: Callback to run. If omitted/None, Tk blocks for `ms` milliseconds
28
+ while still processing events (use sparingly).
29
+ *args: Arguments to pass to `func` when it is called.
30
+
31
+ Returns:
32
+ An identifier that can be used with `after_cancel`.
33
+ """
34
+ return super().after(ms, func, *args) # type: ignore[misc]
35
+
36
+ def after_idle(self, func: Callable[..., Any], *args: Any) -> str:
37
+ """Schedule a callback to run when the event loop is idle.
38
+
39
+ Idle callbacks run after Tk has finished processing the current batch of
40
+ events and pending UI work.
41
+
42
+ Args:
43
+ func: Callback to run.
44
+ *args: Arguments to pass to `func` when it is called.
45
+
46
+ Returns:
47
+ An identifier that can be used with `after_cancel`.
48
+ """
49
+ return super().after_idle(func, *args) # type: ignore[misc]
50
+
51
+ def after_cancel(self, id: str) -> None:
52
+ """Cancel a scheduled callback.
53
+
54
+ Args:
55
+ id: The identifier returned by `after` or `after_idle`.
56
+ """
57
+ return super().after_cancel(id) # type: ignore[misc]
58
+
59
+ # -------------------------------------------------------------------------
60
+ # Convenience helpers (optional)
61
+ # -------------------------------------------------------------------------
62
+
63
+ def after_repeat(self, ms: int, func: Callable[..., Any], *args: Any) -> Callable[[], None]:
64
+ """Call `func` repeatedly every `ms` milliseconds.
65
+
66
+ This helper schedules `func` and then automatically reschedules it after
67
+ each run. It returns a `cancel()` function you can call to stop repetition.
68
+
69
+ Args:
70
+ ms: Interval in milliseconds.
71
+ func: Callback to run each interval.
72
+ *args: Arguments to pass to `func`.
73
+
74
+ Returns:
75
+ A `cancel()` callable. Call it to stop the repeating schedule.
76
+
77
+ Examples:
78
+ >>> cancel = widget.after_repeat(250, tick)
79
+ >>> cancel()
80
+ """
81
+ cancelled = False
82
+ token: str | None = None
83
+
84
+ def _run():
85
+ nonlocal token
86
+ if cancelled:
87
+ return
88
+ func(*args)
89
+ token = self.after(ms, _run)
90
+
91
+ token = self.after(ms, _run)
92
+
93
+ def cancel() -> None:
94
+ nonlocal cancelled, token
95
+ cancelled = True
96
+ if token is not None:
97
+ try:
98
+ self.after_cancel(token)
99
+ except Exception:
100
+ pass
101
+ token = None
102
+
103
+ return cancel
@@ -0,0 +1,192 @@
1
+ """Event binding capabilities mixin for bootstack widgets."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any, Callable, TYPE_CHECKING
5
+
6
+ from typing_extensions import TypedDict
7
+
8
+ if TYPE_CHECKING:
9
+ from typing_extensions import Unpack
10
+
11
+
12
+ class EventGenerateKwargs(TypedDict, total=False):
13
+ """Keyword options for `event_generate` (Tk event field overrides).
14
+
15
+ All fields are optional. Only supply fields relevant to the event type
16
+ being synthesized (e.g., `x`/`y` for mouse events, `keysym` for key events).
17
+ """
18
+ x: int
19
+ """Widget-relative x-coordinate in pixels."""
20
+ y: int
21
+ """Widget-relative y-coordinate in pixels."""
22
+ rootx: int
23
+ """Screen (root) x-coordinate in pixels."""
24
+ rooty: int
25
+ """Screen (root) y-coordinate in pixels."""
26
+ state: int
27
+ """Modifier key bitmask (Shift, Ctrl, Alt, etc.)."""
28
+ time: int
29
+ """Event timestamp in milliseconds."""
30
+ keycode: int
31
+ """Key code for keyboard events."""
32
+ keysym: str
33
+ """Key symbol name for keyboard events (e.g., `'Return'`, `'Escape'`, `'a'`)."""
34
+ button: int
35
+ """Mouse button number — 1=left, 2=middle, 3=right."""
36
+ delta: int
37
+ """Scroll wheel delta (positive = up, negative = down)."""
38
+ width: int
39
+ """Width value for Configure events."""
40
+ height: int
41
+ """Height value for Configure events."""
42
+ when: str
43
+ """When to deliver the event — `'now'`, `'tail'`, `'mark'`, or `'head'`. Defaults to `'tail'`."""
44
+
45
+
46
+ class BindingsMixin:
47
+ """Event binding and virtual event generation.
48
+
49
+ This mixin documents the *Tkinter-style* binding API (`bind`, `unbind`,
50
+ `bind_all`, etc.) while reflecting bootstack v2's enhanced event system.
51
+
52
+ Differences from stock Tkinter:
53
+ - Virtual events generated via `event_generate("<<Name>>", data=...)` may
54
+ carry **arbitrary Python objects** as event payload.
55
+ - Event handlers receive an event object with a consistent `.data` attribute:
56
+ - `.data` is the Python object you passed for virtual events.
57
+ - `.data` is `None` for non-virtual events.
58
+
59
+ Notes:
60
+ - Prefer `bind` over `bind_all` unless you truly need a global binding.
61
+ - Return the string `"break"` from a handler to stop further processing.
62
+ - Virtual event data is intended for application-local messaging.
63
+ """
64
+
65
+ # ---------------------------------------------------------------------
66
+ # Binding (widget, class, and application/global)
67
+ # ---------------------------------------------------------------------
68
+
69
+ def bind(
70
+ self,
71
+ sequence: str | None = None,
72
+ func: Callable[..., Any] | None = None,
73
+ add: bool | str | None = None,
74
+ ) -> str | None:
75
+ """Bind an event sequence to a handler.
76
+
77
+ Args:
78
+ sequence: Event pattern string (e.g. `"<Button-1>"`, `"<KeyPress>"`, `"<<MyEvent>>"`).
79
+ If None, returns a string describing all bindings on this widget.
80
+ func: Handler callable. The handler is called with a single argument:
81
+ the event object. For bootstack enhanced events, `event.data`
82
+ is always present (None for regular events, payload for virtual events).
83
+ add: If true/`"+"` then this binding is added in addition to existing bindings.
84
+ If false/None then any existing binding for this sequence is replaced.
85
+
86
+ Returns:
87
+ If `func` is provided, returns an internal Tk binding id that can be used
88
+ with `unbind(sequence, funcid)`. If `func` is None, returns a Tcl binding
89
+ script string (Tkinter behavior varies by version) or None.
90
+
91
+ Examples:
92
+ Bind a regular event:
93
+
94
+ widget.bind("<Button-1>", on_click)
95
+
96
+ Bind a virtual event that carries Python data:
97
+
98
+ widget.bind("<<Save>>", on_save)
99
+ widget.event_generate("<<Save>>", data={"path": "doc.txt"})
100
+ """
101
+ return super().bind(sequence, func, add) # type: ignore[misc]
102
+
103
+ def unbind(self, sequence: str, funcid: str | None = None) -> None:
104
+ """Remove a binding for an event sequence.
105
+
106
+ Args:
107
+ sequence: The event sequence that was previously bound.
108
+ funcid: The binding id returned from `bind`. If omitted, removes all
109
+ handlers for the given sequence on this widget.
110
+ """
111
+ return super().unbind(sequence, funcid) # type: ignore[misc]
112
+
113
+ def bind_all(
114
+ self,
115
+ sequence: str | None = None,
116
+ func: Callable[..., Any] | None = None,
117
+ add: bool | str | None = None,
118
+ ) -> str | None:
119
+ """Bind an event sequence at the application level (all widgets).
120
+
121
+ Use sparingly. This affects *every* widget in the application.
122
+
123
+ Args:
124
+ sequence: Event pattern string.
125
+ func: Handler callable.
126
+ add: Whether to add alongside existing bindings.
127
+
128
+ Returns:
129
+ A binding id when setting a binding, otherwise a binding script string
130
+ (version-dependent) or None.
131
+ """
132
+ return super().bind_all(sequence, func, add) # type: ignore[misc]
133
+
134
+ def unbind_all(self, sequence: str) -> None:
135
+ """Remove an application-level binding for the given sequence.
136
+
137
+ Args:
138
+ sequence: The event sequence to unbind.
139
+ """
140
+ return super().unbind_all(sequence) # type: ignore[misc]
141
+
142
+ def bind_class(
143
+ self,
144
+ className: str,
145
+ sequence: str | None = None,
146
+ func: Callable[..., Any] | None = None,
147
+ add: bool | str | None = None,
148
+ ) -> str | None:
149
+ """Bind an event sequence to a Tk widget class.
150
+
151
+ This attaches a handler to *all widgets of a given Tk class name*
152
+ (e.g. `"TButton"`, `"TEntry"`).
153
+
154
+ Args:
155
+ className: Tk class name.
156
+ sequence: Event pattern string.
157
+ func: Handler callable.
158
+ add: Whether to add alongside existing bindings.
159
+
160
+ Returns:
161
+ A binding id when setting a binding, otherwise a binding script string
162
+ (version-dependent) or None.
163
+ """
164
+ return super().bind_class(className, sequence, func, add) # type: ignore[misc]
165
+
166
+ def unbind_class(self, className: str, sequence: str) -> None:
167
+ """Remove a class-level binding.
168
+
169
+ Args:
170
+ className: Tk class name.
171
+ sequence: Event sequence to unbind for that class.
172
+ """
173
+ return super().unbind_class(className, sequence) # type: ignore[misc]
174
+
175
+ # ---------------------------------------------------------------------
176
+ # Event generation (including virtual-event payloads)
177
+ # ---------------------------------------------------------------------
178
+
179
+ def event_generate(self, sequence: str, data: Any | None = None, **kw: Unpack[EventGenerateKwargs]) -> None:
180
+ """Generate an event.
181
+
182
+ Synthesizes both physical events (e.g. `"<Button-1>"`) and virtual events
183
+ (e.g. `"<<MyEvent>>"`). For virtual events, bootstack supports attaching
184
+ a Python payload via `data`.
185
+
186
+ Args:
187
+ sequence: Event sequence to generate (commonly `"<<Name>>"` for virtual events).
188
+ data: Optional Python object payload for virtual events. Handlers receive
189
+ an event whose `.data` is this value. Ignored for non-virtual events.
190
+ **kw: See `EventGenerateKwargs` for Tk event field overrides (x, y, state, etc.).
191
+ """
192
+ return super().event_generate(sequence, data=data, **kw) # type: ignore[misc]
@@ -0,0 +1,112 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Sequence
4
+
5
+
6
+ class BindtagsMixin:
7
+ """Bindtags helpers (bindtags).
8
+
9
+ Bindtags control **the order in which Tk processes bindings** for an event.
10
+
11
+ Every widget has a list of bindtags. When an event occurs on a widget, Tk
12
+ processes bindings in tag order. Each tag may have bindings associated with it.
13
+
14
+ Typical default bindtags for a widget look like:
15
+
16
+ (widget_pathname, widget_class, toplevel_pathname, "all")
17
+
18
+ Practical uses:
19
+ - Insert a custom tag (e.g. "MyApp") to apply shared behaviors across widgets.
20
+ - Reorder tags to change precedence (e.g. run class bindings before widget bindings).
21
+ - Remove a tag to disable a layer of default behavior (use with care).
22
+
23
+ Notes:
24
+ - Bindtags affect event dispatch only; they do not change focus or grab behavior.
25
+ - Misordering tags can break default widget behaviors (Tab traversal, selection,
26
+ text editing, etc.), so keep changes minimal and well-scoped.
27
+ """
28
+
29
+ def bindtags(self, tags: Sequence[str] | None = None) -> tuple[str, ...]:
30
+ """Get or set the bindtags for this widget.
31
+
32
+ Args:
33
+ tags: The bindtags to set. If None, returns the current bindtags.
34
+ Tags are processed in order when dispatching events.
35
+
36
+ Returns:
37
+ The current bindtags as a tuple.
38
+ """
39
+ # Tkinter's `bindtags()` returns a tuple and accepts a sequence for setting.
40
+ if tags is None:
41
+ return super().bindtags() # type: ignore[misc]
42
+ return super().bindtags(tags) # type: ignore[misc]
43
+
44
+ # -------------------------------------------------------------------------
45
+ # Convenience helpers (optional)
46
+ # -------------------------------------------------------------------------
47
+
48
+ def bindtags_prepend(self, tag: str) -> tuple[str, ...]:
49
+ """Prepend a tag to the bindtags list.
50
+
51
+ This increases the tag's priority (it will be processed earlier).
52
+
53
+ Args:
54
+ tag: Tag name to prepend.
55
+
56
+ Returns:
57
+ The updated bindtags tuple.
58
+ """
59
+ current = list(self.bindtags())
60
+ if tag not in current:
61
+ current.insert(0, tag)
62
+ self.bindtags(current)
63
+ return tuple(current)
64
+
65
+ def bindtags_append(self, tag: str) -> tuple[str, ...]:
66
+ """Append a tag to the bindtags list.
67
+
68
+ This decreases the tag's priority (it will be processed later).
69
+
70
+ Args:
71
+ tag: Tag name to append.
72
+
73
+ Returns:
74
+ The updated bindtags tuple.
75
+ """
76
+ current = list(self.bindtags())
77
+ if tag not in current:
78
+ current.append(tag)
79
+ self.bindtags(current)
80
+ return tuple(current)
81
+
82
+ def bindtags_remove(self, tag: str) -> tuple[str, ...]:
83
+ """Remove a tag from the bindtags list.
84
+
85
+ Args:
86
+ tag: Tag name to remove.
87
+
88
+ Returns:
89
+ The updated bindtags tuple.
90
+ """
91
+ current = [t for t in self.bindtags() if t != tag]
92
+ self.bindtags(current)
93
+ return tuple(current)
94
+
95
+ def bindtags_replace(self, old: str, new: str) -> tuple[str, ...]:
96
+ """Replace a bindtag with another tag.
97
+
98
+ Args:
99
+ old: Existing tag name.
100
+ new: Replacement tag name.
101
+
102
+ Returns:
103
+ The updated bindtags tuple.
104
+ """
105
+ current = list(self.bindtags())
106
+ try:
107
+ idx = current.index(old)
108
+ except ValueError:
109
+ return tuple(current)
110
+ current[idx] = new
111
+ self.bindtags(current)
112
+ return tuple(current)