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,510 @@
1
+ """Menu utilities for bootstack.
2
+
3
+ This module provides utilities for creating menus with icon support and
4
+ theme-aware color updates.
5
+
6
+ Examples:
7
+ ```python
8
+ import bootstack as bs
9
+ from bootstack.menu import create_menu
10
+
11
+ app = bs.Window()
12
+
13
+ menu_items = [
14
+ {
15
+ "label": "File",
16
+ "items": [
17
+ {"label": "Open", "icon": "folder2-open"},
18
+ {"label": "Save", "icon": "save"},
19
+ {"type": "separator"},
20
+ {"label": "Exit", "command": app.quit, "icon": "x-circle"}
21
+ ],
22
+ },
23
+ {
24
+ "label": "Edit",
25
+ "items": [
26
+ {"label": "Undo", "icon": "arrow-counterclockwise"},
27
+ {"label": "Redo", "icon": "arrow-clockwise"},
28
+ ]
29
+ }
30
+ ]
31
+
32
+ create_menu(app, menu_items)
33
+ app.mainloop()
34
+ ```
35
+ """
36
+ import tkinter as tk
37
+ from tkinter import font, ttk
38
+ from typing import Any, Optional, Union
39
+
40
+ from ttkbootstrap_icons_bs import BootstrapIcon
41
+ from bootstack.core.localization import MessageCatalog
42
+ from bootstack.runtime.shortcuts import format_shortcut
43
+ from bootstack.style.style import get_style
44
+
45
+
46
+ class MenuManager:
47
+ """Manages menus with icon support and theme-aware color updates.
48
+
49
+ This class provides a declarative way to create menus with automatic icon
50
+ support and theme-aware color updates. When the theme changes, all menu
51
+ icons are automatically updated to match the new theme's foreground color.
52
+
53
+ The MenuManager tracks all menu items that have icons and listens for
54
+ `<<ThemeChanged>>` events on the root window. When a theme change is detected,
55
+ it recreates and updates all icons to ensure they match the new theme.
56
+
57
+ Attributes:
58
+ parent: The parent widget (typically a Window or Toplevel).
59
+ style: The Style instance for accessing theme colors.
60
+ menu_items: Dictionary tracking menu items with icons for theme updates.
61
+ """
62
+
63
+ def __init__(self, parent: Any):
64
+ """Initialize the MenuManager.
65
+
66
+ Sets up the menu manager with the given parent widget, initializes
67
+ the style and icon provider, and establishes theme change monitoring
68
+ to automatically update icon colors when themes change.
69
+
70
+ Args:
71
+ parent: The parent widget, typically a Window, Toplevel, or root
72
+ widget. This is used to access the style, icon provider, and
73
+ to bind theme change events.
74
+ """
75
+ self.parent: Any = parent
76
+ self.style = get_style()
77
+ self.menu_items: dict[str, tuple[tk.Menu, int, str, int]] = {}
78
+
79
+ # Set up theme change monitoring
80
+ self._setup_theme_monitoring()
81
+
82
+ @classmethod
83
+ def for_widget(cls, widget: Any) -> "MenuManager":
84
+ """Return the singleton MenuManager for `widget`'s root window.
85
+
86
+ Creates one on first access and stores it on the root as
87
+ `_menu_manager`. Use this to share icon-tracking and theme
88
+ monitoring across all tk.Menu-based widgets in an application
89
+ (menubars, context menus, etc.) without each one binding its own
90
+ `<<ThemeChanged>>` handler.
91
+ """
92
+ root = widget.winfo_toplevel() if hasattr(widget, 'winfo_toplevel') else widget
93
+ existing = getattr(root, '_menu_manager', None)
94
+ if existing is not None:
95
+ return existing
96
+ mgr = cls(root)
97
+ try:
98
+ root._menu_manager = mgr
99
+ except Exception:
100
+ pass
101
+ return mgr
102
+
103
+ def _setup_theme_monitoring(self):
104
+ """Set up monitoring for theme and macOS appearance changes."""
105
+ # Get the root window
106
+ root = self.parent.winfo_toplevel() if hasattr(self.parent, 'winfo_toplevel') else self.parent
107
+
108
+ if not hasattr(root, 'bind'):
109
+ return
110
+
111
+ # bootstack theme changes
112
+ root.bind('<<ThemeChanged>>', self._on_theme_changed, add='+')
113
+ # macOS light/dark appearance toggle (Tk 8.6.10+ on Aqua). Without
114
+ # this, icons rendered with a cached system-text color stay stale
115
+ # after the user flips system Appearance.
116
+ try:
117
+ root.bind('<<TkSystemAppearanceChanged>>', self._on_theme_changed, add='+')
118
+ except tk.TclError:
119
+ pass
120
+
121
+ def _menu_icon_color(self) -> str:
122
+ """Return the right foreground color for icons going into a tk.Menu.
123
+
124
+ On Aqua, NSMenu always uses system appearance regardless of the
125
+ app theme, so icons must match the system text color (which Tk
126
+ keeps in sync with macOS light/dark mode). Everywhere else, the
127
+ app theme's foreground is the right answer.
128
+ """
129
+ try:
130
+ winsys = self.parent.tk.call('tk', 'windowingsystem')
131
+ except tk.TclError:
132
+ winsys = None
133
+
134
+ if winsys == 'aqua':
135
+ try:
136
+ # winfo_rgb returns 16-bit channels; pack into a hex string
137
+ # BootstrapIcon (and PIL underneath) understands.
138
+ r, g, b = self.parent.winfo_rgb('systemTextColor')
139
+ return f'#{r >> 8:02x}{g >> 8:02x}{b >> 8:02x}'
140
+ except tk.TclError:
141
+ pass
142
+
143
+ return self.style.style_builder.color('foreground')
144
+
145
+ def _on_theme_changed(self, event=None):
146
+ """Update all menu icon colors when theme or system appearance changes."""
147
+ fg_color = self._menu_icon_color()
148
+
149
+ # Update all menu items (including cascades)
150
+ for menu, index, icon_name, size in self.menu_items.values():
151
+ # Recreate the icon with new foreground color
152
+ new_icon = BootstrapIcon(icon_name, size, fg_color)
153
+
154
+ try:
155
+ menu.entryconfigure(index, image=new_icon)
156
+ except tk.TclError:
157
+ # Menu item may have been deleted
158
+ pass
159
+
160
+ # ----- Public helpers for tk.Menu callers --------------------------------
161
+
162
+ @staticmethod
163
+ def translate_label(text: Optional[str]) -> Optional[str]:
164
+ """Run a label through `MessageCatalog.translate`.
165
+
166
+ Semantic keys (e.g. `'table.sort_asc'`) become localized strings;
167
+ plain text passes through unchanged because `translate` returns
168
+ the source when no translation is registered.
169
+ """
170
+ if not text:
171
+ return text
172
+ try:
173
+ return MessageCatalog.translate(text)
174
+ except Exception:
175
+ return text
176
+
177
+ def resolve_icon(self, icon_spec: Union[str, dict, None]) -> tuple[Any, Optional[str], int]:
178
+ """Resolve an icon spec to a `(PhotoImage, name, size)` triple.
179
+
180
+ Returns `(None, None, 0)` for empty/unsupported specs. The returned
181
+ PhotoImage is the same kind `MenuManager` uses internally for its
182
+ own menus, so the caller can pass it straight to
183
+ `menu.add_command(image=..., compound='left')`.
184
+ """
185
+ if not icon_spec or icon_spec == 'empty':
186
+ return None, None, 0
187
+ name, size = self._parse_icon_spec(icon_spec)
188
+ if not name:
189
+ return None, None, 0
190
+ try:
191
+ icon = BootstrapIcon(name, size, self._menu_icon_color())
192
+ except Exception:
193
+ return None, None, 0
194
+ return icon, name, size
195
+
196
+ def register_icon(self, menu: tk.Menu, index: int, icon_name: str, icon_size: int) -> None:
197
+ """Track a menu item for theme-aware icon re-rendering.
198
+
199
+ Call after `menu.add_*(image=icon)` so subsequent
200
+ `<<ThemeChanged>>` events refresh the entry's icon color.
201
+ """
202
+ self._track_icon(menu, index, icon_name, icon_size)
203
+
204
+ def unregister_menu(self, menu: tk.Menu) -> None:
205
+ """Drop all tracking entries for `menu`.
206
+
207
+ Call when the menu is being destroyed or fully rebuilt so stale
208
+ `(menu, index)` references don't try to reconfigure deleted entries
209
+ on the next `<<ThemeChanged>>`.
210
+ """
211
+ prefix = f"{id(menu)}_"
212
+ for key in [k for k in self.menu_items if k.startswith(prefix)]:
213
+ del self.menu_items[key]
214
+
215
+ def _parse_icon_spec(self, icon_spec: Union[str, dict]) -> tuple[Optional[str], int]:
216
+ """Parse icon specification into name and size tuple."""
217
+ # Use menu font linespace as default icon size
218
+ menu_font = font.nametofont("TkMenuFont")
219
+ default_size = menu_font.metrics("linespace")
220
+
221
+ if isinstance(icon_spec, str):
222
+ return icon_spec, default_size
223
+ elif isinstance(icon_spec, dict):
224
+ name = icon_spec.get('name')
225
+ size = icon_spec.get('size', default_size)
226
+ return name, size
227
+ return None, default_size
228
+
229
+ def _is_aqua_special_name(self, name: str) -> bool:
230
+ """Return True if `name` triggers macOS-native menu handling.
231
+
232
+ Tk on Aqua reserves three submenu names off the menubar: `apple`
233
+ (the app menu — gets auto-filled with About/Hide/Quit), `window`
234
+ (auto-populated with open Toplevels), and `help` (gets the
235
+ system Help search field). Names are case-sensitive and only have
236
+ meaning under windowingsystem='aqua'.
237
+ """
238
+ try:
239
+ winsys = self.parent.tk.call('tk', 'windowingsystem')
240
+ except tk.TclError:
241
+ return False
242
+ return winsys == 'aqua' and name in ('apple', 'window', 'help')
243
+
244
+ def create_menu(self, parent: Any, items: list[dict]) -> tk.Menu:
245
+ """Create a menu from a list of item dictionaries.
246
+
247
+ Args:
248
+ parent: The parent widget (Window, Toplevel, or Menu).
249
+ items: List of menu item dictionaries defining the menu structure.
250
+
251
+ Returns:
252
+ The created Menu object.
253
+ """
254
+ menubar = None
255
+
256
+ # If parent is a window, create the menubar first
257
+ if not isinstance(parent, tk.Menu):
258
+ menubar = tk.Menu(parent, tearoff=0)
259
+ parent['menu'] = menubar
260
+ parent = menubar # Now work with the menubar
261
+
262
+ for options in items:
263
+ options = options.copy()
264
+ sub_items = options.pop('items', [])
265
+
266
+ # Pull off the optional `name` early so it's never passed to
267
+ # add_cascade. On Aqua, three magic names get system handling:
268
+ # 'apple' → app menu (auto-fills with About/Hide/Quit),
269
+ # 'window' → Tk auto-populates the open Toplevel list,
270
+ # 'help' → system menu search across all menus.
271
+ menu_name = options.pop('name', None)
272
+
273
+ # Translate the label so semantic keys (e.g. 'menu.file') resolve
274
+ # via MessageCatalog. Plain text passes through unchanged.
275
+ if 'label' in options:
276
+ options['label'] = self.translate_label(options['label'])
277
+
278
+ # Handle icon for cascade menu BEFORE popping tearoff
279
+ icon_spec = options.pop('icon', None)
280
+ icon_name = None
281
+ icon_size = 16
282
+
283
+ if icon_spec:
284
+ icon, icon_name, icon_size = self.resolve_icon(icon_spec)
285
+ if icon is not None:
286
+ options['image'] = icon
287
+ options['compound'] = options.get('compound', 'left')
288
+
289
+ options.setdefault('tearoff', 0)
290
+
291
+ # Create a menu for this item. On Aqua, propagate the magic name
292
+ # so Tk wires up NSApp's app/window/help menu integration.
293
+ menu_kwargs: dict[str, Any] = {'tearoff': options.pop('tearoff')}
294
+ if menu_name and self._is_aqua_special_name(menu_name):
295
+ menu_kwargs['name'] = menu_name
296
+ menu = tk.Menu(parent, **menu_kwargs)
297
+
298
+ # Add it as a cascade to the parent menu
299
+ parent.add_cascade(menu=menu, **options)
300
+
301
+ # Track cascade icon if present
302
+ if icon_name:
303
+ self.register_icon(parent, parent.index('end'), icon_name, icon_size)
304
+
305
+ # Add all sub-items to this menu
306
+ self._add_menu_items(menu, sub_items)
307
+
308
+ return parent if isinstance(parent, tk.Menu) else menubar
309
+
310
+ def _add_menu_items(self, menu: tk.Menu, items: list[dict]):
311
+ """Add items to a menu with icon support and theme tracking."""
312
+ for opts in items:
313
+ opts = opts.copy()
314
+
315
+ # Check if this is a submenu (cascade)
316
+ if 'items' in opts:
317
+ # This item has subitems, so it's a cascade
318
+ # Pass to create_menu which will handle the cascade
319
+ self.create_menu(menu, [opts])
320
+ continue
321
+
322
+ # Regular menu item (not a cascade)
323
+ if 'label' in opts:
324
+ opts['label'] = self.translate_label(opts['label'])
325
+
326
+ # Resolve a shortcut spec (registered key or modifier pattern)
327
+ # to a platform-correct accelerator display. Caller-supplied
328
+ # `accelerator` wins (legacy literal pass-through), so existing
329
+ # menus with `accelerator='Ctrl+S'` are not auto-translated.
330
+ shortcut_spec = opts.pop('shortcut', None)
331
+ if shortcut_spec and 'accelerator' not in opts:
332
+ display = format_shortcut(shortcut_spec)
333
+ if display:
334
+ opts['accelerator'] = display
335
+
336
+ icon_spec = opts.pop('icon', None)
337
+ icon_name = None
338
+ icon_size = 0
339
+ if icon_spec:
340
+ icon, icon_name, icon_size = self.resolve_icon(icon_spec)
341
+ if icon is not None:
342
+ opts['image'] = icon
343
+ opts['compound'] = opts.get('compound', 'left')
344
+
345
+ item_type = opts.pop('type', 'command')
346
+ if item_type == 'separator':
347
+ menu.add_separator()
348
+ continue
349
+
350
+ adder = {
351
+ 'command': menu.add_command,
352
+ 'checkbutton': menu.add_checkbutton,
353
+ 'radiobutton': menu.add_radiobutton,
354
+ }.get(item_type, menu.add_command)
355
+ adder(**opts)
356
+
357
+ if icon_name:
358
+ self.register_icon(menu, menu.index('end'), icon_name, icon_size)
359
+
360
+ def _track_icon(self, menu: tk.Menu, index: int, icon_name: str, icon_size: int):
361
+ """Register a menu item with an icon for automatic theme updates."""
362
+ item_id = f"{id(menu)}_{index}"
363
+ self.menu_items[item_id] = (menu, index, icon_name, icon_size)
364
+
365
+
366
+ def create_menu(parent: Any, items: list[dict]) -> tk.Menu:
367
+ """Create a menu with icon and theme support.
368
+
369
+ This is a convenience function that creates or retrieves a MenuManager
370
+ for the parent window and uses it to build a menu from a declarative
371
+ structure. The resulting menu automatically updates icon colors when
372
+ the theme changes.
373
+
374
+ Each menu item is defined by a dictionary that can contain:
375
+ - **label** (str): The text displayed for the menu item
376
+ - **icon** (str or dict): Icon specification. Can be a string icon
377
+ name (e.g., "folder2-open") or a dict with 'name' and 'size' keys
378
+ (e.g., {"name": "folder2-open", "size": 20})
379
+ - **items** (list): List of submenu items for cascade menus
380
+ - **command** (callable): Callback function executed when clicked
381
+ - **type** (str): Menu item type - 'command', 'checkbutton',
382
+ 'radiobutton', or 'separator'
383
+ - **variable** (Variable): Tkinter variable for checkbutton/radiobutton
384
+ - **value** (Any): Value for radiobutton items
385
+ - **name** (str): Optional Tcl widget name for the cascade. On macOS
386
+ three names trigger system-native menu integration: `'apple'`
387
+ gives you the application menu (Tk auto-fills it with About,
388
+ Hide, Hide Others, Show All, Quit; any items you add appear
389
+ before the system items), `'window'` gets auto-populated with
390
+ open Toplevels, and `'help'` enables system Help search.
391
+ Ignored on Win/Linux.
392
+ - **shortcut** (str): Platform-aware accelerator. Accepts a
393
+ registered shortcut key (e.g. `'save'` if you've called
394
+ `Shortcuts.register('save', 'Mod+S', save_file)`) or a
395
+ modifier pattern like `'Mod+S'`, `'Ctrl+Shift+N'`, `'F5'`.
396
+ Renders as `⌘S` on macOS and `Ctrl+S` on Win/Linux.
397
+ For the actual keypress binding, register the shortcut and call
398
+ `Shortcuts.bind_to(app)` — that's the canonical pathway.
399
+ - **accelerator** (str): Legacy literal display string passed
400
+ straight through to `tk.Menu` (e.g. `'Ctrl+S'`). No platform
401
+ translation. Prefer `shortcut` for new code. If both are
402
+ provided, `accelerator` wins.
403
+ - Any other valid Tkinter menu item options (underline, etc.)
404
+
405
+ Args:
406
+ parent: The parent widget (Window, Toplevel, or Menu). If a Window
407
+ or Toplevel is provided, the menu becomes the window's menubar.
408
+ If a Menu is provided, items are added to that menu.
409
+ items: List of dictionaries defining the menu structure. Each
410
+ dictionary represents a menu item with its configuration.
411
+
412
+ Returns:
413
+ The created Menu object. For window menubars, this is the menubar
414
+ itself. For menus attached to other widgets, this is the menu.
415
+
416
+ Examples:
417
+ Basic menubar with icons:
418
+ ```python
419
+ import bootstack as bs
420
+
421
+ app = bs.App()
422
+
423
+ menu_items = [
424
+ {
425
+ "label": "File",
426
+ "items": [
427
+ {"label": "New", "icon": "file-plus", "command": new_file},
428
+ {"label": "Open", "icon": "folder2-open", "command": open_file},
429
+ {"type": "separator"},
430
+ {"label": "Exit", "icon": "x-circle", "command": app.quit}
431
+ ]
432
+ },
433
+ {
434
+ "label": "Edit",
435
+ "items": [
436
+ {"label": "Undo", "icon": "arrow-counterclockwise"},
437
+ {"label": "Redo", "icon": "arrow-clockwise"}
438
+ ]
439
+ }
440
+ ]
441
+
442
+ bs.create_menu(app, menu_items)
443
+ app.mainloop()
444
+ ```
445
+
446
+ Nested submenus with custom icon sizes:
447
+ ```python
448
+ menu_items = [
449
+ {
450
+ "label": "File",
451
+ "items": [
452
+ {
453
+ "label": "Recent",
454
+ "icon": {"name": "clock-history", "size": 18},
455
+ "items": [
456
+ {"label": "Document 1.txt"},
457
+ {"label": "Document 2.txt"}
458
+ ]
459
+ }
460
+ ]
461
+ }
462
+ ]
463
+ ```
464
+
465
+ Menu with checkbuttons and radiobuttons:
466
+ ```python
467
+ view_var = bs.BooleanVar(value=True)
468
+ theme_var = bs.StringVar(value="light")
469
+
470
+ menu_items = [
471
+ {
472
+ "label": "View",
473
+ "items": [
474
+ {
475
+ "label": "Show Toolbar",
476
+ "type": "checkbutton",
477
+ "variable": view_var
478
+ }
479
+ ]
480
+ },
481
+ {
482
+ "label": "Theme",
483
+ "items": [
484
+ {
485
+ "label": "Light",
486
+ "type": "radiobutton",
487
+ "variable": theme_var,
488
+ "value": "light"
489
+ },
490
+ {
491
+ "label": "Dark",
492
+ "type": "radiobutton",
493
+ "variable": theme_var,
494
+ "value": "dark"
495
+ }
496
+ ]
497
+ }
498
+ ]
499
+ ```
500
+ """
501
+ # Get or create MenuManager for this window
502
+ root = parent.winfo_toplevel() if hasattr(parent, 'winfo_toplevel') else parent
503
+
504
+ if not hasattr(root, '_menu_manager'):
505
+ root._menu_manager = MenuManager(root)
506
+
507
+ return root._menu_manager.create_menu(parent, items)
508
+
509
+
510
+ __all__ = ['create_menu']