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,269 @@
1
+ """Treeview widget style builders.
2
+
3
+ This module contains style builders for ttk.Treeview widget and variants.
4
+
5
+ TODO there is a strange bug that causes the treeview to request more size when the custom border element is used.
6
+ """
7
+ import tkinter as tk
8
+ from tkinter import font
9
+
10
+ from ttkbootstrap_icons_bs import BootstrapIcon
11
+ from bootstack.style.bootstyle_builder_ttk import BootstyleBuilderTTk
12
+ from bootstack.style.element import Element, ElementImage
13
+ from bootstack.style.utility import create_transparent_image, recolor_element_image
14
+ from bootstack.style.builders.utils import normalize_button_density
15
+
16
+
17
+ def _tk_version_at_least(major: int, minor: int, patch: int) -> bool:
18
+ """Check if the current Tk version is at least the specified version.
19
+
20
+ This is used to work around a regression in Tk 8.6.13+ where user1/user2
21
+ states don't work properly with custom image elements for treeview indicators.
22
+ See: https://core.tcl-lang.org/tk/timeline?r=rfe-d632d28ba4
23
+ """
24
+ try:
25
+ version_str = tk._default_root.tk.call('info', 'patchlevel')
26
+ parts = version_str.split('.')
27
+ current = (int(parts[0]), int(parts[1]), int(parts[2]))
28
+ return current >= (major, minor, patch)
29
+ except Exception:
30
+ # If we can't determine version, assume newer Tk (safer fallback)
31
+ return True
32
+
33
+
34
+ def _treeview_font(density: str) -> str:
35
+ """Get font token based on density."""
36
+ return 'caption' if density == 'compact' else 'body'
37
+
38
+
39
+ def _treeview_row_height(density: str) -> float:
40
+ """Get row height multiplier based on density."""
41
+ return 1.6 if density == 'compact' else 1.75
42
+
43
+
44
+ def _treeview_indicator_size(density: str) -> int:
45
+ """Get indicator size based on density."""
46
+ return 10 if density == 'compact' else 12
47
+
48
+
49
+ def _treeview_icon_size(density: str) -> int:
50
+ """Get custom icon size based on density."""
51
+ return 12 if density == 'compact' else 16
52
+
53
+
54
+ def _treeview_item_padding(density: str) -> tuple[int, int]:
55
+ """Get item padding based on density."""
56
+ return (4, 0) if density == 'compact' else (6, 0)
57
+
58
+
59
+ def _treeview_heading_padding(density: str) -> tuple[int, int]:
60
+ """Get heading padding based on density."""
61
+ return (4, 4) if density == 'compact' else (8, 10)
62
+
63
+
64
+ def _treeview_cell_padding(density: str) -> tuple[int, int]:
65
+ """Get cell padding based on density."""
66
+ return (2, 0) if density == 'compact' else (6, 0)
67
+
68
+
69
+ @BootstyleBuilderTTk.register_builder('default', 'Treeview')
70
+ @BootstyleBuilderTTk.register_builder('tree', 'Treeview')
71
+ def build_tree_style(b: BootstyleBuilderTTk, ttk_style: str, **options):
72
+ """
73
+ Create treeview style.
74
+
75
+ Available options via `style_options`:
76
+ * border_color
77
+ * show_border
78
+ * open_icon
79
+ * close_icon
80
+ * select_background
81
+ * header_background
82
+ * density ('default' or 'compact')
83
+ """
84
+ surface_token = options.get('surface', 'content')
85
+ density = normalize_button_density(options.get('density', 'default'))
86
+ surface = b.color(surface_token)
87
+
88
+ if options.get('show_border', True):
89
+ if options.get('border_color'):
90
+ border_color = b.color(options.get('border_color'))
91
+ else:
92
+ border_color = b.border(surface)
93
+ else:
94
+ border_color = surface
95
+
96
+ if options.get('header_background'):
97
+ heading_color = b.color(options.get('header_background'))
98
+ heading_hover = b.active(heading_color)
99
+ else:
100
+ heading_color = b.elevate(surface, 3)
101
+ heading_hover = b.active(heading_color)
102
+
103
+ on_heading = b.on_color(heading_color)
104
+ on_surface = b.on_color(surface)
105
+ on_surface_disabled = b.disabled('text', surface)
106
+ hover = b.active(surface)
107
+
108
+ select_background_token = options.get('select_background', 'primary')
109
+ select_background = b.color(select_background_token)
110
+ select_hover = b.active(select_background)
111
+ on_select = b.on_color(select_background)
112
+
113
+ # Density-based sizing
114
+ body_font = _treeview_font(density)
115
+ row_multiplier = _treeview_row_height(density)
116
+ indicator_size = _treeview_indicator_size(density)
117
+ item_padding = _treeview_item_padding(density)
118
+ heading_padding = _treeview_heading_padding(density)
119
+ cell_padding = _treeview_cell_padding(density)
120
+
121
+ # Calculate row height - use TkDefaultFont for metrics when using font spec
122
+ metrics_font = 'TkDefaultFont' if body_font.startswith('-') else body_font
123
+ f = font.nametofont(metrics_font)
124
+ row_height = int(f.metrics()['linespace'] * row_multiplier)
125
+
126
+ # Tk 8.6.13+ has a regression where user1/user2 states don't work with
127
+ # custom image elements for treeview indicators. Use native indicator on
128
+ # newer Tk versions until TIP #719 lands with proper open/leaf states.
129
+ # See: https://core.tcl-lang.org/tk/timeline?r=rfe-d632d28ba4
130
+ use_native_indicator = _tk_version_at_least(8, 6, 13)
131
+
132
+ if use_native_indicator:
133
+ # Use native Treeitem.indicator with custom foreground colors
134
+ # The native indicator uses triangles that rotate based on open/closed state
135
+ # Create a spacer element to add space between indicator and text
136
+ spacer_width = 8 if density == 'compact' else 8
137
+ spacer = create_transparent_image(b.scale(spacer_width), 1)
138
+ b.create_style_element_image(
139
+ ElementImage(f'{ttk_style}.spacer', spacer, sticky='', width=b.scale(spacer_width))
140
+ )
141
+
142
+ b.create_style_layout(
143
+ f'{ttk_style}.Item',
144
+ Element('Treeitem.padding').children(
145
+ [
146
+ Element('Treeitem.indicator', side='left', sticky=''),
147
+ Element(f'{ttk_style}.spacer', side='left', sticky=''),
148
+ Element('Treeitem.image', side='left', sticky=''),
149
+ Element('Treeitem.text', side='left', sticky='w')
150
+ ])
151
+ )
152
+
153
+ indicator_margins = (0, 0, 0, 2) if density == 'compact' else (0, 0, 0, 2)
154
+ b.configure_style(
155
+ f'{ttk_style}.Item',
156
+ padding=b.scale(item_padding),
157
+ foreground=on_surface,
158
+ indicatorsize=b.scale(indicator_size),
159
+ indicatormargins=b.scale(indicator_margins)
160
+ )
161
+ b.map_style(
162
+ f'{ttk_style}.Item',
163
+ foreground=[
164
+ ('selected', on_select),
165
+ ('', on_surface)
166
+ ]
167
+ )
168
+ else:
169
+ # Use custom image indicator with user1/user2 states (works on Tk < 8.6.13)
170
+ open_icon = options.get('open_icon', 'chevron-right')
171
+ closed_icon = options.get('close_icon', 'chevron-down')
172
+ icon_size = b.scale(_treeview_icon_size(density))
173
+
174
+ expand_icon_normal = BootstrapIcon(open_icon, icon_size, on_surface).image
175
+ expand_icon_selected = BootstrapIcon(open_icon, icon_size, on_select).image
176
+ collapse_icon_normal = BootstrapIcon(closed_icon, icon_size, on_surface).image
177
+ collapse_icon_selected = BootstrapIcon(closed_icon, icon_size, on_select).image
178
+ leaf = create_transparent_image(icon_size, icon_size)
179
+
180
+ indicator_height = 12 if density == 'compact' else 14
181
+ b.create_style_element_image(
182
+ ElementImage(
183
+ f'{ttk_style}.indicator', expand_icon_normal,
184
+ sticky='w', height=b.scale(indicator_height), width=b.scale(icon_size + 10)).state_specs(
185
+ [
186
+ ('user2', leaf),
187
+ ('user1 selected', collapse_icon_selected),
188
+ ('user1', collapse_icon_normal),
189
+ ('!user1 selected', expand_icon_selected),
190
+ ])
191
+ )
192
+
193
+ b.create_style_layout(
194
+ f'{ttk_style}.Item',
195
+ Element('Treeitem.padding').children(
196
+ [
197
+ Element(f'{ttk_style}.indicator', side='left', sticky=''),
198
+ Element('Treeitem.image', side='left', sticky=''),
199
+ Element('Treeitem.text', side='left', sticky='w')
200
+ ])
201
+ )
202
+
203
+ b.configure_style(f'{ttk_style}.Item', padding=b.scale(item_padding))
204
+
205
+ # customize the tree field
206
+ border_img = recolor_element_image('border', surface, border_color, surface, surface)
207
+
208
+ b.create_style_element_image(
209
+ ElementImage(
210
+ f'{ttk_style}.field', border_img.image, sticky='nsew',
211
+ border=border_img.meta.border, padding=border_img.meta.border,
212
+ width=0, height=0
213
+ )
214
+ )
215
+
216
+ b.create_style_layout(
217
+ ttk_style, Element(f'{ttk_style}.field', sticky="nsew").children(
218
+ [
219
+ Element('Treeview.padding', sticky="nsew").children(
220
+ [
221
+ Element('Treeview.treearea', sticky="nsew")
222
+ ]),
223
+ ]))
224
+
225
+ # configure header
226
+ heading_font = 'caption' if density == 'compact' else 'label'
227
+ b.configure_style(
228
+ f'{ttk_style}.Heading',
229
+ font=heading_font,
230
+ background=heading_color,
231
+ foreground=on_heading,
232
+ padding=b.scale(heading_padding)
233
+ )
234
+ b.map_style(
235
+ f'{ttk_style}.Heading',
236
+ foreground=[('disabled', on_surface_disabled), ('', on_heading)],
237
+ background=[('active !disabled', heading_hover), ('', heading_color)]
238
+ )
239
+
240
+ # configure tree body
241
+ b.configure_style(
242
+ ttk_style,
243
+ font=body_font,
244
+ background=surface,
245
+ fieldbackground=surface,
246
+ foreground=on_surface,
247
+ borderwidth=0,
248
+ padding=0,
249
+ rowheight=row_height,
250
+ relief='flat'
251
+ )
252
+
253
+ b.map_style(
254
+ ttk_style,
255
+ background=[
256
+ ('active !disabled', hover),
257
+ ('selected active !disabled', select_hover),
258
+ ('selected !disabled', select_background)
259
+ # do not set fallback or it will override tag formats
260
+ ],
261
+ foreground=[
262
+ ('disabled', on_surface_disabled),
263
+ ('selected !disabled', on_select)
264
+ # do not set fallback or it will override tag formats
265
+ ]
266
+ )
267
+
268
+ # configure cell
269
+ b.configure_style(f"{ttk_style}.Cell", font=body_font, padding=b.scale(cell_padding))
@@ -0,0 +1,404 @@
1
+ """Utility functions for style builders.
2
+
3
+ This module provides common utilities used across builder functions,
4
+ including accent extraction, variant parsing, and style name manipulation.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Any, Optional
10
+
11
+ from bootstack.style.element import Element
12
+
13
+ if TYPE_CHECKING:
14
+ from bootstack.style.bootstyle_builder_ttk import BootstyleBuilderTTk
15
+
16
+ # Standard bootstack color tokens
17
+ COLORS = {
18
+ 'primary', 'secondary', 'success', 'info',
19
+ 'warning', 'danger', 'light', 'dark', 'blue'
20
+ }
21
+
22
+
23
+ def extract_accent_from_style(ttk_style: str, default: str = 'primary') -> str:
24
+ """Extract accent token from TTK style name.
25
+
26
+ Args:
27
+ ttk_style: Full TTK style name (e.g., "custom_abc.success.Outline.TButton")
28
+ default: Default accent if none found
29
+
30
+ Returns:
31
+ Accent token name (e.g., "success")
32
+
33
+ Examples:
34
+ >>> extract_accent_from_style("success.Outline.TButton")
35
+ 'success'
36
+ >>> extract_accent_from_style("custom_abc.danger.TLabel")
37
+ 'danger'
38
+ >>> extract_accent_from_style("TButton")
39
+ 'primary'
40
+ """
41
+ # Remove custom prefix if present
42
+ parts = ttk_style.split('.')
43
+ if parts and parts[0].startswith('custom_'):
44
+ parts = parts[1:]
45
+
46
+ # Find accent in parts
47
+ for part in parts:
48
+ if part.lower() in COLORS:
49
+ return part.lower()
50
+
51
+ return default
52
+
53
+
54
+ def extract_variant_from_style(ttk_style: str) -> Optional[str]:
55
+ """Extract variant name from TTK style name.
56
+
57
+ Args:
58
+ ttk_style: Full TTK style name (e.g., "success.Outline.TButton")
59
+
60
+ Returns:
61
+ Variant name (lowercase) or None
62
+
63
+ Examples:
64
+ >>> extract_variant_from_style("success.Outline.TButton")
65
+ 'outline'
66
+ >>> extract_variant_from_style("primary.TLabel") is None
67
+ True
68
+ """
69
+ parts = ttk_style.split('.')
70
+
71
+ # Remove custom prefix if present
72
+ if parts and parts[0].startswith('custom_'):
73
+ parts = parts[1:]
74
+
75
+ # Find variant (not accent, not widget class)
76
+ for part in parts:
77
+ part_lower = part.lower()
78
+ if part_lower not in COLORS and not part.startswith('T'):
79
+ return part_lower
80
+
81
+ return None
82
+
83
+
84
+ def extract_widget_class_from_style(ttk_style: str) -> Optional[str]:
85
+ """Extract widget class from TTK style name.
86
+
87
+ Args:
88
+ ttk_style: Full TTK style name (e.g., "success.Outline.TButton")
89
+
90
+ Returns:
91
+ Widget class name or None
92
+
93
+ Examples:
94
+ >>> extract_widget_class_from_style("success.Outline.TButton")
95
+ 'TButton'
96
+ >>> extract_widget_class_from_style("primary.TLabel")
97
+ 'TLabel'
98
+ """
99
+ parts = ttk_style.split('.')
100
+
101
+ # Find widget class (starts with 'T')
102
+ for part in parts:
103
+ if part.startswith('T'):
104
+ return part
105
+
106
+ return None
107
+
108
+
109
+ def parse_style_components(ttk_style: str) -> dict:
110
+ """Parse TTK style name into all components.
111
+
112
+ Args:
113
+ ttk_style: Full TTK style name
114
+
115
+ Returns:
116
+ Dictionary with parsed components:
117
+ {
118
+ 'custom_prefix': 'custom_abc123' or None,
119
+ 'accent': 'success' or default,
120
+ 'variant': 'outline' or None,
121
+ 'widget_class': 'TButton'
122
+ }
123
+
124
+ Examples:
125
+ >>> parse_style_components("custom_abc.success.Outline.TButton")
126
+ {'custom_prefix': 'custom_abc', 'accent': 'success', 'variant': 'outline', 'widget_class': 'TButton'}
127
+ >>> parse_style_components("danger.TLabel")
128
+ {'custom_prefix': None, 'accent': 'danger', 'variant': None, 'widget_class': 'TLabel'}
129
+ """
130
+ parts = ttk_style.split('.')
131
+
132
+ # Check for custom prefix
133
+ custom_prefix = None
134
+ if parts and parts[0].startswith('custom_'):
135
+ custom_prefix = parts[0]
136
+
137
+ return {
138
+ 'custom_prefix': custom_prefix,
139
+ 'accent': extract_accent_from_style(ttk_style),
140
+ 'variant': extract_variant_from_style(ttk_style),
141
+ 'widget_class': extract_widget_class_from_style(ttk_style),
142
+ }
143
+
144
+
145
+ # Button utilities
146
+ # These utilities are used by button style builders and can be reused by other widgets.
147
+
148
+ # Valid button densities: 'default' (normal) and 'compact' (smaller/tighter)
149
+ BUTTON_DENSITIES = {'default', 'compact'}
150
+
151
+
152
+ def normalize_button_density(density: str) -> str:
153
+ """Normalize button density to valid values ('default' or 'compact').
154
+
155
+ Args:
156
+ density: The requested button density.
157
+
158
+ Returns:
159
+ 'compact' for compact buttons, 'default' for all other densities.
160
+ """
161
+ return 'compact' if density == 'compact' else 'default'
162
+
163
+
164
+ def button_layout(ttk_style: str) -> Element:
165
+ """Create the standard button element layout.
166
+
167
+ Args:
168
+ ttk_style: The TTK style name prefix for the button.
169
+
170
+ Returns:
171
+ Element tree representing the button layout.
172
+ """
173
+ return Element(f"{ttk_style}.Button.border", sticky="nsew").children(
174
+ [
175
+ Element("Button.padding", sticky="nsew").children(
176
+ [
177
+ Element("Button.label", sticky="nsew")
178
+ ])
179
+ ])
180
+
181
+
182
+ def toolbutton_layout(ttk_style: str) -> Element:
183
+ """Create the standard toolbutton element layout.
184
+
185
+ Args:
186
+ ttk_style: The TTK style name prefix for the toolbutton.
187
+
188
+ Returns:
189
+ Element tree representing the toolbutton layout.
190
+ """
191
+ return Element(f"{ttk_style}.border", sticky="nsew").children(
192
+ [
193
+ Element("Toolbutton.padding", sticky="nsew").children(
194
+ [
195
+ Element("Toolbutton.label", sticky="nsew")
196
+ ])
197
+ ])
198
+
199
+
200
+ def icon_size(icon_only: bool, density: str) -> int:
201
+ """Determine icon size based on button density and icon_only flag.
202
+
203
+ Args:
204
+ icon_only: Whether the button displays only an icon (no text).
205
+ density: The button density ('default' or 'compact').
206
+
207
+ Returns:
208
+ The icon size in pixels.
209
+ """
210
+ from tkinter import font
211
+
212
+ if icon_only:
213
+ return 23 if density != 'compact' else 18
214
+
215
+ # Get icon size from font ascent for proper alignment with text
216
+ # Different buffers compensate for y_bias effect per density
217
+ font_name = 'caption' if density == 'compact' else 'body'
218
+ f = font.nametofont(font_name)
219
+ buffer = 4 if density == 'compact' else 3
220
+ return f.metrics()['ascent'] + buffer
221
+
222
+
223
+ def button_font(density: str) -> str:
224
+ """Get the font token for a button based on its density.
225
+
226
+ Args:
227
+ density: The button density ('default' or 'compact').
228
+
229
+ Returns:
230
+ The font token name.
231
+ """
232
+ return 'caption' if density == 'compact' else 'body'
233
+
234
+
235
+ def button_padding(b: BootstyleBuilderTTk, icon_only: bool, density: Any) -> int | tuple[int, ...]:
236
+ """Calculate button padding based on options.
237
+
238
+ Args:
239
+ b: The bootstyle builder instance.
240
+ icon_only: Whether the button displays only an icon.
241
+ density: The button density ('default' or 'compact').
242
+
243
+ Returns:
244
+ Padding value (0 for icon_only, scaled tuple otherwise).
245
+ """
246
+ if icon_only:
247
+ return b.scale((2, 3, 2, 3)) if density == 'compact' else 0
248
+ if density == 'compact':
249
+ # (left, top, right, bottom) - extra top padding to center text
250
+ return b.scale((6, 5, 6, 3))
251
+ return b.scale((8, 0))
252
+
253
+
254
+ def apply_icon_mapping(
255
+ b: BootstyleBuilderTTk,
256
+ options: dict,
257
+ state_spec: dict,
258
+ default_size: int | None = None
259
+ ) -> dict:
260
+ """Apply icon mapping to a state specification dictionary.
261
+
262
+ Args:
263
+ b: The bootstyle builder instance.
264
+ options: Style options dictionary containing 'icon' and 'icon_only' keys.
265
+ state_spec: The state specification dictionary to update.
266
+ default_size: Default icon size, or None to use normalize_icon_spec defaults.
267
+
268
+ Returns:
269
+ Updated state_spec with icon mappings applied.
270
+ """
271
+ icon = options.get('icon')
272
+ if icon is None:
273
+ return state_spec
274
+
275
+ if default_size is None:
276
+ icon = b.normalize_icon_spec(icon)
277
+ else:
278
+ icon = b.normalize_icon_spec(icon, default_size)
279
+
280
+ state_spec['image'] = b.map_stateful_icons(icon, state_spec['foreground'])
281
+ # Set compound to 'left' so text is visible alongside the icon
282
+ icon_only = options.get('icon_only', False)
283
+ if not icon_only:
284
+ state_spec['compound'] = 'left'
285
+ return state_spec
286
+
287
+
288
+ # Entry/Field utilities
289
+ # These utilities are used by entry-type style builders (Entry, Combobox, Spinbox, Field).
290
+
291
+ def entry_font(density: str) -> str:
292
+ """Get the font for an entry widget based on its density.
293
+
294
+ Args:
295
+ density: The entry density ('default' or 'compact').
296
+
297
+ Returns:
298
+ The Tk font name.
299
+ """
300
+ from bootstack.style.typography import get_font
301
+ font_token = 'caption' if density == 'compact' else 'body'
302
+ return str(get_font(font_token))
303
+
304
+
305
+ def entry_padding(b: BootstyleBuilderTTk, density: str) -> tuple:
306
+ """Get entry padding based on density.
307
+
308
+ Args:
309
+ b: The bootstyle builder instance.
310
+ density: The entry density ('default' or 'compact').
311
+
312
+ Returns:
313
+ Scaled padding tuple (horizontal, vertical).
314
+ """
315
+ if density == 'compact':
316
+ return b.scale((6, 0))
317
+ return b.scale((6, 0))
318
+
319
+ def field_height(b: BootstyleBuilderTTk, density: str) -> int:
320
+ """Get entry element height based on density.
321
+
322
+ Args:
323
+ b: The bootstyle builder instance.
324
+ density: The entry density ('default' or 'compact').
325
+
326
+ Returns:
327
+ Scaled height in pixels.
328
+ """
329
+ return b.scale(26) if density == 'compact' else b.scale(33)
330
+
331
+ def entry_height(b: BootstyleBuilderTTk, density: str) -> int:
332
+ """Get entry element height based on density.
333
+
334
+ Args:
335
+ b: The bootstyle builder instance.
336
+ density: The entry density ('default' or 'compact').
337
+
338
+ Returns:
339
+ Scaled height in pixels.
340
+ """
341
+ return b.scale(25) if density == 'compact' else b.scale(31)
342
+
343
+
344
+ def entry_icon_size(b: BootstyleBuilderTTk, density: str) -> int:
345
+ """Get icon size for entry widgets (chevrons, spinner arrows).
346
+
347
+ Args:
348
+ b: The bootstyle builder instance.
349
+ density: The entry density ('default' or 'compact').
350
+
351
+ Returns:
352
+ Scaled icon size in pixels.
353
+ """
354
+ return b.scale(12) if density == 'compact' else b.scale(14)
355
+
356
+
357
+ def entry_image_key(base: str, density: str) -> str:
358
+ """Get density-aware manifest key for entry elements.
359
+
360
+ Args:
361
+ base: Base key name (e.g., 'input', 'input_before', 'input_after').
362
+ density: The entry density ('default' or 'compact').
363
+
364
+ Returns:
365
+ Full manifest key with density suffix (e.g., 'input_default', 'input_compact').
366
+ """
367
+ return f'{base}_{density}'
368
+
369
+
370
+ def spinner_arrow_height(b: BootstyleBuilderTTk, density: str) -> int:
371
+ """Get height for spinner arrow elements based on density.
372
+
373
+ Args:
374
+ b: The bootstyle builder instance.
375
+ density: The entry density ('default' or 'compact').
376
+
377
+ Returns:
378
+ Scaled arrow height in pixels.
379
+ """
380
+ return b.scale(10) if density == 'compact' else b.scale(13)
381
+
382
+
383
+ def spinner_arrow_width(b: BootstyleBuilderTTk) -> int:
384
+ """Get width for spinner arrow elements.
385
+
386
+ Args:
387
+ b: The bootstyle builder instance.
388
+
389
+ Returns:
390
+ Scaled arrow width in pixels.
391
+ """
392
+ return b.scale(16)
393
+
394
+
395
+ def chevron_width(b: BootstyleBuilderTTk) -> int:
396
+ """Get width for combobox chevron element.
397
+
398
+ Args:
399
+ b: The bootstyle builder instance.
400
+
401
+ Returns:
402
+ Scaled chevron width in pixels.
403
+ """
404
+ return b.scale(16)
@@ -0,0 +1,16 @@
1
+ """Tk (legacy tkinter) widget builders for bootstack.
2
+
3
+ Importing this package registers default builder functions for common Tk
4
+ widgets using the BootstyleBuilderTk registry. Builders receive the actual
5
+ widget instance, plus theme/color utilities via the builder object.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ # Import defaults to trigger registration
11
+ from . import defaults # noqa: F401
12
+
13
+ __all__ = [
14
+ 'defaults',
15
+ ]
16
+