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,479 @@
1
+ from __future__ import annotations
2
+
3
+ import tkinter as tk
4
+ from typing import Literal, Optional, Any, Union
5
+
6
+ from bootstack.widgets.primitives.frame import Frame
7
+ from bootstack.widgets.mixins.configure_mixin import configure_delegate
8
+ from bootstack.widgets.types import Master
9
+
10
+ Direction = Literal["vertical", "horizontal", "row", "column", "row-reverse", "column-reverse"]
11
+ Fill = Literal["none", "x", "y", "both"]
12
+ Side = Literal["top", "bottom", "left", "right"]
13
+ Anchor = Literal["n", "ne", "e", "se", "s", "sw", "w", "nw", "center"]
14
+ Sticky = Literal["n", "s", "e", "w", "ns", "ew", "nsew", "ne", "nw", "se", "sw", "nse", "nsw", "new", "sew", ""]
15
+ AutoFlow = Literal["row", "column", "row-dense", "column-dense", "none"]
16
+ Gap = Union[int, tuple[int, int]]
17
+
18
+
19
+ def _parse_size(value: Union[int, str]) -> tuple[int, int]:
20
+ """Parse size value into (weight, minsize) tuple."""
21
+ if isinstance(value, int):
22
+ return value, 0
23
+ if isinstance(value, str):
24
+ if value == "auto":
25
+ return 0, 0
26
+ if value.endswith("px"):
27
+ try:
28
+ return 0, int(value[:-2])
29
+ except ValueError:
30
+ return 0, 0
31
+ return 0, 0
32
+
33
+
34
+ class GridFrame(Frame):
35
+ """A Frame with simplified grid-based layout management and auto-placement.
36
+
37
+ GridFrame extends the bootstack Frame with automatic grid-based
38
+ layout management, including support for row/column definitions,
39
+ gap spacing, auto-placement, and default sticky behavior.
40
+
41
+ Children gridded into this frame automatically receive the frame's
42
+ default layout options. Simply use the standard `grid()` method
43
+ on child widgets — no special `add()` method is needed.
44
+
45
+ Example:
46
+ ```python
47
+ frame = GridFrame(columns=3, gap=10, sticky_items="nsew")
48
+ Label(frame, text="A").grid() # auto-placed at row=0, col=0
49
+ Label(frame, text="B").grid() # auto-placed at row=0, col=1
50
+ Label(frame, text="C").grid() # auto-placed at row=0, col=2
51
+ Label(frame, text="D").grid() # auto-placed at row=1, col=0
52
+ Label(frame, text="Wide").grid(columnspan=2) # spans 2 columns
53
+ ```
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ master: Master = None,
59
+ *,
60
+ rows: Optional[Union[int, list[Union[int, str]]]] = None,
61
+ columns: Optional[Union[int, list[Union[int, str]]]] = None,
62
+ gap: Gap = 0,
63
+ sticky_items: Optional[Sticky] = None,
64
+ propagate: Optional[bool] = None,
65
+ auto_flow: AutoFlow = "row",
66
+ **kwargs: Any,
67
+ ) -> None:
68
+ """Create a GridFrame with automatic grid-based layout.
69
+
70
+ Args:
71
+ master: Parent widget. If None, uses the default root window.
72
+ rows: Number of rows as an `int`, or a list of size specs where each
73
+ spec is an `int` weight or a string such as `'auto'` or `'100px'`.
74
+ columns: Number of columns or a list of size specs (same format as `rows`).
75
+ gap: Spacing between cells. An `int` applies the same gap in both
76
+ directions; a `(col_gap, row_gap)` tuple sets them independently.
77
+ sticky_items: Default `sticky` value applied to all children when
78
+ they call `grid()`. If None, no default sticky is applied.
79
+ propagate: If False, the frame will not resize to fit its contents.
80
+ Defaults to None (Tk default behaviour).
81
+ auto_flow: Auto-placement mode — `'row'` (default), `'column'`,
82
+ `'row-dense'`, `'column-dense'`, or `'none'`.
83
+ **kwargs: Additional keyword arguments forwarded to `Frame`.
84
+ """
85
+ super().__init__(master, **kwargs)
86
+
87
+ self._gap = self._normalize_gap(gap)
88
+ self._default_sticky = sticky_items
89
+ self._auto_flow = auto_flow
90
+
91
+ # Track managed widgets: list of (widget, user_options, computed_position)
92
+ # computed_position is (row, col, rowspan, colspan)
93
+ self._managed: list[tuple[tk.Widget, dict[str, Any], tuple[int, int, int, int]]] = []
94
+
95
+ # Track occupied cells for auto-placement
96
+ self._occupied: set[tuple[int, int]] = set()
97
+
98
+ # Track widgets hidden via grid_remove (still managed, just hidden)
99
+ self._removed: set[tk.Widget] = set()
100
+
101
+ # Auto-placement cursor
102
+ self._next_row = 0
103
+ self._next_col = 0
104
+
105
+ # Parse and store row/column definitions
106
+ self._row_defs: list[tuple[int, int]] = []
107
+ self._col_defs: list[tuple[int, int]] = []
108
+
109
+ if isinstance(rows, int):
110
+ self._row_defs = [(1, 0)] * rows
111
+ elif isinstance(rows, list):
112
+ self._row_defs = [_parse_size(r) for r in rows]
113
+
114
+ if isinstance(columns, int):
115
+ self._col_defs = [(1, 0)] * columns
116
+ elif isinstance(columns, list):
117
+ self._col_defs = [_parse_size(c) for c in columns]
118
+
119
+ # Apply initial row/column configuration
120
+ for i, (weight, minsize) in enumerate(self._row_defs):
121
+ self.rowconfigure(i, weight=weight, minsize=minsize)
122
+ for i, (weight, minsize) in enumerate(self._col_defs):
123
+ self.columnconfigure(i, weight=weight, minsize=minsize)
124
+
125
+ if propagate is not None:
126
+ self.grid_propagate(propagate)
127
+
128
+ @staticmethod
129
+ def _normalize_gap(gap: Gap) -> tuple[int, int]:
130
+ """Normalize gap to (column_gap, row_gap) tuple."""
131
+ if isinstance(gap, int):
132
+ return gap, gap
133
+ return gap
134
+
135
+ @property
136
+ def _column_gap(self) -> int:
137
+ """Get the column gap."""
138
+ return self._gap[0]
139
+
140
+ @property
141
+ def _row_gap(self) -> int:
142
+ """Get the row gap."""
143
+ return self._gap[1]
144
+
145
+ @configure_delegate('gap')
146
+ def _delegate_gap(self, value=None) -> tuple[int, int]:
147
+ """Get or set the gap between cells."""
148
+ if value is None:
149
+ return self._gap
150
+ self._gap = self._normalize_gap(value)
151
+ # Regrid all widgets with new gap
152
+ self._regrid_all()
153
+
154
+ @property
155
+ def _num_columns(self) -> int:
156
+ """Number of defined columns, or a large default for auto-placement."""
157
+ return len(self._col_defs) if self._col_defs else 100
158
+
159
+ @property
160
+ def _num_rows(self) -> int:
161
+ """Number of defined rows, or a large default for auto-placement."""
162
+ return len(self._row_defs) if self._row_defs else 100
163
+
164
+ def _is_area_free(self, row: int, col: int, rowspan: int, colspan: int) -> bool:
165
+ """Check if a rectangular area is free."""
166
+ return all(
167
+ (row + dr, col + dc) not in self._occupied
168
+ for dr in range(rowspan)
169
+ for dc in range(colspan)
170
+ )
171
+
172
+ def _occupy_area(self, row: int, col: int, rowspan: int, colspan: int) -> None:
173
+ """Mark a rectangular area as occupied."""
174
+ for dr in range(rowspan):
175
+ for dc in range(colspan):
176
+ self._occupied.add((row + dr, col + dc))
177
+
178
+ def _free_area(self, row: int, col: int, rowspan: int, colspan: int) -> None:
179
+ """Mark a rectangular area as free."""
180
+ for dr in range(rowspan):
181
+ for dc in range(colspan):
182
+ self._occupied.discard((row + dr, col + dc))
183
+
184
+ def _find_next_position(self, rowspan: int = 1, colspan: int = 1) -> tuple[int, int]:
185
+ """Find the next available position using auto-flow rules."""
186
+ if self._auto_flow == "none":
187
+ return 0, 0
188
+
189
+ max_cols = self._num_columns
190
+ max_rows = self._num_rows
191
+
192
+ if "dense" in self._auto_flow:
193
+ # Dense packing: search from (0,0)
194
+ if self._auto_flow == "row-dense":
195
+ for r in range(max_rows):
196
+ for c in range(max_cols - colspan + 1):
197
+ if self._is_area_free(r, c, rowspan, colspan):
198
+ return r, c
199
+ else: # column-dense
200
+ for c in range(max_cols):
201
+ for r in range(max_rows - rowspan + 1):
202
+ if self._is_area_free(r, c, rowspan, colspan):
203
+ return r, c
204
+ else:
205
+ # Normal flow: continue from cursor
206
+ if self._auto_flow == "row":
207
+ r, c = self._next_row, self._next_col
208
+ while r < max_rows:
209
+ while c <= max_cols - colspan:
210
+ if self._is_area_free(r, c, rowspan, colspan):
211
+ # Update cursor for next placement
212
+ next_c = c + colspan
213
+ if self._col_defs and next_c >= len(self._col_defs):
214
+ self._next_row = r + 1
215
+ self._next_col = 0
216
+ else:
217
+ self._next_row = r
218
+ self._next_col = next_c
219
+ return r, c
220
+ c += 1
221
+ r += 1
222
+ c = 0
223
+ else: # column
224
+ r, c = self._next_row, self._next_col
225
+ while c < max_cols:
226
+ while r <= max_rows - rowspan:
227
+ if self._is_area_free(r, c, rowspan, colspan):
228
+ # Update cursor for next placement
229
+ next_r = r + rowspan
230
+ if self._row_defs and next_r >= len(self._row_defs):
231
+ self._next_col = c + 1
232
+ self._next_row = 0
233
+ else:
234
+ self._next_col = c
235
+ self._next_row = next_r
236
+ return r, c
237
+ r += 1
238
+ c += 1
239
+ r = 0
240
+
241
+ return 0, 0 # Fallback
242
+
243
+ def _compute_gap_padding(
244
+ self, row: int, col: int, user_padx: Any = None, user_pady: Any = None
245
+ ) -> dict[str, Any]:
246
+ """Compute padding that includes gap for non-first rows/columns."""
247
+ result: dict[str, Any] = {}
248
+
249
+ # Handle column gap (padx)
250
+ if col > 0 and self._column_gap:
251
+ gap_padx = (self._column_gap, 0)
252
+ if user_padx is not None:
253
+ result["padx"] = self._merge_padding(gap_padx, user_padx)
254
+ else:
255
+ result["padx"] = gap_padx
256
+ elif user_padx is not None:
257
+ result["padx"] = user_padx
258
+
259
+ # Handle row gap (pady)
260
+ if row > 0 and self._row_gap:
261
+ gap_pady = (self._row_gap, 0)
262
+ if user_pady is not None:
263
+ result["pady"] = self._merge_padding(gap_pady, user_pady)
264
+ else:
265
+ result["pady"] = gap_pady
266
+ elif user_pady is not None:
267
+ result["pady"] = user_pady
268
+
269
+ return result
270
+
271
+ @staticmethod
272
+ def _merge_padding(
273
+ gap_pad: tuple[int, int], user_pad: Any
274
+ ) -> tuple[int, int]:
275
+ """Merge gap padding with user padding."""
276
+ if isinstance(user_pad, int):
277
+ return (gap_pad[0] + user_pad, user_pad)
278
+ elif isinstance(user_pad, (tuple, list)) and len(user_pad) == 2:
279
+ return (gap_pad[0] + user_pad[0], user_pad[1])
280
+ return gap_pad
281
+
282
+ def _build_options(
283
+ self,
284
+ row: int,
285
+ col: int,
286
+ rowspan: int,
287
+ colspan: int,
288
+ user_options: dict[str, Any],
289
+ ) -> dict[str, Any]:
290
+ """Build final grid options."""
291
+ options: dict[str, Any] = {
292
+ "in_": self,
293
+ "row": row,
294
+ "column": col,
295
+ }
296
+
297
+ if rowspan > 1:
298
+ options["rowspan"] = rowspan
299
+ if colspan > 1:
300
+ options["columnspan"] = colspan
301
+
302
+ # Apply gap padding
303
+ gap_padding = self._compute_gap_padding(
304
+ row, col,
305
+ user_options.get("padx"),
306
+ user_options.get("pady")
307
+ )
308
+ options.update(gap_padding)
309
+
310
+ # Apply default sticky
311
+ if self._default_sticky and "sticky" not in user_options:
312
+ options["sticky"] = self._default_sticky
313
+
314
+ # User options override (except padx/pady which we handled)
315
+ for key, value in user_options.items():
316
+ if key not in ("padx", "pady", "row", "column"):
317
+ options[key] = value
318
+
319
+ return options
320
+
321
+ def _regrid_all(self) -> None:
322
+ """Remove and re-grid all widgets."""
323
+ # Ungrid all (except those in _removed which are already hidden)
324
+ for widget, _, _ in self._managed:
325
+ if widget not in self._removed:
326
+ tk.Grid.forget(widget)
327
+
328
+ # Clear and rebuild occupied set
329
+ self._occupied.clear()
330
+ self._next_row = 0
331
+ self._next_col = 0
332
+
333
+ # Regrid in order, recalculating positions
334
+ new_managed: list[tuple[tk.Widget, dict[str, Any], tuple[int, int, int, int]]] = []
335
+
336
+ for widget, user_options, _ in self._managed:
337
+ rowspan = int(user_options.get("rowspan", 1))
338
+ colspan = int(user_options.get("columnspan", 1))
339
+
340
+ # Check if user specified explicit position
341
+ explicit_row = user_options.get("row")
342
+ explicit_col = user_options.get("column")
343
+
344
+ if explicit_row is not None and explicit_col is not None:
345
+ row, col = int(explicit_row), int(explicit_col)
346
+ else:
347
+ row, col = self._find_next_position(rowspan, colspan)
348
+
349
+ self._occupy_area(row, col, rowspan, colspan)
350
+ new_managed.append((widget, user_options, (row, col, rowspan, colspan)))
351
+
352
+ # Only configure visible widgets (not those in _removed)
353
+ if widget not in self._removed:
354
+ options = self._build_options(row, col, rowspan, colspan, user_options)
355
+ tk.Grid.configure(widget, **options)
356
+
357
+ self._managed = new_managed
358
+
359
+ def _find_widget_index(self, widget: tk.Widget) -> int:
360
+ """Find index of widget in managed list, return -1 if not found."""
361
+ for i, (w, _, _) in enumerate(self._managed):
362
+ if w is widget:
363
+ return i
364
+ return -1
365
+
366
+ # -------------------------------------------------------------------------
367
+ # Hook methods called by GridMixin
368
+ # -------------------------------------------------------------------------
369
+
370
+ def _on_child_grid(self, widget: tk.Widget, **options: Any) -> None:
371
+ """Hook called when a child widget calls grid().
372
+
373
+ Applies frame defaults, handles gap spacing, auto-placement, and tracks the widget.
374
+ """
375
+ # Check if widget was hidden via grid_remove and is being restored
376
+ if widget in self._removed and not options:
377
+ # Restore widget to its original position
378
+ self._removed.discard(widget)
379
+ idx = self._find_widget_index(widget)
380
+ if idx >= 0:
381
+ _, user_options, (row, col, rowspan, colspan) = self._managed[idx]
382
+ grid_options = self._build_options(row, col, rowspan, colspan, user_options)
383
+ tk.Grid.configure(widget, **grid_options)
384
+ return
385
+
386
+ # Check if widget is already managed (reconfigure case)
387
+ existing_idx = self._find_widget_index(widget)
388
+
389
+ rowspan = int(options.get("rowspan", 1))
390
+ colspan = int(options.get("columnspan", 1))
391
+
392
+ # Check if user specified explicit position
393
+ explicit_row = options.get("row")
394
+ explicit_col = options.get("column")
395
+
396
+ if existing_idx >= 0:
397
+ # Widget already managed - update its options and regrid all
398
+ _, _, old_pos = self._managed[existing_idx]
399
+ self._free_area(*old_pos)
400
+ self._managed[existing_idx] = (widget, options, (0, 0, 1, 1)) # temp position
401
+ self._regrid_all()
402
+ else:
403
+ # New widget
404
+ if explicit_row is not None and explicit_col is not None:
405
+ row, col = int(explicit_row), int(explicit_col)
406
+ else:
407
+ row, col = self._find_next_position(rowspan, colspan)
408
+
409
+ self._occupy_area(row, col, rowspan, colspan)
410
+ grid_options = self._build_options(row, col, rowspan, colspan, options)
411
+ tk.Grid.configure(widget, **grid_options)
412
+ self._managed.append((widget, options, (row, col, rowspan, colspan)))
413
+
414
+ def _on_child_grid_forget(self, widget: tk.Widget) -> None:
415
+ """Hook called when a child widget calls grid_forget().
416
+
417
+ Removes widget from tracking and frees its occupied area.
418
+ """
419
+ idx = self._find_widget_index(widget)
420
+ if idx < 0:
421
+ # Not managed by us, just forget it normally
422
+ tk.Grid.forget(widget)
423
+ return
424
+
425
+ _, _, (row, col, rowspan, colspan) = self._managed[idx]
426
+ tk.Grid.forget(widget)
427
+ self._free_area(row, col, rowspan, colspan)
428
+ self._managed.pop(idx)
429
+ self._removed.discard(widget) # Clean up if it was in removed set
430
+
431
+ def _on_child_grid_remove(self, widget: tk.Widget) -> None:
432
+ """Hook called when a child widget calls grid_remove().
433
+
434
+ Hides widget but keeps its configuration for later restore via grid().
435
+ The widget's position is preserved so it can be restored with grid().
436
+ """
437
+ idx = self._find_widget_index(widget)
438
+ if idx < 0:
439
+ # Not managed by us, just remove it normally
440
+ tk.Grid.grid_remove(widget)
441
+ return
442
+
443
+ # Hide the widget but keep it in _managed for position restoration
444
+ tk.Grid.grid_remove(widget)
445
+ self._removed.add(widget)
446
+
447
+ # -------------------------------------------------------------------------
448
+ # Public configuration methods
449
+ # -------------------------------------------------------------------------
450
+
451
+ def configure_row(
452
+ self,
453
+ index: int,
454
+ weight: int = 1,
455
+ minsize: Optional[int] = None,
456
+ pad: Optional[int] = None,
457
+ ) -> None:
458
+ """Configure a row's properties."""
459
+ kwargs: dict[str, Any] = {"weight": weight}
460
+ if minsize is not None:
461
+ kwargs["minsize"] = minsize
462
+ if pad is not None:
463
+ kwargs["pad"] = pad
464
+ self.rowconfigure(index, **kwargs)
465
+
466
+ def configure_column(
467
+ self,
468
+ index: int,
469
+ weight: int = 1,
470
+ minsize: Optional[int] = None,
471
+ pad: Optional[int] = None,
472
+ ) -> None:
473
+ """Configure a column's properties."""
474
+ kwargs: dict[str, Any] = {"weight": weight}
475
+ if minsize is not None:
476
+ kwargs["minsize"] = minsize
477
+ if pad is not None:
478
+ kwargs["pad"] = pad
479
+ self.columnconfigure(index, **kwargs)
@@ -0,0 +1,95 @@
1
+ from __future__ import annotations
2
+
3
+ from tkinter import ttk
4
+ from typing import Any, Literal, TYPE_CHECKING, TypedDict
5
+
6
+ from typing_extensions import Unpack
7
+
8
+ from bootstack.core.mixins.ttk_state import TtkStateMixin
9
+ from bootstack.core.mixins.widget import WidgetCapabilitiesMixin
10
+ from bootstack.widgets.internal.wrapper_base import TTKWrapperBase
11
+ from bootstack.widgets.mixins import IconMixin, LocalizationMixin, TextSignalMixin
12
+ from bootstack.widgets.types import Master
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.core.signals import Signal
16
+
17
+
18
+ class LabelKwargs(TypedDict, total=False):
19
+ # Standard ttk.Label options
20
+ text: Any
21
+ image: Any
22
+ icon: Any
23
+ icon_only: bool
24
+ compound: Literal['text', 'image', 'top', 'bottom', 'left', 'right', 'center', 'none'] | str
25
+ anchor: Any
26
+ justify: Any
27
+ padding: Any
28
+ width: int
29
+ wraplength: Any
30
+ font: Any
31
+ foreground: str
32
+ background: str
33
+ relief: Any
34
+ localize: bool | Literal['auto']
35
+ value_format: dict | str
36
+ state: Literal['normal', 'active', 'disabled', 'readonly'] | str
37
+ takefocus: Any
38
+ format_spec: str | dict
39
+ style: str
40
+ class_: str
41
+ cursor: str
42
+ name: str
43
+ textvariable: Any
44
+ textsignal: Signal[str]
45
+
46
+ # bootstack-specific extensions
47
+ bootstyle: str # DEPRECATED: Use accent and variant instead
48
+ accent: str
49
+ variant: str
50
+ surface: str
51
+ style_options: dict[str, Any]
52
+
53
+
54
+ class Label(LocalizationMixin, TextSignalMixin, IconMixin, TTKWrapperBase, WidgetCapabilitiesMixin, TtkStateMixin, ttk.Label):
55
+ """bootstack wrapper for `ttk.Label` with bootstyle and icon support."""
56
+
57
+ _ttk_base = ttk.Label
58
+
59
+ def __init__(self, master: Master = None, **kwargs: Unpack[LabelKwargs]) -> None:
60
+ """Create a themed bootstack Label.
61
+
62
+ Args:
63
+ master: Parent widget. If None, uses the default root window.
64
+
65
+ Other Parameters:
66
+ text (str): Text to display in the label.
67
+ textvariable (Variable): Tk variable linked to the label text.
68
+ textsignal (Signal[str]): Reactive Signal linked to the label text (auto-synced with textvariable).
69
+ image (PhotoImage): Image to display.
70
+ icon (str | dict): Theme-aware icon spec handled by the style system.
71
+ icon_only (bool): If True, removes the additional padding reserved for label text.
72
+ compound (str): Placement of the image relative to text.
73
+ anchor (str): Alignment of the label's content within its area.
74
+ justify (str): How to justify multiple lines of text.
75
+ localize (bool | Literal['auto']): Determines the widget's localization mode.
76
+ value_format (str | dict): Format specification for the label value.
77
+ padding (int | tuple): Extra space around the label content.
78
+ width (int): Width of the label in characters.
79
+ wraplength (int): Maximum width before wrapping text.
80
+ font (str | Font): Font for text.
81
+ foreground (str): Text color.
82
+ background (str): Background color.
83
+ relief (str): Border style.
84
+ state (str): Widget state.
85
+ takefocus (bool): Whether the widget participates in focus traversal.
86
+ style (str): Explicit ttk style name (overrides accent/variant).
87
+ accent (str): Accent token for styling, e.g. 'primary', 'danger', 'success'.
88
+ variant (str): Style variant, e.g. 'default', 'inverse'.
89
+ bootstyle (str): DEPRECATED - Use `accent` and `variant` instead.
90
+ Combined style tokens (e.g., 'secondary', 'info').
91
+ surface (str): Optional surface token; otherwise inherited.
92
+ style_options (dict): Optional dict forwarded to the style builder.
93
+ """
94
+ kwargs.update(style_options=self._capture_style_options(['icon_only', 'icon', 'density'], kwargs))
95
+ super().__init__(master, **kwargs)
@@ -0,0 +1,63 @@
1
+ from __future__ import annotations
2
+
3
+ from tkinter import ttk
4
+ from typing import Any, Literal, TypedDict
5
+
6
+ from typing_extensions import Unpack
7
+
8
+ from bootstack.core.mixins.ttk_state import TtkStateMixin
9
+ from bootstack.core.mixins.widget import WidgetCapabilitiesMixin
10
+ from bootstack.widgets.internal.wrapper_base import TTKWrapperBase
11
+ from bootstack.widgets.mixins import LocalizationMixin
12
+ from bootstack.widgets.types import Master
13
+
14
+
15
+ class LabelFrameKwargs(TypedDict, total=False):
16
+ # Standard ttk.Labelframe options
17
+ text: Any
18
+ labelanchor: Any
19
+ padding: Any
20
+ relief: Any
21
+ borderwidth: Any
22
+ width: int
23
+ height: int
24
+ style: str
25
+ class_: str
26
+ cursor: str
27
+ name: str
28
+
29
+ # bootstack-specific extensions
30
+ bootstyle: str # DEPRECATED: Use accent and variant instead
31
+ accent: str
32
+ surface: str
33
+ style_options: dict[str, Any]
34
+ localize: bool | Literal['auto']
35
+
36
+
37
+ class LabelFrame(LocalizationMixin, TTKWrapperBase, WidgetCapabilitiesMixin, TtkStateMixin, ttk.LabelFrame):
38
+ """bootstack wrapper for `ttk.Labelframe` with bootstyle support."""
39
+
40
+ _ttk_base = ttk.Labelframe
41
+
42
+ def __init__(self, master: Master = None, **kwargs: Unpack[LabelFrameKwargs]) -> None:
43
+ """Create a themed bootstack Labelframe.
44
+
45
+ Args:
46
+ master: Parent widget. If None, uses the default root window.
47
+
48
+ Other Parameters:
49
+ text (str): Text for the embedded label.
50
+ labelanchor (str): Position of the label relative to the frame.
51
+ padding (int | tuple): Extra internal padding.
52
+ relief (str): Border style.
53
+ borderwidth (int): Border width.
54
+ width (int): Requested width in pixels.
55
+ height (int): Requested height in pixels.
56
+ style (str): Explicit ttk style name (overrides accent/variant).
57
+ accent (str): Accent token for styling, e.g. 'primary', 'secondary'.
58
+ bootstyle (str): DEPRECATED - Use `accent` instead.
59
+ surface (str): Optional surface token; otherwise inherited.
60
+ style_options (dict): Optional dict forwarded to the style builder.
61
+ localize (bool | Literal['auto']): Determines the widget's localization mode.
62
+ """
63
+ super().__init__(master, **kwargs)