bootstack 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. bootstack/__init__.py +249 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/api/__init__.py +127 -0
  4. bootstack/api/app.py +30 -0
  5. bootstack/api/constants.py +3 -0
  6. bootstack/api/data.py +23 -0
  7. bootstack/api/dialogs.py +44 -0
  8. bootstack/api/i18n.py +17 -0
  9. bootstack/api/localization.py +16 -0
  10. bootstack/api/menu.py +7 -0
  11. bootstack/api/style.py +23 -0
  12. bootstack/api/utils.py +24 -0
  13. bootstack/api/widgets.py +137 -0
  14. bootstack/assets/__init__.py +24 -0
  15. bootstack/assets/bootstack-transparent.png +0 -0
  16. bootstack/assets/bootstack.ico +0 -0
  17. bootstack/assets/bootstack.png +0 -0
  18. bootstack/assets/elements/__init__.py +0 -0
  19. bootstack/assets/elements/badge-pill.png +0 -0
  20. bootstack/assets/elements/badge-square.png +0 -0
  21. bootstack/assets/elements/border.png +0 -0
  22. bootstack/assets/elements/button-compact.png +0 -0
  23. bootstack/assets/elements/button-default.png +0 -0
  24. bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
  25. bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
  26. bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
  27. bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
  28. bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
  29. bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
  30. bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
  31. bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
  32. bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
  33. bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
  34. bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
  35. bootstack/assets/elements/button-group-vertical-center-default.png +0 -0
  36. bootstack/assets/elements/checkbox-checked.png +0 -0
  37. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  38. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  39. bootstack/assets/elements/field.png +0 -0
  40. bootstack/assets/elements/input-after-compact.png +0 -0
  41. bootstack/assets/elements/input-after-default.png +0 -0
  42. bootstack/assets/elements/input-before-compact.png +0 -0
  43. bootstack/assets/elements/input-before-default.png +0 -0
  44. bootstack/assets/elements/input-compact.png +0 -0
  45. bootstack/assets/elements/input-default.png +0 -0
  46. bootstack/assets/elements/list-item-separated.png +0 -0
  47. bootstack/assets/elements/list-item.png +0 -0
  48. bootstack/assets/elements/manifest.toml +480 -0
  49. bootstack/assets/elements/menu-item.png +0 -0
  50. bootstack/assets/elements/nav-button-compact.png +0 -0
  51. bootstack/assets/elements/nav-button-default.png +0 -0
  52. bootstack/assets/elements/nav-icon-button-compact.png +0 -0
  53. bootstack/assets/elements/nav-icon-button-default.png +0 -0
  54. bootstack/assets/elements/notebook-client-border.png +0 -0
  55. bootstack/assets/elements/notebook-tab-active.png +0 -0
  56. bootstack/assets/elements/notebook-tab-bar.png +0 -0
  57. bootstack/assets/elements/notebook-tab-normal.png +0 -0
  58. bootstack/assets/elements/notebook-tab-pill.png +0 -0
  59. bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
  60. bootstack/assets/elements/progress-bar-solid.png +0 -0
  61. bootstack/assets/elements/progress-bar-thin.png +0 -0
  62. bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
  63. bootstack/assets/elements/radio-selected.png +0 -0
  64. bootstack/assets/elements/radio-unselected.png +0 -0
  65. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  66. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  67. bootstack/assets/elements/slider-handle-focus.png +0 -0
  68. bootstack/assets/elements/slider-handle.png +0 -0
  69. bootstack/assets/elements/slider-track-horizontal.png +0 -0
  70. bootstack/assets/elements/slider-track-vertical.png +0 -0
  71. bootstack/assets/elements/switch-off.png +0 -0
  72. bootstack/assets/elements/switch-on.png +0 -0
  73. bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
  74. bootstack/assets/elements/tabs-bar-vertical.png +0 -0
  75. bootstack/assets/elements/tabs-pill.png +0 -0
  76. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  77. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
  78. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
  79. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  80. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
  81. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  82. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
  83. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  84. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
  85. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  86. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
  87. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  88. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
  89. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  90. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
  91. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  92. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
  93. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  94. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
  95. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  96. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
  97. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  98. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
  99. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  100. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
  101. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  102. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
  103. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  104. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
  105. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  106. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
  107. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  108. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
  109. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  110. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
  111. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  112. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
  113. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  114. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
  115. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  116. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
  117. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  118. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
  119. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  120. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
  121. bootstack/assets/themes/__init__.py +0 -0
  122. bootstack/assets/themes/amber-dark.json +32 -0
  123. bootstack/assets/themes/amber-light.json +32 -0
  124. bootstack/assets/themes/aurora-dark.json +32 -0
  125. bootstack/assets/themes/aurora-light.json +32 -0
  126. bootstack/assets/themes/bootstrap-dark.json +32 -0
  127. bootstack/assets/themes/bootstrap-light.json +32 -0
  128. bootstack/assets/themes/classic-dark.json +32 -0
  129. bootstack/assets/themes/classic-light.json +32 -0
  130. bootstack/assets/themes/docs-dark.json +32 -0
  131. bootstack/assets/themes/docs-light.json +32 -0
  132. bootstack/assets/themes/forest-dark.json +32 -0
  133. bootstack/assets/themes/forest-light.json +32 -0
  134. bootstack/assets/themes/ocean-dark.json +32 -0
  135. bootstack/assets/themes/ocean-light.json +32 -0
  136. bootstack/assets/themes/rose-dark.json +32 -0
  137. bootstack/assets/themes/rose-light.json +32 -0
  138. bootstack/assets/widgets/__init__.py +0 -0
  139. bootstack/assets/widgets/badge-default.png +0 -0
  140. bootstack/assets/widgets/badge-pill.png +0 -0
  141. bootstack/assets/widgets/border.png +0 -0
  142. bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
  143. bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
  144. bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
  145. bootstack/assets/widgets/button-group-vertical-after.png +0 -0
  146. bootstack/assets/widgets/button-group-vertical-before.png +0 -0
  147. bootstack/assets/widgets/button-group-vertical-center.png +0 -0
  148. bootstack/assets/widgets/button.png +0 -0
  149. bootstack/assets/widgets/checkbox-checked.png +0 -0
  150. bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
  151. bootstack/assets/widgets/checkbox-unchecked.png +0 -0
  152. bootstack/assets/widgets/field.png +0 -0
  153. bootstack/assets/widgets/icon-button.png +0 -0
  154. bootstack/assets/widgets/input-inner.png +0 -0
  155. bootstack/assets/widgets/input-prefix.png +0 -0
  156. bootstack/assets/widgets/input-suffix.png +0 -0
  157. bootstack/assets/widgets/input.png +0 -0
  158. bootstack/assets/widgets/list-item-focus.png +0 -0
  159. bootstack/assets/widgets/list-item-separated.png +0 -0
  160. bootstack/assets/widgets/menu-item-separated.png +0 -0
  161. bootstack/assets/widgets/notebook-client-border.png +0 -0
  162. bootstack/assets/widgets/notebook-pill-active.png +0 -0
  163. bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
  164. bootstack/assets/widgets/notebook-tab-active.png +0 -0
  165. bootstack/assets/widgets/notebook-tab-border.png +0 -0
  166. bootstack/assets/widgets/notebook-tab-normal.png +0 -0
  167. bootstack/assets/widgets/notebook-underline.png +0 -0
  168. bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
  169. bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
  170. bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
  171. bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
  172. bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
  173. bootstack/assets/widgets/progress-trough-vertical.png +0 -0
  174. bootstack/assets/widgets/radio-selected.png +0 -0
  175. bootstack/assets/widgets/radio-unselected.png +0 -0
  176. bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
  177. bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
  178. bootstack/assets/widgets/separator-horizontal.png +0 -0
  179. bootstack/assets/widgets/separator-vertical.png +0 -0
  180. bootstack/assets/widgets/slider-handle-focus.png +0 -0
  181. bootstack/assets/widgets/slider-handle.png +0 -0
  182. bootstack/assets/widgets/slider-track-horizontal.png +0 -0
  183. bootstack/assets/widgets/slider-track-vertical.png +0 -0
  184. bootstack/assets/widgets/switch-off.png +0 -0
  185. bootstack/assets/widgets/switch-on.png +0 -0
  186. bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
  187. bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
  188. bootstack/assets/widgets/tabs-pill.png +0 -0
  189. bootstack/cli/__init__.py +124 -0
  190. bootstack/cli/__main__.py +6 -0
  191. bootstack/cli/add.py +439 -0
  192. bootstack/cli/build.py +115 -0
  193. bootstack/cli/config.py +287 -0
  194. bootstack/cli/demo.py +1267 -0
  195. bootstack/cli/doctor.py +195 -0
  196. bootstack/cli/list_cmd.py +71 -0
  197. bootstack/cli/promote.py +120 -0
  198. bootstack/cli/pyinstaller.py +246 -0
  199. bootstack/cli/run.py +99 -0
  200. bootstack/cli/start.py +105 -0
  201. bootstack/cli/templates/__init__.py +861 -0
  202. bootstack/constants.py +325 -0
  203. bootstack/core/__init__.py +34 -0
  204. bootstack/core/capabilities/__init__.py +45 -0
  205. bootstack/core/capabilities/after.py +103 -0
  206. bootstack/core/capabilities/bind.py +154 -0
  207. bootstack/core/capabilities/bindtags.py +112 -0
  208. bootstack/core/capabilities/busy.py +61 -0
  209. bootstack/core/capabilities/clipboard.py +88 -0
  210. bootstack/core/capabilities/focus.py +118 -0
  211. bootstack/core/capabilities/grab.py +65 -0
  212. bootstack/core/capabilities/grid.py +188 -0
  213. bootstack/core/capabilities/localization.py +231 -0
  214. bootstack/core/capabilities/pack.py +119 -0
  215. bootstack/core/capabilities/place.py +92 -0
  216. bootstack/core/capabilities/selection.py +136 -0
  217. bootstack/core/capabilities/signals.py +242 -0
  218. bootstack/core/capabilities/winfo.py +315 -0
  219. bootstack/core/colorutils.py +234 -0
  220. bootstack/core/exceptions.py +95 -0
  221. bootstack/core/images.py +283 -0
  222. bootstack/core/localization/README.md +90 -0
  223. bootstack/core/localization/__init__.py +13 -0
  224. bootstack/core/localization/intl_format.py +580 -0
  225. bootstack/core/localization/msgcat.py +425 -0
  226. bootstack/core/localization/specs.py +143 -0
  227. bootstack/core/mixins/__init__.py +1 -0
  228. bootstack/core/mixins/ttk_state.py +35 -0
  229. bootstack/core/mixins/widget.py +132 -0
  230. bootstack/core/publisher.py +147 -0
  231. bootstack/core/signals/README.md +112 -0
  232. bootstack/core/signals/__init__.py +8 -0
  233. bootstack/core/signals/integration.py +100 -0
  234. bootstack/core/signals/signal.py +317 -0
  235. bootstack/core/signals/types.py +4 -0
  236. bootstack/core/validation/__init__.py +5 -0
  237. bootstack/core/validation/types.py +13 -0
  238. bootstack/core/validation/validation_result.py +17 -0
  239. bootstack/core/validation/validation_rules.py +112 -0
  240. bootstack/core/variables.py +62 -0
  241. bootstack/datasource/README.md +607 -0
  242. bootstack/datasource/__init__.py +51 -0
  243. bootstack/datasource/base.py +474 -0
  244. bootstack/datasource/file_source.py +541 -0
  245. bootstack/datasource/memory_source.py +482 -0
  246. bootstack/datasource/sqlite_source.py +453 -0
  247. bootstack/datasource/types.py +259 -0
  248. bootstack/dialogs/__init__.py +56 -0
  249. bootstack/dialogs/colorchooser.py +674 -0
  250. bootstack/dialogs/colordropper.py +257 -0
  251. bootstack/dialogs/datedialog.py +404 -0
  252. bootstack/dialogs/dialog.py +514 -0
  253. bootstack/dialogs/filterdialog.py +358 -0
  254. bootstack/dialogs/fontdialog.py +339 -0
  255. bootstack/dialogs/formdialog.py +541 -0
  256. bootstack/dialogs/message.py +489 -0
  257. bootstack/dialogs/query.py +561 -0
  258. bootstack/py.typed +1 -0
  259. bootstack/runtime/__init__.py +3 -0
  260. bootstack/runtime/app.py +879 -0
  261. bootstack/runtime/base_window.py +786 -0
  262. bootstack/runtime/events.py +399 -0
  263. bootstack/runtime/menu.py +510 -0
  264. bootstack/runtime/shortcuts.py +423 -0
  265. bootstack/runtime/tk_patch.py +31 -0
  266. bootstack/runtime/toplevel.py +131 -0
  267. bootstack/runtime/utility.py +371 -0
  268. bootstack/runtime/visual_focus.py +228 -0
  269. bootstack/runtime/window_utilities.py +1043 -0
  270. bootstack/style/__init__.py +5498 -0
  271. bootstack/style/bootstyle.py +507 -0
  272. bootstack/style/bootstyle_builder_base.py +752 -0
  273. bootstack/style/bootstyle_builder_mixed.py +93 -0
  274. bootstack/style/bootstyle_builder_tk.py +109 -0
  275. bootstack/style/bootstyle_builder_ttk.py +354 -0
  276. bootstack/style/builders/__init__.py +51 -0
  277. bootstack/style/builders/badge.py +44 -0
  278. bootstack/style/builders/button.py +453 -0
  279. bootstack/style/builders/buttongroup.py +344 -0
  280. bootstack/style/builders/calendar.py +271 -0
  281. bootstack/style/builders/checkbutton.py +95 -0
  282. bootstack/style/builders/combobox.py +112 -0
  283. bootstack/style/builders/contextmenu.py +268 -0
  284. bootstack/style/builders/entry.py +83 -0
  285. bootstack/style/builders/expander.py +171 -0
  286. bootstack/style/builders/field.py +312 -0
  287. bootstack/style/builders/frame.py +27 -0
  288. bootstack/style/builders/label.py +28 -0
  289. bootstack/style/builders/labelframe.py +41 -0
  290. bootstack/style/builders/listview.py +267 -0
  291. bootstack/style/builders/menubar.py +74 -0
  292. bootstack/style/builders/menubutton.py +408 -0
  293. bootstack/style/builders/notebook.py +316 -0
  294. bootstack/style/builders/panedwindow.py +25 -0
  295. bootstack/style/builders/progressbar.py +71 -0
  296. bootstack/style/builders/radiobutton.py +68 -0
  297. bootstack/style/builders/scale.py +66 -0
  298. bootstack/style/builders/scrollbar.py +360 -0
  299. bootstack/style/builders/separator.py +45 -0
  300. bootstack/style/builders/sidenav.py +313 -0
  301. bootstack/style/builders/sizegrip.py +15 -0
  302. bootstack/style/builders/spinbox.py +119 -0
  303. bootstack/style/builders/switch.py +67 -0
  304. bootstack/style/builders/tabitem.py +205 -0
  305. bootstack/style/builders/toolbutton.py +260 -0
  306. bootstack/style/builders/tooltip.py +26 -0
  307. bootstack/style/builders/treeview.py +269 -0
  308. bootstack/style/builders/utils.py +404 -0
  309. bootstack/style/builders_tk/__init__.py +16 -0
  310. bootstack/style/builders_tk/defaults.py +229 -0
  311. bootstack/style/element.py +173 -0
  312. bootstack/style/style.py +499 -0
  313. bootstack/style/theme_provider.py +449 -0
  314. bootstack/style/tk_patch.py +5 -0
  315. bootstack/style/token_maps.py +42 -0
  316. bootstack/style/types.py +32 -0
  317. bootstack/style/typography.py +527 -0
  318. bootstack/style/utility.py +696 -0
  319. bootstack/themes/__init__.py +12 -0
  320. bootstack/themes/standard.py +415 -0
  321. bootstack/themes/user.py +45 -0
  322. bootstack/widgets/__init__.py +53 -0
  323. bootstack/widgets/composites/__init__.py +38 -0
  324. bootstack/widgets/composites/accordion.py +385 -0
  325. bootstack/widgets/composites/appshell.py +445 -0
  326. bootstack/widgets/composites/buttongroup.py +391 -0
  327. bootstack/widgets/composites/calendar.py +914 -0
  328. bootstack/widgets/composites/compositeframe.py +282 -0
  329. bootstack/widgets/composites/contextmenu.py +1754 -0
  330. bootstack/widgets/composites/dateentry.py +261 -0
  331. bootstack/widgets/composites/dropdownbutton.py +190 -0
  332. bootstack/widgets/composites/expander.py +508 -0
  333. bootstack/widgets/composites/field.py +448 -0
  334. bootstack/widgets/composites/floodgauge.py +434 -0
  335. bootstack/widgets/composites/form.py +983 -0
  336. bootstack/widgets/composites/labeledscale.py +209 -0
  337. bootstack/widgets/composites/list/__init__.py +15 -0
  338. bootstack/widgets/composites/list/listitem.py +733 -0
  339. bootstack/widgets/composites/list/listview.py +1507 -0
  340. bootstack/widgets/composites/menubar.py +303 -0
  341. bootstack/widgets/composites/meter.py +882 -0
  342. bootstack/widgets/composites/numericentry.py +183 -0
  343. bootstack/widgets/composites/pagestack.py +330 -0
  344. bootstack/widgets/composites/passwordentry.py +149 -0
  345. bootstack/widgets/composites/pathentry.py +223 -0
  346. bootstack/widgets/composites/radiogroup.py +466 -0
  347. bootstack/widgets/composites/scrolledtext.py +388 -0
  348. bootstack/widgets/composites/scrolledtext.pyi +186 -0
  349. bootstack/widgets/composites/scrollview.py +675 -0
  350. bootstack/widgets/composites/selectbox.py +544 -0
  351. bootstack/widgets/composites/sidenav/__init__.py +24 -0
  352. bootstack/widgets/composites/sidenav/group.py +485 -0
  353. bootstack/widgets/composites/sidenav/header.py +83 -0
  354. bootstack/widgets/composites/sidenav/item.py +413 -0
  355. bootstack/widgets/composites/sidenav/separator.py +51 -0
  356. bootstack/widgets/composites/sidenav/view.py +919 -0
  357. bootstack/widgets/composites/spinnerentry.py +232 -0
  358. bootstack/widgets/composites/tableview/__init__.py +5 -0
  359. bootstack/widgets/composites/tableview/tableview.py +2254 -0
  360. bootstack/widgets/composites/tableview/types.py +169 -0
  361. bootstack/widgets/composites/tabs/__init__.py +6 -0
  362. bootstack/widgets/composites/tabs/tabitem.py +372 -0
  363. bootstack/widgets/composites/tabs/tabs.py +478 -0
  364. bootstack/widgets/composites/tabs/tabview.py +352 -0
  365. bootstack/widgets/composites/textentry.py +90 -0
  366. bootstack/widgets/composites/timeentry.py +189 -0
  367. bootstack/widgets/composites/toast.py +364 -0
  368. bootstack/widgets/composites/togglegroup.py +382 -0
  369. bootstack/widgets/composites/toolbar.py +393 -0
  370. bootstack/widgets/composites/tooltip.py +404 -0
  371. bootstack/widgets/internal/__init__.py +0 -0
  372. bootstack/widgets/internal/wrapper_base.py +304 -0
  373. bootstack/widgets/mixins/__init__.py +25 -0
  374. bootstack/widgets/mixins/configure_mixin.py +186 -0
  375. bootstack/widgets/mixins/entry_mixin.py +70 -0
  376. bootstack/widgets/mixins/font_mixin.py +346 -0
  377. bootstack/widgets/mixins/icon_mixin.py +38 -0
  378. bootstack/widgets/mixins/localization_mixin.py +255 -0
  379. bootstack/widgets/mixins/signal_mixin.py +272 -0
  380. bootstack/widgets/mixins/validation_mixin.py +204 -0
  381. bootstack/widgets/parts/__init__.py +11 -0
  382. bootstack/widgets/parts/numberentry_part.py +345 -0
  383. bootstack/widgets/parts/spinnerentry_part.py +394 -0
  384. bootstack/widgets/parts/textentry_part.py +344 -0
  385. bootstack/widgets/primitives/__init__.py +55 -0
  386. bootstack/widgets/primitives/badge.py +44 -0
  387. bootstack/widgets/primitives/button.py +89 -0
  388. bootstack/widgets/primitives/card.py +66 -0
  389. bootstack/widgets/primitives/checkbutton.py +124 -0
  390. bootstack/widgets/primitives/checktoggle.py +53 -0
  391. bootstack/widgets/primitives/combobox.py +165 -0
  392. bootstack/widgets/primitives/entry.py +98 -0
  393. bootstack/widgets/primitives/frame.py +206 -0
  394. bootstack/widgets/primitives/gridframe.py +479 -0
  395. bootstack/widgets/primitives/label.py +95 -0
  396. bootstack/widgets/primitives/labelframe.py +63 -0
  397. bootstack/widgets/primitives/menubutton.py +118 -0
  398. bootstack/widgets/primitives/notebook.py +551 -0
  399. bootstack/widgets/primitives/optionmenu.py +248 -0
  400. bootstack/widgets/primitives/packframe.py +228 -0
  401. bootstack/widgets/primitives/panedwindow.py +58 -0
  402. bootstack/widgets/primitives/progressbar.py +95 -0
  403. bootstack/widgets/primitives/radiobutton.py +115 -0
  404. bootstack/widgets/primitives/radiotoggle.py +50 -0
  405. bootstack/widgets/primitives/scale.py +85 -0
  406. bootstack/widgets/primitives/scrollbar.py +56 -0
  407. bootstack/widgets/primitives/separator.py +56 -0
  408. bootstack/widgets/primitives/sizegrip.py +47 -0
  409. bootstack/widgets/primitives/spinbox.py +91 -0
  410. bootstack/widgets/primitives/switch.py +41 -0
  411. bootstack/widgets/primitives/treeview.py +77 -0
  412. bootstack/widgets/types.py +20 -0
  413. bootstack-0.1.0a1.dist-info/METADATA +196 -0
  414. bootstack-0.1.0a1.dist-info/RECORD +419 -0
  415. bootstack-0.1.0a1.dist-info/WHEEL +5 -0
  416. bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
  417. bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
  418. bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
  419. bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,272 @@
