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,448 @@
1
+ """Field widget module.
2
+
3
+ Provides a flexible generic entry field composite widget used as the foundation
4
+ for creating specialized entry widgets like TextEntry, PasswordEntry, NumberEntry, etc.
5
+ """
6
+
7
+ from tkinter import TclError, Variable
8
+ from typing import Any, Callable, Literal, Type, TypedDict, Union, cast
9
+
10
+ from bootstack.core.signals import Signal
11
+ from bootstack.widgets.primitives.button import Button
12
+ from bootstack.widgets.primitives.frame import Frame
13
+ from bootstack.widgets.primitives.label import Label
14
+ from bootstack.widgets.primitives.checkbutton import CheckButton
15
+ from bootstack.widgets.mixins import configure_delegate
16
+ from bootstack.widgets.mixins.entry_mixin import EntryMixin
17
+ from bootstack.widgets.parts.numberentry_part import NumberEntryPart
18
+ from bootstack.widgets.parts.textentry_part import TextEntryPart
19
+ from bootstack.widgets.parts.spinnerentry_part import SpinnerEntryPart
20
+ from bootstack.widgets.types import Master
21
+
22
+ FieldKind = Literal['text', 'numeric', 'spinbox']
23
+ """Type alias for field kind specification.
24
+
25
+ Determines which entry part widget to use:
26
+ - 'text': Uses TextEntryPart for text input with formatting support
27
+ - 'numeric': Uses NumberEntryPart for numeric input with bounds and stepping
28
+ - 'spinbox': Uses SpinnerEntryPart for spinner input (supports text or numeric values)
29
+ """
30
+
31
+
32
+ class FieldOptions(TypedDict, total=False):
33
+ """Type hints for Field widget configuration options.
34
+
35
+ Attributes:
36
+ allow_blank: If True, empty input is allowed. If False, empty input preserves previous value.
37
+ accent: Accent token for the focus ring and active border of the input.
38
+ density: Widget density. 'default' for normal size, 'compact' for smaller size.
39
+ variant: Style variant (if applicable).
40
+ cursor: Cursor to display when hovering over the widget.
41
+ value_format: ICU format pattern for parsing/formatting (e.g., '$#,##0.00' for currency).
42
+ exportselection: If True, selected text is exported to X selection.
43
+ font: Font to use for text display.
44
+ foreground: Text color.
45
+ initial_focus: If True, widget receives focus when created.
46
+ justify: Text justification ('left', 'center', 'right').
47
+ show_message: If True, displays message text below the field.
48
+ padding: Padding around the entry widget.
49
+ show: Character to display instead of typed characters (for password fields).
50
+ state: The widget state. One of 'normal', 'disabled', or 'readonly'.
51
+ takefocus: If True, widget can receive focus via Tab key.
52
+ textvariable: Tkinter Variable to link with the entry text.
53
+ textsignal: Signal object for reactive text updates.
54
+ width: Width of the entry in characters.
55
+ required: If True, field cannot be empty (adds validation rule).
56
+ xscrollcommand: Callback for horizontal scrolling.
57
+ localize: Determines the field label localization mode. 'auto', True, False.
58
+ """
59
+ allow_blank: bool
60
+ accent: str
61
+ density: Literal['default', 'compact']
62
+ variant: str
63
+ cursor: str
64
+ value_format: str
65
+ exportselection: bool
66
+ font: str
67
+ foreground: str
68
+ initial_focus: bool
69
+ justify: str
70
+ show_message: bool
71
+ padding: str
72
+ show: str
73
+ state: Literal['normal', 'disabled', 'readonly']
74
+ takefocus: bool
75
+ textvariable: Variable
76
+ textsignal: Signal
77
+ width: int
78
+ required: bool
79
+ xscrollcommand: Callable[[int, int], None]
80
+ localize: bool | Literal['auto']
81
+
82
+
83
+ class Field(EntryMixin, Frame):
84
+ """A flexible generic composite entry field widget.
85
+
86
+ Field is a base composite widget that combines a label, entry input, and
87
+ message area into a complete input field component. It serves as the foundation
88
+ for creating specialized entry widgets like TextEntry, PasswordEntry, NumberEntry,
89
+ and other custom entry types.
90
+
91
+ The widget automatically handles layout, focus states, validation feedback, and
92
+ provides a consistent API for all entry-based components. It supports both text
93
+ and numeric input types through the `kind` parameter.
94
+
95
+ !!! note "Events"
96
+
97
+ - `<<Input>>`: Triggered on each keystroke.
98
+ Provides `event.data` with keys: `text`.
99
+
100
+ - `<<Change>>`: Triggered when value changes after commit.
101
+ Provides `event.data` with keys: `value`, `prev_value`, `text`.
102
+
103
+ - `<<Valid>>`: Triggered when validation passes.
104
+ Provides `event.data` with keys: `value`, `is_valid` (True), `message`.
105
+
106
+ - `<<Invalid>>`: Triggered when validation fails.
107
+ Provides `event.data` with keys: `value`, `is_valid` (False), `message`.
108
+
109
+ - `<<Validate>>`: Triggered after any validation.
110
+ Provides `event.data` with keys: `value`, `is_valid` (bool), `message`.
111
+
112
+ Attributes:
113
+ variable (Variable): Tkinter Variable linked to entry text.
114
+ signal (Signal): Signal object for reactive updates.
115
+ """
116
+
117
+ def __init__(
118
+ self,
119
+ master: Master = None,
120
+ *,
121
+ value: str | int | float = None,
122
+ label: str = None,
123
+ message: str = None,
124
+ show_message: bool = False,
125
+ required: bool = False,
126
+ kind: FieldKind = "text",
127
+ **kwargs: Any
128
+ ):
129
+ """Initialize a Field widget.
130
+
131
+ Creates a composite entry field with optional label, message area, and
132
+ validation support. The field type is determined by the 'kind' parameter,
133
+ which selects either TextEntryPart or NumberEntryPart as the underlying
134
+ entry widget.
135
+
136
+ Args:
137
+ master: Parent widget. If None, uses the default root window.
138
+ value: Initial value to display. Can be str, int, or float depending
139
+ on the field kind. For 'text' kind, should be a string. For
140
+ 'numeric' kind, can be int or float. Default is None.
141
+ label: Optional label text to display above the entry field.
142
+ If required=True, an asterisk (*) is automatically appended to
143
+ indicate the field is mandatory.
144
+ message: Optional message text to display below the entry field.
145
+ Used for hints, instructions, or help text. This text is replaced
146
+ by validation error messages when validation fails, and restored
147
+ when validation passes. Default is None (no message).
148
+ show_message: If True, displays the message area below the field.
149
+ If False, hides the message area entirely (validation errors
150
+ won't be shown). Default is True.
151
+ required: If True, marks the field as required and automatically adds
152
+ a 'required' validation rule. An asterisk (*) is appended to the
153
+ label. The field cannot be left empty. Default is False.
154
+ kind: Type of entry field to create. Either 'text' for text input
155
+ (uses TextEntryPart) or 'numeric' for numeric input (uses
156
+ NumberEntryPart). Default is 'text'.
157
+
158
+ Other Parameters:
159
+ value_format (str): ICU format pattern for parsing/formatting.
160
+ allow_blank (bool): Allow empty input.
161
+ locale (str): Locale for formatting (e.g., 'en_US').
162
+ initial_focus (bool): Focus on creation.
163
+ show (str): Character to mask input (e.g., '*' for passwords).
164
+ width (int): Width in characters.
165
+ font (str): Font specification.
166
+ justify (str): Text alignment ('left', 'center', 'right').
167
+ minvalue (int | float): Minimum allowed value (numeric kind only).
168
+ maxvalue (int | float): Maximum allowed value (numeric kind only).
169
+ increment (int | float): Step size for up/down arrows (numeric kind only).
170
+ wrap (bool): Wrap around at boundaries (numeric kind only).
171
+ """
172
+ # Accept legacy parameter name and prevent it from reaching the Tk widget.
173
+ if 'show_messages' in kwargs:
174
+ show_message = kwargs.pop('show_messages')
175
+ # Track if user explicitly provided show_message
176
+ show_message_explicit = 'show_message' in kwargs
177
+ show_message = kwargs.pop('show_message', show_message)
178
+
179
+ # Auto-enable show_message if message is provided and user didn't explicitly disable it
180
+ if message and not show_message_explicit:
181
+ show_message = True
182
+
183
+ accent = kwargs.pop('accent', None)
184
+ self._density = kwargs.pop('density', 'default')
185
+ self._localize = cast(bool | Literal['auto'], kwargs.pop('localize', 'auto'))
186
+
187
+ # Field itself (outer Frame) doesn't need styling - only pass master
188
+ super().__init__(master)
189
+
190
+ # Set accent AFTER super().__init__ to avoid being overwritten by wrapper
191
+ self._accent = accent
192
+
193
+ # configuration
194
+ self._message_text = message
195
+ self._show_messages = show_message
196
+ self._addons: dict[str, Button | Label | CheckButton] = {}
197
+ self._required = required
198
+ self._kind = kind
199
+ self._label_text = label
200
+ self._value = value
201
+
202
+ self._entry: TextEntryPart | NumberEntryPart | SpinnerEntryPart
203
+ self._addons: dict[str, Union[Button, Label, CheckButton]] = {}
204
+
205
+ # layout
206
+ label_text = self._label_text or ''
207
+ self._label_lbl = Label(
208
+ self,
209
+ localize=self._localize,
210
+ text=f"{label_text}*" if required else label_text,
211
+ font="label[normal]"
212
+ )
213
+ self._message_lbl = Label(self, localize=self._localize, text=message or '', font="caption", accent="secondary")
214
+
215
+ # field container & field - pass density for styling via style_options
216
+ field_padding = 4 if self._density == 'compact' else 5
217
+ self._field = Frame(self, accent=self._accent, padding=field_padding, ttk_class="TField", style_options={'density': self._density})
218
+
219
+ if kind == "numeric":
220
+ self._entry = NumberEntryPart(self._field, value=value, density=self._density, **kwargs)
221
+ elif kind == "spinbox":
222
+ self._entry = SpinnerEntryPart(self._field, value=value, density=self._density, **kwargs)
223
+ else:
224
+ self._entry = TextEntryPart(self._field, value=value, density=self._density, **kwargs)
225
+
226
+ # attach widgets
227
+ if label:
228
+ self._label_lbl.pack(side='top', fill='x', padx=(4, 0))
229
+
230
+ self._field.pack(side='top', fill='x', expand=True)
231
+ self._entry.pack(side='left', fill='x', expand=True, padx=(0, 6) if kind == "spinbox" else 0, pady=0)
232
+
233
+ self._entry.bind('<<StateChanged>>', self._sync_addon_state, add=True)
234
+ self._sync_addon_state()
235
+
236
+ if self._show_messages:
237
+ self._message_lbl.pack(side='top', fill='x', padx=4)
238
+
239
+ self._entry.bind('<<Invalid>>', self._show_error, add=True)
240
+ self._entry.bind('<<Valid>>', self._clear_error, add=True)
241
+
242
+ # bind focus styling to the field frame
243
+ self._entry.bind('<FocusIn>', lambda _: self._field.state(['focus']), add=True)
244
+ self._entry.bind('<FocusOut>', lambda _: self._field.state(['!focus']), add=True)
245
+
246
+ # add required validation
247
+ if required:
248
+ self._entry.add_validation_rule("required")
249
+
250
+ # forward reference entry methods
251
+ self.on_input = self._entry.on_input
252
+ self.off_input = self._entry.off_input
253
+ self.on_changed = self._entry.on_changed
254
+ self.off_changed = self._entry.off_changed
255
+ self.on_enter = self._entry.on_enter
256
+ self.off_enter = self._entry.off_enter
257
+ self.on_invalid = self._entry.on_invalid
258
+ self.off_invalid = self._entry.off_invalid
259
+ self.on_valid = self._entry.on_valid
260
+ self.off_valid = self._entry.off_valid
261
+ self.on_validated = self._entry.on_validated
262
+ self.off_validated = self._entry.off_validated
263
+
264
+ # entry state
265
+ self.variable = self._entry.textvariable
266
+ self.signal = self._entry.textsignal
267
+
268
+ # enty validation
269
+ self.add_validation_rule = self._entry.add_validation_rule
270
+ self.add_validation_rules = self._entry.add_validation_rules
271
+ self.validation = self._entry.validate
272
+
273
+ # Copy Field's delegate handlers to entry for configuration forwarding
274
+ for key, method_name in self._configure_delegate_map.items():
275
+ if hasattr(self, method_name):
276
+ # Attach the Field's handler method to the entry instance
277
+ setattr(self._entry, method_name, getattr(self, method_name))
278
+ # Add to entry's delegate map
279
+ self._entry._configure_delegate_map[key] = method_name
280
+
281
+ # Forward configuration methods to entry widget
282
+ self.configure = self._entry.configure
283
+ self.config = self._entry.config
284
+ self.cget = self._entry.cget
285
+ self.__getitem__ = self._entry.__getitem__
286
+ self.__setitem__ = self._entry.__setitem__
287
+
288
+ @property
289
+ def value(self):
290
+ """Get or set the parsed value via the underlying entry widget."""
291
+ return self._entry.value()
292
+
293
+ @value.setter
294
+ def value(self, value):
295
+ self._entry.value(value)
296
+
297
+ def get(self):
298
+ """Return the raw text from the underlying entry widget."""
299
+ return self._entry.get()
300
+
301
+ @property
302
+ def entry_widget(self) -> NumberEntryPart | TextEntryPart:
303
+ """Get the underlying entry widget."""
304
+ return self._entry
305
+
306
+ @property
307
+ def label_widget(self):
308
+ """Get the label widget."""
309
+ return self._label_lbl
310
+
311
+ @property
312
+ def message_widget(self):
313
+ """Get the message widget."""
314
+ return self._message_lbl
315
+
316
+ @property
317
+ def addons(self):
318
+ """Get the dictionary of inserted addon widgets"""
319
+ return self._addons
320
+
321
+ @configure_delegate
322
+ def _config_accent(self, value=None):
323
+ if value is None:
324
+ return self._accent
325
+ else:
326
+ self._accent = value
327
+ self._field['accent'] = value
328
+ return None
329
+
330
+
331
+ def disable(self):
332
+ """Disable the field, preventing user input."""
333
+ self._entry.state(['disabled !readonly'])
334
+ self._field.state(['disabled'])
335
+ self._set_addons_state(True)
336
+
337
+ def enable(self):
338
+ """Enable the field, allowing user input."""
339
+ self._entry.state(['!disabled !readonly'])
340
+ self._field.state(['!disabled'])
341
+ self._set_addons_state(False)
342
+
343
+ def readonly(self, value: bool = None):
344
+ """Set or toggle the readonly state of the field."""
345
+ if value == False:
346
+ self._field.state(['disabled'])
347
+ self._entry.state(['readonly'])
348
+ elif value:
349
+ self._field.state(['!disabled'])
350
+ self._entry.state(['readonly'])
351
+ else:
352
+ self._entry.state(['readonly !disabled'])
353
+ self._field.state(['disabled'])
354
+ self._sync_addon_state()
355
+
356
+ def insert_addon(
357
+ self,
358
+ widget: Type[Union[Button, Label, CheckButton]],
359
+ position: Literal['before', 'after'],
360
+ name: str | None = None,
361
+ pack_options: dict[str, Any] = None,
362
+ **kwargs: Any
363
+ ):
364
+ """Insert a widget addon before or after the entry input.
365
+
366
+ Addons are Button, Label, or Checkbutton widgets positioned inside the field container,
367
+ either before (left of) or after (right of) the entry input. Common use
368
+ cases include search buttons, icons, clear buttons, or status indicators.
369
+
370
+ The addon widget automatically:
371
+ - Inherits the field's disabled state
372
+ - Participates in focus state styling (highlights field on addon focus)
373
+ - Is stored in the addons dictionary for later reference
374
+
375
+ Args:
376
+ widget: Widget class to instantiate. Must be Button, Label, or Checkbutton.
377
+ position: Position relative to the entry input:
378
+ - 'before': Insert to the left of the entry (prefix)
379
+ - 'after': Insert to the right of the entry (suffix)
380
+ name: Optional name for the addon. If provided, the addon can be
381
+ retrieved from the addons dictionary using this name. If None,
382
+ the widget's string representation is used as the key.
383
+ pack_options: Optional dictionary of additional pack() options to
384
+ apply when placing the addon widget. Common options include
385
+ padx, pady, etc. The side and after/before options are set
386
+ automatically based on position.
387
+ **kwargs (Any): Additional keyword arguments passed to the widget constructor.
388
+ For Button: text, command, icon, bootstyle, etc.
389
+ For Label: text, icon, image, bootstyle, etc.
390
+ Note: bootstyle and takefocus are set automatically but can be
391
+ overridden.
392
+ """
393
+ variant = "suffix" if position == "after" else "prefix"
394
+ kwargs.setdefault('ttk_class', 'TField')
395
+ kwargs.setdefault('variant', variant)
396
+ kwargs.setdefault('takefocus', False)
397
+ kwargs.setdefault('density', self._density)
398
+
399
+ if widget in (Button, CheckButton):
400
+ icon_only = kwargs.get('icon_only', False)
401
+ if 'style_options' in kwargs:
402
+ kwargs['style_options'].update(use_active_states=True, density=self._density, icon_only=icon_only)
403
+ else:
404
+ kwargs['style_options'] = dict(use_active_states=True, density=self._density, icon_only=icon_only)
405
+ instance = widget(master=self._field, **kwargs)
406
+ key = name or str(instance)
407
+ self._addons[key] = instance
408
+
409
+ # configure layout
410
+ options = pack_options or {}
411
+ if position == "after":
412
+ options.update(side="right", after=self._entry)
413
+ else:
414
+ options.update(side="left", before=self._entry)
415
+ instance.pack(**options)
416
+
417
+ # match parent disabled state
418
+ self._sync_addon_state()
419
+
420
+ # bind focus events to field frame
421
+ instance.bind('<FocusIn>', lambda _: self._field.state(['focus']), add=True)
422
+ instance.bind('<FocusOut>', lambda _: self._field.state(['!focus']), add=True)
423
+
424
+ def _show_error(self, event: Any) -> None:
425
+ """Display a validation error message below the input field."""
426
+ self._message_lbl['text'] = event.data['message']
427
+ self._message_lbl['accent'] = "danger"
428
+ self._message_lbl.pack(side='top', after=self._field, padx=4)
429
+
430
+ def _clear_error(self, _: Any) -> None:
431
+ """Clear the error message and restore the original message text."""
432
+ self._message_lbl['text'] = self._message_text
433
+ self._message_lbl['accent'] = "secondary"
434
+
435
+ def _set_addons_state(self, disabled: bool) -> None:
436
+ """Configure addon widgets based on whether the entry is interactive."""
437
+ state_value = 'disabled' if disabled else '!disabled'
438
+ for item in self._addons.values():
439
+ try:
440
+ item.configure(state=state_value)
441
+ except TclError:
442
+ pass
443
+
444
+ def _sync_addon_state(self, event: Any = None) -> None:
445
+ """Ensure addons match the entry's interactivity state."""
446
+ entry_states = self._entry.state()
447
+ disabled = 'disabled' in entry_states or 'readonly' in entry_states
448
+ self._set_addons_state(disabled)