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,485 @@
1
+ """SideNavGroup widget for grouping navigation items."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from tkinter import TclError, Variable
6
+ from typing import Any, TYPE_CHECKING
7
+
8
+ from typing_extensions import TypedDict, Unpack
9
+
10
+ from bootstack.widgets.primitives.frame import Frame
11
+ from bootstack.widgets.primitives.gridframe import GridFrame
12
+ from bootstack.widgets.primitives.label import Label
13
+ from bootstack.widgets.composites.compositeframe import CompositeFrame
14
+ from bootstack.widgets.composites.contextmenu import ContextMenu
15
+ from bootstack.widgets.mixins import configure_delegate
16
+ from bootstack.widgets.types import Master
17
+
18
+ if TYPE_CHECKING:
19
+ from bootstack.core.signals import Signal
20
+ from bootstack.widgets.composites.sidenav.item import SideNavItem
21
+
22
+
23
+ class SideNavGroupKwargs(TypedDict, total=False):
24
+ key: str
25
+ text: str
26
+ icon: Any
27
+ signal: Any
28
+ variable: Variable
29
+ is_expanded: bool
30
+ accent: str
31
+ # Frame options
32
+ padding: Any
33
+ width: int
34
+ height: int
35
+
36
+
37
+ class SideNavGroup(Frame):
38
+ """A collapsible group of navigation items.
39
+
40
+ SideNavGroup provides a container for related navigation items.
41
+ In expanded mode, it behaves like an Expander with a chevron toggle.
42
+ In compact mode, clicking the group shows a popup flyout to the right
43
+ containing the group's items.
44
+
45
+ Uses a single CompositeFrame container with separate icon, text, and
46
+ chevron labels. In compact mode, text and chevron are hidden and the
47
+ icon is centered.
48
+
49
+ The group shows as selected if any of its child items are currently selected.
50
+
51
+ !!! note "Events"
52
+ - `<<GroupExpanding>>`: Fired before the group expands.
53
+ `event.data = {'key': str}`
54
+ - `<<GroupCollapsed>>`: Fired after the group collapses.
55
+ `event.data = {'key': str}`
56
+
57
+ Example:
58
+ ```python
59
+ # Groups are created via SideNav.add_group()
60
+ nav.add_group('files', text='Files', icon='folder')
61
+ nav.add_item('local', text='Local', icon='hdd', group='files')
62
+ nav.add_item('cloud', text='Cloud', icon='cloud', group='files')
63
+ ```
64
+ """
65
+
66
+ # Default padding values (same as SideNavItem)
67
+ DEFAULT_PADDING_X = 12
68
+ DEFAULT_PADDING_Y = 6
69
+ DEFAULT_ICON_GAP = 10
70
+ COMPACT_PADDING_X = 6
71
+ COMPACT_PADDING_Y = 6
72
+
73
+ def __init__(
74
+ self,
75
+ master: Master = None,
76
+ key: str = '',
77
+ text: str = '',
78
+ icon: str | dict = None,
79
+ signal: 'Signal[Any]' = None,
80
+ variable: Variable = None,
81
+ is_expanded: bool = False,
82
+ **kwargs: Unpack[SideNavGroupKwargs]
83
+ ):
84
+ """Initialize a SideNavGroup.
85
+
86
+ Args:
87
+ master (Master | None): Parent widget.
88
+ key (str): Unique identifier for this group.
89
+ text (str): Display text for the group.
90
+ icon (str | dict | None): Icon name or configuration dict.
91
+ signal (Signal | None): Reactive signal for selection state.
92
+ variable (Variable | None): Shared variable for selection tracking.
93
+ is_expanded (bool): Initial expansion state. Default False.
94
+ **kwargs: Additional arguments passed to Frame.
95
+ """
96
+ if not key:
97
+ raise ValueError("SideNavGroup requires a non-empty 'key'")
98
+
99
+ # Extract styling kwargs before super().__init__
100
+ # Must set these AFTER super().__init__ because TTKWrapperBase also sets _accent
101
+ saved_accent = kwargs.pop('accent', 'primary')
102
+
103
+ super().__init__(master, **kwargs)
104
+
105
+ # Set after super() to avoid being overwritten by TTKWrapperBase
106
+ self._accent = saved_accent
107
+
108
+ self._key = key
109
+ self._text = text
110
+ self._icon = icon
111
+ self._signal = signal
112
+ self._variable = variable
113
+ self._is_expanded = is_expanded
114
+
115
+ # Track child items (managed by SideNav)
116
+ self._items: dict[str, 'SideNavItem'] = {}
117
+ self._item_order: list[str] = []
118
+
119
+ # Compact mode state
120
+ self._compact = False
121
+
122
+ # Widget references
123
+ self._container: CompositeFrame | None = None
124
+ self._icon_label: Label | None = None
125
+ self._text_label: Label | None = None
126
+ self._chevron_label: Label | None = None
127
+ self._content_frame: Frame | None = None
128
+ self._popup: ContextMenu | None = None
129
+
130
+ # Selection state is now managed centrally by SideNav
131
+ # for better performance (only affected items are updated)
132
+ self._trace_id: str | None = None
133
+
134
+ # Build internal structure
135
+ self._build_widget()
136
+
137
+ def _build_widget(self):
138
+ """Build the internal widget structure.
139
+
140
+ Uses CompositeFrame with NavigationButton styles for the header.
141
+ Child labels are registered for automatic state coordination.
142
+ """
143
+ # Container using NavigationButton.TFrame for selection indicator
144
+ self._container = CompositeFrame(
145
+ self,
146
+ ttk_class='NavigationButton.TFrame',
147
+ accent=self._accent,
148
+ padding=(self.DEFAULT_PADDING_X, self.DEFAULT_PADDING_Y,
149
+ self.DEFAULT_PADDING_X, self.DEFAULT_PADDING_Y),
150
+ takefocus=True,
151
+ )
152
+ self._container.pack(fill='x')
153
+
154
+ # Icon label
155
+ if self._icon:
156
+ self._icon_label = Label(
157
+ self._container,
158
+ icon=self._icon,
159
+ icon_only=True,
160
+ ttk_class='NavigationButton.TLabel',
161
+ accent=self._accent,
162
+ takefocus=False,
163
+ )
164
+ self._container.register_composite(self._icon_label)
165
+
166
+ # Text label
167
+ self._text_label = Label(
168
+ self._container,
169
+ text=self._text,
170
+ anchor='w',
171
+ ttk_class='NavigationButton.TLabel',
172
+ accent=self._accent,
173
+ takefocus=False,
174
+ )
175
+ self._container.register_composite(self._text_label)
176
+
177
+ # Chevron for expand/collapse indicator
178
+ self._chevron_label = Label(
179
+ self._container,
180
+ icon=self._get_chevron_icon(),
181
+ icon_only=True,
182
+ ttk_class='NavigationButton.TLabel',
183
+ accent=self._accent,
184
+ takefocus=False,
185
+ )
186
+ self._container.register_composite(self._chevron_label)
187
+
188
+ # Apply initial layout
189
+ self._apply_layout()
190
+
191
+ # Bind click events
192
+ self._bind_events()
193
+
194
+ # Content frame for child items
195
+ self._content_frame = GridFrame(
196
+ self,
197
+ columns=1,
198
+ gap=(0, 0),
199
+ sticky_items='ew',
200
+ )
201
+ if self._is_expanded:
202
+ self._content_frame.pack(fill='both', expand=True)
203
+
204
+ # Set initial selection state
205
+ self._update_selection_state()
206
+
207
+ def _apply_layout(self):
208
+ """Apply the current layout based on compact mode."""
209
+ # Clear current layout
210
+ if self._icon_label:
211
+ self._icon_label.pack_forget()
212
+ self._text_label.pack_forget()
213
+ self._chevron_label.pack_forget()
214
+
215
+ if self._compact:
216
+ # Compact mode: tighter padding, icon centered
217
+ px = self.COMPACT_PADDING_X
218
+ py = self.COMPACT_PADDING_Y
219
+ self._container.configure(padding=(px, py, px, py))
220
+ if self._icon_label:
221
+ self._icon_label.pack(expand=True)
222
+ else:
223
+ # Expanded mode: restore default padding, icon + text + chevron
224
+ self._container.configure(
225
+ padding=(self.DEFAULT_PADDING_X, self.DEFAULT_PADDING_Y,
226
+ self.DEFAULT_PADDING_X, self.DEFAULT_PADDING_Y)
227
+ )
228
+ if self._icon_label:
229
+ self._icon_label.pack(side='left', padx=(0, self.DEFAULT_ICON_GAP))
230
+ self._text_label.pack(side='left', fill='x', expand=True)
231
+ self._chevron_label.pack(side='right')
232
+
233
+ def _bind_events(self):
234
+ """Bind click and keyboard events.
235
+
236
+ Binds click to container and all child widgets since Tkinter
237
+ doesn't bubble events from children to parents.
238
+ """
239
+ self._container.bind('<Button-1>', self._on_header_click, add='+')
240
+ if self._icon_label:
241
+ self._icon_label.bind('<Button-1>', self._on_header_click, add='+')
242
+ self._text_label.bind('<Button-1>', self._on_header_click, add='+')
243
+ self._chevron_label.bind('<Button-1>', self._on_header_click, add='+')
244
+
245
+ # Keyboard support on focusable container
246
+ self._container.bind('<Return>', self._on_header_click, add='+')
247
+ self._container.bind('<space>', self._on_header_click, add='+')
248
+
249
+ def _get_chevron_icon(self) -> dict:
250
+ """Get the appropriate chevron icon for current state."""
251
+ if self._is_expanded:
252
+ return {'name': 'chevron-up', 'size': 16}
253
+ else:
254
+ return {'name': 'chevron-down', 'size': 16}
255
+
256
+ def _on_header_click(self, event=None):
257
+ """Handle header click - toggle expand/collapse or show popup."""
258
+ self._container.focus_set()
259
+
260
+ if self._compact:
261
+ # In compact mode, show popup
262
+ self._show_popup()
263
+ else:
264
+ # In expanded mode, toggle expand/collapse
265
+ self.toggle()
266
+
267
+ def _update_selection_state(self):
268
+ """Update visual state based on whether any child is selected."""
269
+ is_any_selected = self._is_any_child_selected()
270
+ self._container.set_selected(is_any_selected)
271
+
272
+ def set_child_selected(self, has_selected_child: bool) -> None:
273
+ """Directly set whether a child is selected.
274
+
275
+ This is called by SideNav for efficient selection updates,
276
+ avoiding the need to iterate through children.
277
+
278
+ Args:
279
+ has_selected_child: True if any child item is selected.
280
+ """
281
+ self._container.set_selected(has_selected_child)
282
+
283
+ def _is_any_child_selected(self) -> bool:
284
+ """Check if any child item is currently selected."""
285
+ if not self._variable:
286
+ return False
287
+ current = self._variable.get()
288
+ return current in self._items
289
+
290
+ def _show_popup(self):
291
+ """Show the popup flyout with group items using ContextMenu."""
292
+ # Always destroy existing popup and create fresh one
293
+ # (ContextMenu handles click-outside-to-close automatically)
294
+ self._hide_popup()
295
+
296
+ # Create ContextMenu positioned to the right of the container.
297
+ # SideNav opens this popup via its own click flow, so opt out of
298
+ # ContextMenu's auto right-click trigger.
299
+ self._popup = ContextMenu(
300
+ self,
301
+ target=self._container,
302
+ anchor='nw',
303
+ attach='ne',
304
+ offset=(4, 0),
305
+ minwidth=180,
306
+ trigger=None,
307
+ )
308
+
309
+ # Add items as commands
310
+ for key in self._item_order:
311
+ item = self._items[key]
312
+ item_key = key # Capture for closure
313
+ self._popup.add_command(
314
+ text=item.cget('text'),
315
+ icon=item.cget('icon'),
316
+ command=lambda k=item_key: self._on_popup_item_click(k),
317
+ )
318
+
319
+ # Show the popup
320
+ self._popup.show()
321
+
322
+ def _on_popup_item_click(self, key: str):
323
+ """Handle click on a popup menu item."""
324
+ if key in self._items:
325
+ # Set selection
326
+ if self._variable:
327
+ self._variable.set(key)
328
+ # Fire item invoked event
329
+ self._items[key].event_generate('<<ItemInvoked>>', data={'key': key})
330
+
331
+ def _hide_popup(self):
332
+ """Hide and destroy the popup."""
333
+ if self._popup:
334
+ try:
335
+ self._popup.destroy()
336
+ except TclError:
337
+ pass
338
+ self._popup = None
339
+
340
+ # --- Public API ---
341
+
342
+ def set_compact(self, compact: bool) -> None:
343
+ """Set compact mode.
344
+
345
+ In compact mode, only the icon is shown and clicking opens a popup
346
+ with the group's items.
347
+
348
+ Args:
349
+ compact (bool): True for compact mode, False for full display.
350
+ """
351
+ if self._compact == compact:
352
+ return
353
+
354
+ self._compact = compact
355
+ self._hide_popup()
356
+ self._apply_layout()
357
+
358
+ if compact:
359
+ # Hide content in compact mode
360
+ self._content_frame.pack_forget()
361
+ else:
362
+ # Restore content if expanded
363
+ if self._is_expanded:
364
+ self._content_frame.pack(fill='both', expand=True)
365
+
366
+ self._update_selection_state()
367
+
368
+ def expand(self) -> None:
369
+ """Expand to show items (expanded mode only)."""
370
+ if self._compact or self._is_expanded:
371
+ return
372
+
373
+ self._is_expanded = True
374
+ self._content_frame.pack(fill='both', expand=True)
375
+ self._chevron_label.configure(icon=self._get_chevron_icon())
376
+ self.event_generate('<<GroupExpanding>>', data={'key': self._key})
377
+
378
+ def collapse(self) -> None:
379
+ """Collapse to hide items (expanded mode only)."""
380
+ if self._compact or not self._is_expanded:
381
+ return
382
+
383
+ self._is_expanded = False
384
+ self._content_frame.pack_forget()
385
+ self._chevron_label.configure(icon=self._get_chevron_icon())
386
+ self.event_generate('<<GroupCollapsed>>', data={'key': self._key})
387
+
388
+ def toggle(self) -> None:
389
+ """Toggle expansion state (expanded mode only)."""
390
+ if self._compact:
391
+ return
392
+
393
+ if self._is_expanded:
394
+ self.collapse()
395
+ else:
396
+ self.expand()
397
+
398
+ # --- Internal: Item management (called by SideNav) ---
399
+
400
+ def _add_item(self, item: 'SideNavItem') -> None:
401
+ """Add an item to this group (internal use by SideNav)."""
402
+ self._items[item.key] = item
403
+ self._item_order.append(item.key)
404
+
405
+ def _remove_item(self, key: str) -> None:
406
+ """Remove an item from this group (internal use by SideNav)."""
407
+ if key in self._items:
408
+ del self._items[key]
409
+ self._item_order.remove(key)
410
+
411
+ # --- Properties ---
412
+
413
+ @property
414
+ def key(self) -> str:
415
+ """Get the group's unique key."""
416
+ return self._key
417
+
418
+ @property
419
+ def content_frame(self) -> Frame:
420
+ """Get the content frame for adding items."""
421
+ return self._content_frame
422
+
423
+ @property
424
+ def is_expanded(self) -> bool:
425
+ """Check if group is currently expanded."""
426
+ return self._is_expanded
427
+
428
+ @property
429
+ def has_items(self) -> bool:
430
+ """Check if this group has any items."""
431
+ return len(self._items) > 0
432
+
433
+ @property
434
+ def items(self) -> list['SideNavItem']:
435
+ """Get all items in order."""
436
+ return [self._items[key] for key in self._item_order]
437
+
438
+ @property
439
+ def is_any_selected(self) -> bool:
440
+ """Check if any child item is selected."""
441
+ return self._is_any_child_selected()
442
+
443
+ # --- Configuration Delegates ---
444
+
445
+ @configure_delegate('text')
446
+ def _delegate_text(self, value: str = None):
447
+ """Configure the group text."""
448
+ if value is None:
449
+ return self._text
450
+ self._text = value
451
+ if self._text_label:
452
+ self._text_label.configure(text=value)
453
+ return None
454
+
455
+ @configure_delegate('icon')
456
+ def _delegate_icon(self, value: str | dict = None):
457
+ """Configure the group icon."""
458
+ if value is None:
459
+ return self._icon
460
+ self._icon = value
461
+
462
+ if self._icon_label is not None:
463
+ self._icon_label.configure(icon=value)
464
+ elif value is not None:
465
+ # Create icon label if it doesn't exist
466
+ self._icon_label = Label(
467
+ self._container,
468
+ icon=value,
469
+ icon_only=True,
470
+ ttk_class='NavigationButton.TLabel',
471
+ accent=self._accent,
472
+ takefocus=False,
473
+ )
474
+ self._container.register_composite(self._icon_label)
475
+ self._icon_label.bind('<Button-1>', self._on_header_click, add='+')
476
+ # Re-apply layout
477
+ self._apply_layout()
478
+ return None
479
+
480
+ # --- Cleanup ---
481
+
482
+ def destroy(self):
483
+ """Clean up resources."""
484
+ self._hide_popup()
485
+ super().destroy()
@@ -0,0 +1,83 @@
1
+ """SideNavHeader widget for section labels in navigation menus."""
2
+
3
+ from typing import Any
4
+
5
+ from typing_extensions import TypedDict, Unpack
6
+
7
+ from bootstack.widgets.primitives.frame import Frame
8
+ from bootstack.widgets.primitives.label import Label
9
+ from bootstack.widgets.mixins import configure_delegate
10
+ from bootstack.widgets.types import Master
11
+
12
+
13
+ class SideNavHeaderKwargs(TypedDict, total=False):
14
+ text: str
15
+ # Frame options
16
+ padding: Any
17
+ width: int
18
+ height: int
19
+
20
+
21
+ class SideNavHeader(Frame):
22
+ """A non-selectable section header for grouping navigation items.
23
+
24
+ SideNavHeader provides a text label to identify groups of related
25
+ navigation items. Unlike SideNavItem, headers are not selectable
26
+ and serve only as visual labels. Uses the 'label' font token for styling.
27
+
28
+ Example:
29
+ ```python
30
+ nav.add_item('home', text='Home', icon='house')
31
+ nav.add_header('Favorites') # Creates SideNavHeader
32
+ nav.add_item('photos', text='Photos', icon='image')
33
+ nav.add_item('music', text='Music', icon='music-note')
34
+ ```
35
+ """
36
+
37
+ DEFAULT_PADDING = (8, 20, 8, 4)
38
+ DEFAULT_FONT = 'label'
39
+ DEFAULT_ACCENT = 'secondary'
40
+
41
+ def __init__(
42
+ self,
43
+ master: Master = None,
44
+ text: str = '',
45
+ **kwargs: Unpack[SideNavHeaderKwargs]
46
+ ):
47
+ """Initialize a SideNavHeader.
48
+
49
+ Args:
50
+ master (Master | None): Parent widget.
51
+ text (str): The header text to display.
52
+ **kwargs: Additional arguments passed to Frame.
53
+ """
54
+ self._text = text
55
+
56
+ # Default padding: more top margin for visual separation between sections
57
+ kwargs.setdefault('padding', self.DEFAULT_PADDING)
58
+
59
+ super().__init__(master, **kwargs)
60
+
61
+ # Create header label with 'label' font (smaller, bold) and secondary accent
62
+ self._text_label = Label(
63
+ self,
64
+ text=text,
65
+ font=self.DEFAULT_FONT,
66
+ accent=self.DEFAULT_ACCENT,
67
+ anchor='w',
68
+ )
69
+ self._text_label.pack(fill='x')
70
+
71
+ @property
72
+ def text(self) -> str:
73
+ """Get the header text."""
74
+ return self._text
75
+
76
+ @configure_delegate('text')
77
+ def _delegate_text(self, value: str = None):
78
+ """Configure the header text."""
79
+ if value is None:
80
+ return self._text
81
+ self._text = value
82
+ self._text_label.configure(text=value)
83
+ return None