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,508 @@
1
+ """Expander widget - a collapsible container with header and content."""
2
+ from __future__ import annotations
3
+
4
+ from tkinter import Widget, Variable
5
+ from typing import Any, Callable, Literal, TYPE_CHECKING
6
+
7
+ from bootstack.widgets.primitives.frame import Frame
8
+ from bootstack.widgets.primitives.label import Label
9
+ from bootstack.widgets.composites.compositeframe import CompositeFrame
10
+ from bootstack.widgets.mixins import configure_delegate
11
+ from bootstack.widgets.types import Master
12
+ from bootstack.core.capabilities.signals import normalize_signal
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.core.signals import Signal
16
+
17
+
18
+ class Expander(Frame):
19
+ """A collapsible container with a clickable header and expandable content.
20
+
21
+ The Expander displays a header with an optional icon, title, and chevron
22
+ button. Clicking anywhere on the header toggles the visibility of the
23
+ content area.
24
+
25
+ Expander also supports selection state via `signal`/`variable` and
26
+ `value`, similar to RadioButton. When clicked, it sets the variable to
27
+ its value, enabling radio-group-like behavior for navigation.
28
+
29
+ Attributes:
30
+ content (Frame): The content container frame (read-only).
31
+ is_selected (bool): Whether this expander's value matches the variable (read-only).
32
+
33
+ !!! note "Events"
34
+ - `<<Toggle>>`: Fired when expanded/collapsed.
35
+ `event.data = {'expanded': bool}`
36
+ - `<<Selected>>`: Fired when this expander is selected.
37
+ `event.data = {'value': Any}`
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ master: Master = None,
43
+ title: str = "",
44
+ icon: str | dict = None,
45
+ expanded: bool = True,
46
+ collapsible: bool = True,
47
+ highlight: bool = False,
48
+ icon_expanded: str | dict = None,
49
+ icon_collapsed: str | dict = None,
50
+ icon_position: Literal["before", "after"] = "after",
51
+ signal: 'Signal[Any]' = None,
52
+ variable: Variable = None,
53
+ value: Any = None,
54
+ **kwargs
55
+ ):
56
+ """Create an Expander widget.
57
+
58
+ Args:
59
+ master (Master): Parent widget. If None, uses the default root window.
60
+ title (str): Header title text.
61
+ icon (str | dict): Icon to display in header (left of title).
62
+ expanded (bool): Initial expansion state. Default is True (expanded).
63
+ collapsible (bool): Whether the expander can be toggled. Default is True.
64
+ highlight (bool): If True, header shows 'selected' state when expanded.
65
+ icon_expanded (str | dict): Icon spec for expanded state. Default is chevron-up.
66
+ icon_collapsed (str | dict): Icon spec for collapsed state. Default is chevron-down.
67
+ icon_position (Literal["before", "after"]): Position of chevron relative to title.
68
+ signal (Signal): Reactive Signal for selection state (preferred over variable).
69
+ variable (Variable): Tk variable for selection state (synced with signal).
70
+ value (Any): Value to set on signal/variable when selected.
71
+ **kwargs: Additional arguments passed to Frame. Use `accent` and `variant`
72
+ for styling the header and chevron.
73
+ """
74
+ self._header_accent = kwargs.pop('accent', None)
75
+ self._header_variant = kwargs.pop('variant', None)
76
+ if 'show_border' in kwargs:
77
+ kwargs.setdefault('padding', 3) # need 3 pixels to avoid cutting off corners
78
+ kwargs.setdefault('takefocus', False) # Outer container shouldn't take focus
79
+ super().__init__(master, **kwargs)
80
+
81
+ self._title = title
82
+ self._icon = icon
83
+ self._expanded = expanded
84
+ self._collapsible = collapsible
85
+ self._highlight = highlight
86
+ self._icon_expanded = icon_expanded
87
+ self._icon_collapsed = icon_collapsed
88
+ self._icon_position = icon_position
89
+ self._content_widget = None
90
+ self._value = value
91
+ self._compact = False
92
+
93
+ # Selection state - signal/variable syncing
94
+ self._signal: Signal[Any] | None = None
95
+ self._variable: Variable | None = None
96
+ self._trace_id: str | None = None
97
+
98
+ # Widget references
99
+ self._icon_label: Label | None = None
100
+ self._title_label: Label | None = None
101
+
102
+ self._build_widget()
103
+
104
+ # Set up signal/variable after widget is built
105
+ # Prefer signal if both provided
106
+ if signal is not None:
107
+ self._set_signal_or_variable(signal)
108
+ elif variable is not None:
109
+ self._set_signal_or_variable(variable)
110
+
111
+ def _set_signal_or_variable(self, value: Any):
112
+ """Set up signal/variable binding with trace for selection updates."""
113
+ # Remove old trace if exists
114
+ if self._variable is not None and self._trace_id is not None:
115
+ try:
116
+ self._variable.trace_remove('write', self._trace_id)
117
+ except Exception:
118
+ pass
119
+
120
+ # Normalize to get both signal and variable
121
+ binding = normalize_signal(value)
122
+ if binding is not None:
123
+ self._signal = binding.signal
124
+ self._variable = binding.variable
125
+ else:
126
+ # Direct variable
127
+ self._variable = value
128
+ self._signal = None
129
+
130
+ # Add trace to update selection state
131
+ if self._variable is not None:
132
+ self._trace_id = self._variable.trace_add('write', self._on_variable_changed)
133
+ # Initial update
134
+ self._update_selection_state()
135
+
136
+ def _on_variable_changed(self, *args):
137
+ """Handle variable changes to update selection state."""
138
+ self._update_selection_state()
139
+
140
+ def _update_selection_state(self):
141
+ """Update visual state based on selection."""
142
+ # For now, just track state - visual updates can be added later
143
+ # when a dedicated nav style is created
144
+ pass
145
+
146
+ @property
147
+ def _current_chevron_icon(self):
148
+ """Get the appropriate chevron icon for current state."""
149
+ if self._expanded:
150
+ return self._icon_expanded or {'name': 'chevron-up', 'size': 16}
151
+ else:
152
+ return self._icon_collapsed or {'name': 'chevron-down', 'size': 16}
153
+
154
+ def _build_widget(self):
155
+ """Build the internal widget structure."""
156
+ accent = self._header_accent
157
+ variant = self._header_variant
158
+
159
+ # Use CompositeFrame for header to enable hover/pressed/focus states
160
+ self._header_frame = CompositeFrame(
161
+ self, ttk_class='Expander.TFrame',
162
+ accent=accent, variant=variant, padding=8, takefocus=True
163
+ )
164
+ self._header_frame.pack(fill='x')
165
+
166
+ # Icon (optional, before title)
167
+ if self._icon:
168
+ self._icon_label = Label(
169
+ self._header_frame,
170
+ icon=self._icon,
171
+ icon_only=True,
172
+ ttk_class='Expander.TLabel',
173
+ accent=accent, variant=variant,
174
+ takefocus=False,
175
+ )
176
+ self._header_frame.register_composite(self._icon_label)
177
+ self._icon_label.pack(side='left', padx=(0, 8))
178
+
179
+ # Title label
180
+ self._title_label = Label(
181
+ self._header_frame,
182
+ text=self._title,
183
+ anchor='w',
184
+ ttk_class='Expander.TLabel',
185
+ accent=accent, variant=variant,
186
+ takefocus=False,
187
+ )
188
+ self._header_frame.register_composite(self._title_label)
189
+
190
+ # Toggle button (chevron)
191
+ self._toggle_button = Label(
192
+ self._header_frame,
193
+ icon=self._current_chevron_icon,
194
+ icon_only=True,
195
+ accent=accent, variant=variant,
196
+ ttk_class='Expander.TLabel',
197
+ takefocus=False,
198
+ )
199
+ self._header_frame.register_composite(self._toggle_button)
200
+
201
+ # Layout based on icon_position
202
+ if self._icon_position == "before":
203
+ self._toggle_button.pack(side='left')
204
+ self._title_label.pack(side='left', fill='x', expand=True)
205
+ else:
206
+ self._title_label.pack(side='left', fill='x', expand=True)
207
+ self._toggle_button.pack(side='right')
208
+
209
+ # Hide button if not collapsible
210
+ if not self._collapsible:
211
+ self._toggle_button.pack_forget()
212
+
213
+ # Content frame
214
+ self._content_frame = Frame(self)
215
+ if self._expanded:
216
+ self._content_frame.pack(fill='both', expand=True)
217
+
218
+ # Set initial highlight state
219
+ if self._highlight and self._expanded:
220
+ self._header_frame.set_selected(True)
221
+
222
+ # Bind header events
223
+ self._bind_header_events()
224
+
225
+ def _bind_header_events(self):
226
+ """Make entire header clickable and keyboard accessible."""
227
+ # Always bind for selection, even if not collapsible
228
+ self._header_frame.bind('<Button-1>', self._on_header_click, add='+')
229
+ self._title_label.bind('<Button-1>', self._on_header_click, add='+')
230
+ if self._icon_label:
231
+ self._icon_label.bind('<Button-1>', self._on_header_click, add='+')
232
+
233
+ # Keyboard support
234
+ self._header_frame.bind('<Return>', self._on_header_click, add='+')
235
+ self._header_frame.bind('<space>', self._on_header_click, add='+')
236
+
237
+ def _on_header_click(self, event=None):
238
+ """Handle header click - select and optionally toggle."""
239
+ # Request focus on click
240
+ self._header_frame.focus_set()
241
+
242
+ # Set selection if variable is configured
243
+ if self._variable is not None and self._value is not None:
244
+ self._variable.set(self._value)
245
+ self.event_generate('<<Selected>>', data={'value': self._value})
246
+
247
+ # Toggle expansion if collapsible
248
+ if self._collapsible:
249
+ self.toggle()
250
+
251
+ def toggle(self):
252
+ """Toggle expanded/collapsed state."""
253
+ if not self._collapsible:
254
+ return
255
+
256
+ if self._expanded:
257
+ self.collapse()
258
+ else:
259
+ self.expand()
260
+
261
+ def expand(self):
262
+ """Expand the content area."""
263
+ if self._expanded:
264
+ return
265
+
266
+ self._expanded = True
267
+ self._content_frame.pack(fill='both', expand=True)
268
+ self._toggle_button.configure(icon=self._current_chevron_icon)
269
+ if self._highlight:
270
+ self._header_frame.set_selected(True)
271
+ self.event_generate('<<Toggle>>', data={'expanded': True})
272
+
273
+ def collapse(self):
274
+ """Collapse the content area."""
275
+ if not self._expanded:
276
+ return
277
+
278
+ self._expanded = False
279
+ self._content_frame.pack_forget()
280
+ self._toggle_button.configure(icon=self._current_chevron_icon)
281
+ if self._highlight:
282
+ self._header_frame.set_selected(False)
283
+ self.event_generate('<<Toggle>>', data={'expanded': False})
284
+
285
+ def select(self):
286
+ """Select this expander (set variable to this expander's value)."""
287
+ if self._variable is not None and self._value is not None:
288
+ self._variable.set(self._value)
289
+
290
+ def add(self, widget: Widget = None, **kwargs) -> Widget:
291
+ """Add content widget, or create and return an empty frame.
292
+
293
+ Args:
294
+ widget (Widget | None): Optional widget to use as content. If None, creates a Frame.
295
+ **kwargs: When widget is None, these are passed to Frame (e.g., padding).
296
+
297
+ Returns:
298
+ Widget: The content widget (passed or created).
299
+
300
+ Raises:
301
+ ValueError: If content already exists and widget is provided.
302
+ """
303
+ # If content exists and no widget passed, return existing (idempotent)
304
+ if self._content_widget is not None:
305
+ if widget is not None:
306
+ raise ValueError("Expander already has content.")
307
+ return self._content_widget
308
+
309
+ if widget is None:
310
+ widget = Frame(self._content_frame, **kwargs)
311
+
312
+ self._content_widget = widget
313
+ widget.pack(fill='both', expand=True)
314
+ return widget
315
+
316
+ @property
317
+ def content(self) -> Frame:
318
+ """Get the content frame (for direct child parenting)."""
319
+ return self._content_frame
320
+
321
+ @property
322
+ def is_selected(self) -> bool:
323
+ """Check if this expander is currently selected."""
324
+ if self._variable is not None and self._value is not None:
325
+ return self._variable.get() == self._value
326
+ return False
327
+
328
+ def on_toggled(self, callback: Callable) -> str:
329
+ """Bind callback to `<<Toggle>>` events.
330
+
331
+ Args:
332
+ callback: Function to call when toggled. Receives event with
333
+ `event.data = {'expanded': bool}`.
334
+
335
+ Returns:
336
+ Bind ID that can be passed to `off_toggled` to remove this callback.
337
+ """
338
+ return self.bind('<<Toggle>>', callback, add='+')
339
+
340
+ def off_toggled(self, bind_id: str | None = None) -> None:
341
+ """Unbind `<<Toggle>>` callback(s).
342
+
343
+ Args:
344
+ bind_id: Bind ID returned by `on_toggled`. If None, unbinds all.
345
+ """
346
+ self.unbind('<<Toggle>>', bind_id)
347
+
348
+ def on_selected(self, callback: Callable) -> str:
349
+ """Bind callback to `<<Selected>>` events.
350
+
351
+ Args:
352
+ callback: Function to call when selected. Receives event with
353
+ `event.data = {'value': Any}`.
354
+
355
+ Returns:
356
+ Bind ID that can be passed to `off_selected` to remove this callback.
357
+ """
358
+ return self.bind('<<Selected>>', callback, add='+')
359
+
360
+ def off_selected(self, bind_id: str = None):
361
+ """Unbind `<<Selected>>` callback(s).
362
+
363
+ Args:
364
+ bind_id (str | None): Bind ID returned by `on_selected`. If None, unbinds all.
365
+ """
366
+ self.unbind('<<Selected>>', bind_id)
367
+
368
+ @configure_delegate('title')
369
+ def _delegate_title(self, value=None):
370
+ """Get or set the title text."""
371
+ if value is None:
372
+ return self._title
373
+ self._title = value
374
+ self._title_label.configure(text=value)
375
+ return None
376
+
377
+ @configure_delegate('icon')
378
+ def _delegate_icon(self, value=None):
379
+ """Get or set the header icon."""
380
+ if value is None:
381
+ return self._icon
382
+ self._icon = value
383
+ if self._icon_label is not None:
384
+ self._icon_label.configure(icon=value)
385
+ elif value is not None:
386
+ # Create icon label if it doesn't exist
387
+ self._icon_label = Label(
388
+ self._header_frame,
389
+ icon=value,
390
+ icon_only=True,
391
+ ttk_class='Expander.TLabel',
392
+ accent=self._header_accent, variant=self._header_variant,
393
+ takefocus=False,
394
+ )
395
+ self._header_frame.register_composite(self._icon_label)
396
+ # Insert at beginning of header
397
+ self._icon_label.pack(side='left', padx=(0, 8), before=self._title_label)
398
+ self._icon_label.bind('<Button-1>', self._on_header_click, add='+')
399
+ return None
400
+
401
+ @configure_delegate('collapsible')
402
+ def _delegate_collapsible(self, value=None):
403
+ """Get or set whether the expander can be toggled."""
404
+ if value is None:
405
+ return self._collapsible
406
+ self._collapsible = value
407
+ if value:
408
+ side = 'left' if self._icon_position == 'before' else 'right'
409
+ self._toggle_button.pack(side=side)
410
+ else:
411
+ self._toggle_button.pack_forget()
412
+ return None
413
+
414
+ @configure_delegate('icon_expanded')
415
+ def _delegate_icon_expanded(self, value=None):
416
+ """Get or set the expanded state chevron icon."""
417
+ if value is None:
418
+ return self._icon_expanded
419
+ self._icon_expanded = value
420
+ if self._expanded:
421
+ self._toggle_button.configure(icon=self._current_chevron_icon)
422
+ return None
423
+
424
+ @configure_delegate('icon_collapsed')
425
+ def _delegate_icon_collapsed(self, value=None):
426
+ """Get or set the collapsed state chevron icon."""
427
+ if value is None:
428
+ return self._icon_collapsed
429
+ self._icon_collapsed = value
430
+ if not self._expanded:
431
+ self._toggle_button.configure(icon=self._current_chevron_icon)
432
+ return None
433
+
434
+ @configure_delegate('value')
435
+ def _delegate_value(self, value=None):
436
+ """Get or set the selection value."""
437
+ if value is None:
438
+ return self._value
439
+ self._value = value
440
+ return None
441
+
442
+ @configure_delegate('compact')
443
+ def _delegate_compact(self, value=None):
444
+ """Get or set compact mode (hides title, shows icon only)."""
445
+ if value is None:
446
+ return self._compact
447
+ self._compact = value
448
+ if value:
449
+ # Hide title
450
+ if self._title_label is not None:
451
+ self._title_label.pack_forget()
452
+ # Center the icon
453
+ if self._icon_label is not None:
454
+ self._icon_label.pack_forget()
455
+ self._icon_label.pack(expand=True)
456
+ else:
457
+ # Restore icon to left-aligned
458
+ if self._icon_label is not None:
459
+ self._icon_label.pack_forget()
460
+ self._icon_label.pack(side='left', padx=(0, 8))
461
+ # Re-pack title in correct position
462
+ if self._title_label is not None:
463
+ if self._icon_position == "before":
464
+ self._title_label.pack(side='left', fill='x', expand=True)
465
+ else:
466
+ # Pack after icon (if exists) or at left
467
+ if self._icon_label is not None:
468
+ self._title_label.pack(side='left', fill='x', expand=True, after=self._icon_label)
469
+ else:
470
+ self._title_label.pack(side='left', fill='x', expand=True)
471
+ return None
472
+
473
+ @configure_delegate('highlight')
474
+ def _delegate_highlight(self, value=None):
475
+ """Get or set highlight mode (shows 'selected' state when expanded)."""
476
+ if value is None:
477
+ return self._highlight
478
+ self._highlight = value
479
+ # Update the current state based on new highlight value
480
+ self._header_frame.set_selected(value and self._expanded)
481
+ return None
482
+
483
+ @configure_delegate('expanded')
484
+ def _delegate_expanded(self, value=None):
485
+ """Get or set the expansion state."""
486
+ if value is None:
487
+ return self._expanded
488
+ if value:
489
+ self.expand()
490
+ else:
491
+ self.collapse()
492
+ return None
493
+
494
+ @configure_delegate('signal')
495
+ def _delegate_signal(self, value=None):
496
+ """Get or set the signal for selection state."""
497
+ if value is None:
498
+ return self._signal
499
+ self._set_signal_or_variable(value)
500
+ return None
501
+
502
+ @configure_delegate('variable')
503
+ def _delegate_variable(self, value=None):
504
+ """Get or set the variable for selection state."""
505
+ if value is None:
506
+ return self._variable
507
+ self._set_signal_or_variable(value)
508
+ return None