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,358 @@
1
+ """FilterDialog - A dialog for filtering and selecting multiple items from a list.
2
+
3
+ This module provides a multi-select dialog with optional search and select-all
4
+ functionality. Items can be displayed with checkboxes, and the dialog supports
5
+ both standard and undecorated (custom-chrome) display modes.
6
+ """
7
+
8
+ from tkinter import Widget
9
+ from typing import Any, Callable, Literal, Optional, Tuple, Union
10
+ from types import SimpleNamespace
11
+
12
+ from bootstack.widgets._impl.primitives import CheckButton, Frame, Label, Separator
13
+ from bootstack.widgets.types import Master
14
+ from bootstack.widgets._impl.composites.textentry import TextEntry
15
+ from bootstack._runtime.app import Window
16
+ from bootstack.dialogs._impl.dialog import Dialog, DialogButton
17
+ from bootstack.widgets._impl.composites.scrollview import ScrollView
18
+ from bootstack.widgets._impl.primitives.flexframe import FlexFrame
19
+ from bootstack._runtime.window_utilities import AnchorPoint
20
+
21
+ ttk = SimpleNamespace(
22
+ Checkbutton=CheckButton,
23
+ Frame=Frame,
24
+ Label=Label,
25
+ Separator=Separator,
26
+ TextEntry=TextEntry,
27
+ Window=Window,
28
+ )
29
+
30
+
31
+ class FilterDialogContent(ttk.Frame):
32
+ """Internal content frame for FilterDialog.
33
+
34
+ This frame contains the search box, select-all checkbox, and scrollable
35
+ list of checkboxes for filtering items.
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ master: Master = None,
41
+ enable_search: bool = False,
42
+ enable_select_all: bool = False,
43
+ items: list[str | dict[str, Any]] = None
44
+ ):
45
+ """Initialize the FilterDialogContent frame.
46
+
47
+ Args:
48
+ master: Parent widget. If None, uses the default root window.
49
+ enable_search: If True, includes a search box to filter items by text.
50
+ enable_select_all: If True, includes a "Select All" checkbox.
51
+ items: List of items to display. Can be strings or dicts with keys:
52
+ - text (str): Display text (required for dict items)
53
+ - value (Any): Value to return when selected (defaults to text)
54
+ - selected (bool): Initial selection state (defaults to False)
55
+ """
56
+ super().__init__(master)
57
+ self._enable_search = enable_search
58
+ self._enable_select_all = enable_select_all
59
+ self._selected_items = []
60
+ self._items = self._normalize_items(items)
61
+ self._filter: str | None = None
62
+ self._check_buttons: dict[str, ttk.Checkbutton] = {}
63
+ self._select_all_cb: ttk.Checkbutton | None = None
64
+ self._scroll_container: ttk.Frame | None = None
65
+ self._build_content()
66
+
67
+ def _normalize_items(self, items: list[str | dict[str, Any]] | None) -> list[dict[str, Any]]:
68
+ """Normalize items to a consistent dict format.
69
+
70
+ Args:
71
+ items: List of strings or dicts representing items.
72
+
73
+ Returns:
74
+ List of dicts with 'text', 'value', and 'selected' keys.
75
+
76
+ Raises:
77
+ ValueError: If a dict item is missing the 'text' key.
78
+ """
79
+ if items is None:
80
+ return []
81
+
82
+ out = []
83
+ for item in items:
84
+ if isinstance(item, str):
85
+ out.append(dict(text=item, value=item, selected=False))
86
+ else:
87
+ if 'text' not in item:
88
+ raise ValueError('Item must have "text" key')
89
+
90
+ if 'selected' not in item:
91
+ item['selected'] = False
92
+ item.setdefault('value', item['text'])
93
+ if item['selected']:
94
+ self._selected_items.append(item['value'])
95
+ out.append(item)
96
+ return out
97
+
98
+ def _build_content(self):
99
+ """Build and layout all UI components."""
100
+ # Search box
101
+ if self._enable_search:
102
+ search_entry = ttk.TextEntry(self)
103
+ search_entry.insert_addon(ttk.Label, 'before', icon='search')
104
+ search_entry.pack(fill='x')
105
+ search_entry.on_input(self._on_search_input)
106
+
107
+ # Select all checkbox
108
+ if self._enable_select_all:
109
+ self._select_all_cb = ttk.Checkbutton(self, text='edit.select_all')
110
+ self._select_all_cb.invoke()
111
+ self._select_all_cb.invoke()
112
+ self._select_all_cb['command'] = self._handle_select_all
113
+ self._select_all_cb.pack(fill='x', padx=8, pady=(12, 8))
114
+ ttk.Separator(self).pack(fill='x')
115
+
116
+ # Scrollable container for checkboxes
117
+ scroll_view = ScrollView(
118
+ self,
119
+ scroll_direction='vertical',
120
+ scrollbar_visibility='always',
121
+ scrollbar_variant='thin'
122
+ )
123
+ scroll_view.pack(fill='both', expand=False, pady=(8, 0))
124
+ scroll_view.configure(height=230)
125
+
126
+ # Managed flex content frame — the same one the public ScrollView uses
127
+ # (direction='vertical', horizontal_items='stretch'), so rows fill the
128
+ # viewport width and the canvas sizing is handled for us. Replaces the old
129
+ # raw frame, which hand-rolled the width-stretch and clipped at the edge.
130
+ self._scroll_container = FlexFrame(
131
+ scroll_view.canvas, direction='vertical', horizontal_items='stretch'
132
+ )
133
+ scroll_view.add(self._scroll_container)
134
+
135
+ # Add item checkboxes
136
+ for item in self._items:
137
+ cb = ttk.Checkbutton(self._scroll_container, text=item['text'])
138
+ cb.invoke()
139
+ if not item['selected']:
140
+ cb.invoke()
141
+ cb['command'] = lambda value=item['value']: self._on_item_clicked(value)
142
+ self._scroll_container.add_child(cb, {'padx': 8, 'pady': 8})
143
+ self._check_buttons[item['text']] = cb
144
+
145
+ def _handle_select_all(self):
146
+ """Toggle selection state of all checkboxes."""
147
+ if 'selected' in self._select_all_cb.state():
148
+ for item in self._check_buttons.values():
149
+ item.instate(['!selected'], item.invoke)
150
+ else:
151
+ for item in self._check_buttons.values():
152
+ item.instate(['selected'], item.invoke)
153
+
154
+ def _on_search_input(self, event):
155
+ """Filter visible checkboxes based on search text."""
156
+ self._filter = (event.data.text or '').lower()
157
+
158
+ # Re-flow only the matching rows, in their original order.
159
+ for cb in self._check_buttons.values():
160
+ self._scroll_container.remove_child(cb)
161
+ for key, cb in self._check_buttons.items():
162
+ if self._filter in key.lower():
163
+ self._scroll_container.add_child(cb, {'padx': 8, 'pady': 8})
164
+
165
+ def _on_item_clicked(self, value):
166
+ """Update selected items list when a checkbox is clicked."""
167
+ if value in self._selected_items:
168
+ self._selected_items.remove(value)
169
+ else:
170
+ self._selected_items.append(value)
171
+
172
+ def get_selected_items(self):
173
+ """Return the list of selected item values."""
174
+ return self._selected_items
175
+
176
+
177
+ class FilterDialog(ttk.Frame):
178
+ """A dialog for filtering and selecting multiple items from a list.
179
+
180
+ This dialog displays a list of checkboxes with optional search and select-all
181
+ functionality. When the user clicks OK, the selected values are stored in
182
+ the result property.
183
+
184
+ Attributes:
185
+ result (list[Any] | None): List of selected values after dialog is closed,
186
+ or None if canceled.
187
+ """
188
+
189
+ def __init__(
190
+ self,
191
+ master: Master = None,
192
+ title: str = "Filter",
193
+ items: list[str | dict[str, Any]] = None,
194
+ enable_search: bool = False,
195
+ enable_select_all: bool = False,
196
+ undecorated: bool = False
197
+ ):
198
+ """Initialize the FilterDialog.
199
+
200
+ Args:
201
+ master: Parent widget. If None, uses the default root window.
202
+ title: Dialog window title.
203
+ items: List of items to display. Can be strings or dicts with keys:
204
+ - text (str): Display text (required for dict items)
205
+ - value (Any): Value to return when selected (defaults to text)
206
+ - selected (bool): Initial selection state (defaults to False)
207
+ enable_search: If True, includes a search box to filter items by text.
208
+ enable_select_all: If True, includes a "Select All" checkbox.
209
+ undecorated: If True, removes window decorations and displays with a
210
+ border frame. Enables dismiss-on-outside-click behavior.
211
+ """
212
+ super().__init__(master)
213
+ self._master = master if master else self.master
214
+ self._title = title
215
+ self._items = items or []
216
+ self._enable_search = enable_search
217
+ self._enable_select_all = enable_select_all
218
+ self._undecorated = undecorated
219
+ self._content: FilterDialogContent | None = None
220
+ self._dialog: Dialog | None = None
221
+ self.result: list[Any] | None = None
222
+
223
+ def _build_content(self, parent):
224
+ """Build the dialog content with FilterDialogContent."""
225
+ self._content = FilterDialogContent(
226
+ master=parent,
227
+ enable_search=self._enable_search,
228
+ enable_select_all=self._enable_select_all,
229
+ items=self._items
230
+ )
231
+ padding = 0 if self._undecorated else 10
232
+ self._content.pack(fill='both', expand=True, padx=padding, pady=padding)
233
+
234
+ # Setup dismiss-on-click for undecorated after dialog is built
235
+ if self._undecorated:
236
+ parent.after(10, self._setup_undecorated_dismiss)
237
+
238
+ def _on_ok(self, dialog: Dialog):
239
+ """Save selected items to result when OK button is clicked."""
240
+ if self._content:
241
+ self.result = self._content.get_selected_items()
242
+ # Generate selection changed event on confirmation
243
+ if self.result is not None:
244
+ self.event_generate('<<SelectionChange>>', data={"selected": self.result.copy()})
245
+
246
+ def on_selection_changed(self, callback: Callable) -> str:
247
+ """Bind to `<<SelectionChange>>`. Callback receives `event.data = {"selected": list[Any]}`.
248
+
249
+ Returns:
250
+ Binding identifier for use with off_selection_changed().
251
+ """
252
+ return self.bind('<<SelectionChange>>', callback, add=True)
253
+
254
+ def off_selection_changed(self, bind_id: str = None):
255
+ """Unbind callback from <<SelectionChange>> event.
256
+
257
+ Args:
258
+ bind_id: Binding identifier from on_selection_changed().
259
+ """
260
+ self.unbind('<<SelectionChange>>', bind_id)
261
+
262
+ def _on_click(self, event):
263
+ """Check if click is outside dialog and dismiss if so."""
264
+ if not self._dialog or not self._dialog.toplevel:
265
+ return
266
+
267
+ try:
268
+ # Get dialog window bounds
269
+ x = self._dialog.toplevel.winfo_rootx()
270
+ y = self._dialog.toplevel.winfo_rooty()
271
+ w = self._dialog.toplevel.winfo_width()
272
+ h = self._dialog.toplevel.winfo_height()
273
+
274
+ # Check if click is outside dialog
275
+ if not (x <= event.x_root <= x + w and y <= event.y_root <= y + h):
276
+ self._dialog.toplevel.destroy()
277
+ except:
278
+ pass
279
+
280
+ def _setup_undecorated_dismiss(self):
281
+ """Setup dismiss-on-outside-click for undecorated dialogs."""
282
+ if self._undecorated and self._dialog and self._dialog.toplevel:
283
+ # Bind to root window to catch all clicks
284
+ root = self._dialog.toplevel.winfo_toplevel()
285
+ while root.master:
286
+ root = root.master.winfo_toplevel()
287
+ root.bind('<Button-1>', self._on_click, add='+')
288
+
289
+ def show(
290
+ self,
291
+ position: Optional[Tuple[int, int]] = None,
292
+ modal: Optional[bool] = None,
293
+ *,
294
+ anchor_to: Optional[Union[Widget, Literal["screen", "cursor", "parent"]]] = None,
295
+ anchor_point: AnchorPoint = 'center',
296
+ window_point: AnchorPoint = 'center',
297
+ offset: Tuple[int, int] = (0, 0),
298
+ auto_flip: Union[bool, Literal['vertical', 'horizontal']] = False
299
+ ) -> Optional[list[Any]]:
300
+ """Show the dialog and return the selected items.
301
+
302
+ Args:
303
+ position: Optional (x, y) coordinates to position the dialog.
304
+ If provided, takes precedence over anchor-based positioning.
305
+ modal: Override the mode's default modality.
306
+ If None, uses True (modal mode).
307
+ anchor_to: Positioning target. Can be:
308
+ - Widget: Anchor to a specific widget
309
+ - "screen": Anchor to screen edges/corners
310
+ - "cursor": Anchor to mouse cursor location
311
+ - "parent": Anchor to parent window (same as widget)
312
+ - None: Centers on parent (default)
313
+ anchor_point: Point on the anchor target (n, s, e, w, ne, nw, se, sw, center).
314
+ Default 'center'.
315
+ window_point: Point on the dialog window (n, s, e, w, ne, nw, se, sw, center).
316
+ Default 'center'.
317
+ offset: Additional (x, y) offset in pixels from the anchor position.
318
+ auto_flip: Smart positioning to keep window on screen.
319
+ - False: No flipping (default)
320
+ - True: Flip both vertically and horizontally as needed
321
+ - 'vertical': Only flip up/down
322
+ - 'horizontal': Only flip left/right
323
+
324
+ Returns:
325
+ List of selected item values, or None if canceled.
326
+ """
327
+ self._dialog: Dialog = Dialog(
328
+ parent=self._master,
329
+ title=self._title,
330
+ content_builder=self._build_content,
331
+ _raw_content=True,
332
+ buttons=[
333
+ DialogButton(text="button.cancel", role="cancel", result=None),
334
+ DialogButton(
335
+ text="button.ok",
336
+ role="primary",
337
+ result=True,
338
+ default=True,
339
+ command=self._on_ok
340
+ )
341
+ ],
342
+ min_size=(250, 200),
343
+ max_size=(250, 380),
344
+ resizable=(False, True),
345
+ mode="modal",
346
+ undecorated=self._undecorated
347
+ )
348
+
349
+ self._dialog.show(
350
+ position=position,
351
+ modal=modal,
352
+ anchor_to=anchor_to,
353
+ anchor_point=anchor_point,
354
+ window_point=window_point,
355
+ offset=offset,
356
+ auto_flip=auto_flip
357
+ )
358
+ return self.result