1
+ """Signal integration mixins for bootstack widgets.
2
+
3
+ Provides seamless integration between tkinter Variables and reactive Signals,
4
+ exposing both as properties on widgets that support `textvariable` and `variable`
5
+ options. The mixins maintain bidirectional synchronization between Variables and
6
+ Signals automatically.
7
+
8
+ These mixins are thin glue layers that delegate to the core signal capability
9
+ module for normalization and binding logic.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import tkinter as tk
15
+ from typing import Any, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ from bootstack.core.signals import Signal
19
+
20
+ from bootstack.core.capabilities.signals import (
21
+ is_signal,
22
+ is_variable,
23
+ normalize_signal,
24
+ create_signal,
25
+ infer_default_value_for_widget,
26
+ query_binding,
27
+ )
28
+ from bootstack.widgets.mixins.configure_mixin import configure_delegate
29
+
30
+
31
+ class TextSignalMixin:
32
+ """Mixin providing `.textvariable` and `.textsignal` properties for text-based widgets.
33
+
34
+ For widgets that support the `textvariable` option (Entry, Label, Button, etc.),
35
+ this mixin exposes both the underlying tk.Variable and a reactive Signal as properties,
36
+ maintaining bidirectional synchronization between them.
37
+
38
+ This mixin delegates normalization and binding logic to the core signals capability.
39
+
40
+ Attributes:
41
+ textvariable (Variable): The underlying tk.Variable (usually StringVar).
42
+ textsignal (Signal): The reactive Signal wrapper with subscribe/map capabilities.
43
+ """
44
+
45
+ def __init__(self, *args, **kwargs):
46
+ """Initialize mixin and extract textsignal/textvariable parameters before tkinter sees them."""
47
+ # Extract textsignal and textvariable before passing kwargs to tkinter
48
+ textsignal_value = kwargs.pop('textsignal', None)
49
+ textvariable_value = kwargs.pop('textvariable', None)
50
+
51
+ # Call parent __init__
52
+ super().__init__(*args, **kwargs)
53
+
54
+ # Apply textsignal or textvariable after widget construction
55
+ # Prefer textsignal if both are provided
56
+ if textsignal_value is not None:
57
+ self._config_delegate_set('textsignal', textsignal_value)
58
+ elif textvariable_value is not None:
59
+ self._config_delegate_set('textvariable', textvariable_value)
60
+
61
+ @configure_delegate("textvariable", "textsignal")
62
+ def _delegate_textsignal(self, value: Any = None):
63
+ """Handle textvariable and textsignal configuration.
64
+
65
+ Args:
66
+ value: Signal, tk.Variable, or None for query.
67
+
68
+ Returns:
69
+ Current value for query path, None for set path.
70
+ """
71
+ # Query path - return stored value
72
+ if value is None:
73
+ return query_binding(
74
+ getattr(self, '_textsignal', None),
75
+ getattr(self, '_textvariable', None),
76
+ self._ttk_base, # type: ignore[misc]
77
+ self,
78
+ 'textvariable',
79
+ )
80
+
81
+ # Set path - normalize and apply
82
+ binding = normalize_signal(value, default_value="")
83
+ if binding is not None:
84
+ self._textsignal = binding.signal
85
+ self._textvariable = binding.variable
86
+ var_to_set = binding.tk_value
87
+ else:
88
+ # String (Tcl variable name) or other - pass through
89
+ var_to_set = value
90
+ if value:
91
+ self._textvariable = value
92
+
93
+ # Apply via base ttk widget to avoid recursion
94
+ return self._ttk_base.configure(self, textvariable=var_to_set) # type: ignore[misc]
95
+
96
+ @property
97
+ def textsignal(self) -> 'Signal[str]':
98
+ """Get or lazily create the textsignal.
99
+
100
+ If no textvariable has been set, creates a new Signal with empty string.
101
+ If textvariable exists, wraps it in a Signal.
102
+
103
+ Returns:
104
+ The reactive Signal for this widget's text.
105
+ """
106
+ if not hasattr(self, '_textsignal'):
107
+ # Create fresh signal
108
+ binding = create_signal("")
109
+ self._textsignal = binding.signal
110
+ self._textvariable = binding.variable
111
+ try:
112
+ self._ttk_base.configure(self, textvariable=binding.tk_value) # type: ignore[misc]
113
+ except Exception:
114
+ pass
115
+ return self._textsignal
116
+
117
+ @textsignal.setter
118
+ def textsignal(self, value: 'Signal[str]') -> None:
119
+ """Set the textsignal, extracting and configuring its underlying variable.
120
+
121
+ Args:
122
+ value: Signal to use for this widget's text.
123
+ """
124
+ self._delegate_textsignal(value)
125
+
126
+ @property
127
+ def textvariable(self) -> tk.Variable:
128
+ """Get the underlying tk.Variable.
129
+
130
+ If not yet created, accessing this property will trigger lazy creation
131
+ via the textsignal property.
132
+
133
+ Returns:
134
+ The tk.Variable (usually StringVar) for this widget's text.
135
+ """
136
+ if not hasattr(self, '_textvariable'):
137
+ # Trigger lazy creation via textsignal
138
+ _ = self.textsignal
139
+ return self._textvariable
140
+
141
+ @textvariable.setter
142
+ def textvariable(self, value: tk.Variable) -> None:
143
+ """Set the textvariable, creating a synced Signal automatically.
144
+
145
+ Args:
146
+ value: tk.Variable to use for this widget's text.
147
+ """
148
+ self._delegate_textsignal(value)
149
+
150
+
151
+ class SignalMixin:
152
+ """Mixin providing `.variable` and `.signal` properties for value-based widgets.
153
+
154
+ For widgets that support the `variable` option (Checkbutton, Radiobutton, Scale, etc.),
155
+ this mixin exposes both the underlying tk.Variable and a reactive Signal as properties,
156
+ maintaining bidirectional synchronization between them.
157
+
158
+ This mixin delegates normalization and binding logic to the core signals capability.
159
+
160
+ Attributes:
161
+ variable (Variable): The underlying tk.Variable (IntVar, DoubleVar, BooleanVar, etc.).
162
+ signal (Signal): The reactive Signal wrapper with subscribe/map capabilities.
163
+ """
164
+
165
+ def __init__(self, *args, **kwargs):
166
+ """Initialize mixin and extract signal/variable parameters before tkinter sees them."""
167
+ # Extract signal and variable before passing kwargs to tkinter
168
+ signal_value = kwargs.pop('signal', None)
169
+ variable_value = kwargs.pop('variable', None)
170
+
171
+ # Call parent __init__
172
+ super().__init__(*args, **kwargs)
173
+
174
+ # Apply signal or variable after widget construction
175
+ # Prefer signal if both are provided
176
+ if signal_value is not None:
177
+ self._config_delegate_set('signal', signal_value)
178
+ elif variable_value is not None:
179
+ self._config_delegate_set('variable', variable_value)
180
+
181
+ @configure_delegate("variable", "signal")
182
+ def _delegate_signal(self, value: Any = None):
183
+ """Handle variable and signal configuration.
184
+
185
+ Args:
186
+ value: Signal, tk.Variable, or None for query.
187
+
188
+ Returns:
189
+ Current value for query path, None for set path.
190
+ """
191
+ # Query path - return stored value
192
+ if value is None:
193
+ return query_binding(
194
+ getattr(self, '_signal', None),
195
+ getattr(self, '_variable', None),
196
+ self._ttk_base, # type: ignore[misc]
197
+ self,
198
+ 'variable',
199
+ )
200
+
201
+ # Set path - normalize and apply
202
+ binding = normalize_signal(value)
203
+ if binding is not None:
204
+ self._signal = binding.signal
205
+ self._variable = binding.variable
206
+ var_to_set = binding.tk_value
207
+ else:
208
+ # String (Tcl variable name) or other - pass through
209
+ var_to_set = value
210
+ if value:
211
+ self._variable = value
212
+
213
+ # Apply via base ttk widget to avoid recursion
214
+ return self._ttk_base.configure(self, variable=var_to_set) # type: ignore[misc]
215
+
216
+ @property
217
+ def signal(self) -> 'Signal[Any]':
218
+ """Get or lazily create the signal.
219
+
220
+ If no variable has been set, creates a new Signal with appropriate default
221
+ (False for Checkbutton, 0 for Scale, etc.). If variable exists, wraps it in a Signal.
222
+
223
+ Returns:
224
+ The reactive Signal for this widget's value.
225
+ """
226
+ if not hasattr(self, '_signal'):
227
+ # Infer default value based on widget type
228
+ default_value = infer_default_value_for_widget(self.winfo_class())
229
+ binding = create_signal(default_value)
230
+ self._signal = binding.signal
231
+ self._variable = binding.variable
232
+ try:
233
+ self._ttk_base.configure(self, variable=binding.tk_value) # type: ignore[misc]
234
+ except Exception:
235
+ pass
236
+ return self._signal
237
+
238
+ @signal.setter
239
+ def signal(self, value: 'Signal[Any]') -> None:
240
+ """Set the signal, extracting and configuring its underlying variable.
241
+
242
+ Args:
243
+ value: Signal to use for this widget's value.
244
+ """
245
+ self._delegate_signal(value)
246
+
247
+ @property
248
+ def variable(self) -> tk.Variable:
249
+ """Get the underlying tk.Variable.
250
+
251
+ If not yet created, accessing this property will trigger lazy creation
252
+ via the signal property.
253
+
254
+ Returns:
255
+ The tk.Variable (IntVar, BooleanVar, DoubleVar, etc.) for this widget's value.
256
+ """
257
+ if not hasattr(self, '_variable'):
258
+ # Trigger lazy creation via signal
259
+ _ = self.signal
260
+ return self._variable
261
+
262
+ @variable.setter
263
+ def variable(self, value: tk.Variable) -> None:
264
+ """Set the variable, creating a synced Signal automatically.
265
+
266
+ Args:
267
+ value: tk.Variable to use for this widget's value.
268
+ """
269
+ self._delegate_signal(value)
270
+
271
+
272
+ __all__ = ["TextSignalMixin", "SignalMixin"]
@@ -0,0 +1,204 @@
1
+ """Validation mixin for widgets with enhanced event system.
2
+
3
+ This mixin provides validation functionality using the enhanced event system
4
+ that allows passing data directly through virtual events.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from tkinter import TclError
10
+ from tkinter.ttk import Widget
11
+ from typing import Any, Callable, Optional
12
+
13
+ from bootstack.core.validation import ValidationRule
14
+ from bootstack.core.validation.types import RuleTriggerType, RuleType, ValidationOptions
15
+
16
+
17
+ class ValidationMixin(Widget):
18
+ """Pure-Tkinter validation mixin for bound widgets.
19
+
20
+ Provides debounced auto-validation on key/blur with virtual event emission.
21
+ Event data is accessible via `event.data` in handlers.
22
+
23
+ !!! note "Events"
24
+
25
+ - `<<Valid>>`: Fired when validation passes.
26
+ Provides `event.data` with keys: `value`, `is_valid` (True), `message`.
27
+
28
+ - `<<Invalid>>`: Fired when validation fails.
29
+ Provides `event.data` with keys: `value`, `is_valid` (False), `message`.
30
+
31
+ - `<<Validate>>`: Fired after any validation.
32
+ Provides `event.data` with keys: `value`, `is_valid` (bool), `message`.
33
+ """
34
+
35
+ EVENT_VALID = '<<Valid>>'
36
+ EVENT_INVALID = '<<Invalid>>'
37
+ EVENT_VALIDATED = '<<Validate>>'
38
+ SEQ_KEYUP = '<KeyRelease>'
39
+ SEQ_BLUR = '<FocusOut>'
40
+
41
+ def __init__(self, *args, **kwargs):
42
+ """Initialize validation mixin."""
43
+ # Validation rules
44
+ self._rules: list[ValidationRule] = []
45
+
46
+ # Debounce tracking
47
+ self._debounce_ids: dict[str, str] = {}
48
+
49
+ # Optional convenience callbacks
50
+ self._on_invalid_command: Optional[Callable[[dict[str, Any]], None]] = None
51
+ self._on_valid_command: Optional[Callable[[dict[str, Any]], None]] = None
52
+ self._on_validated_command: Optional[Callable[[dict[str, Any]], None]] = None
53
+
54
+ super().__init__(*args, **kwargs) # next in MRO must be a Tk/ttk widget
55
+ self._setup_validation_binds()
56
+
57
+ # ---------------- Public API ----------------
58
+
59
+ def value(self) -> Any:
60
+ """Default value accessor; override for non-Entry widgets.
61
+
62
+ Returns:
63
+ Current widget value
64
+ """
65
+ if hasattr(self, 'get'):
66
+ try:
67
+ return self.get()
68
+ except AttributeError:
69
+ return None
70
+ return None
71
+
72
+ def add_validation_rule(self, rule_type: RuleType, **kwargs: ValidationOptions) -> None:
73
+ """Add a single validation rule.
74
+
75
+ Args:
76
+ rule_type: Type of validation rule (e.g., 'required', 'min_length')
77
+ **kwargs: Rule-specific options (e.g., min_length=5, message='...')
78
+ """
79
+ self._rules.append(ValidationRule(rule_type, **kwargs))
80
+
81
+ def add_validation_rules(self, rules: list[ValidationRule]) -> None:
82
+ """Replace all validation rules.
83
+
84
+ Args:
85
+ rules: List of ValidationRule objects
86
+ """
87
+ self._rules = list(rules)
88
+
89
+ def validate(self, value: Any, trigger: RuleTriggerType = "manual") -> bool:
90
+ """Run validation rules against a value.
91
+
92
+ Emits `<<Valid>>`, `<<Invalid>>`, and `<<Validate>>` events
93
+ with data payload containing validation results.
94
+
95
+ Args:
96
+ value: Value to validate
97
+ trigger: Trigger type ('manual', 'key', 'blur', or 'always')
98
+
99
+ Returns:
100
+ True if validation was performed (regardless of result)
101
+ """
102
+ ran_rule = False
103
+ payload: dict[str, Any] = {"value": value, "is_valid": True, "message": ""}
104
+
105
+ for rule in self._rules:
106
+ if trigger != "manual" and rule.trigger not in ("always", trigger):
107
+ continue
108
+
109
+ ran_rule = True
110
+ result = rule.validate(value)
111
+ payload.update(is_valid=result.is_valid, message=result.message)
112
+
113
+ if not result.is_valid:
114
+ # Emit invalid and validated events with data
115
+ self.event_generate(self.EVENT_INVALID, data=payload)
116
+ self.event_generate(self.EVENT_VALIDATED, data=payload)
117
+ return False
118
+
119
+ if ran_rule:
120
+ # Emit valid and validated events with data
121
+ self.event_generate(self.EVENT_VALID, data=payload)
122
+ self.event_generate(self.EVENT_VALIDATED, data=payload)
123
+
124
+ return ran_rule
125
+
126
+ # Optional: ergonomic callback registration
127
+ def on_invalid(self, func: Callable[[dict[str, Any]], None]) -> None:
128
+ """Register callback for invalid validation."""
129
+ self._on_invalid_command = func
130
+
131
+ def off_invalid(self, bind_id: str | None = None):
132
+ """Remove the callback for the <<Invalid>> event"""
133
+ self.unbind('<<Invalid>>', bind_id)
134
+
135
+ def on_valid(self, func: Callable[[dict[str, Any]], None]) -> None:
136
+ """Register callback for valid validation."""
137
+ self._on_valid_command = func
138
+
139
+ def off_valid(self, bind_id: str | None = None):
140
+ """Remove the callback for the <<Valid>> event"""
141
+ self.unbind('<<Valid>>', bind_id)
142
+
143
+ def on_validated(self, func: Callable[[dict[str, Any]], None]) -> None:
144
+ """Register callback for any validation (valid or invalid)."""
145
+ self._on_validated_command = func
146
+
147
+ def off_validated(self, bind_id: str | None = None):
148
+ """Remove the callback for validated event"""
149
+ self.unbind('<<Validate>>', bind_id)
150
+
151
+ # ---------------- Internals ----------------
152
+
153
+ def _get_validation_value(self) -> Any:
154
+ """Get the current value for validation purposes.
155
+
156
+ For entry widgets, this should return the current text being typed,
157
+ not the committed value. Prefers get() method over value() method.
158
+ """
159
+ if hasattr(self, 'get'):
160
+ try:
161
+ return self.get()
162
+ except (AttributeError, TclError):
163
+ pass
164
+ return self.value()
165
+
166
+ def _setup_validation_binds(self, keyup_delay_ms: int = 50, blur_delay_ms: int = 50) -> None:
167
+ """Set up automatic validation bindings with debouncing."""
168
+ # Auto-validate (debounced)
169
+ self.bind(self.SEQ_KEYUP, lambda e: self._debounced("key", keyup_delay_ms), add=True)
170
+ self.bind(self.SEQ_BLUR, lambda e: self._debounced("blur", blur_delay_ms), add=True)
171
+
172
+ # Wire optional convenience callbacks
173
+ self.bind(self.EVENT_VALIDATED, self._dispatch_validated, add=True)
174
+ self.bind(self.EVENT_VALID, self._dispatch_valid, add=True)
175
+ self.bind(self.EVENT_INVALID, self._dispatch_invalid, add=True)
176
+
177
+ def _debounced(self, trigger: RuleTriggerType, ms: int) -> None:
178
+ """Debounce validation to avoid excessive checks during typing."""
179
+ key = f"debounce:{trigger}"
180
+ aid: Optional[str] = self._debounce_ids.get(key)
181
+ if aid:
182
+ try:
183
+ self.after_cancel(aid)
184
+ except TclError:
185
+ pass
186
+ # defer reading value until the timer fires
187
+ self._debounce_ids[key] = self.after(ms, lambda: self.validate(self._get_validation_value(), trigger))
188
+
189
+ # ----- optional dispatchers for on_* convenience -----
190
+
191
+ def _dispatch_validated(self, event) -> None:
192
+ """Dispatch validated event to registered callback."""
193
+ if self._on_validated_command:
194
+ self._on_validated_command(event.data)
195
+
196
+ def _dispatch_valid(self, event) -> None:
197
+ """Dispatch valid event to registered callback."""
198
+ if self._on_valid_command:
199
+ self._on_valid_command(event.data)
200
+
201
+ def _dispatch_invalid(self, event) -> None:
202
+ """Dispatch invalid event to registered callback."""
203
+ if self._on_invalid_command:
204
+ self._on_invalid_command(event.data)
@@ -0,0 +1,11 @@
1
+ """Widget parts module for composite widgets."""
2
+
3
+ from bootstack.widgets.parts.textentry_part import TextEntryPart
4
+ from bootstack.widgets.parts.numberentry_part import NumberEntryPart
5
+ from bootstack.widgets.parts.spinnerentry_part import SpinnerEntryPart
6
+
7
+ __all__ = [
8
+ 'TextEntryPart',
9
+ 'NumberEntryPart',
10
+ 'SpinnerEntryPart',
11
+ ]