bootstack 0.1.0__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 (471) hide show
  1. bootstack/__init__.py +157 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/_core/__init__.py +21 -0
  4. bootstack/_core/capabilities/__init__.py +45 -0
  5. bootstack/_core/capabilities/after.py +103 -0
  6. bootstack/_core/capabilities/bind.py +192 -0
  7. bootstack/_core/capabilities/bindtags.py +112 -0
  8. bootstack/_core/capabilities/busy.py +72 -0
  9. bootstack/_core/capabilities/clipboard.py +89 -0
  10. bootstack/_core/capabilities/focus.py +118 -0
  11. bootstack/_core/capabilities/grab.py +65 -0
  12. bootstack/_core/capabilities/grid.py +211 -0
  13. bootstack/_core/capabilities/localization.py +231 -0
  14. bootstack/_core/capabilities/pack.py +140 -0
  15. bootstack/_core/capabilities/place.py +113 -0
  16. bootstack/_core/capabilities/selection.py +136 -0
  17. bootstack/_core/capabilities/signals.py +244 -0
  18. bootstack/_core/capabilities/winfo.py +315 -0
  19. bootstack/_core/colorutils.py +234 -0
  20. bootstack/_core/exceptions.py +25 -0
  21. bootstack/_core/images.py +463 -0
  22. bootstack/_core/mixins/__init__.py +1 -0
  23. bootstack/_core/mixins/ttk_state.py +35 -0
  24. bootstack/_core/mixins/widget.py +132 -0
  25. bootstack/_core/paths.py +49 -0
  26. bootstack/_core/publisher.py +149 -0
  27. bootstack/_core/variables.py +62 -0
  28. bootstack/_runtime/__init__.py +3 -0
  29. bootstack/_runtime/app.py +930 -0
  30. bootstack/_runtime/base_window.py +945 -0
  31. bootstack/_runtime/events.py +399 -0
  32. bootstack/_runtime/shortcuts.py +496 -0
  33. bootstack/_runtime/tk_patch.py +43 -0
  34. bootstack/_runtime/toplevel.py +276 -0
  35. bootstack/_runtime/utility.py +457 -0
  36. bootstack/_runtime/visual_focus.py +240 -0
  37. bootstack/_runtime/window_utilities.py +1123 -0
  38. bootstack/assets/__init__.py +21 -0
  39. bootstack/assets/bootstack.ico +0 -0
  40. bootstack/assets/bootstack.png +0 -0
  41. bootstack/assets/elements/__init__.py +0 -0
  42. bootstack/assets/elements/badge-pill.png +0 -0
  43. bootstack/assets/elements/badge-square.png +0 -0
  44. bootstack/assets/elements/button-compact.png +0 -0
  45. bootstack/assets/elements/button-default.png +0 -0
  46. bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
  47. bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
  48. bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
  49. bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
  50. bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
  51. bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
  52. bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
  53. bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
  54. bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
  55. bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
  56. bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
  57. bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
  58. bootstack/assets/elements/card.png +0 -0
  59. bootstack/assets/elements/checkbox-checked.png +0 -0
  60. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  61. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  62. bootstack/assets/elements/field.png +0 -0
  63. bootstack/assets/elements/input-addon-compact.png +0 -0
  64. bootstack/assets/elements/input-addon-default.png +0 -0
  65. bootstack/assets/elements/input-compact.png +0 -0
  66. bootstack/assets/elements/input-default.png +0 -0
  67. bootstack/assets/elements/list-item-separated.png +0 -0
  68. bootstack/assets/elements/list-item.png +0 -0
  69. bootstack/assets/elements/listrow-compact.png +0 -0
  70. bootstack/assets/elements/listrow-default.png +0 -0
  71. bootstack/assets/elements/manifest.toml +361 -0
  72. bootstack/assets/elements/menu-item.png +0 -0
  73. bootstack/assets/elements/navitem-compact.png +0 -0
  74. bootstack/assets/elements/navitem-default.png +0 -0
  75. bootstack/assets/elements/progressbar-h-compact.png +0 -0
  76. bootstack/assets/elements/progressbar-h-default.png +0 -0
  77. bootstack/assets/elements/progressbar-v-compact.png +0 -0
  78. bootstack/assets/elements/progressbar-v-default.png +0 -0
  79. bootstack/assets/elements/radiobutton.png +0 -0
  80. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  81. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  82. bootstack/assets/elements/slider-handle.png +0 -0
  83. bootstack/assets/elements/slider-track-h.png +0 -0
  84. bootstack/assets/elements/slider-track-v.png +0 -0
  85. bootstack/assets/elements/switch-off.png +0 -0
  86. bootstack/assets/elements/switch-on.png +0 -0
  87. bootstack/assets/elements/tab-h.png +0 -0
  88. bootstack/assets/elements/tab-v.png +0 -0
  89. bootstack/assets/icons/bootstrap.ttf +0 -0
  90. bootstack/assets/icons/glyphmap.json +2080 -0
  91. bootstack/assets/icons/icon_metrics.json +12470 -0
  92. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  93. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +856 -0
  94. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
  95. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +878 -0
  96. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  97. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +856 -0
  98. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  99. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +856 -0
  100. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  101. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +856 -0
  102. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  103. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +878 -0
  104. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  105. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +856 -0
  106. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  107. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +856 -0
  108. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  109. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +854 -0
  110. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  111. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +845 -0
  112. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  113. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +844 -0
  114. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  115. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +917 -0
  116. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  117. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +845 -0
  118. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  119. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +844 -0
  120. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  121. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +844 -0
  122. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  123. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +845 -0
  124. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  125. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +845 -0
  126. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  127. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +845 -0
  128. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  129. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +845 -0
  130. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  131. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +845 -0
  132. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  133. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +845 -0
  134. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  135. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +845 -0
  136. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  137. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +845 -0
  138. bootstack/cli/__init__.py +133 -0
  139. bootstack/cli/__main__.py +6 -0
  140. bootstack/cli/add.py +395 -0
  141. bootstack/cli/appicon.py +285 -0
  142. bootstack/cli/build.py +115 -0
  143. bootstack/cli/config.py +313 -0
  144. bootstack/cli/demo.py +564 -0
  145. bootstack/cli/dev.py +153 -0
  146. bootstack/cli/doctor.py +195 -0
  147. bootstack/cli/icons.py +98 -0
  148. bootstack/cli/promote.py +120 -0
  149. bootstack/cli/pyinstaller.py +268 -0
  150. bootstack/cli/run.py +95 -0
  151. bootstack/cli/start.py +117 -0
  152. bootstack/cli/templates/__init__.py +931 -0
  153. bootstack/clipboard.py +48 -0
  154. bootstack/constants.py +318 -0
  155. bootstack/data/README.md +615 -0
  156. bootstack/data/__init__.py +78 -0
  157. bootstack/data/_observable.py +276 -0
  158. bootstack/data/base.py +780 -0
  159. bootstack/data/file_source.py +367 -0
  160. bootstack/data/memory_source.py +450 -0
  161. bootstack/data/query.py +367 -0
  162. bootstack/data/readers.py +289 -0
  163. bootstack/data/sqlite_source.py +869 -0
  164. bootstack/data/types.py +354 -0
  165. bootstack/data/writers.py +232 -0
  166. bootstack/dev/__init__.py +36 -0
  167. bootstack/dev/_capture.py +141 -0
  168. bootstack/dev/_env.py +43 -0
  169. bootstack/dev/_registry.py +140 -0
  170. bootstack/dev/_reloader.py +351 -0
  171. bootstack/dev/_reset.py +50 -0
  172. bootstack/dev/_watcher.py +91 -0
  173. bootstack/dialogs/__init__.py +948 -0
  174. bootstack/dialogs/_impl/__init__.py +47 -0
  175. bootstack/dialogs/_impl/colorchooser.py +588 -0
  176. bootstack/dialogs/_impl/datedialog.py +450 -0
  177. bootstack/dialogs/_impl/dialog.py +594 -0
  178. bootstack/dialogs/_impl/filterdialog.py +358 -0
  179. bootstack/dialogs/_impl/fontdialog.py +364 -0
  180. bootstack/dialogs/_impl/formdialog.py +564 -0
  181. bootstack/dialogs/_impl/message.py +486 -0
  182. bootstack/dialogs/_impl/query.py +570 -0
  183. bootstack/errors.py +67 -0
  184. bootstack/events/__init__.py +111 -0
  185. bootstack/events/_event.py +135 -0
  186. bootstack/events/_payloads.py +539 -0
  187. bootstack/events/_subscription.py +38 -0
  188. bootstack/i18n/README.md +77 -0
  189. bootstack/i18n/__init__.py +23 -0
  190. bootstack/i18n/catalog.py +121 -0
  191. bootstack/i18n/intl_format.py +584 -0
  192. bootstack/i18n/msgcat.py +425 -0
  193. bootstack/i18n/specs.py +156 -0
  194. bootstack/images.py +563 -0
  195. bootstack/py.typed +1 -0
  196. bootstack/scheduling/__init__.py +11 -0
  197. bootstack/scheduling/_schedule.py +218 -0
  198. bootstack/shortcuts.py +21 -0
  199. bootstack/signals/README.md +98 -0
  200. bootstack/signals/__init__.py +10 -0
  201. bootstack/signals/integration.py +100 -0
  202. bootstack/signals/signal.py +353 -0
  203. bootstack/signals/types.py +6 -0
  204. bootstack/store.py +286 -0
  205. bootstack/streams/__init__.py +12 -0
  206. bootstack/streams/_stream.py +321 -0
  207. bootstack/style/__init__.py +38 -0
  208. bootstack/style/builders/__init__.py +51 -0
  209. bootstack/style/builders/badge.py +46 -0
  210. bootstack/style/builders/button.py +339 -0
  211. bootstack/style/builders/buttongroup.py +311 -0
  212. bootstack/style/builders/calendar.py +271 -0
  213. bootstack/style/builders/checkbutton.py +110 -0
  214. bootstack/style/builders/combobox.py +113 -0
  215. bootstack/style/builders/contextmenu.py +268 -0
  216. bootstack/style/builders/entry.py +82 -0
  217. bootstack/style/builders/expander.py +148 -0
  218. bootstack/style/builders/field.py +335 -0
  219. bootstack/style/builders/frame.py +50 -0
  220. bootstack/style/builders/label.py +28 -0
  221. bootstack/style/builders/labelframe.py +34 -0
  222. bootstack/style/builders/listview.py +369 -0
  223. bootstack/style/builders/menubar.py +91 -0
  224. bootstack/style/builders/menubutton.py +359 -0
  225. bootstack/style/builders/panedwindow.py +25 -0
  226. bootstack/style/builders/progressbar.py +67 -0
  227. bootstack/style/builders/radiobutton.py +99 -0
  228. bootstack/style/builders/scale.py +64 -0
  229. bootstack/style/builders/scrollbar.py +225 -0
  230. bootstack/style/builders/separator.py +49 -0
  231. bootstack/style/builders/sidenav.py +643 -0
  232. bootstack/style/builders/sizegrip.py +15 -0
  233. bootstack/style/builders/spinbox.py +119 -0
  234. bootstack/style/builders/switch.py +70 -0
  235. bootstack/style/builders/tabitem.py +204 -0
  236. bootstack/style/builders/togglegroup.py +294 -0
  237. bootstack/style/builders/toolbutton.py +275 -0
  238. bootstack/style/builders/tooltip.py +26 -0
  239. bootstack/style/builders/treeview.py +193 -0
  240. bootstack/style/builders/utils.py +455 -0
  241. bootstack/style/builders_tk/__init__.py +16 -0
  242. bootstack/style/builders_tk/defaults.py +229 -0
  243. bootstack/style/element.py +173 -0
  244. bootstack/style/fonts.py +123 -0
  245. bootstack/style/style.py +609 -0
  246. bootstack/style/style_builder_base.py +716 -0
  247. bootstack/style/style_builder_mixed.py +93 -0
  248. bootstack/style/style_builder_tk.py +109 -0
  249. bootstack/style/style_builder_ttk.py +353 -0
  250. bootstack/style/style_resolver.py +447 -0
  251. bootstack/style/theme.py +245 -0
  252. bootstack/style/theme_provider.py +471 -0
  253. bootstack/style/themes/__init__.py +128 -0
  254. bootstack/style/tk_patch.py +5 -0
  255. bootstack/style/token_maps.py +41 -0
  256. bootstack/style/types.py +32 -0
  257. bootstack/style/typography.py +523 -0
  258. bootstack/style/utility.py +746 -0
  259. bootstack/types.py +39 -0
  260. bootstack/validation/__init__.py +6 -0
  261. bootstack/validation/types.py +15 -0
  262. bootstack/validation/validation_result.py +17 -0
  263. bootstack/validation/validation_rules.py +205 -0
  264. bootstack/widgets/__init__.py +74 -0
  265. bootstack/widgets/_core/__init__.py +31 -0
  266. bootstack/widgets/_core/app_config.py +266 -0
  267. bootstack/widgets/_core/base.py +461 -0
  268. bootstack/widgets/_core/container.py +334 -0
  269. bootstack/widgets/_core/context.py +35 -0
  270. bootstack/widgets/_core/events.py +130 -0
  271. bootstack/widgets/_core/field_mixin.py +353 -0
  272. bootstack/widgets/_core/icon_image_props.py +72 -0
  273. bootstack/widgets/_core/image_binding.py +93 -0
  274. bootstack/widgets/_core/navmodel.py +345 -0
  275. bootstack/widgets/_core/options.py +210 -0
  276. bootstack/widgets/_core/selection_group.py +130 -0
  277. bootstack/widgets/_core/window_controls.py +96 -0
  278. bootstack/widgets/_core/window_menu.py +246 -0
  279. bootstack/widgets/_impl/__init__.py +1 -0
  280. bootstack/widgets/_impl/_internal/__init__.py +0 -0
  281. bootstack/widgets/_impl/_internal/wrapper_base.py +307 -0
  282. bootstack/widgets/_impl/_parts/__init__.py +11 -0
  283. bootstack/widgets/_impl/_parts/numberentry_part.py +385 -0
  284. bootstack/widgets/_impl/_parts/spinnerentry_part.py +434 -0
  285. bootstack/widgets/_impl/_parts/textentry_part.py +406 -0
  286. bootstack/widgets/_impl/composites/__init__.py +33 -0
  287. bootstack/widgets/_impl/composites/_dateutils.py +33 -0
  288. bootstack/widgets/_impl/composites/_image_fit.py +105 -0
  289. bootstack/widgets/_impl/composites/accordion.py +381 -0
  290. bootstack/widgets/_impl/composites/avatar.py +191 -0
  291. bootstack/widgets/_impl/composites/buttongroup.py +371 -0
  292. bootstack/widgets/_impl/composites/calendar.py +972 -0
  293. bootstack/widgets/_impl/composites/carousel.py +567 -0
  294. bootstack/widgets/_impl/composites/chart.py +882 -0
  295. bootstack/widgets/_impl/composites/compositeframe.py +298 -0
  296. bootstack/widgets/_impl/composites/contextmenu.py +1951 -0
  297. bootstack/widgets/_impl/composites/dateentry.py +404 -0
  298. bootstack/widgets/_impl/composites/dropdownbutton.py +325 -0
  299. bootstack/widgets/_impl/composites/expander.py +515 -0
  300. bootstack/widgets/_impl/composites/field.py +670 -0
  301. bootstack/widgets/_impl/composites/form.py +1066 -0
  302. bootstack/widgets/_impl/composites/gallery.py +551 -0
  303. bootstack/widgets/_impl/composites/list/__init__.py +15 -0
  304. bootstack/widgets/_impl/composites/list/listitem.py +802 -0
  305. bootstack/widgets/_impl/composites/list/listview.py +1433 -0
  306. bootstack/widgets/_impl/composites/menu/__init__.py +18 -0
  307. bootstack/widgets/_impl/composites/menu/model.py +358 -0
  308. bootstack/widgets/_impl/composites/menu/render_native.py +134 -0
  309. bootstack/widgets/_impl/composites/menu/render_themed.py +134 -0
  310. bootstack/widgets/_impl/composites/meter.py +860 -0
  311. bootstack/widgets/_impl/composites/numericentry.py +201 -0
  312. bootstack/widgets/_impl/composites/pagestack.py +395 -0
  313. bootstack/widgets/_impl/composites/passwordentry.py +142 -0
  314. bootstack/widgets/_impl/composites/pathentry.py +168 -0
  315. bootstack/widgets/_impl/composites/picture.py +289 -0
  316. bootstack/widgets/_impl/composites/radiogroup.py +511 -0
  317. bootstack/widgets/_impl/composites/scrolledtext.py +375 -0
  318. bootstack/widgets/_impl/composites/scrolledtext.pyi +186 -0
  319. bootstack/widgets/_impl/composites/scrollview.py +764 -0
  320. bootstack/widgets/_impl/composites/selectbox.py +1026 -0
  321. bootstack/widgets/_impl/composites/shell/__init__.py +40 -0
  322. bootstack/widgets/_impl/composites/shell/content_host.py +52 -0
  323. bootstack/widgets/_impl/composites/shell/layout.py +335 -0
  324. bootstack/widgets/_impl/composites/shell/nav_panel.py +345 -0
  325. bootstack/widgets/_impl/composites/shell/providers.py +558 -0
  326. bootstack/widgets/_impl/composites/shell/rail.py +117 -0
  327. bootstack/widgets/_impl/composites/shell/shell.py +581 -0
  328. bootstack/widgets/_impl/composites/shell/workspace.py +273 -0
  329. bootstack/widgets/_impl/composites/sidenav/__init__.py +16 -0
  330. bootstack/widgets/_impl/composites/sidenav/header.py +81 -0
  331. bootstack/widgets/_impl/composites/sidenav/separator.py +44 -0
  332. bootstack/widgets/_impl/composites/slider/__init__.py +7 -0
  333. bootstack/widgets/_impl/composites/slider/_shared.py +195 -0
  334. bootstack/widgets/_impl/composites/slider/rangeslider.py +982 -0
  335. bootstack/widgets/_impl/composites/slider/slider.py +851 -0
  336. bootstack/widgets/_impl/composites/spinnerentry.py +185 -0
  337. bootstack/widgets/_impl/composites/tableview/__init__.py +5 -0
  338. bootstack/widgets/_impl/composites/tableview/tableview.py +3388 -0
  339. bootstack/widgets/_impl/composites/tableview/types.py +169 -0
  340. bootstack/widgets/_impl/composites/tabs/__init__.py +23 -0
  341. bootstack/widgets/_impl/composites/tabs/tabitem.py +389 -0
  342. bootstack/widgets/_impl/composites/tabs/tabs.py +974 -0
  343. bootstack/widgets/_impl/composites/tabs/tabview.py +650 -0
  344. bootstack/widgets/_impl/composites/textarea/__init__.py +26 -0
  345. bootstack/widgets/_impl/composites/textarea/change.py +46 -0
  346. bootstack/widgets/_impl/composites/textarea/codeeditor.py +526 -0
  347. bootstack/widgets/_impl/composites/textarea/core.py +495 -0
  348. bootstack/widgets/_impl/composites/textarea/decoration.py +42 -0
  349. bootstack/widgets/_impl/composites/textarea/diff.py +127 -0
  350. bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +1 -0
  351. bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +138 -0
  352. bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +158 -0
  353. bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +138 -0
  354. bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +312 -0
  355. bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +177 -0
  356. bootstack/widgets/_impl/composites/textarea/filter.py +171 -0
  357. bootstack/widgets/_impl/composites/textarea/search_overlay.py +459 -0
  358. bootstack/widgets/_impl/composites/textarea/sidebar.py +88 -0
  359. bootstack/widgets/_impl/composites/textarea/style_registry.py +178 -0
  360. bootstack/widgets/_impl/composites/textarea/textarea.py +606 -0
  361. bootstack/widgets/_impl/composites/textarea/undo.py +217 -0
  362. bootstack/widgets/_impl/composites/textentry.py +57 -0
  363. bootstack/widgets/_impl/composites/timeentry.py +176 -0
  364. bootstack/widgets/_impl/composites/toast.py +390 -0
  365. bootstack/widgets/_impl/composites/toast_stack.py +156 -0
  366. bootstack/widgets/_impl/composites/togglegroup.py +418 -0
  367. bootstack/widgets/_impl/composites/toolbar.py +608 -0
  368. bootstack/widgets/_impl/composites/tooltip.py +491 -0
  369. bootstack/widgets/_impl/composites/tree/__init__.py +7 -0
  370. bootstack/widgets/_impl/composites/tree/source_binding.py +136 -0
  371. bootstack/widgets/_impl/composites/tree/treeitem.py +393 -0
  372. bootstack/widgets/_impl/composites/tree/treenode.py +174 -0
  373. bootstack/widgets/_impl/composites/tree/treeview.py +841 -0
  374. bootstack/widgets/_impl/mixins/__init__.py +24 -0
  375. bootstack/widgets/_impl/mixins/configure_mixin.py +216 -0
  376. bootstack/widgets/_impl/mixins/entry_mixin.py +134 -0
  377. bootstack/widgets/_impl/mixins/font_mixin.py +368 -0
  378. bootstack/widgets/_impl/mixins/icon_mixin.py +61 -0
  379. bootstack/widgets/_impl/mixins/localization_mixin.py +253 -0
  380. bootstack/widgets/_impl/mixins/signal_mixin.py +268 -0
  381. bootstack/widgets/_impl/mixins/validation_mixin.py +226 -0
  382. bootstack/widgets/_impl/primitives/__init__.py +49 -0
  383. bootstack/widgets/_impl/primitives/_menubutton.py +107 -0
  384. bootstack/widgets/_impl/primitives/badge.py +45 -0
  385. bootstack/widgets/_impl/primitives/button.py +76 -0
  386. bootstack/widgets/_impl/primitives/card.py +45 -0
  387. bootstack/widgets/_impl/primitives/checkbutton.py +124 -0
  388. bootstack/widgets/_impl/primitives/checktoggle.py +62 -0
  389. bootstack/widgets/_impl/primitives/combobox.py +156 -0
  390. bootstack/widgets/_impl/primitives/entry.py +87 -0
  391. bootstack/widgets/_impl/primitives/flexframe.py +448 -0
  392. bootstack/widgets/_impl/primitives/frame.py +185 -0
  393. bootstack/widgets/_impl/primitives/gridframe.py +546 -0
  394. bootstack/widgets/_impl/primitives/label.py +84 -0
  395. bootstack/widgets/_impl/primitives/labelframe.py +54 -0
  396. bootstack/widgets/_impl/primitives/optionmenu.py +387 -0
  397. bootstack/widgets/_impl/primitives/packframe.py +227 -0
  398. bootstack/widgets/_impl/primitives/panedwindow.py +45 -0
  399. bootstack/widgets/_impl/primitives/progressbar.py +83 -0
  400. bootstack/widgets/_impl/primitives/radiobutton.py +115 -0
  401. bootstack/widgets/_impl/primitives/radiotoggle.py +54 -0
  402. bootstack/widgets/_impl/primitives/scrollbar.py +42 -0
  403. bootstack/widgets/_impl/primitives/separator.py +43 -0
  404. bootstack/widgets/_impl/primitives/sizegrip.py +33 -0
  405. bootstack/widgets/_impl/primitives/spinbox.py +95 -0
  406. bootstack/widgets/_impl/primitives/switch.py +44 -0
  407. bootstack/widgets/_impl/primitives/treeview.py +69 -0
  408. bootstack/widgets/app.py +371 -0
  409. bootstack/widgets/appshell.py +1179 -0
  410. bootstack/widgets/avatar.py +140 -0
  411. bootstack/widgets/boolean_controls.py +455 -0
  412. bootstack/widgets/button.py +224 -0
  413. bootstack/widgets/buttongroup.py +239 -0
  414. bootstack/widgets/calendar.py +195 -0
  415. bootstack/widgets/card.py +159 -0
  416. bootstack/widgets/carousel.py +241 -0
  417. bootstack/widgets/chart.py +302 -0
  418. bootstack/widgets/codeeditor.py +675 -0
  419. bootstack/widgets/contextmenu.py +371 -0
  420. bootstack/widgets/datatable.py +688 -0
  421. bootstack/widgets/datefield.py +395 -0
  422. bootstack/widgets/divider.py +60 -0
  423. bootstack/widgets/expander.py +579 -0
  424. bootstack/widgets/form.py +200 -0
  425. bootstack/widgets/gallery.py +250 -0
  426. bootstack/widgets/gauge.py +168 -0
  427. bootstack/widgets/grid.py +121 -0
  428. bootstack/widgets/groupbox.py +162 -0
  429. bootstack/widgets/label.py +229 -0
  430. bootstack/widgets/listview.py +354 -0
  431. bootstack/widgets/menubutton.py +419 -0
  432. bootstack/widgets/numberfield.py +431 -0
  433. bootstack/widgets/pagestack.py +345 -0
  434. bootstack/widgets/passwordfield.py +383 -0
  435. bootstack/widgets/pathfield.py +454 -0
  436. bootstack/widgets/picture.py +251 -0
  437. bootstack/widgets/progressbar.py +106 -0
  438. bootstack/widgets/radio_variants.py +271 -0
  439. bootstack/widgets/radiogroup.py +228 -0
  440. bootstack/widgets/scrollbar.py +64 -0
  441. bootstack/widgets/scrollview.py +186 -0
  442. bootstack/widgets/select.py +302 -0
  443. bootstack/widgets/selectbutton.py +182 -0
  444. bootstack/widgets/sidebar_toggle.py +130 -0
  445. bootstack/widgets/sizegrip.py +42 -0
  446. bootstack/widgets/slider.py +408 -0
  447. bootstack/widgets/spinbox.py +147 -0
  448. bootstack/widgets/spinnerfield.py +413 -0
  449. bootstack/widgets/splash.py +367 -0
  450. bootstack/widgets/splitview.py +482 -0
  451. bootstack/widgets/stacks.py +249 -0
  452. bootstack/widgets/statusbar.py +189 -0
  453. bootstack/widgets/tabs.py +425 -0
  454. bootstack/widgets/textarea.py +459 -0
  455. bootstack/widgets/textfield.py +410 -0
  456. bootstack/widgets/theme_toggle.py +92 -0
  457. bootstack/widgets/timefield.py +340 -0
  458. bootstack/widgets/toast.py +314 -0
  459. bootstack/widgets/togglegroup.py +231 -0
  460. bootstack/widgets/toolbar.py +347 -0
  461. bootstack/widgets/tooltip.py +94 -0
  462. bootstack/widgets/tree.py +648 -0
  463. bootstack/widgets/types.py +305 -0
  464. bootstack/widgets/window.py +307 -0
  465. bootstack-0.1.0.dist-info/METADATA +301 -0
  466. bootstack-0.1.0.dist-info/RECORD +471 -0
  467. bootstack-0.1.0.dist-info/WHEEL +5 -0
  468. bootstack-0.1.0.dist-info/entry_points.txt +2 -0
  469. bootstack-0.1.0.dist-info/licenses/LICENSE +21 -0
  470. bootstack-0.1.0.dist-info/licenses/NOTICE +10 -0
  471. bootstack-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,418 @@
