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,345 @@
1
+ """The static navigation panel — single-select items, headers, separators, footer.
2
+
3
+ `NavPanel` renders a flat, single-select list into a sidebar region: items in a
4
+ scrolling main area plus a pinned footer area. Each item is a `RadioToggle`
5
+ sharing one `Signal`, so single-select is the radio machinery itself — no
6
+ hand-rolled selection state. The items are styled via a native Toolbutton
7
+ **variant** (`nav-quiet` under a rail; `nav-pill` standalone is added later), so
8
+ the look is driven by the style engine, not custom composite state.
9
+
10
+ Selection truth still lives in the shell's `NavModel`: clicking an item reports
11
+ the key via the `on_select` callback; the shell decides what becomes active and
12
+ calls `select()` back (setting the shared signal) to reflect it.
13
+
14
+ Section headers are plain, non-interactive labels (they chunk a flat list and
15
+ hide on compaction). There is no built-in collapsible section — hiding/revealing
16
+ a sub-list is a content concern (compose `bs.Accordion` in a custom panel).
17
+ Compaction to icon-only is a native `-compound` toggle on each item
18
+ (`'left'` <-> `'image'`); headers and separators hide while compact.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Callable
24
+
25
+ from bootstack.signals import Signal
26
+ from bootstack.style.style import get_style
27
+ from bootstack.widgets._impl.primitives.frame import Frame
28
+ from bootstack.widgets._impl.primitives.radiotoggle import RadioToggle
29
+ from bootstack.widgets._impl.composites.scrollview import ScrollView
30
+ from bootstack.widgets._impl.composites.sidenav.header import SideNavHeader
31
+ from bootstack.widgets._impl.composites.sidenav.separator import SideNavSeparator
32
+
33
+
34
+ # Container-controlled spacing (the button's own size is the style's job).
35
+ _ITEM_GAP = 3 # vertical gap between nav buttons
36
+ _COMPACT_INSET = 6 # horizontal inset of the compact (rail-width) sidebar
37
+
38
+
39
+ class NavPanel(Frame):
40
+ """A flat, single-select list of navigation items with a pinned footer.
41
+
42
+ Args:
43
+ master: Parent widget (a sidebar region).
44
+ on_select: Called with an item key when that item is clicked.
45
+ accent: Accent token for the active item.
46
+ variant: Toolbutton style variant for the items (the tier treatment) —
47
+ `'nav-quiet'` under a rail, `'nav-pill'` standalone.
48
+ surface: Surface token the items sit on (the sidebar region surface).
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ master,
54
+ *,
55
+ on_select: Callable[[str], None],
56
+ accent: str | None = None,
57
+ variant: str = "nav-quiet",
58
+ surface: str = "card",
59
+ selection: str = "ghost",
60
+ ) -> None:
61
+ super().__init__(master, surface=surface)
62
+ self._on_select = on_select
63
+ self._accent = accent
64
+ self._variant = variant
65
+ self._surface = surface
66
+ self._selection = selection
67
+ self._items: dict[str, RadioToggle] = {}
68
+ self._compact = False
69
+ # Shared selection signal: value is the selected item key (radio
70
+ # single-select). "" is the sentinel for "nothing selected" (a Signal is
71
+ # typed by its initial value, so it can't hold None here).
72
+ self._signal: Signal = Signal("")
73
+ # Insertion-ordered main-area children (items, headers, separators) so
74
+ # compaction can re-pack them in order; footer items tracked separately.
75
+ self._main_children: list = []
76
+ self._footer_items: list = []
77
+
78
+ # Pill items are inset from the sidebar edges (the rounded pill needs
79
+ # breathing room from the container); quiet rows run full-width.
80
+ self._inset = 8 if variant == "nav-pill" else 0
81
+ self._current_inset = self._inset
82
+
83
+ # Footer pinned to the bottom; the item area scrolls in the space above it
84
+ # (a wheel-scrollable canvas with an auto-hiding bar — the footer itself
85
+ # never scrolls). The canvas background is painted to the sidebar surface
86
+ # so the area below short content doesn't flash the default canvas color.
87
+ self._footer = Frame(self, surface=surface)
88
+ self._footer.pack(side="bottom", fill="x")
89
+ # A divider above the footer, shown ONLY when the item area scrolls — so a
90
+ # pinned footer reads as its own band instead of abutting a clipped row.
91
+ # When everything fits it stays hidden (no needless chrome). The vertical
92
+ # padding gives the line breathing room from the last scrolled row above
93
+ # and the footer item below (a flush line reads as cramped).
94
+ self._footer_divider = SideNavSeparator(self, surface=surface, padding=(0, 8, 0, 8))
95
+ # Start with no gutter/bar; overflow detection switches it on only when the
96
+ # content is actually tall enough to scroll (see _update_overflow_state).
97
+ self._scroll = ScrollView(
98
+ self,
99
+ scroll_direction="vertical",
100
+ scrollbar_visibility="never",
101
+ scrollbar_variant="thin",
102
+ surface=surface,
103
+ )
104
+ self._scroll.pack(side="top", fill="both", expand=True)
105
+ self._main = self._scroll.add(surface=surface)
106
+ self._updating_overflow = False
107
+ self._paint_canvas_surface()
108
+ # Re-evaluate the gutter/bar + footer divider whenever the content height
109
+ # or viewport changes (items added/removed, sidebar resized, compaction).
110
+ self._scroll.canvas.bind("<Configure>", lambda _e: self._update_overflow_state(), add="+")
111
+ self._main.bind("<Configure>", lambda _e: self._update_overflow_state(), add="+")
112
+ self._apply_inset(self._inset)
113
+
114
+ def add_item(self, key: str, *, text: str = "", icon=None) -> RadioToggle:
115
+ """Add a selectable item to the main area; wire its click to `on_select`."""
116
+ return self._add_item(self._main, key, text=text, icon=icon, footer=False)
117
+
118
+ def add_footer_item(self, key: str, *, text: str = "", icon=None) -> RadioToggle:
119
+ """Add a selectable item pinned to the footer."""
120
+ return self._add_item(self._footer, key, text=text, icon=icon, footer=True)
121
+
122
+ def _add_item(self, parent: Frame, key: str, *, text: str, icon, footer: bool) -> RadioToggle:
123
+ if key in self._items:
124
+ raise ValueError(f"duplicate nav item key: {key!r}")
125
+ item = RadioToggle(
126
+ parent,
127
+ value=key,
128
+ signal=self._signal,
129
+ text=text,
130
+ icon=icon,
131
+ compound="image" if self._compact else "left",
132
+ accent=self._accent,
133
+ surface=self._surface,
134
+ variant=self._item_variant(),
135
+ style_options={"selection_style": self._selection},
136
+ )
137
+ item.pack(fill="x", pady=(0, _ITEM_GAP))
138
+ # Click reports the key to the shell (which drives NavModel). The radio
139
+ # also updates the shared signal on click; the shell reconciles via select().
140
+ item.bind("<Button-1>", lambda _e, k=key: self._on_select(k), add="+")
141
+ self._items[key] = item
142
+ (self._footer_items if footer else self._main_children).append(item)
143
+ if footer:
144
+ # A footer item may appear after the content is laid out; the divider
145
+ # gate depends on footer presence, so re-evaluate now.
146
+ self._update_overflow_state()
147
+ return item
148
+
149
+ def remove_item(self, key: str) -> None:
150
+ """Remove and destroy an item by key (no error if absent)."""
151
+ item = self._items.pop(key, None)
152
+ if item is not None:
153
+ for tracker in (self._main_children, self._footer_items):
154
+ if item in tracker:
155
+ tracker.remove(item)
156
+ item.destroy()
157
+ if self._signal() == key:
158
+ self._signal.set("")
159
+ self._update_overflow_state()
160
+
161
+ def update_item(self, key: str, *, text: str | None = None, icon=None) -> None:
162
+ """Update an existing item's label and/or icon in place."""
163
+ item = self._items.get(key)
164
+ if item is None:
165
+ return
166
+ if text is not None:
167
+ item.configure(text=text)
168
+ if icon is not None:
169
+ item.configure(icon=icon)
170
+
171
+ def add_header(self, text: str) -> SideNavHeader:
172
+ """Add a plain section-label header to the main area.
173
+
174
+ A header is a quiet, non-interactive label that chunks the flat list; it
175
+ hides while the panel is compacted. (There is no collapsible-header
176
+ primitive — a collapsible sub-list is a content concern.)
177
+
178
+ Uses a tighter top margin than the stock `SideNavHeader` default — the
179
+ header alone carries enough separation, so a roomy top gap reads as
180
+ excess (especially when it follows an item).
181
+ """
182
+ # (left, top, right, bottom) — aligned to the item icon column. A roomier
183
+ # top gap separates the new group from the one above; the small bottom gap
184
+ # keeps the header bound to its own items.
185
+ header = SideNavHeader(self._main, text=text, padding=(12, 16, 12, 4))
186
+ if not self._compact:
187
+ header.pack(fill="x")
188
+ self._main_children.append(header)
189
+ return header
190
+
191
+ def add_divider(self) -> SideNavSeparator:
192
+ """Add a divider to the main area."""
193
+ sep = SideNavSeparator(self._main)
194
+ if not self._compact:
195
+ sep.pack(fill="x")
196
+ self._main_children.append(sep)
197
+ return sep
198
+
199
+ def _relayout_main(self) -> None:
200
+ """Re-pack the main area in insertion order, honoring compact.
201
+
202
+ Compact renders items icon-only (`-compound='image'`) and hides headers
203
+ and separators (a label-less icon strip); expanded shows everything.
204
+ """
205
+ for child in self._main_children:
206
+ child.pack_forget()
207
+ for child in self._main_children:
208
+ if isinstance(child, (SideNavHeader, SideNavSeparator)):
209
+ if not self._compact:
210
+ child.pack(fill="x")
211
+ else: # RadioToggle nav item
212
+ child.pack(fill="x", pady=(0, _ITEM_GAP))
213
+
214
+ def _item_variant(self) -> str:
215
+ """The Toolbutton style variant for items in the current mode."""
216
+ return f"{self._variant}-compact" if self._compact else self._variant
217
+
218
+ def _apply_inset(self, inset: int) -> None:
219
+ """Inset the scrolled item area + footer from the sidebar edges.
220
+
221
+ Pills need breathing room; quiet rows run flush (inset 0). The item area
222
+ is a canvas window (not pack-managed), so its inset is its own padding.
223
+ """
224
+ self._current_inset = inset
225
+ self._apply_insets()
226
+
227
+ def _gutter(self) -> int:
228
+ """Width reserved for the scrollbar while the content overflows (else 0)."""
229
+ if not self._content_overflows():
230
+ return 0
231
+ try:
232
+ w = self._scroll.vertical_scrollbar.winfo_reqwidth()
233
+ return w if w > 1 else 0
234
+ except Exception:
235
+ return 0
236
+
237
+ def _apply_insets(self) -> None:
238
+ """Apply the content + footer insets, accounting for the scrollbar gutter.
239
+
240
+ The gutter sits WITHIN the right inset rather than adding to it, so the
241
+ right margin stays about the left inset (not inset + gutter). The content's
242
+ right padding is reduced by the gutter; the footer (not scrolled) reserves
243
+ max(inset, gutter) so a footer item's right edge still lines up with the
244
+ scrolled rows.
245
+ """
246
+ inset = self._current_inset
247
+ gutter = self._gutter()
248
+ self._main.configure(padding=(inset, inset, max(inset - gutter, 0), 0))
249
+ self._footer.pack_configure(padx=(inset, max(inset, gutter)), pady=(0, inset))
250
+
251
+ def _paint_canvas_surface(self) -> None:
252
+ """Match the scroll canvas background to the sidebar surface token."""
253
+ try:
254
+ color = get_style().style_builder.color(self._surface)
255
+ self._scroll.canvas.configure(background=color)
256
+ except Exception:
257
+ pass
258
+
259
+ # The unified theme walk re-applies the canvas surface on a theme change.
260
+ _bs_apply_theme = _paint_canvas_surface
261
+
262
+ def _content_overflows(self) -> bool:
263
+ """Whether the item content is taller than the scroll viewport.
264
+
265
+ Uses a small epsilon so a 1–4px overhang doesn't toggle the gutter — and,
266
+ with the gutter's own width, gives stable hysteresis (no flicker).
267
+ """
268
+ try:
269
+ bbox = self._scroll.canvas.bbox("all")
270
+ if not bbox:
271
+ return False
272
+ viewport_h = self._scroll.canvas.winfo_height()
273
+ return viewport_h > 1 and (bbox[3] - bbox[1]) > viewport_h + 4
274
+ except Exception:
275
+ return False
276
+
277
+ def _update_overflow_state(self) -> None:
278
+ """Reserve the scrollbar gutter + show the footer divider only on overflow.
279
+
280
+ When the content fits, the bar/gutter is off (`'never'`) so items run
281
+ full-width and there's no footer divider; when it overflows, the gutter +
282
+ auto-hiding bar turn on (`'scroll'`) and a divider separates the pinned
283
+ footer from the scrolling rows.
284
+ """
285
+ if self._updating_overflow:
286
+ return
287
+ self._updating_overflow = True
288
+ try:
289
+ overflow = self._content_overflows()
290
+ desired = "scroll" if overflow else "never"
291
+ if self._scroll.cget("scrollbar_visibility") != desired:
292
+ self._scroll.configure(scrollbar_visibility=desired)
293
+ show_divider = overflow and bool(self._footer_items)
294
+ mapped = self._footer_divider.winfo_manager() != ""
295
+ if show_divider and not mapped:
296
+ # Pack the divider BEFORE the expanding scroll view in the pack
297
+ # order — otherwise, when the content overflows, the `expand=True`
298
+ # scroll claims the whole cavity first and the divider (last in
299
+ # order) is squeezed to zero height and never maps. `side="bottom"`
300
+ # still seats it just above the (earlier-packed) footer.
301
+ self._footer_divider.pack(side="bottom", fill="x", before=self._scroll)
302
+ elif not show_divider and mapped:
303
+ self._footer_divider.pack_forget()
304
+ # Keep the content + footer insets in sync with the gutter so the
305
+ # right margin stays even and footer items align with the scrolled rows.
306
+ self._apply_insets()
307
+ finally:
308
+ self._updating_overflow = False
309
+
310
+ def set_compact(self, compact: bool) -> None:
311
+ """Render items icon-only (compact) or with labels (expanded).
312
+
313
+ Compaction swaps each item to the matching `-compact` style variant (a
314
+ centered icon-only layout) and flips `-compound` to hide the label — both
315
+ native, no custom composite state.
316
+ """
317
+ if self._compact == compact:
318
+ return
319
+ self._compact = compact
320
+ # Compact shrinks the sidebar to the rail width; use a small inset so the
321
+ # pills don't touch the edges (the card pill is narrow enough to fit).
322
+ self._apply_inset(_COMPACT_INSET if compact else self._inset)
323
+ variant = self._item_variant()
324
+ compound = "image" if compact else "left"
325
+ for item in self._items.values():
326
+ item.configure(variant=variant, compound=compound)
327
+ self._relayout_main()
328
+
329
+ @property
330
+ def compact(self) -> bool:
331
+ """Whether the panel is rendering items icon-only."""
332
+ return self._compact
333
+
334
+ def select(self, key: str | None) -> None:
335
+ """Set the visual selection to `key` (or clear it with `None`)."""
336
+ self._signal.set(key if key is not None else "")
337
+
338
+ @property
339
+ def selected(self) -> str | None:
340
+ """The currently selected item key, or `None`."""
341
+ return self._signal() or None
342
+
343
+ def item_keys(self) -> tuple[str, ...]:
344
+ """All item keys (main + footer) in insertion order."""
345
+ return tuple(self._items)