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,234 @@
1
+ """Color utility functions for bootstack.
2
+
3
+ This module provides utilities for converting between different color models
4
+ and manipulating colors (adjusting hue, saturation, luminance).
5
+
6
+ Supported color models:
7
+ - RGB: Red, Green, Blue tuple (0-255)
8
+ - HSL: Hue (0-360), Saturation (0-100), Luminance (0-100)
9
+ - HEX: Hexadecimal color string (#RRGGBB)
10
+ - NAME: Named colors (e.g., 'red', 'blue')
11
+
12
+ Functions:
13
+ color_to_rgb: Convert any color model to RGB
14
+ color_to_hex: Convert any color model to HEX
15
+ color_to_hsl: Convert any color model to HSL
16
+ update_color: Modify HSL values of a color
17
+ contrast_color: Get contrasting foreground color for readability
18
+
19
+ Example:
20
+ ```python
21
+ from bootstack.colorutils import *
22
+
23
+ # Convert hex to RGB
24
+ rgb = color_to_rgb('#FF5733', model=HEX) # (255, 87, 51)
25
+
26
+ # Adjust color lightness
27
+ lighter = update_color('#FF5733', lum=80, inmodel=HEX, outmodel=HEX)
28
+
29
+ # Get contrasting text color
30
+ fg_color = contrast_color('#FF5733') # Returns 'white' or 'black'
31
+ ```
32
+ """
33
+ from PIL import ImageColor
34
+ from colorsys import rgb_to_hls
35
+
36
+ RGB = 'rgb'
37
+ HSL = 'hsl'
38
+ HEX = 'hex'
39
+ NAME = 'name'
40
+
41
+ HUE = 360
42
+ SAT = 100
43
+ LUM = 100
44
+
45
+
46
+ def color_to_rgb(color, model=HEX):
47
+ """Convert color value to rgb.
48
+
49
+ The color and model parameters represent the color to be converted.
50
+ The value is expected to be a string for "name" and "hex" models and
51
+ a Tuple or List for "rgb" and "hsl" models.
52
+
53
+ Parameters:
54
+
55
+ color (Any):
56
+ The color values for the model being converted.
57
+
58
+ model (str):
59
+ The color model being converted.
60
+
61
+ Returns:
62
+
63
+ tuple[int, int, int]:
64
+ The rgb color values.
65
+ """
66
+ color_ = conform_color_model(color, model)
67
+ return ImageColor.getrgb(color_)
68
+
69
+
70
+ def color_to_hex(color, model=RGB):
71
+ """Convert color value to hex.
72
+
73
+ The color and model parameters represent the color to be converted.
74
+ The value is expected to be a string for "name" and "hex" models and
75
+ a Tuple or List for "rgb" and "hsl" models.
76
+
77
+ Parameters:
78
+
79
+ color (Any):
80
+ The color values for the model being converted.
81
+
82
+ model (str):
83
+ The color model being converted.
84
+
85
+ Returns:
86
+
87
+ str:
88
+ The hexadecimal color value.
89
+ """
90
+ r, g, b = color_to_rgb(color, model)
91
+ return f'#{r:02x}{g:02x}{b:02x}'
92
+
93
+ def color_to_hsl(color, model=HEX):
94
+ """Convert color value to hsl.
95
+
96
+ The color and model parameters represent the color to be converted.
97
+ The value is expected to be a string for "name" and "hex" models and
98
+ a Tuple or List for "rgb" and "hsl" models.
99
+
100
+ Parameters:
101
+
102
+ color (Any):
103
+ The color values for the model being converted.
104
+
105
+ model (str):
106
+ The color model being converted.
107
+
108
+ Returns:
109
+
110
+ tuple[int, int, int]:
111
+ The hsl color values.
112
+ """
113
+ r, g, b = color_to_rgb(color, model)
114
+ hls = rgb_to_hls(r/255, g/255, b/255)
115
+ h = int(hls[0]*HUE)
116
+ l = int(hls[1]*LUM)
117
+ s = int(hls[2]*SAT)
118
+ return h, s, l
119
+
120
+ def update_hsl_value(color, hue=None, sat=None, lum=None, inmodel=HSL, outmodel=HSL):
121
+ """Change hue, saturation, or lumenosity of the color based on the
122
+ hue, sat, lum parameters provided.
123
+
124
+ Parameters:
125
+
126
+ color (Any):
127
+ The color
128
+
129
+ hue (int):
130
+ A number between 0 and 360.
131
+
132
+ sat (int):
133
+ A number between 0 and 100.
134
+
135
+ lum (int):
136
+ A number between 0 and 100.
137
+
138
+ inmodel (str):
139
+ The color model used by the color to be changed. One of
140
+ hsl, rgb, hex, name.
141
+
142
+ outmodel (str):
143
+ The color value model to be returned when the color is
144
+ changed. One of hsl, rgb, hex.
145
+
146
+ Returns:
147
+
148
+ Union[tuple[int, int, int], str]:
149
+ The color value based on the selected color model.
150
+ """
151
+ h, s, l = color_to_hsl(color, inmodel)
152
+ if hue is not None:
153
+ h = hue
154
+ if sat is not None:
155
+ s = sat
156
+ if lum is not None:
157
+ l = lum
158
+ if outmodel == RGB:
159
+ return color_to_rgb([h, s, l], HSL)
160
+ elif outmodel == HEX:
161
+ return color_to_hex([h, s, l], HSL)
162
+ else:
163
+ return h, s, l
164
+
165
+
166
+ """
167
+ https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color
168
+
169
+ """
170
+
171
+ def contrast_color(color, model=RGB, darkcolor='#000', lightcolor='#fff'):
172
+ """Returns the best matching contrasting light or dark color for
173
+ the given color.
174
+
175
+ Parameters:
176
+
177
+ color (Any):
178
+ The color value to evaluate.
179
+
180
+ model (str):
181
+ The model of the color value to be evaluated. 'rgb' by
182
+ default.
183
+
184
+ darkcolor (Any):
185
+ The color value to be returned when the constrasting color
186
+ should be dark.
187
+
188
+ lightcolor (Any):
189
+ The color value to be returned when the constrasting color
190
+ should be light.
191
+
192
+ Returns:
193
+
194
+ str:
195
+ The matching color value.
196
+ """
197
+ if model != RGB:
198
+ r, g, b = color_to_rgb(color, model)
199
+ else:
200
+ r, g, b = color
201
+
202
+ luminance = ((0.299 * r) + (0.587 * g) + (0.114 * b))/255
203
+ if luminance > 0.5:
204
+ return darkcolor
205
+ else:
206
+ return lightcolor
207
+
208
+
209
+ def conform_color_model(color, model):
210
+ """Conform the color values to a string that can be interpreted
211
+ by the `PIL.ImageColor.getrgb method`.
212
+
213
+ Parameters:
214
+
215
+ color (Union[tuple[int, int, int], str]):
216
+ The color value to conform.
217
+
218
+ model (str):
219
+ One of 'HSL', 'RGB', or 'HEX'
220
+
221
+ Returns:
222
+
223
+ str:
224
+ A color value string that can be used as a parameter in the
225
+ PIL.ImageColor.getrgb method.
226
+ """
227
+ if model == HSL:
228
+ h, s, l = color
229
+ return f'hsl({h},{s}%,{l}%)'
230
+ elif model == RGB:
231
+ r, g, b = color
232
+ return f'rgb({r},{g},{b})'
233
+ else:
234
+ return color
@@ -0,0 +1,95 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+
6
+ class TTKBootstrapError(Exception):
7
+ """Base for all bootstack errors."""
8
+ __slots__ = ("hint", "code", "widget_id")
9
+
10
+ def __init__(
11
+ self, message: str, *, hint: Optional[str] = None,
12
+ code: Optional[str] = None, widget_id: Optional[str] = None):
13
+ """Create a bootstack error.
14
+
15
+ Args:
16
+ message: Human-readable description of what went wrong.
17
+ hint: Optional suggestion for how to resolve the error.
18
+ code: Optional machine-readable error code for programmatic handling.
19
+ widget_id: Optional Tk widget path string identifying the source widget.
20
+ """
21
+ super().__init__(message)
22
+ self.hint = hint
23
+ self.code = code
24
+ self.widget_id = widget_id
25
+
26
+ def __str__(self) -> str:
27
+ base = super().__str__()
28
+ if self.hint:
29
+ return f"{base} — Hint: {self.hint}"
30
+ return base
31
+
32
+
33
+ class LayoutError(TTKBootstrapError):
34
+ """Raised when a widget layout operation fails.
35
+
36
+ Examples: invalid geometry manager usage, pane configuration errors,
37
+ or attempting to pack/grid/place a widget into an incompatible container.
38
+ """
39
+
40
+
41
+ class ThemeError(TTKBootstrapError):
42
+ """Raised when a theme-related operation fails.
43
+
44
+ Examples: requesting an unknown theme name, loading a malformed theme
45
+ definition, or applying a theme before the style system is initialised.
46
+ """
47
+
48
+
49
+ class ConfigError(TTKBootstrapError):
50
+ """Raised when a widget or application configuration is invalid.
51
+
52
+ Examples: passing mutually exclusive options, supplying an unsupported
53
+ value for a configuration key, or configuring a widget after it has
54
+ been destroyed.
55
+ """
56
+
57
+
58
+ class StateError(TTKBootstrapError):
59
+ """Raised when an operation is attempted while the widget is in an invalid state.
60
+
61
+ Examples: calling `start()` on an already-running animation, or
62
+ modifying a widget that has been destroyed.
63
+ """
64
+
65
+
66
+ class NavigationError(TTKBootstrapError):
67
+ """Raised when a navigation operation fails.
68
+
69
+ Examples: referencing a tab key that does not exist, supplying an index
70
+ that is out of range, or navigating in a container that has no items.
71
+ """
72
+
73
+
74
+ class BootstyleBuilderError(TTKBootstrapError):
75
+ """Raised when a style builder encounters an error during style construction.
76
+
77
+ Examples: a builder receiving an unsupported option, a required theme
78
+ color token being missing, or an internal style-engine failure.
79
+ """
80
+
81
+
82
+ class BootstyleParsingError(TTKBootstrapError):
83
+ """Raised when a bootstyle string cannot be parsed into valid tokens.
84
+
85
+ Examples: an unrecognised accent name, an invalid variant, or a
86
+ combination of tokens that the parser cannot resolve.
87
+ """
88
+
89
+
90
+ class ConfigurationWarning(Warning):
91
+ """Issued when a widget receives a deprecated or questionable configuration option.
92
+
93
+ Examples: passing the legacy `bootstyle` keyword instead of the
94
+ recommended `accent`/`variant` pair.
95
+ """
@@ -0,0 +1,283 @@
1
+ """Image loading and caching utilities for bootstack.
2
+
3
+ This module provides a unified image service for loading, caching, and managing
4
+ Tk-compatible PhotoImage objects. It uses Pillow as the backend to support a wide
5
+ variety of image formats beyond what Tk natively supports.
6
+
7
+ The primary interface is the `Image` class, which provides class methods for
8
+ loading images from various sources while automatically caching them to avoid
9
+ repeated decoding and to prevent garbage collection issues with Tk images.
10
+
11
+ Examples:
12
+ Basic usage with file paths:
13
+
14
+ ```python
15
+ from bootstack import Image
16
+
17
+ # Load an image from disk (cached automatically)
18
+ photo = Image.open("icons/save.png")
19
+ button = Button(app, image=photo)
20
+ ```
21
+
22
+ Loading from bytes (e.g., embedded resources):
23
+
24
+ ```python
25
+ photo = Image.from_bytes(icon_data)
26
+ ```
27
+
28
+ Creating transparent spacer images:
29
+
30
+ ```python
31
+ spacer = Image.transparent(16, 16)
32
+ ```
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ import hashlib
38
+ import io
39
+ from dataclasses import dataclass
40
+ from pathlib import Path
41
+ from typing import Hashable
42
+
43
+ from PIL import Image as PILImage
44
+ from PIL.ImageTk import PhotoImage as PILPhotoImage
45
+
46
+
47
+ @dataclass(frozen=True)
48
+ class ImageCacheInfo:
49
+ """Information about the current state of an image cache.
50
+
51
+ Attributes:
52
+ items: The number of images currently stored in the cache.
53
+ """
54
+
55
+ items: int
56
+
57
+
58
+ class Image:
59
+ """Platform image service for loading and caching PhotoImage objects.
60
+
61
+ This class provides a centralized service for working with images in
62
+ bootstack applications. It handles:
63
+
64
+ - Loading images from files, bytes, or PIL Image objects
65
+ - Automatic caching to avoid repeated decoding
66
+ - Keeping strong references to prevent Tk garbage collection issues
67
+ - Support for many image formats via Pillow (PNG, JPEG, GIF, BMP, etc.)
68
+
69
+ All methods are class methods, so no instantiation is required.
70
+
71
+ Examples:
72
+ ```python
73
+ # From a file path
74
+ icon = Image.open("path/to/icon.png")
75
+
76
+ # From raw bytes
77
+ icon = Image.from_bytes(embedded_data)
78
+
79
+ # From a PIL Image object
80
+ pil_img = PILImage.open("photo.jpg").resize((100, 100))
81
+ icon = Image.from_pil(pil_img)
82
+
83
+ # Create a transparent spacer
84
+ spacer = Image.transparent(32, 32)
85
+ ```
86
+
87
+ Note:
88
+ Images are cached by default using automatically generated keys based
89
+ on the source (file path, content hash, or object id). You can provide
90
+ a custom `key` parameter to control caching behavior.
91
+ """
92
+
93
+ _cache: dict[Hashable, PILPhotoImage] = {}
94
+
95
+ # =========================================================================
96
+ # Cache Management
97
+ # =========================================================================
98
+
99
+ @classmethod
100
+ def get_cached(cls, key: Hashable) -> PILPhotoImage | None:
101
+ """Retrieve a cached PhotoImage by its key.
102
+
103
+ Args:
104
+ key: The cache key to look up.
105
+
106
+ Returns:
107
+ The cached PhotoImage if found, or None if not in cache.
108
+ """
109
+ return cls._cache.get(key)
110
+
111
+ @classmethod
112
+ def set_cached(cls, key: Hashable, img: PILPhotoImage) -> PILPhotoImage:
113
+ """Store a PhotoImage in the cache.
114
+
115
+ Args:
116
+ key: The cache key to store the image under.
117
+ img: The PhotoImage to cache.
118
+
119
+ Returns:
120
+ The same PhotoImage that was passed in (for chaining).
121
+ """
122
+ cls._cache[key] = img
123
+ return img
124
+
125
+ @classmethod
126
+ def clear_cache(cls) -> None:
127
+ """Clear all cached images.
128
+
129
+ This removes all images from the cache. Use with caution, as any
130
+ widgets still referencing these images may display incorrectly.
131
+ """
132
+ cls._cache.clear()
133
+
134
+ @classmethod
135
+ def cache_info(cls) -> ImageCacheInfo:
136
+ """Get information about the current cache state.
137
+
138
+ Returns:
139
+ An ImageCacheInfo object containing cache statistics.
140
+
141
+ Examples:
142
+ >>> info = Image.cache_info()
143
+ >>> print(f"Cached images: {info.items}")
144
+ """
145
+ return ImageCacheInfo(items=len(cls._cache))
146
+
147
+ # =========================================================================
148
+ # Image Constructors
149
+ # =========================================================================
150
+
151
+ @classmethod
152
+ def open(cls, path: str | Path, *, key: Hashable | None = None) -> PILPhotoImage:
153
+ """Load an image from a file path.
154
+
155
+ Opens an image file using Pillow and converts it to a Tk-compatible
156
+ PhotoImage. The result is cached to avoid repeated disk reads and
157
+ decoding for the same file.
158
+
159
+ Args:
160
+ path: Path to the image file. Supports ~ expansion and relative paths.
161
+ key: Optional custom cache key. If not provided, the absolute file
162
+ path is used as the cache key.
163
+
164
+ Returns:
165
+ A Tk-compatible PhotoImage that can be used with widgets.
166
+
167
+ Examples:
168
+ >>> photo = Image.open("assets/logo.png")
169
+ >>> label = Label(app, image=photo)
170
+
171
+ >>> # With custom cache key for versioning
172
+ >>> photo = Image.open("icon.png", key=("icon", "v2"))
173
+ """
174
+ p = Path(path).expanduser().resolve()
175
+ cache_key = key if key is not None else ("file", str(p))
176
+ cached = cls.get_cached(cache_key)
177
+ if cached is not None:
178
+ return cached
179
+
180
+ pil = PILImage.open(p)
181
+ photo = PILPhotoImage(image=pil)
182
+ return cls.set_cached(cache_key, photo)
183
+
184
+ @classmethod
185
+ def from_pil(cls, image: PILImage.Image, *, key: Hashable | None = None) -> PILPhotoImage:
186
+ """Convert a PIL Image to a Tk PhotoImage.
187
+
188
+ Wraps an existing PIL Image object in a Tk-compatible PhotoImage.
189
+ This is useful when you need to perform image manipulation (resizing,
190
+ filtering, etc.) before displaying the image.
191
+
192
+ Args:
193
+ image: A PIL Image object to convert.
194
+ key: Optional custom cache key. If not provided, the object id
195
+ of the PIL Image is used (note: this means the same PIL Image
196
+ object will be cached, but copies won't hit the cache).
197
+
198
+ Returns:
199
+ A Tk-compatible PhotoImage that can be used with widgets.
200
+
201
+ Examples:
202
+ >>> from PIL import Image as PILImage
203
+ >>> pil_img = PILImage.open("photo.jpg")
204
+ >>> pil_img = pil_img.resize((100, 100))
205
+ >>> photo = Image.from_pil(pil_img)
206
+ """
207
+ cache_key = key if key is not None else ("pil", id(image))
208
+ cached = cls.get_cached(cache_key)
209
+ if cached is not None:
210
+ return cached
211
+
212
+ photo = PILPhotoImage(image=image)
213
+ return cls.set_cached(cache_key, photo)
214
+
215
+ @classmethod
216
+ def from_bytes(cls, data: bytes, *, key: Hashable | None = None) -> PILPhotoImage:
217
+ """Create a PhotoImage from raw image bytes.
218
+
219
+ Decodes image data from bytes using Pillow and converts it to a
220
+ Tk-compatible PhotoImage. This is useful for embedded resources,
221
+ downloaded images, or any other source of raw image data.
222
+
223
+ Args:
224
+ data: Raw image bytes in any format supported by Pillow
225
+ (PNG, JPEG, GIF, BMP, etc.).
226
+ key: Optional custom cache key. If not provided, an MD5 hash
227
+ of the bytes is used as the cache key.
228
+
229
+ Returns:
230
+ A Tk-compatible PhotoImage that can be used with widgets.
231
+
232
+ Examples:
233
+ >>> # Load from embedded resource
234
+ >>> with open("icon.png", "rb") as f:
235
+ ... icon_data = f.read()
236
+ >>> photo = Image.from_bytes(icon_data)
237
+
238
+ >>> # With custom cache key
239
+ >>> photo = Image.from_bytes(data, key="my-icon")
240
+ """
241
+ digest = hashlib.md5(data).hexdigest()
242
+ cache_key = key if key is not None else ("bytes", digest)
243
+ cached = cls.get_cached(cache_key)
244
+ if cached is not None:
245
+ return cached
246
+
247
+ pil = PILImage.open(io.BytesIO(data))
248
+ photo = PILPhotoImage(image=pil)
249
+ return cls.set_cached(cache_key, photo)
250
+
251
+ @classmethod
252
+ def transparent(cls, width: int, height: int, *, key: Hashable | None = None) -> PILPhotoImage:
253
+ """Create a transparent spacer image.
254
+
255
+ Creates a fully transparent RGBA image of the specified dimensions.
256
+ This is useful for creating spacing in layouts or as a placeholder
257
+ image.
258
+
259
+ Args:
260
+ width: Width of the image in pixels.
261
+ height: Height of the image in pixels.
262
+ key: Optional custom cache key. If not provided, a tuple of
263
+ ("transparent", width, height) is used.
264
+
265
+ Returns:
266
+ A transparent Tk-compatible PhotoImage.
267
+
268
+ Examples:
269
+ >>> # Create a 16x16 transparent spacer
270
+ >>> spacer = Image.transparent(16, 16)
271
+ >>> label = Label(app, image=spacer)
272
+
273
+ >>> # Use as compound image padding
274
+ >>> button = Button(app, image=spacer, compound="left")
275
+ """
276
+ cache_key = key if key is not None else ("transparent", width, height)
277
+ cached = cls.get_cached(cache_key)
278
+ if cached is not None:
279
+ return cached
280
+
281
+ pil = PILImage.new("RGBA", (width, height), (255, 255, 255, 0))
282
+ photo = PILPhotoImage(image=pil)
283
+ return cls.set_cached(cache_key, photo)
@@ -0,0 +1,90 @@
1
+ # Localization (Message Catalog + Babel/gettext)
2
+
3
+ ttkbootstrap uses a unified message catalog that bridges Python gettext (compiled with Babel) and Tcl/Tk msgcat. Catalogs are distributed with the package under `ttkbootstrap/assets/locales`.
4
+
5
+ Highlights
6
+ - Use `_ = MessageCatalog.translate` in code to mark strings.
7
+ - Style auto-initializes the catalog and auto-discovers shipped catalogs.
8
+ - Switch language at runtime with `MessageCatalog.locale('de')`.
9
+ - A virtual event `<<LocaleChanged>>` is emitted on language changes so UIs can refresh.
10
+ - Runtime overrides (`set`, `set_many`) let you add translations that aren't in the catalogs yet.
11
+
12
+ Directory structure
13
+ - `src/ttkbootstrap/assets/locales/<lang>/LC_MESSAGES/ttkbootstrap.po`
14
+ - `src/ttkbootstrap/assets/locales/<lang>/LC_MESSAGES/ttkbootstrap.mo`
15
+
16
+ Marking strings for translation
17
+ - In modules that render UI:
18
+ - `from ttkbootstrap.core.localization import MessageCatalog`
19
+ - `_ = MessageCatalog.translate`
20
+ - Example: `ttk.Label(root, text=_('Cancel'))`
21
+ - Formatting:
22
+ - `_("File: %s", name)` uses Python `%` formatting.
23
+ - Legacy Tcl printf like `%1$s` are supported via a formatting fallback.
24
+
25
+ Language switching
26
+ - Change language at runtime:
27
+ - `MessageCatalog.locale('fr')`
28
+ - Bind a refresh: `root.bind('<<LocaleChanged>>', lambda e: refresh())`
29
+
30
+ Runtime overrides (non-compiled messages)
31
+ - Add translations for a locale during runtime:
32
+ - Single: `MessageCatalog.set('fr', 'Hello', 'Bonjour')`
33
+ - Many: `MessageCatalog.set_many('de', 'Open','Oeffnen', 'Cancel','Abbrechen')`
34
+ - Emit refresh if you're already in that locale: `root.event_generate('<<LocaleChanged>>')`
35
+
36
+ Developer workflow (Babel)
37
+ - Config lives at project root: `babel.cfg` (extracts from `src/**/*.py` and `_()`/gettext keywords).
38
+ - Use the helper to manage catalogs (defaults to `src/ttkbootstrap/assets/locales` and domain `ttkbootstrap`):
39
+ - Extract template: `python tools/make_i18n.py extract`
40
+ - Init locales: `python tools/make_i18n.py init -l de fr`
41
+ - Update catalogs: `python tools/make_i18n.py update`
42
+ - Compile catalogs: `python tools/make_i18n.py compile`
43
+ - The compiled `.mo` files are shipped in the wheel from `assets/locales`.
44
+
45
+ Tools
46
+ - `tools/make_i18n.py` — primary helper for extract/init/update/compile (targets `assets/locales`).
47
+ - `tools/audit_messages.py` — optional QA to spot duplicates and accelerator issues.
48
+ - Scans `src/ttkbootstrap/assets/locales` by default.
49
+
50
+ Note: Legacy migration helpers (e.g., `convert_msgs_to_po.py`, `sync_locales_to_package.py`) have been removed. The workflow compiles directly to `assets/locales`.
51
+
52
+ Contribution notes
53
+ - Prefer base locales (`de`, `fr`, `nl`) unless region-specific differences are required (for example `pt_BR`).
54
+ - Avoid embedding mnemonics `&` in messages; MessageCatalog strips them when rendering.
55
+ - Keep message ids consistent (case and punctuation) to avoid duplicates.
56
+ - Optional: audit keys with `python tools/audit_messages.py`.
57
+
58
+ Demos
59
+ - `examples/localization_widgets_demo.py` - shows `_()` usage and `<<LocaleChanged>>` auto-refresh.
60
+ - `examples/runtime_overrides_demo.py` - shows `set`/`set_many` for messages not in catalogs yet.
61
+
62
+ Contributors
63
+ - Where to place translations:
64
+ - Add or edit `.po` files under `src/ttkbootstrap/assets/locales/<lang>/LC_MESSAGES/ttkbootstrap.po`.
65
+ - Compile to `.mo` with `python tools/make_i18n.py compile`.
66
+ - Workflow for a new language:
67
+ 1) Extract: `python tools/make_i18n.py extract`
68
+ 2) Init: `python tools/make_i18n.py init -l <lang>`
69
+ 3) Translate the new `.po` file
70
+ 4) Compile: `python tools/make_i18n.py compile`
71
+ - Minimum keys to translate for a new language (baseline UI):
72
+ - OK, Ok, Retry, Delete, Next, Prev, Previous
73
+ - Yes, No, Open, Close, Add, Remove, Submit, Cancel
74
+ - Family, Weight, Slant, Effects, Preview, Size
75
+ - Should be of data type, Invalid data type
76
+ - Number cannot be greater than, Number cannot be less than, Out of range
77
+ - The quick brown fox jumps over the lazy dog.
78
+ - Font Selector, Color Chooser, Advanced, Themed, Standard
79
+ - Current, New, Hue, Sat, Lum, Hex, Red, Green, Blue
80
+ - color dropper, Search, Page, of
81
+ - Reset table, Columns, Move, Align
82
+ - Hide column, Delete column, Show All
83
+ - Move to left, Move to right, Move to first, Move to last
84
+ - Align left, Align center, Align right
85
+ - Sort, Filter, Export, Delete selected rows
86
+ - Sort Ascending, Sort Descending, Clear filters
87
+ - Filter by cell's value, Hide select rows, Show only select rows
88
+ - Export all records, Export current page, Export current selection, Export records in filter
89
+ - Move up, Move down, Move to top, Move to bottom
90
+ - Mo, Tu, We, Th, Fr, Sa, Su