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,527 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import platform
5
+ import re
6
+ from dataclasses import dataclass
7
+ from tkinter import Misc, font as tkfont
8
+ from tkinter.font import Font as TkFont
9
+ from typing import Any, Literal, NamedTuple
10
+
11
+
12
+ # =============================================================================
13
+ # Token model
14
+ # =============================================================================
15
+
16
+ class FontSpec(NamedTuple):
17
+ font: str
18
+ size: int
19
+ weight: Literal["normal", "bold"]
20
+ underline: bool = False
21
+ slant: Literal["roman", "italic"] = "roman"
22
+ overstrike: bool = False
23
+
24
+
25
+ class FontTokenNames:
26
+ # Base families
27
+ caption = "caption"
28
+ label = "label"
29
+ body_sm = "body-sm"
30
+ body = "body"
31
+ body_lg = "body-lg"
32
+ body_xl = "body-xl"
33
+
34
+ heading_sm = "heading-sm"
35
+ heading_md = "heading-md"
36
+ heading_lg = "heading-lg"
37
+ heading_xl = "heading-xl"
38
+
39
+ display_lg = "display-lg"
40
+ display_xl = "display-xl"
41
+
42
+ code = "code"
43
+ hyperlink = "hyperlink"
44
+
45
+
46
+ class FontTokens(NamedTuple):
47
+ caption: FontSpec
48
+ label: FontSpec
49
+ body_sm: FontSpec
50
+ body: FontSpec
51
+ body_lg: FontSpec
52
+ body_xl: FontSpec
53
+
54
+ heading_sm: FontSpec
55
+ heading_md: FontSpec
56
+ heading_lg: FontSpec
57
+ heading_xl: FontSpec
58
+
59
+ display_lg: FontSpec
60
+ display_xl: FontSpec
61
+
62
+ code: FontSpec
63
+ hyperlink: FontSpec
64
+
65
+
66
+ # =============================================================================
67
+ # Defaults
68
+ # =============================================================================
69
+
70
+ def _clamp_base_size(base_size: int) -> int:
71
+ # keep sizes sane; your existing file had a similar constraint
72
+ return max(8, min(int(base_size), 14))
73
+
74
+
75
+ def build_desktop_tokens(
76
+ *,
77
+ family: str | None = None,
78
+ mono_family: str | None = None,
79
+ base_size: int = 11,
80
+ ) -> FontTokens:
81
+ """
82
+ Construct default typography tokens tuned for desktop UI.
83
+ """
84
+ base = _clamp_base_size(base_size)
85
+
86
+ system = platform.system().lower()
87
+ if system == "windows":
88
+ default_ui = "Segoe UI"
89
+ default_mono = "Cascadia Mono"
90
+ elif system == "darwin":
91
+ default_ui = "SF Pro Text"
92
+ default_mono = "SF Mono"
93
+ # Tk's pt-to-pixel conversion uses the active scaling factor.
94
+ # macOS defaults to 1.0 (72 DPI baseline) vs ~1.334 on Win/Linux,
95
+ # so the same point size renders ~25% smaller on Mac. Bump the
96
+ # base to keep visual parity across platforms and align with the
97
+ # macOS HIG default control text size (13pt).
98
+ base = _clamp_base_size(base + 2)
99
+ else:
100
+ default_ui = "DejaVu Sans"
101
+ default_mono = "DejaVu Sans Mono"
102
+
103
+ ui = family or default_ui
104
+ mono = mono_family or default_mono
105
+
106
+ # Scale helpers
107
+ def s(delta: int) -> int:
108
+ return base + delta
109
+
110
+ return FontTokens(
111
+ caption=FontSpec(ui, s(-2), "normal"),
112
+ label=FontSpec(ui, s(-2), "bold"),
113
+ body_sm=FontSpec(ui, s(-1), "normal"),
114
+ body=FontSpec(ui, s(0), "normal"),
115
+ body_lg=FontSpec(ui, s(1), "normal"),
116
+ body_xl=FontSpec(ui, s(2), "normal"),
117
+
118
+ heading_sm=FontSpec(ui, s(-1), "bold"),
119
+ heading_md=FontSpec(ui, s(0), "bold"),
120
+ heading_lg=FontSpec(ui, s(1), "bold"),
121
+ heading_xl=FontSpec(ui, s(2), "bold"),
122
+
123
+ display_lg=FontSpec(ui, s(4), "bold"),
124
+ display_xl=FontSpec(ui, s(5), "bold"),
125
+
126
+ code=FontSpec(mono, s(0), "normal"),
127
+ hyperlink=FontSpec(ui, s(0), "normal", underline=True),
128
+ )
129
+
130
+
131
+ DEFAULT_FONT_TOKENS = build_desktop_tokens()
132
+
133
+ FALLBACK_FONT = "TkDefaultFont"
134
+ FALLBACK_MONO = "TkFixedFont"
135
+
136
+
137
+ TK_FONT_OVERRIDES = {
138
+ # Make Tk defaults align with desktop expectations / your token system
139
+ "TkDefaultFont": FontTokenNames.body,
140
+ "TkTextFont": FontTokenNames.body,
141
+ "TkHeadingFont": FontTokenNames.heading_md,
142
+ "TkCaptionFont": FontTokenNames.caption,
143
+ "TkFixedFont": FontTokenNames.code,
144
+ }
145
+
146
+
147
+ # =============================================================================
148
+ # Typography registry (named fonts)
149
+ # =============================================================================
150
+
151
+ class Typography:
152
+ """
153
+ Named-font registry for tokenized typography.
154
+
155
+ - Call Typography.init(root) once.
156
+ - Token fonts become named Tk fonts (e.g. "body", "heading-lg"...)
157
+ - Tk defaults are overridden (TkDefaultFont, etc.) to match tokens.
158
+ """
159
+
160
+ _root: Misc | None = None
161
+ _fonts: FontTokens = DEFAULT_FONT_TOKENS
162
+ _use_fallback: bool = False
163
+ _named_fonts: dict[str, TkFont] = {}
164
+
165
+ @classmethod
166
+ def initialize(cls, root: Misc | None = None) -> None:
167
+ if root is not None:
168
+ cls._root = root
169
+ cls._ensure_named_token_fonts()
170
+ cls._override_tk_fonts()
171
+
172
+ @classmethod
173
+ def use_fonts(cls, fonts: FontTokens, *, fallback: bool = False) -> None:
174
+ cls._fonts = fonts
175
+ cls._use_fallback = bool(fallback)
176
+ cls._ensure_named_token_fonts()
177
+ cls._override_tk_fonts()
178
+
179
+ @classmethod
180
+ def set_global_family(cls, family: str) -> None:
181
+ """
182
+ Update all font tokens to use a single family (except monospace).
183
+ """
184
+ updated = {}
185
+ for name, spec in cls._fonts._asdict().items():
186
+ if name == "code":
187
+ updated[name] = spec
188
+ else:
189
+ updated[name] = FontSpec(
190
+ family,
191
+ spec.size,
192
+ spec.weight,
193
+ spec.underline,
194
+ spec.slant,
195
+ spec.overstrike,
196
+ )
197
+ cls.use_fonts(FontTokens(**updated), fallback=True)
198
+
199
+ @classmethod
200
+ def get_token(cls, name: str) -> FontSpec:
201
+ """
202
+ Return the FontSpec for a token name.
203
+ """
204
+ # allow passing "body-sm" etc.
205
+ # map token string to field name
206
+ field = name.replace("-", "_")
207
+ if hasattr(cls._fonts, field):
208
+ return getattr(cls._fonts, field)
209
+ raise KeyError(f"Unknown font token: {name}")
210
+
211
+ @classmethod
212
+ def token_names(cls) -> set[str]:
213
+ return {
214
+ v for k, v in FontTokenNames.__dict__.items()
215
+ if not k.startswith("_") and isinstance(v, str)
216
+ }
217
+
218
+ @classmethod
219
+ def get_named_token_font(cls, token_name: str) -> TkFont:
220
+ """
221
+ Return the named Tk font for a token.
222
+ """
223
+ if token_name not in cls._named_fonts:
224
+ cls._ensure_named_token_fonts()
225
+ # If it's still missing, try to resolve as Tk named font directly:
226
+ return cls._named_fonts.get(token_name) or TkFont(name=token_name, exists=True)
227
+
228
+ @classmethod
229
+ def update_font_token(cls, name: str, **kwargs: Any) -> None:
230
+ """
231
+ Replace the given token with updated fields (NamedTuple-safe).
232
+ """
233
+ field = name.replace("-", "_")
234
+ if not hasattr(cls._fonts, field):
235
+ raise KeyError(f"Unknown font token: {name}")
236
+
237
+ old: FontSpec = getattr(cls._fonts, field)
238
+ new = old._replace(**kwargs)
239
+ # rebuild the FontTokens instance
240
+ data = cls._fonts._asdict()
241
+ data[field] = new
242
+ cls.use_fonts(FontTokens(**data), fallback=cls._use_fallback)
243
+
244
+ @classmethod
245
+ def _ensure_named_token_fonts(cls) -> None:
246
+ """
247
+ Create/update named Tk fonts for every token.
248
+ """
249
+ for token_name, spec in cls._iter_tokens():
250
+ fallback = FALLBACK_MONO if token_name == FontTokenNames.code else FALLBACK_FONT
251
+
252
+ family = spec.font if not cls._use_fallback else fallback
253
+
254
+ if token_name in tkfont.names():
255
+ f = tkfont.nametofont(token_name)
256
+ f.configure(
257
+ family=family,
258
+ size=spec.size,
259
+ weight=spec.weight,
260
+ slant=spec.slant,
261
+ underline=bool(spec.underline),
262
+ overstrike=bool(spec.overstrike),
263
+ )
264
+ else:
265
+ f = TkFont(
266
+ name=token_name,
267
+ family=family,
268
+ size=spec.size,
269
+ weight=spec.weight,
270
+ slant=spec.slant,
271
+ underline=bool(spec.underline),
272
+ overstrike=bool(spec.overstrike),
273
+ )
274
+ cls._named_fonts[token_name] = f
275
+
276
+ @classmethod
277
+ def _override_tk_fonts(cls) -> None:
278
+ """
279
+ Override Tk’s default named fonts to align with tokens.
280
+ """
281
+ for tk_name, token_name in TK_FONT_OVERRIDES.items():
282
+ spec = cls.get_token(token_name)
283
+ fallback = FALLBACK_MONO if token_name == FontTokenNames.code else FALLBACK_FONT
284
+ family = spec.font if not cls._use_fallback else fallback
285
+
286
+ if tk_name in tkfont.names():
287
+ tkfont.nametofont(tk_name).configure(
288
+ family=family,
289
+ size=spec.size,
290
+ weight=spec.weight,
291
+ slant=spec.slant,
292
+ )
293
+
294
+ @classmethod
295
+ def _iter_tokens(cls):
296
+ d = cls._fonts._asdict()
297
+ for field_name, spec in d.items():
298
+ token_name = field_name.replace("_", "-")
299
+ yield token_name, spec
300
+
301
+
302
+ # =============================================================================
303
+ # Public Font abstraction (token + modifiers -> named Tk font)
304
+ # =============================================================================
305
+
306
+ _BRACKET_RE = re.compile(r"\[([^]]+)]")
307
+
308
+
309
+ @dataclass(frozen=True)
310
+ class FontModifierSpec:
311
+ token: str
312
+ size: int | None = None # absolute override
313
+ size_delta: int = 0 # "+1"/"-1" after token
314
+ weight: str | None = None # "bold"|"normal"
315
+ slant: str | None = None # "italic"|"roman"
316
+ underline: bool | None = None
317
+ overstrike: bool | None = None
318
+
319
+ def key(self) -> tuple:
320
+ return (
321
+ self.token,
322
+ self.size,
323
+ self.size_delta,
324
+ self.weight,
325
+ self.slant,
326
+ self.underline,
327
+ self.overstrike,
328
+ )
329
+
330
+
331
+ _DERIVED_FONTS: dict[tuple, TkFont] = {}
332
+
333
+
334
+ def _hash(parts: Any) -> str:
335
+ return hashlib.md5(repr(parts).encode("utf-8")).hexdigest()[:10]
336
+
337
+
338
+ def parse_font(value: str, *, default_token: str = FontTokenNames.body) -> FontModifierSpec:
339
+ """
340
+ Parse:
341
+ "body[bold]"
342
+ "heading-lg+1[italic][underline]"
343
+ "[16][bold]" -> default token + size/mods
344
+
345
+ Brackets can contain:
346
+ - size: 16, 16px
347
+ - modifiers: bold, normal, italic, roman, underline, overstrike
348
+ - comma/space separated lists: [bold, italic]
349
+ """
350
+ s = (value or "").strip()
351
+ if not s:
352
+ return FontModifierSpec(default_token)
353
+
354
+ head = s.split("[", 1)[0].strip()
355
+ mods = _BRACKET_RE.findall(s)
356
+
357
+ token = default_token
358
+ size_delta = 0
359
+
360
+ if head:
361
+ # allow token+delta like "body+1" or "body-2"
362
+ m = re.match(r"^\s*([^+\-]+?)\s*([+-])\s*(\d+)\s*$", head)
363
+ if m:
364
+ token = m.group(1).strip() or default_token
365
+ sign = m.group(2)
366
+ n = int(m.group(3))
367
+ size_delta = n if sign == "+" else -n
368
+ else:
369
+ token = head
370
+
371
+ size: int | None = None
372
+ weight: str | None = None
373
+ slant: str | None = None
374
+ underline: bool | None = None
375
+ overstrike: bool | None = None
376
+
377
+ for raw in mods:
378
+ part = raw.strip()
379
+ if not part:
380
+ continue
381
+
382
+ bits = [b.strip().lower() for b in re.split(r"[,\s]+", part) if b.strip()]
383
+ for b in bits:
384
+ if b.endswith("px") and b[:-2].isdigit():
385
+ size = -int(b[:-2])
386
+ elif b.isdigit():
387
+ size = int(b)
388
+ elif b in ("bold", "normal"):
389
+ weight = b
390
+ elif b in ("italic", "roman"):
391
+ slant = b
392
+ elif b == "underline":
393
+ underline = True
394
+ elif b in ("no-underline", "nounderline"):
395
+ underline = False
396
+ elif b in ("overstrike", "strike", "strikethrough"):
397
+ overstrike = True
398
+ elif b in ("no-overstrike", "no-strike", "nostrike"):
399
+ overstrike = False
400
+
401
+ return FontModifierSpec(
402
+ token=token,
403
+ size=size,
404
+ size_delta=size_delta,
405
+ weight=weight,
406
+ slant=slant,
407
+ underline=underline,
408
+ overstrike=overstrike,
409
+ )
410
+
411
+
412
+ def resolve_modifier_font(spec: FontModifierSpec) -> TkFont:
413
+ """
414
+ Resolve a modifier spec to a named, cached TkFont.
415
+ """
416
+ key = spec.key()
417
+ cached = _DERIVED_FONTS.get(key)
418
+ if cached is not None:
419
+ return cached
420
+
421
+ # If token exists in our system, prefer it; otherwise treat as Tk named font
422
+ try:
423
+ base = Typography.get_named_token_font(spec.token)
424
+ except Exception:
425
+ base = TkFont(name=spec.token, exists=True)
426
+
427
+ actual = base.actual()
428
+
429
+ cfg: dict[str, Any] = {
430
+ "family": actual.get("family"),
431
+ "size": actual.get("size"),
432
+ "weight": actual.get("weight", "normal"),
433
+ "slant": actual.get("slant", "roman"),
434
+ "underline": int(actual.get("underline", 0) or 0),
435
+ "overstrike": int(actual.get("overstrike", 0) or 0),
436
+ }
437
+
438
+ if spec.size is not None:
439
+ cfg["size"] = spec.size
440
+ if spec.size_delta:
441
+ cfg["size"] = int(cfg.get("size") or 0) + spec.size_delta
442
+
443
+ if spec.weight is not None:
444
+ cfg["weight"] = spec.weight
445
+ if spec.slant is not None:
446
+ cfg["slant"] = spec.slant
447
+ if spec.underline is not None:
448
+ cfg["underline"] = 1 if spec.underline else 0
449
+ if spec.overstrike is not None:
450
+ cfg["overstrike"] = 1 if spec.overstrike else 0
451
+
452
+ # If nothing changed, return base
453
+ if (
454
+ spec.size is None
455
+ and spec.size_delta == 0
456
+ and spec.weight is None
457
+ and spec.slant is None
458
+ and spec.underline is None
459
+ and spec.overstrike is None
460
+ ):
461
+ _DERIVED_FONTS[key] = base
462
+ return base
463
+
464
+ name = f"bootstack.font.{_hash(key)}"
465
+ try:
466
+ f = TkFont(name=name, exists=True)
467
+ f.configure(**cfg)
468
+ except Exception:
469
+ f = TkFont(name=name, **cfg)
470
+
471
+ _DERIVED_FONTS[key] = f
472
+ return f
473
+
474
+
475
+ class Font:
476
+ """
477
+ Public, reusable typography primitive.
478
+
479
+ Works with the same inline syntax you already allow on widgets:
480
+ Font("body[bold]")
481
+ Font("heading-lg+1[italic]")
482
+ Font("[16][bold]") # default token + size/mods
483
+ Font("Segoe UI[14][bold]") # explicit family + mods
484
+
485
+ Can be passed directly to Tk widgets:
486
+ ttk.Label(..., font=Font("body[bold]"))
487
+
488
+ Measurement helpers:
489
+ Font(...).measure("text")
490
+ Font(...).metrics(...)
491
+ """
492
+
493
+ __slots__ = ("spec", "_tkfont")
494
+
495
+ def __init__(self, value: str, *, default_token: str = FontTokenNames.body):
496
+ self.spec = parse_font(value, default_token=default_token)
497
+ self._tkfont: TkFont | None = None
498
+
499
+ @property
500
+ def tkfont(self) -> TkFont:
501
+ if self._tkfont is None:
502
+ self._tkfont = resolve_modifier_font(self.spec)
503
+ return self._tkfont
504
+
505
+ @property
506
+ def name(self) -> str:
507
+ return str(self.tkfont)
508
+
509
+ def measure(self, text: str) -> int:
510
+ return int(self.tkfont.measure(text))
511
+
512
+ def metrics(self, *args, **kwargs):
513
+ return self.tkfont.metrics(*args, **kwargs)
514
+
515
+ def actual(self, *args, **kwargs):
516
+ return self.tkfont.actual(*args, **kwargs)
517
+
518
+ def __str__(self) -> str:
519
+ return self.name
520
+
521
+
522
+ def get_font(value: str, *, default_token: str = FontTokenNames.body) -> Font:
523
+ """
524
+ Convenience factory:
525
+ get_font("body[bold]")
526
+ """
527
+ return Font(value, default_token=default_token)