1
+ from __future__ import annotations
2
+
3
+ from tkinter import StringVar
4
+ from typing import Any, Callable, Literal, TYPE_CHECKING
5
+
6
+ from typing_extensions import TypedDict, Unpack
7
+
8
+ from bootstack.widgets._impl.primitives.radiotoggle import RadioToggle
9
+ from bootstack.widgets._impl.primitives.checktoggle import CheckToggle
10
+ from bootstack._core.variables import SetVar
11
+ from bootstack.widgets._impl.mixins.configure_mixin import configure_delegate
12
+ from bootstack.widgets._impl.primitives import Frame
13
+ from bootstack.widgets.types import Orient, AccentToken, SurfaceToken
14
+
15
+ if TYPE_CHECKING:
16
+ from bootstack.signals import Signal
17
+ import tkinter as tk
18
+
19
+
20
+ class ToggleGroupKwargs(TypedDict, total=False):
21
+ mode: Literal['single', 'multi']
22
+ variable: Any
23
+ signal: Signal[Any]
24
+ value: str | set[str]
25
+ orient: Orient
26
+ accent: AccentToken | str
27
+ variant: str
28
+ show_border: bool
29
+ surface: SurfaceToken | str
30
+ style_options: dict[str, Any]
31
+ # Frame options
32
+ padding: Any
33
+ width: int
34
+ height: int
35
+
36
+
37
+ class ToggleGroup(Frame):
38
+ """A group of toggle buttons with single or multi-selection support.
39
+
40
+ The ToggleGroup widget provides a convenient way to create groups of toggle
41
+ buttons with automatic position tracking and styling. It supports both single
42
+ selection (radio button behavior) and multi-selection (checkbox behavior).
43
+ """
44
+
45
+ def __init__(self, master: Any = None, **kwargs: Unpack[ToggleGroupKwargs]):
46
+ """Initialize the ToggleGroup.
47
+
48
+ Args:
49
+ master: Parent widget. If None, uses the default root window.
50
+
51
+ Other Parameters:
52
+ mode: Selection mode - 'single' for radio button behavior (default),
53
+ or 'multi' for checkbox behavior allowing multiple selections.
54
+ orient: Layout orientation - 'horizontal' (default) or 'vertical'.
55
+ accent: Accent token for styling (e.g., 'primary', 'danger').
56
+ Defaults to 'default' (a neutral selected state).
57
+ variant: Style variant (e.g., 'outline', 'ghost').
58
+ variable: Optional tk.Variable for controlling the value. For single mode,
59
+ use StringVar; for multi mode, use SetVar.
60
+ See [tkinter Variables](https://docs.python.org/3/library/tkinter.html#tkinter-variables).
61
+ signal: Optional Signal instance for reactive programming.
62
+ value: Initial value - string for single mode, set for multi mode.
63
+ show_border: If True, draws a border around the group.
64
+ surface: Optional surface token; otherwise inherited.
65
+ style_options: Additional style options passed to child buttons.
66
+ padding: Frame padding. Defaults to 1.
67
+ width: Requested width in pixels.
68
+ height: Requested height in pixels.
69
+ """
70
+ # Extract ToggleGroup-specific options before super().__init__
71
+ self._mode = kwargs.pop('mode', 'single')
72
+ self._orientation = kwargs.pop('orient', 'horizontal')
73
+ accent = kwargs.pop('accent', None) or 'default'
74
+ variant = kwargs.pop('variant', None) # None (default), 'outline', or 'ghost'
75
+ self._state = kwargs.pop('state', 'normal')
76
+
77
+ # Handle signal/variable/value similar to CheckToggle pattern
78
+ initial_value = kwargs.pop('value', None)
79
+
80
+ style_options = kwargs.pop('style_options', {})
81
+
82
+ # Initialize internal state
83
+ self._buttons: dict[str, RadioToggle | CheckToggle] = {}
84
+
85
+ # Extract signal/variable before Frame init
86
+ signal_value = kwargs.pop('signal', None)
87
+ variable_value = kwargs.pop('variable', None)
88
+
89
+ # Call super().__init__() - just Frame now
90
+ if 'padding' not in kwargs:
91
+ kwargs['padding'] = 1
92
+ super().__init__(master, style_options=style_options, **kwargs)
93
+
94
+ # Restore accent/variant (super().__init__ overwrites them with None)
95
+ self._accent = accent
96
+ self._variant = variant
97
+
98
+ # Handle variable/signal setup manually
99
+ if signal_value is not None:
100
+ # Signal provided - extract its variable
101
+ self._signal = signal_value
102
+ self._variable = signal_value.var
103
+ elif variable_value is not None:
104
+ # Variable provided - wrap in Signal
105
+ from bootstack.signals import Signal
106
+ self._variable = variable_value
107
+ self._signal = Signal.from_variable(variable_value)
108
+ # Set initial value if provided
109
+ if initial_value is not None:
110
+ self._variable.set(initial_value)
111
+ else:
112
+ # Neither provided - create internal variable
113
+ from bootstack.signals import Signal
114
+ if self._mode == 'single':
115
+ internal_var = StringVar(value=initial_value or '')
116
+ else:
117
+ internal_var = SetVar(value=initial_value or set())
118
+ self._variable = internal_var
119
+ self._signal = Signal.from_variable(internal_var)
120
+
121
+ @property
122
+ def variable(self) -> 'tk.Variable':
123
+ """Get the underlying tk.Variable.
124
+
125
+ See [tkinter Variables](https://docs.python.org/3/library/tkinter.html#tkinter-variables).
126
+ """
127
+ return self._variable
128
+
129
+ @variable.setter
130
+ def variable(self, value: 'tk.Variable') -> None:
131
+ """Set the variable."""
132
+ from bootstack.signals import Signal
133
+ self._variable = value
134
+ self._signal = Signal.from_variable(value)
135
+
136
+ @property
137
+ def signal(self) -> Signal[Any]:
138
+ """Get the signal."""
139
+ return self._signal
140
+
141
+ @signal.setter
142
+ def signal(self, value: Signal[Any]) -> None:
143
+ """Set the signal."""
144
+ self._signal = value
145
+ self._variable = value.var
146
+
147
+ def add(self, text: str = None, value: Any = None, key: str | None = None, **kwargs: Any) -> RadioToggle | CheckToggle:
148
+ """Add a toggle button to the group.
149
+
150
+ Args:
151
+ text: Text to display on the button.
152
+ value: Value this button represents (required).
153
+ key: Unique identifier. Defaults to value.
154
+ **kwargs: Additional arguments passed to RadioToggle or CheckToggle.
155
+
156
+ Returns:
157
+ The created button widget.
158
+ """
159
+ if value is None:
160
+ raise ValueError("The 'value' argument is required.")
161
+
162
+ key = key or value
163
+ if key in self._buttons:
164
+ raise ValueError(f"A button with the key '{key}' already exists.")
165
+
166
+ btn_kwargs = kwargs.copy()
167
+ # Set the ToggleGroup ttk_class - position will be updated by _update_button_positions
168
+ custom_accent = btn_kwargs.pop('accent', None) or self._accent
169
+ btn_kwargs['accent'] = custom_accent
170
+ btn_kwargs['ttk_class'] = 'ToggleGroup'
171
+ if 'state' not in btn_kwargs:
172
+ btn_kwargs['state'] = self._state
173
+ # variant can be None (default), 'outline', or 'ghost' - use group's variant if not specified
174
+ if 'variant' not in btn_kwargs:
175
+ btn_kwargs['variant'] = self._variant
176
+ # Merge orient and initial position into style_options
177
+ existing_style_opts = btn_kwargs.get('style_options', {}).copy()
178
+ existing_style_opts['orient'] = self._orientation
179
+ existing_style_opts.setdefault('position', 'before') # Default position, will be corrected later
180
+ btn_kwargs['style_options'] = existing_style_opts
181
+
182
+ if self._mode == 'single':
183
+ button = RadioToggle(self, text=text, value=value, variable=self.variable, **btn_kwargs)
184
+ else: # multi
185
+ button = CheckToggle(self, text=text, **btn_kwargs)
186
+
187
+ # Set initial state based on current SetVar value
188
+ current_set = self.variable.get()
189
+ if not isinstance(current_set, set):
190
+ current_set = set()
191
+ button.variable.set(value in current_set)
192
+
193
+ # Bind command to update SetVar
194
+ # Pop command to avoid double-calling
195
+ original_command = btn_kwargs.pop('command', None)
196
+
197
+ def toggle_command():
198
+ self._on_multi_toggle(value)
199
+ if original_command:
200
+ original_command()
201
+
202
+ button.configure(command=toggle_command)
203
+
204
+ if self._orientation == 'horizontal':
205
+ button.pack(side='left')
206
+ else: # vertical
207
+ button.pack(side='top', fill='x')
208
+
209
+ self._buttons[key] = button
210
+ self._update_button_positions()
211
+ return button
212
+
213
+ def _update_button_positions(self):
214
+ """Update button styles based on their position in the group.
215
+
216
+ Note: Relies on dictionary insertion order (Python 3.7+) to maintain
217
+ button order based on when they were added.
218
+ """
219
+ # List conversion maintains insertion order (Python 3.7+)
220
+ button_list = list(self._buttons.values())
221
+ num_buttons = len(button_list)
222
+
223
+ if num_buttons == 0:
224
+ return
225
+
226
+ for idx, button in enumerate(button_list):
227
+ if num_buttons == 1:
228
+ # Single button - use 'before' position (fully rounded on left/top)
229
+ position = 'before'
230
+ elif idx == 0:
231
+ # First button
232
+ position = 'before'
233
+ elif idx == num_buttons - 1:
234
+ # Last button
235
+ position = 'after'
236
+ else:
237
+ # Middle button
238
+ position = 'center'
239
+
240
+ # Update position and rebuild style
241
+ button.configure_style_options(position=position)
242
+ button.rebuild_style()
243
+
244
+ def _on_multi_toggle(self, val: str):
245
+ """Callback to update the SetVar when a CheckToggle is clicked."""
246
+ current_set = self.get()
247
+ if val in current_set:
248
+ current_set.remove(val)
249
+ else:
250
+ current_set.add(val)
251
+ self.set(current_set)
252
+
253
+ def get(self) -> str | set[str]:
254
+ """Return the current value (string for single mode, set for multi mode)."""
255
+ return self.variable.get()
256
+
257
+ def set(self, value: str | set[str]) -> None:
258
+ """Set the value (string for single mode, set for multi mode).
259
+
260
+ Args:
261
+ value: The value to set.
262
+
263
+ Raises:
264
+ TypeError: If value type doesn't match the mode.
265
+ """
266
+ # Validate value type matches mode
267
+ if self._mode == 'single':
268
+ if not isinstance(value, str):
269
+ raise TypeError(f"Single mode requires a string value, got {type(value).__name__}")
270
+ else: # multi mode
271
+ if not isinstance(value, set):
272
+ raise TypeError(f"Multi mode requires a set value, got {type(value).__name__}")
273
+
274
+ self.variable.set(value)
275
+
276
+ # For multi mode, update CheckToggle states to match new value
277
+ if self._mode == 'multi':
278
+ for key, button in self._buttons.items():
279
+ button.variable.set(key in value)
280
+
281
+ @property
282
+ def value(self) -> str | set[str]:
283
+ """Get or set the value (string for single mode, set for multi mode)."""
284
+ return self.get()
285
+
286
+ @value.setter
287
+ def value(self, value: str | set[str]) -> None:
288
+ self.set(value)
289
+
290
+ def text_for(self, value: Any) -> str | None:
291
+ """Return the display text of the option with the given value, or None.
292
+
293
+ The selection variable coerces values to strings, so match on the
294
+ stringified key when an exact lookup misses.
295
+ """
296
+ if value is None or value == "":
297
+ return None
298
+ button = self._buttons.get(value)
299
+ if button is None:
300
+ button = next((b for k, b in self._buttons.items() if str(k) == str(value)), None)
301
+ return button.cget('text') if button is not None else None
302
+
303
+ def remove(self, key: str):
304
+ """Remove a button by its key."""
305
+ if key in self._buttons:
306
+ button = self._buttons.pop(key)
307
+ button.destroy()
308
+ self._update_button_positions()
309
+
310
+ def items(self) -> tuple[RadioToggle | CheckToggle, ...]:
311
+ """Get all button widgets in the group.
312
+
313
+ Returns:
314
+ A tuple of all button instances in the group.
315
+ """
316
+ return tuple(self._buttons.values())
317
+
318
+ def item(self, key: str) -> RadioToggle | CheckToggle:
319
+ """Get a button by its key.
320
+
321
+ Args:
322
+ key: The key of the button to retrieve.
323
+
324
+ Returns:
325
+ The button instance.
326
+
327
+ Raises:
328
+ KeyError: If no button with the given key exists.
329
+ """
330
+ if key not in self._buttons:
331
+ raise KeyError(f"No button with key '{key}'")
332
+ return self._buttons[key]
333
+
334
+ def configure_item(self, key: str, option: str = None, **kwargs: Any):
335
+ """Configure a specific button by its key.
336
+
337
+ Args:
338
+ key: The key of the button to configure.
339
+ option: If provided, return the value of this option.
340
+ **kwargs: Configuration options to apply to the button.
341
+
342
+ Returns:
343
+ If option is provided, returns the value of that option.
344
+ """
345
+ button = self.item(key)
346
+ if option is not None:
347
+ return button.cget(option)
348
+ button.configure(**kwargs)
349
+
350
+ def keys(self) -> tuple[str, ...]:
351
+ """Get all button keys.
352
+
353
+ Returns:
354
+ A tuple of all button keys in the group.
355
+ """
356
+ return tuple(self._buttons.keys())
357
+
358
+ def on_changed(self, callback: Callable) -> Any:
359
+ """Subscribe to value changes.
360
+
361
+ Args:
362
+ callback: Called when the selection changes. Receives the new value
363
+ directly (not a Tk event object): `str` in single mode,
364
+ `set[str]` in multi mode.
365
+
366
+ Returns:
367
+ Subscription ID — pass to `off_changed()` to unsubscribe.
368
+ """
369
+ return self._signal.subscribe(callback)
370
+
371
+ def off_changed(self, bind_id: Any) -> None:
372
+ """Cancel a subscription created by `on_changed()`.
373
+
374
+ Args:
375
+ bind_id: The handle returned by `on_changed()`.
376
+ """
377
+ if bind_id is not None:
378
+ bind_id.cancel()
379
+
380
+ @configure_delegate('accent')
381
+ def _delegate_accent(self, value=None):
382
+ """Get or set the accent. Updates all buttons when changed."""
383
+ if value is None:
384
+ return self._accent
385
+
386
+ self._accent = value
387
+ # Update all buttons with new accent
388
+ self._update_button_positions()
389
+
390
+ @configure_delegate('orient')
391
+ def _delegate_orient(self, value=None):
392
+ """Get or set orientation ('horizontal' or 'vertical'). Repacks buttons when changed."""
393
+ if value is None:
394
+ return self._orientation
395
+
396
+ if value not in ('horizontal', 'vertical'):
397
+ raise ValueError("orient must be 'horizontal' or 'vertical'")
398
+
399
+ self._orientation = value
400
+
401
+ # Repack all buttons in new orientation
402
+ for button in self._buttons.values():
403
+ button.pack_forget()
404
+ button.configure_style_options(orient=value)
405
+ if self._orientation == 'horizontal':
406
+ button.pack(side='left')
407
+ else:
408
+ button.pack(side='top', fill='x')
409
+
410
+ # Update button styles with new orientation
411
+ self._update_button_positions()
412
+
413
+ @configure_delegate('value')
414
+ def _delegate_value(self, value=None):
415
+ """Get or set the value via configure."""
416
+ if value is None:
417
+ return self.get()
418
+ self.set(value)