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,138 @@
1
+ """BracketMatcher — highlights matching bracket pairs on cursor move.
2
+
3
+ Filter-style extension: binds to cursor-movement events and applies a
4
+ highlight tag to the bracket under the cursor and its matching pair.
5
+ Uses a flash-and-restore pattern borrowed from idlelib/parenmatch.py.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import tkinter as tk
10
+ from typing import TYPE_CHECKING
11
+
12
+ from bootstack.widgets._impl.composites.textarea.filter import EditFilter
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.widgets._impl.composites.textarea.core import _MultilineCore
16
+
17
+ _OPENERS = "([{"
18
+ _CLOSERS = ")]}"
19
+ _PAIRS = dict(zip(_OPENERS, _CLOSERS))
20
+ _REVERSE = dict(zip(_CLOSERS, _OPENERS))
21
+
22
+ _LAYER = "bracket"
23
+ _STYLE = "match"
24
+ _TAG = f"bs::{_LAYER}::{_STYLE}"
25
+ _FLASH_MS = 500 # how long to show the highlight
26
+
27
+
28
+ class BracketMatcher(EditFilter):
29
+ """Highlights matching bracket pairs when the cursor rests on a bracket.
30
+
31
+ Install via `core.add_filter(BracketMatcher())`.
32
+ The highlight tag `bs::bracket::match` is applied to both the bracket
33
+ under the cursor and its matching partner. It is removed after
34
+ `_FLASH_MS` milliseconds or on the next cursor move.
35
+ """
36
+
37
+ def __init__(self) -> None:
38
+ super().__init__()
39
+ self._core: _MultilineCore | None = None
40
+ self._after_id: str | None = None
41
+
42
+ def attach(self, core: _MultilineCore) -> None:
43
+ self._core = core
44
+ core.define_style(_STYLE, foreground="primary", background="primary[subtle]")
45
+ core.register_layer(_LAYER, priority=5)
46
+ core.text.bind("<<CursorMove>>", self._on_cursor_move, add="+")
47
+ core.text.bind("<KeyRelease>", self._on_cursor_move, add="+")
48
+ core.text.bind("<ButtonRelease-1>", self._on_cursor_move, add="+")
49
+
50
+ def detach(self, core: _MultilineCore) -> None:
51
+ self._clear()
52
+ self._core = None
53
+
54
+ # ── filter pass-through (BracketMatcher doesn't intercept edits) ──────
55
+
56
+ def insert(self, index: str, chars: str, tags=None) -> None:
57
+ self.delegate.insert(index, chars, tags)
58
+
59
+ def delete(self, index1: str, index2: str | None = None) -> None:
60
+ self.delegate.delete(index1, index2)
61
+
62
+ # ── matching logic ────────────────────────────────────────────────────
63
+
64
+ def _on_cursor_move(self, _event=None) -> None:
65
+ self._clear()
66
+ if self._core is None:
67
+ return
68
+ text = self._core.text
69
+ cursor = text.index("insert")
70
+ # Check character at cursor and the one before it
71
+ for idx in (cursor, f"{cursor}-1c"):
72
+ ch = text.get(idx)
73
+ if ch in _OPENERS:
74
+ partner = self._find_close(text, idx, ch)
75
+ if partner:
76
+ self._highlight(idx, partner)
77
+ return
78
+ if ch in _CLOSERS:
79
+ partner = self._find_open(text, idx, ch)
80
+ if partner:
81
+ self._highlight(partner, idx)
82
+ return
83
+
84
+ def _find_close(self, text: tk.Text, start: str, opener: str) -> str | None:
85
+ closer = _PAIRS[opener]
86
+ depth = 1
87
+ idx = text.index(f"{start}+1c")
88
+ end = text.index("end")
89
+ while text.compare(idx, "<", end):
90
+ ch = text.get(idx)
91
+ if ch == opener:
92
+ depth += 1
93
+ elif ch == closer:
94
+ depth -= 1
95
+ if depth == 0:
96
+ return idx
97
+ idx = text.index(f"{idx}+1c")
98
+ return None
99
+
100
+ def _find_open(self, text: tk.Text, start: str, closer: str) -> str | None:
101
+ opener = _REVERSE[closer]
102
+ depth = 1
103
+ idx = text.index(f"{start}-1c")
104
+ while text.compare(idx, ">=", "1.0"):
105
+ ch = text.get(idx)
106
+ if ch == closer:
107
+ depth += 1
108
+ elif ch == opener:
109
+ depth -= 1
110
+ if depth == 0:
111
+ return idx
112
+ if text.compare(idx, "==", "1.0"):
113
+ break
114
+ idx = text.index(f"{idx}-1c")
115
+ return None
116
+
117
+ def _highlight(self, a: str, b: str) -> None:
118
+ if self._core is None:
119
+ return
120
+ text = self._core.text
121
+ for idx in (a, b):
122
+ text.tag_add(_TAG, idx, f"{idx}+1c")
123
+ if self._after_id is not None:
124
+ text.after_cancel(self._after_id)
125
+ self._after_id = text.after(_FLASH_MS, self._clear)
126
+
127
+ def _clear(self) -> None:
128
+ if self._after_id is not None and self._core is not None:
129
+ try:
130
+ self._core.text.after_cancel(self._after_id)
131
+ except Exception:
132
+ pass
133
+ self._after_id = None
134
+ if self._core is not None:
135
+ try:
136
+ self._core.text.tag_remove(_TAG, "1.0", "end")
137
+ except Exception:
138
+ pass
@@ -0,0 +1,158 @@
1
+ """IndentGuides — draws subtle guide marks at each indent stop.
2
+
3
+ Filter-style extension: on each edit (debounced), scans all lines and
4
+ places a single-character background highlight at the last space of each
5
+ tab-stop in the leading whitespace, producing a visual column guide.
6
+
7
+ Only space-based indentation is supported. Tab-character indentation is
8
+ ignored (guide count will be zero for tab-indented lines).
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from typing import Any, TYPE_CHECKING
13
+
14
+ from bootstack.widgets._impl.composites.textarea.filter import EditFilter
15
+ from bootstack.widgets._impl.composites.textarea.decoration import Position, RangeDecoration
16
+
17
+ if TYPE_CHECKING:
18
+ from bootstack.widgets._impl.composites.textarea.core import _MultilineCore
19
+
20
+
21
+ _LAYER = "indent"
22
+ _DEBOUNCE_MS = 200
23
+ _STYLE = "guide"
24
+
25
+
26
+ class IndentGuides(EditFilter):
27
+ """Draws subtle vertical guide marks at each indent stop.
28
+
29
+ Install via the `show_indent_guides=True` parameter on `CodeEditor`,
30
+ or manually: `core.add_filter(IndentGuides())`.
31
+
32
+ Guide marks are placed on the last space character of each tab-stop
33
+ group in a line's leading whitespace (e.g. at column 3, 7, 11, ...
34
+ for `tab_width=4`). Only space-indented lines receive guides.
35
+
36
+ Args:
37
+ tab_width: Spaces per indent level. Should match `SmartIndent`.
38
+ """
39
+
40
+ def __init__(self, tab_width: int = 4) -> None:
41
+ super().__init__()
42
+ self._core: _MultilineCore | None = None
43
+ self._after_id: str | None = None
44
+ self._tab_width = tab_width
45
+ self._theme_root: Any = None
46
+ self._theme_bind_id: str | None = None
47
+
48
+ # ── EditFilter protocol ───────────────────────────────────────────────
49
+
50
+ def attach(self, core: _MultilineCore) -> None:
51
+ self._core = core
52
+ core.register_layer(_LAYER, priority=0)
53
+ self._apply_guide_style(core)
54
+ core.text.bind("<<EditorBgChanged>>", self._on_theme_changed, add="+")
55
+ # Recalibrate guide color after a theme rebuild. Bind <<BsThemeChanged>>
56
+ # on the root — fired ONCE by bootstack after the full rebuild (correct
57
+ # colors) — NOT the ttk <<ThemeChanged>>, which fires mid-rebuild.
58
+ self._theme_root = core.winfo_toplevel()
59
+ self._theme_bind_id = self._theme_root.bind(
60
+ "<<BsThemeChanged>>", self._on_theme_changed, add="+"
61
+ )
62
+ self._schedule()
63
+
64
+ def detach(self, core: _MultilineCore) -> None:
65
+ self._cancel()
66
+ if self._theme_bind_id is not None and self._theme_root is not None:
67
+ try:
68
+ self._theme_root.unbind("<<BsThemeChanged>>", self._theme_bind_id)
69
+ except Exception:
70
+ pass
71
+ self._theme_bind_id = None
72
+ self._theme_root = None
73
+ if self._core is not None:
74
+ core.clear_decorations(_LAYER)
75
+ self._core = None
76
+
77
+ def insert(self, index: str, chars: str, tags=None) -> None:
78
+ self.delegate.insert(index, chars, tags)
79
+ self._schedule()
80
+
81
+ def delete(self, index1: str, index2: str | None = None) -> None:
82
+ self.delegate.delete(index1, index2)
83
+ self._schedule()
84
+
85
+ # ── internal ──────────────────────────────────────────────────────────
86
+
87
+ def _apply_guide_style(self, core: _MultilineCore) -> None:
88
+ try:
89
+ bg = core.text.cget("background")
90
+ guide_bg = _subtle_variant(bg)
91
+ except Exception:
92
+ guide_bg = "#cccccc"
93
+ core.define_style(_STYLE, background=guide_bg)
94
+
95
+ def _on_theme_changed(self, _event=None) -> None:
96
+ if self._core is not None:
97
+ self._apply_guide_style(self._core)
98
+
99
+ def _schedule(self) -> None:
100
+ self._cancel()
101
+ if self._core is not None:
102
+ self._after_id = self._core.text.after(_DEBOUNCE_MS, self._update)
103
+
104
+ def _cancel(self) -> None:
105
+ if self._after_id is not None and self._core is not None:
106
+ try:
107
+ self._core.text.after_cancel(self._after_id)
108
+ except Exception:
109
+ pass
110
+ self._after_id = None
111
+
112
+ def _update(self) -> None:
113
+ self._after_id = None
114
+ if self._core is None:
115
+ return
116
+ try:
117
+ text = self._core.value
118
+ except Exception:
119
+ return
120
+
121
+ decorations = _compute_guides(text, self._tab_width)
122
+ self._core.set_decorations(_LAYER, decorations)
123
+
124
+
125
+ def _compute_guides(text: str, tab_width: int) -> list[RangeDecoration]:
126
+ """Return guide decorations for every indent stop in `text`."""
127
+ decorations: list[RangeDecoration] = []
128
+ for line_num, line in enumerate(text.split("\n"), 1):
129
+ n = len(line) - len(line.lstrip(" "))
130
+ for k in range(1, n // tab_width + 1):
131
+ col = k * tab_width - 1
132
+ decorations.append(RangeDecoration(
133
+ Position(line_num, col),
134
+ Position(line_num, col + 1),
135
+ _STYLE,
136
+ ))
137
+ return decorations
138
+
139
+
140
+ def _subtle_variant(hex_color: str) -> str:
141
+ """Return a slightly darker or lighter shade of `hex_color`."""
142
+ h = hex_color.lstrip("#")
143
+ if len(h) < 6:
144
+ return "#cccccc"
145
+ try:
146
+ r, g, b = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)
147
+ luminance = 0.299 * r + 0.587 * g + 0.114 * b
148
+ if luminance > 128:
149
+ r2 = max(0, int(r * 0.88))
150
+ g2 = max(0, int(g * 0.88))
151
+ b2 = max(0, int(b * 0.88))
152
+ else:
153
+ r2 = min(255, r + 28)
154
+ g2 = min(255, g + 28)
155
+ b2 = min(255, b + 28)
156
+ return f"#{r2:02x}{g2:02x}{b2:02x}"
157
+ except Exception:
158
+ return "#cccccc"
@@ -0,0 +1,138 @@
1
+ """LineNumbers sidebar — displays line numbers synced with the main text.
2
+
3
+ Port of idlelib/sidebar.py LineNumbers. Uses a sibling tk.Text widget
4
+ (read-only, no padding, matching font) placed to the left of the main text.
5
+ Width auto-adjusts when the line count crosses a power-of-ten boundary.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import tkinter as tk
10
+ from typing import TYPE_CHECKING
11
+
12
+ from bootstack.widgets._impl.composites.textarea.sidebar import Sidebar
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.widgets._impl.composites.textarea.core import _MultilineCore
16
+
17
+ _PADX = 6 # horizontal padding inside the line-number gutter
18
+ _PADY = 1 # top padding to align with text widget baseline
19
+
20
+
21
+ class LineNumbers(Sidebar):
22
+ """Displays line numbers alongside the text, scroll-synced.
23
+
24
+ Add to a `CodeEditor` or `TextArea` core via::
25
+
26
+ core.add_sidebar(LineNumbers())
27
+ """
28
+
29
+ def __init__(self) -> None:
30
+ super().__init__()
31
+ self._widget: tk.Text | None = None
32
+ self._core: _MultilineCore | None = None
33
+ self._last_line_count: int = 0
34
+ self._current_width: int = 1 # digits in the widest line number
35
+
36
+ # ── Sidebar protocol ──────────────────────────────────────────────────
37
+
38
+ def _build(self, core: _MultilineCore) -> None:
39
+ self._core = core
40
+ font = core.text.cget("font") or "TkFixedFont"
41
+
42
+ self._widget = tk.Text(
43
+ core,
44
+ width=self._current_width,
45
+ height=core.text.cget("height"),
46
+ padx=_PADX,
47
+ pady=_PADY,
48
+ state=tk.DISABLED,
49
+ wrap=tk.NONE,
50
+ font=font,
51
+ cursor="arrow",
52
+ takefocus=False,
53
+ highlightthickness=0,
54
+ relief=tk.FLAT,
55
+ borderwidth=0,
56
+ )
57
+
58
+ # Grid in col 0 (left sidebar column), same row as the main text
59
+ self._widget.grid(row=0, column=0, sticky="ns")
60
+
61
+ self._apply_colors()
62
+ self._update()
63
+
64
+ def _destroy(self) -> None:
65
+ if self._widget is not None:
66
+ try:
67
+ self._widget.destroy()
68
+ except Exception:
69
+ pass
70
+ self._widget = None
71
+
72
+ def on_scroll(self, first: str, last: str) -> None:
73
+ """Sync the line-number gutter with the main text scroll position."""
74
+ if self._widget is not None:
75
+ self._widget.yview_moveto(first)
76
+
77
+ def on_change(self) -> None:
78
+ """Refresh line numbers after every edit."""
79
+ self._update()
80
+
81
+ def update_font(self) -> None:
82
+ """Sync the gutter font with the main text font."""
83
+ if self._widget and self._core:
84
+ font = self._core.text.cget("font")
85
+ self._widget.configure(font=font)
86
+
87
+ def update_colors(self, event=None) -> None:
88
+ """Reapply theme colors."""
89
+ self._apply_colors()
90
+
91
+ # ── internals ─────────────────────────────────────────────────────────
92
+
93
+ def _update(self) -> None:
94
+ """Recompute and render the line numbers."""
95
+ if self._widget is None or self._core is None:
96
+ return
97
+
98
+ line_count = self._line_count()
99
+ self._adjust_width(line_count)
100
+
101
+ numbers = "\n".join(str(i) for i in range(1, line_count + 1))
102
+
103
+ self._widget.configure(state=tk.NORMAL)
104
+ self._widget.delete("1.0", tk.END)
105
+ self._widget.insert("1.0", numbers)
106
+ self._widget.configure(state=tk.DISABLED)
107
+
108
+ self._last_line_count = line_count
109
+
110
+ def _line_count(self) -> int:
111
+ """Return the number of lines in the main text widget."""
112
+ if self._core is None:
113
+ return 1
114
+ idx = self._core.text.index("end-1c")
115
+ return int(idx.split(".")[0])
116
+
117
+ def _adjust_width(self, line_count: int) -> None:
118
+ """Expand or contract the gutter when line count crosses a decade."""
119
+ needed = len(str(line_count))
120
+ if needed != self._current_width:
121
+ self._current_width = needed
122
+ if self._widget:
123
+ self._widget.configure(width=needed)
124
+
125
+ def _apply_colors(self) -> None:
126
+ """Apply theme-aware foreground/background to the gutter."""
127
+ if self._widget is None:
128
+ return
129
+ try:
130
+ from bootstack.style.style import get_theme_provider
131
+ colors = get_theme_provider().colors
132
+ fg = colors.get("muted", "#888888")
133
+ bg = colors.get("chrome", "#f0f0f0")
134
+ self._widget.configure(foreground=fg, background=bg,
135
+ selectbackground=bg, selectforeground=fg,
136
+ inactiveselectbackground=bg)
137
+ except Exception:
138
+ pass