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,419 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable, TYPE_CHECKING
4
+
5
+ from bootstack.widgets._impl.composites.dropdownbutton import DropdownButton as _InternalDropdownButton
6
+ from bootstack.widgets._core.base import PublicWidgetBase
7
+ from bootstack.widgets._core.icon_image_props import IconProperty
8
+ from bootstack.widgets.types import AccentToken, WidgetDensity, ButtonVariant, IconSpec, LocalizeMode
9
+ from bootstack.events import MenuSelectEvent
10
+
11
+ if TYPE_CHECKING:
12
+ from bootstack.signals import Signal
13
+
14
+ # Public item type names → internal ContextMenu type strings.
15
+ _ITEM_TYPE_MAP: dict[str, str] = {
16
+ "command": "command",
17
+ "check": "checkbutton",
18
+ "radio": "radiobutton",
19
+ "divider": "separator",
20
+ # accept legacy/internal names so existing code doesn't break
21
+ "checkbutton": "checkbutton",
22
+ "radiobutton": "radiobutton",
23
+ "separator": "separator",
24
+ }
25
+
26
+
27
+ def _resolve_item_type(type_: str) -> str:
28
+ resolved = _ITEM_TYPE_MAP.get(type_)
29
+ if resolved is None:
30
+ raise ValueError(
31
+ f"Unknown item type {type_!r}. "
32
+ f"Use 'command', 'check', 'radio', or 'divider'."
33
+ )
34
+ return resolved
35
+
36
+
37
+ def _translate_item(item: dict[str, Any]) -> dict[str, Any]:
38
+ """Translate a public item dict to the internal ContextMenu shape.
39
+
40
+ Maps the public `type` name to its internal string and the public `on_click`
41
+ callback key to the toolkit's `command`, so item dicts never need toolkit
42
+ names. Returns a copy; the input is left untouched.
43
+ """
44
+ item = dict(item)
45
+ if "type" in item:
46
+ item["type"] = _resolve_item_type(item["type"])
47
+ if "on_click" in item:
48
+ item["command"] = item.pop("on_click")
49
+ return item
50
+
51
+
52
+ # Keys that map to explicit constructor parameters — user **kwargs must not
53
+ # override these silently.
54
+ _RESERVED_INTERNAL_KEYS = frozenset({
55
+ "show_dropdown_button", "popdown_options", "text", "items", "command",
56
+ "icon", "icon_only", "state", "accent", "variant", "density",
57
+ })
58
+
59
+
60
+ class MenuButton(IconProperty, PublicWidgetBase):
61
+ """A button that opens a dropdown menu when clicked.
62
+
63
+ Items are added at construction via `items=` or dynamically with
64
+ `add_item()`. The `on_select` callback fires for every item click,
65
+ receiving a dict with `type`, `text`, and `value` keys.
66
+
67
+ Args:
68
+ text: Button text. Defaults to an empty string.
69
+ items: Initial list of item dicts. Each dict must have a `type`
70
+ key (`'command'`, `'check'`, `'radio'`, or
71
+ `'divider'`) plus item-specific keys such as `text`,
72
+ `icon`, `value`, and `on_click` (the per-item callback).
73
+ on_select: Callback fired when any menu item is activated. Called with
74
+ a :class:`~bootstack.events.MenuSelectEvent` (`type`, `text`,
75
+ `value` of the activated item).
76
+ icon: Icon name shown on the button face.
77
+ icon_only: If `True`, hides the label and shows only the icon.
78
+ Inferred automatically when `icon=` is set and `label` is
79
+ empty. Defaults to `False`.
80
+ show_arrow: If `True` (default), shows the dropdown chevron arrow.
81
+ Pass `False` to hide it (useful when the icon implies the action).
82
+ menu_options: Extra options forwarded to the underlying `ContextMenu`
83
+ at construction (e.g. `{'anchor': 'se', 'offset': 4}`).
84
+ disabled: If `True`, button is shown but non-interactive. Defaults
85
+ to `False`.
86
+ accent: Color intent token. Defaults to the theme default.
87
+ variant: Style variant. Default `'ghost'`.
88
+ density: Layout density.
89
+ textsignal: `Signal[str]` bound to the button label text.
90
+ localize: Whether the button text is translated through the catalog —
91
+ `True`, `False`, or `'auto'`. Defaults to the app's `localize_mode`.
92
+ parent: Override the context-stack parent widget.
93
+ **kwargs: Layout placement options applied by the parent container —
94
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
95
+ See :doc:`/tasks/layout`.
96
+ """
97
+
98
+ def __init__(
99
+ self,
100
+ text: str = "",
101
+ *,
102
+ items: list[Any] | None = None,
103
+ on_select: Callable[[MenuSelectEvent], Any] | None = None,
104
+ icon: str | IconSpec | None = None,
105
+ icon_only: bool = False,
106
+ show_arrow: bool = True,
107
+ menu_options: dict[str, Any] | None = None,
108
+ disabled: bool = False,
109
+ accent: AccentToken | str | None = None,
110
+ variant: ButtonVariant = "default",
111
+ density: WidgetDensity | None = None,
112
+ textsignal: "Signal[str] | None" = None,
113
+ localize: LocalizeMode | None = None,
114
+ parent: Any = None,
115
+ **kwargs: Any,
116
+ ) -> None:
117
+ self._reject_signal_text(text)
118
+ self._parent = self._resolve_parent(parent)
119
+ layout_kw = self._split_layout_kwargs(kwargs)
120
+ tk_master = self._parent._child_master() if self._parent else None
121
+
122
+ # Build internal kwargs from explicit params first, then let **kwargs
123
+ # add extras — but never let **kwargs clobber an explicitly-set key.
124
+ internal_kwargs: dict[str, Any] = {
125
+ "show_dropdown_button": show_arrow,
126
+ }
127
+ if menu_options is not None:
128
+ internal_kwargs["popdown_options"] = menu_options
129
+ if text:
130
+ internal_kwargs["text"] = text
131
+ if items is not None:
132
+ internal_kwargs["items"] = [_translate_item(it) for it in items]
133
+ if on_select is not None:
134
+ _user_on_select = on_select
135
+ def _on_select(data: dict[str, Any]) -> None:
136
+ _user_on_select(MenuSelectEvent(
137
+ type=data.get("type", ""),
138
+ text=data.get("text", ""),
139
+ value=data.get("value"),
140
+ ))
141
+ internal_kwargs["command"] = _on_select
142
+ if icon is not None:
143
+ internal_kwargs["icon"] = icon
144
+ if icon_only:
145
+ internal_kwargs["icon_only"] = True
146
+ if disabled:
147
+ internal_kwargs["state"] = "disabled"
148
+ if accent is not None:
149
+ internal_kwargs["accent"] = accent
150
+ if variant is not None:
151
+ internal_kwargs["variant"] = variant
152
+ if density is not None:
153
+ internal_kwargs["density"] = density
154
+ if textsignal is not None:
155
+ internal_kwargs["textsignal"] = textsignal
156
+ if localize is not None:
157
+ internal_kwargs["localize"] = localize
158
+
159
+ # Merge extra kwargs, skipping any that would override an explicit param.
160
+ for k, v in kwargs.items():
161
+ if k not in _RESERVED_INTERNAL_KEYS:
162
+ internal_kwargs[k] = v
163
+
164
+ self._internal = _InternalDropdownButton(tk_master, **internal_kwargs)
165
+ self._attach_to_parent(layout_kw)
166
+
167
+ # ----- Item management -----
168
+
169
+ def add_item(
170
+ self,
171
+ label: str,
172
+ *,
173
+ on_click: Callable[[], Any] | None = None,
174
+ icon: str | None = None,
175
+ shortcut: str | None = None,
176
+ disabled: bool = False,
177
+ key: str | None = None,
178
+ ) -> str:
179
+ """Add a command item to the dropdown.
180
+
181
+ Args:
182
+ label: Item label text.
183
+ on_click: Callback fired when the item is clicked.
184
+ icon: Icon name shown beside the label.
185
+ shortcut: Keyboard shortcut hint displayed on the right. Accepts a
186
+ modifier pattern (`"Mod+S"` → `"Ctrl+S"` / `"⌘S"`), a
187
+ registered shortcut key name, or a literal display string.
188
+ disabled: If True, item is shown but non-interactive.
189
+ key: Unique string key. Auto-generated if omitted.
190
+
191
+ Returns:
192
+ The key assigned to this item.
193
+ """
194
+ kw: dict[str, Any] = {"text": label, "disabled": disabled}
195
+ if on_click is not None:
196
+ kw["command"] = on_click
197
+ if icon is not None:
198
+ kw["icon"] = icon
199
+ if shortcut is not None:
200
+ kw["shortcut"] = shortcut
201
+ if key is not None:
202
+ kw["key"] = key
203
+ result = self._internal.add_command(**kw)
204
+ return result.key if hasattr(result, "key") else key or label
205
+
206
+ def add_check_item(
207
+ self,
208
+ label: str,
209
+ *,
210
+ value: bool = False,
211
+ on_click: Callable[[], Any] | None = None,
212
+ key: str | None = None,
213
+ ) -> str:
214
+ """Add a checkbutton item to the dropdown.
215
+
216
+ Args:
217
+ label: Item label text.
218
+ value: Initial checked state.
219
+ on_click: Callback fired on toggle.
220
+ key: Unique string key. Auto-generated if omitted.
221
+
222
+ Returns:
223
+ The key assigned to this item.
224
+ """
225
+ kw: dict[str, Any] = {"text": label, "value": value}
226
+ if on_click is not None:
227
+ kw["command"] = on_click
228
+ if key is not None:
229
+ kw["key"] = key
230
+ result = self._internal.add_checkbutton(**kw)
231
+ return result.key if hasattr(result, "key") else key or label
232
+
233
+ def add_radio_item(
234
+ self,
235
+ label: str,
236
+ *,
237
+ value: Any = None,
238
+ selected: bool = False,
239
+ on_click: Callable[[], Any] | None = None,
240
+ key: str | None = None,
241
+ ) -> str:
242
+ """Add a radio-button item to the dropdown.
243
+
244
+ All radio items in a `MenuButton` share one group variable
245
+ automatically. Pass `selected=True` on the item that should be
246
+ pre-selected on first open.
247
+
248
+ Note:
249
+ Values are stored as strings internally. Pass string values
250
+ (e.g. `value="100%"`) for predictable comparisons when reading
251
+ the group selection via `menu`.
252
+
253
+ Args:
254
+ label: Item label text.
255
+ value: Value associated with this radio item. Stored as a string
256
+ internally; defaults to `label` when omitted.
257
+ selected: If `True`, this item is the initial selection.
258
+ Defaults to `False`.
259
+ on_click: Callback fired on selection.
260
+ key: Unique string key. Auto-generated if omitted.
261
+
262
+ Returns:
263
+ The key assigned to this item.
264
+ """
265
+ from tkinter import StringVar
266
+ if not hasattr(self, "_radio_variable"):
267
+ self._radio_variable = StringVar(master=self._internal)
268
+ str_value = str(value) if value is not None else label
269
+ if selected:
270
+ self._radio_variable.set(str_value)
271
+ kw: dict[str, Any] = {
272
+ "text": label,
273
+ "value": str_value,
274
+ "variable": self._radio_variable,
275
+ }
276
+ if on_click is not None:
277
+ kw["command"] = on_click
278
+ if key is not None:
279
+ kw["key"] = key
280
+ result = self._internal.add_radiobutton(**kw)
281
+ return result.key if hasattr(result, "key") else key or label
282
+
283
+ def add_divider(self, *, key: str | None = None) -> None:
284
+ """Add a horizontal divider to the dropdown."""
285
+ kw: dict[str, Any] = {}
286
+ if key is not None:
287
+ kw["key"] = key
288
+ self._internal.add_separator(**kw)
289
+
290
+ def add_items(self, items: list[Any]) -> None:
291
+ """Add multiple items at once from a list of item dicts.
292
+
293
+ Each dict must have a `type` key plus item-specific keys:
294
+
295
+ .. code-block:: python
296
+
297
+ mb.add_items([
298
+ {"type": "command", "text": "Edit", "icon": "pencil", "on_click": edit},
299
+ {"type": "command", "text": "Delete", "icon": "trash", "on_click": delete},
300
+ {"type": "divider"},
301
+ {"type": "check", "text": "Pinned", "value": True},
302
+ {"type": "radio", "text": "Small", "value": "sm"},
303
+ ])
304
+
305
+ Args:
306
+ items: List of item dicts. `type` accepts `'command'`,
307
+ `'check'`, `'radio'`, or `'divider'`; an item's
308
+ `on_click` key sets its per-item callback.
309
+ """
310
+ self._internal.add_items([_translate_item(it) for it in items])
311
+
312
+ def insert_item(self, index: int, type: str, **kwargs: Any) -> str:
313
+ """Insert a new item at a specific position.
314
+
315
+ Args:
316
+ index: Zero-based position to insert at.
317
+ type: Item type — `'command'`, `'check'`, `'radio'`,
318
+ or `'divider'`.
319
+ **kwargs: Forwarded to the matching `add_*` method.
320
+
321
+ Returns:
322
+ The key assigned to the new item.
323
+ """
324
+ if "on_click" in kwargs:
325
+ kwargs["command"] = kwargs.pop("on_click")
326
+ result = self._internal.insert_item(index, _resolve_item_type(type), **kwargs)
327
+ return result.key if hasattr(result, "key") else result
328
+
329
+ def move_item(self, key: str, to_index: int) -> None:
330
+ """Move an existing item to a new position.
331
+
332
+ Args:
333
+ key: Key of the item to move.
334
+ to_index: Target zero-based index.
335
+ """
336
+ self._internal.move_item(key, to_index)
337
+
338
+ def update_item(self, key: str, **kwargs: Any) -> None:
339
+ """Reconfigure a dropdown item after creation.
340
+
341
+ Args:
342
+ key: Key returned by an `add_*` method.
343
+ **kwargs: Options forwarded to the item's configure method.
344
+ """
345
+ self._internal.configure_item(key, **kwargs)
346
+
347
+ def remove_item(self, key: str) -> None:
348
+ """Remove a dropdown item by key.
349
+
350
+ Args:
351
+ key: Key returned by an `add_*` method.
352
+ """
353
+ self._internal.remove_item(key)
354
+
355
+ def show_menu(self) -> None:
356
+ """Open the dropdown menu programmatically.
357
+
358
+ Has no effect if the button is disabled or read-only.
359
+ """
360
+ if not self._internal.instate(("!disabled", "!readonly")):
361
+ return
362
+ self._internal.show_menu()
363
+
364
+ # ----- Properties -----
365
+
366
+ def item(self, key: str) -> Any:
367
+ """Return the item object for `key`.
368
+
369
+ Args:
370
+ key: Key returned by an `add_*` method.
371
+ """
372
+ return self._internal.context_menu.item(key)
373
+
374
+ @property
375
+ def items(self) -> list[Any]:
376
+ """All menu items in insertion order."""
377
+ return self._internal.items() or []
378
+
379
+ @property
380
+ def keys(self) -> tuple[str, ...]:
381
+ """Keys of all menu items in insertion order."""
382
+ return self._internal.keys()
383
+
384
+ @property
385
+ def menu(self) -> Any:
386
+ """The underlying `ContextMenu` — for advanced programmatic access."""
387
+ return self._internal.context_menu
388
+
389
+ @property
390
+ def text(self) -> str:
391
+ """The button's label text.
392
+
393
+ Reading reflects a bound `textsignal` (the option stays synced from
394
+ the variable). Setting writes through the bound variable when one
395
+ owns the text — keeping the signal in sync — and falls back to the
396
+ option otherwise. On an icon-only button the label stays hidden;
397
+ the setter still updates the underlying text.
398
+ """
399
+ return str(self._internal.cget("text"))
400
+
401
+ @text.setter
402
+ def text(self, value: str) -> None:
403
+ # When a textsignal/textvariable owns the text, ttk ignores the `text`
404
+ # option — write through the variable instead (which also keeps the
405
+ # bound signal in sync). Falls back to the option when unbound.
406
+ textvar = getattr(self._internal, "_textvariable", None)
407
+ if textvar is not None:
408
+ textvar.set(value)
409
+ else:
410
+ self._internal.configure(text=value)
411
+
412
+ @property
413
+ def disabled(self) -> bool:
414
+ """Whether the button is non-interactive."""
415
+ return self._internal.instate(("disabled",))
416
+
417
+ @disabled.setter
418
+ def disabled(self, v: bool) -> None:
419
+ self._internal.configure(state="disabled" if v else "normal")