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,305 @@
1
+ """Common type aliases and base TypedDicts for bootstack widgets."""
2
+
3
+ import tkinter
4
+ from typing import Any, Callable, Literal, TypedDict
5
+
6
+ # ---------------------------------------------------------------------------
7
+ # Primitive aliases
8
+ # ---------------------------------------------------------------------------
9
+
10
+ # Internal: parent-widget type. Not part of the public API.
11
+ Master = tkinter.Misc | None
12
+
13
+ # `Event` lives in the public `bootstack.events` package; re-imported here so the
14
+ # many widget modules that pull it alongside the layout aliases keep working.
15
+ from bootstack.events import Event # noqa: E402
16
+
17
+ EventCallback = Callable[["Event"], None]
18
+ """Callback that receives an `Event` object."""
19
+
20
+ CommandCallback = Callable[[], Any]
21
+ """Callback invoked with no arguments, e.g. a button `command=`."""
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Layout literals
25
+ # ---------------------------------------------------------------------------
26
+
27
+ Anchor = Literal['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center']
28
+ """Alignment anchor position."""
29
+
30
+ Orient = Literal['horizontal', 'vertical']
31
+ """Widget orientation."""
32
+
33
+ LocalizeMode = bool | Literal['auto']
34
+ """Whether a widget's text is translated through the catalog — `True`, `False`, or
35
+ `'auto'` (translate when a translation is registered, otherwise show the literal)."""
36
+
37
+ Justify = Literal['left', 'center', 'right']
38
+ """Text justification within a widget."""
39
+
40
+ Relief = Literal['flat', 'raised', 'sunken', 'groove', 'ridge', 'solid']
41
+ """Border relief style."""
42
+
43
+ CompoundMode = Literal['text', 'image', 'top', 'bottom', 'left', 'right', 'center', 'none']
44
+ """Relative position of image to text when both are displayed."""
45
+
46
+ Padding = int | tuple[int, int] | tuple[int, int, int, int]
47
+ """Widget padding in pixels — a single value for all sides, `(x, y)` for the
48
+ horizontal and vertical amounts, or `(left, top, right, bottom)`."""
49
+
50
+ # ---------------------------------------------------------------------------
51
+ # Widget state
52
+ # ---------------------------------------------------------------------------
53
+
54
+ WidgetState = Literal['normal', 'active', 'disabled', 'readonly']
55
+ """Widget interaction state."""
56
+
57
+ WidgetDensity = Literal['default', 'compact']
58
+ """Widget density — `'default'` for normal sizing, `'compact'` for reduced padding."""
59
+
60
+ ScrollbarVariant = Literal['default', 'thin']
61
+ """Scrollbar style — `'default'` for the standard rounded bar, `'thin'` for a slim
62
+ square bar that suits compact lists, panels, and popups."""
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # bootstack styling tokens
66
+ # ---------------------------------------------------------------------------
67
+
68
+ AccentToken = Literal['primary', 'secondary', 'info', 'success', 'warning', 'danger']
69
+ """A semantic color accent. The accent params widen this with `| str`, so
70
+ `'default'`, `'muted'`, and modifiers (`'primary[+1]'`, `'primary[500]'`,
71
+ `'primary[subtle]'`) are also accepted."""
72
+
73
+ SurfaceToken = Literal['content', 'card', 'card_raised', 'chrome', 'overlay']
74
+ """Background surface context token."""
75
+
76
+ WindowStyle = Literal['mica', 'acrylic', 'aero', 'transparent', 'win7']
77
+ """A Windows-only window effect (no-op elsewhere). These are the common effects;
78
+ the underlying pywinstyles library accepts more (pass any as a plain string).
79
+ See https://pypi.org/project/pywinstyles/ for the full set."""
80
+
81
+ # ---------------------------------------------------------------------------
82
+ # Geometry manager literals
83
+ # ---------------------------------------------------------------------------
84
+
85
+ Fill = Literal['none', 'x', 'y', 'both', 'horizontal', 'vertical', 'all']
86
+ """Fill axis for stack layout. `'horizontal'`/`'vertical'`/`'all'` are readable
87
+ aliases for `'x'`/`'y'`/`'both'`."""
88
+
89
+ Sticky = Literal['n', 's', 'e', 'w', 'ns', 'ew', 'nsew', 'ne', 'nw', 'se', 'sw', 'nse', 'nsw', 'new', 'sew', '']
90
+ """Cell alignment for Grid layout. Any combination of `'n'`, `'s'`, `'e'`, `'w'`."""
91
+
92
+ Side = Literal['left', 'top', 'right', 'bottom']
93
+ """Side placement for stack layout."""
94
+
95
+ HAlign = Literal['left', 'center', 'right', 'stretch']
96
+ """Horizontal alignment of a widget within its slot — `'left'`, `'center'`,
97
+ `'right'`, or `'stretch'` (fill the width)."""
98
+
99
+ VAlign = Literal['top', 'center', 'bottom', 'stretch']
100
+ """Vertical alignment of a widget within its slot — `'top'`, `'center'`,
101
+ `'bottom'`, or `'stretch'` (fill the height)."""
102
+
103
+ HArrange = Literal['left', 'center', 'right', 'space-between', 'space-around', 'space-evenly']
104
+ """Horizontal arrangement of a Row's children as a group — cluster them
105
+ (`'left'`/`'center'`/`'right'`) or spread them apart with the `'space-*'` modes."""
106
+
107
+ VArrange = Literal['top', 'center', 'bottom', 'space-between', 'space-around', 'space-evenly']
108
+ """Vertical arrangement of a Column's children as a group — cluster them
109
+ (`'top'`/`'center'`/`'bottom'`) or spread them apart with the `'space-*'` modes."""
110
+
111
+ Direction = Literal['vertical', 'horizontal', 'row', 'column', 'row-reverse', 'column-reverse']
112
+ """Layout direction."""
113
+
114
+ LayoutKind = Literal['column', 'row', 'grid']
115
+ """Internal layout manager for a container — `'column'`/`'row'` pack children
116
+ top-to-bottom / left-to-right; `'grid'` arranges them in rows and columns."""
117
+
118
+ AutoFlow = Literal['row', 'column', 'row-dense', 'column-dense', 'none']
119
+ """Grid auto-placement direction. `'row'`/`'column'` fill along that axis;
120
+ the `'-dense'` variants backfill gaps; `'none'` disables auto-placement."""
121
+
122
+ BorderMode = Literal['inside', 'outside']
123
+ """Border mode for the place geometry manager."""
124
+
125
+ ButtonVariant = Literal['default', 'solid', 'outline', 'ghost']
126
+ """Style variant shared by the button family (Button, ButtonGroup, MenuButton,
127
+ SelectButton, ToggleButton, ToggleGroup, Toolbar) — `'default'`, `'solid'`,
128
+ `'outline'`, or `'ghost'`."""
129
+
130
+ AccordionVariant = Literal['solid', 'default']
131
+ """Accordion header style — `'solid'`, or `'default'` for a ghost/transparent header."""
132
+
133
+ Region = Literal['before', 'center', 'after']
134
+ """Placement region within a menu bar — `'before'`, `'center'`, or `'after'`."""
135
+
136
+ IconPosition = Literal['left', 'right', 'top', 'bottom']
137
+ """Position of an icon relative to a widget's text — `'left'`, `'right'`,
138
+ `'top'`, or `'bottom'`."""
139
+
140
+ SelectionMode = Literal['none', 'single', 'multi']
141
+ """How many rows/items can be selected — `'none'`, `'single'`, or `'multi'`."""
142
+
143
+ ExportScope = Literal['all', 'page', 'selection']
144
+ """Which rows an export covers — `'all'` rows, the current `'page'`, or the
145
+ current `'selection'`."""
146
+
147
+ ExportFormat = Literal['csv', 'tsv', 'xlsx']
148
+ """A tabular export format — `'csv'`, `'tsv'`, or `'xlsx'`."""
149
+
150
+ ToastCorner = Literal['top-left', 'top-right', 'bottom-left', 'bottom-right']
151
+ """A screen corner for a `toast()` or `Notification` — anchored to the corner of
152
+ the monitor the app window is on, where they stack."""
153
+
154
+ SnackbarAlign = Literal['left', 'center', 'right']
155
+ """Horizontal alignment of a `Snackbar` along the app window's bottom edge."""
156
+
157
+ # ---------------------------------------------------------------------------
158
+ # Base TypedDicts
159
+ # ---------------------------------------------------------------------------
160
+
161
+ class BaseWidgetKwargs(TypedDict, total=False):
162
+ """Low-level options shared by all bootstack widget wrappers."""
163
+ style: str
164
+ class_: str
165
+ cursor: str
166
+ name: str
167
+ takefocus: bool
168
+
169
+
170
+ class StyledKwargs(BaseWidgetKwargs, total=False):
171
+ """Extends BaseWidgetKwargs with bootstack styling tokens."""
172
+ accent: AccentToken | str
173
+ variant: str
174
+ surface: SurfaceToken | str
175
+ style_options: dict[str, Any]
176
+
177
+
178
+ # ---------------------------------------------------------------------------
179
+ # Data-entry config types (DataTable columns + add/edit form)
180
+ # ---------------------------------------------------------------------------
181
+
182
+ EditorType = Literal[
183
+ 'textfield',
184
+ 'numberfield',
185
+ 'passwordfield',
186
+ 'datefield',
187
+ 'textarea',
188
+ 'select',
189
+ 'spinnerfield',
190
+ 'switch',
191
+ 'checkbox',
192
+ 'slider',
193
+ ]
194
+ """The field type used to edit a value in a `Form` or `DataTable` add/edit
195
+ dialog. Inferred from the value's `dtype` when omitted."""
196
+
197
+
198
+ class ColumnSpec(TypedDict, total=False):
199
+ """A column definition for `DataTable(columns=...)`.
200
+
201
+ Columns may be plain key strings or these dicts. Only `key` is required; the
202
+ editor keys (`editor`, `editor_options`, `dtype`, `readonly`, `required`)
203
+ shape how the column appears in the built-in add/edit dialog.
204
+ """
205
+
206
+ key: str
207
+ """Record field this column reads and writes."""
208
+ text: str
209
+ """Header label. Defaults to `key`."""
210
+ width: int
211
+ """Column width in pixels."""
212
+ minwidth: int
213
+ """Minimum column width in pixels."""
214
+ anchor: str
215
+ """Cell alignment — `'w'`, `'center'`, or `'e'`."""
216
+ format: "str | Callable[[Any], str]"
217
+ """Display formatter for the cell — a format-spec string applied as
218
+ `spec.format(value)` (e.g. `'${:,.0f}'` → `$70,000`) or a callable
219
+ `(value) -> str`. Display only: sorting, filtering, editing, and export use
220
+ the raw value."""
221
+ dtype: str
222
+ """Value type hint (e.g. `'int'`, `'text'`); drives alignment and the editor."""
223
+ editor: EditorType
224
+ """Field type used to edit this column in the add/edit dialog. Inferred from
225
+ `dtype` when omitted."""
226
+ editor_options: dict
227
+ """Keyword options passed to the editor field."""
228
+ readonly: bool
229
+ """Show the column but make it non-editable in the dialog."""
230
+ required: bool
231
+ """Require a value in the add/edit dialog."""
232
+
233
+
234
+ class FormOptions(TypedDict, total=False):
235
+ """Layout options for the built-in add/edit dialog (`DataTable(form=...)`)."""
236
+
237
+ col_count: int
238
+ """Number of columns the form fields are laid out in. Default `2`."""
239
+ min_col_width: int
240
+ """Minimum width in pixels of each form column. Default `260`."""
241
+ scrollable: bool
242
+ """Scroll the form when it is taller than the dialog. Default `True`."""
243
+ resizable: bool
244
+ """Allow the dialog to be resized. Default `True`."""
245
+
246
+
247
+ # ---------------------------------------------------------------------------
248
+ # Selection options (the shared "data bag" option shape)
249
+ # ---------------------------------------------------------------------------
250
+
251
+ class OptionDict(TypedDict, total=False):
252
+ """A single choice for a selection widget, in dict form.
253
+
254
+ The dict form is a *data bag*: `text` is required (and `value` defaults to
255
+ it) UNLESS the dict carries an `icon` and a `value`, in which case `text` may
256
+ be omitted to request an icon-only option. `text`/`value` and the recognized
257
+ `icon`/`disabled` keys act on rendering; every *other* key rides along as
258
+ carried data — retrievable as the widget's `selection` (the selected
259
+ option's full record). Unrecognized keys are accepted, not rejected, so the
260
+ dict route trades key-typo safety for extensibility.
261
+ """
262
+
263
+ text: str
264
+ """Display label. Required unless `icon` + `value` are given (icon-only)."""
265
+ value: Any
266
+ """Stored and emitted value. Defaults to `text` when omitted."""
267
+ icon: str
268
+ """Optional icon spec rendered beside the label — alone when `text` is blank."""
269
+ disabled: bool
270
+ """When `True`, the option is dimmed and cannot be selected by the user."""
271
+ localize: "bool | Literal['auto']"
272
+ """Per-option translation mode — `True`, `False`, or `'auto'`. Overrides the
273
+ widget's group-level `localize=` for just this option. Set `False` to keep a
274
+ proper noun or identifier untranslated."""
275
+
276
+
277
+ Option = str | tuple[str, Any] | OptionDict
278
+ """A single choice for `Select`, `SelectButton`, `RadioGroup`, or `ToggleGroup`.
279
+
280
+ Three interchangeable forms, all normalized to a `(text, value)` pair:
281
+
282
+ - a plain `str` — text and value are the same (`'Small'`);
283
+ - a `(text, value)` tuple — decoupled label and value (`('Small', 's')`);
284
+ - an `OptionDict` — `{'text': 'Small', 'value': 's'}`; the extensible form."""
285
+
286
+
287
+ class IconSpec(TypedDict, total=False):
288
+ """A detailed icon specification: a Bootstrap icon name with size and color.
289
+
290
+ Use in place of a plain icon name wherever a widget accepts `icon=`, to
291
+ control the rendered size and color — for example
292
+ `icon={'name': 'bell-fill', 'size': 24, 'color': 'primary'}`.
293
+ """
294
+
295
+ name: str
296
+ """Bootstrap Icons name, e.g. `'bell-fill'`."""
297
+ size: int
298
+ """Icon size in pixels (automatically DPI-scaled)."""
299
+ color: str
300
+ """Icon color — a theme color token (e.g. `'primary'`) or a hex string."""
301
+
302
+
303
+ Icon = str | IconSpec
304
+ """An icon as either a Bootstrap Icons name (`'bell-fill'`) or an `IconSpec`
305
+ mapping for control over size and color."""
@@ -0,0 +1,307 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from typing import TYPE_CHECKING, Any, Callable, Literal
5
+
6
+ from bootstack.widgets._impl.primitives.flexframe import FlexFrame
7
+ from bootstack.widgets._core.container import FlexContainer
8
+ from bootstack.widgets._core.window_controls import WindowControlsMixin
9
+ from bootstack.widgets._core.window_menu import ChromeHostMixin
10
+ from bootstack.widgets.types import (
11
+ Padding, HAlign, VArrange, Anchor, SurfaceToken, WindowStyle,
12
+ )
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.images import AppIcon, Image
16
+
17
+
18
+ def _resolve_window_parent(parent: Any) -> Any:
19
+ """Resolve a public widget (or tk widget) to its containing tk window.
20
+
21
+ Accepts an `App`, a `Window`, or any widget inside one, and returns the
22
+ enclosing toplevel — so centering and transient-parenting act on the window,
23
+ not on a small child widget.
24
+ """
25
+ if parent is None:
26
+ return None
27
+ widget = None
28
+ for attr in ("_tk_root", "_tk_toplevel", "_internal"):
29
+ widget = getattr(parent, attr, None)
30
+ if widget is not None:
31
+ break
32
+ if widget is None:
33
+ widget = parent # assume it is already a tk widget
34
+ try:
35
+ return widget.winfo_toplevel()
36
+ except Exception:
37
+ return widget
38
+
39
+
40
+ def _resolve_anchor_widget(target: Any) -> Any:
41
+ """Resolve an anchor target to a tk widget (keeping it, not its toplevel).
42
+
43
+ A string (`'screen'`/`'cursor'`/`'parent'`) passes through; a public widget
44
+ resolves to the underlying tk widget so a window can be placed relative to
45
+ that exact widget (e.g. beside a field).
46
+ """
47
+ if isinstance(target, str) or target is None:
48
+ return target
49
+ for attr in ("_tk_toplevel", "_tk_root", "_internal"):
50
+ widget = getattr(target, attr, None)
51
+ if widget is not None:
52
+ return widget
53
+ return target
54
+
55
+
56
+ class Window(WindowControlsMixin, ChromeHostMixin, FlexContainer):
57
+ """A secondary top-level window.
58
+
59
+ Behaves as an implicit `Column` from the user's perspective: children
60
+ created inside a `with` block are automatically packed into its content
61
+ frame top-to-bottom. Call `show()` to display the window after building
62
+ its content, or `block_until_closed()` to show it and wait for the user
63
+ to close it.
64
+
65
+ Args:
66
+ title: Window title bar text.
67
+ size: Initial size as `(width, height)`.
68
+ icon: Title-bar and taskbar icon — an icon file path, an `Image` handle,
69
+ or an `AppIcon`. Defaults to the bootstack icon.
70
+ position: Initial position as `(x, y)`.
71
+ min_size: Minimum window size as `(width, height)`.
72
+ max_size: Maximum window size as `(width, height)`.
73
+ resizable: Whether the window can be resized as `(width, height)`.
74
+ modal: Modality level. `False` — non-modal (default). `True` or
75
+ `'window'` — grabs input from the parent only. `'app'` — grabs
76
+ input from all windows.
77
+ parent: The window this one belongs to — an `App`, another `Window`, or
78
+ any widget inside one. Makes this window transient to it (stacks
79
+ above it, hides with it) and is the target for `center_on_parent`.
80
+ Defaults to the main application window.
81
+ center_on_parent: Center over `parent` (the main window if `parent` is
82
+ not given).
83
+ center_on_screen: Center on the screen.
84
+ topmost: Keep the window above other windows.
85
+ undecorated: Remove OS window decorations (`overrideredirect`).
86
+ Ignored on macOS. Unless `window_controls=False`, the window gets a
87
+ built-in draggable title bar with min/max/close so it stays movable
88
+ and closeable; add your own with `add_toolbar(show_window_controls=True)`
89
+ to take over the chrome.
90
+ window_controls: When `undecorated`, provide a built-in title bar with
91
+ window controls and dragging if you add no chrome toolbar of your
92
+ own. Set `False` for a truly chromeless window (e.g. a splash or
93
+ popover). Default `True`. No effect on a decorated window.
94
+ window_style: Windows-only window effect. None inherits the app's setting.
95
+ on_close: Callback invoked when the user clicks the close button.
96
+ Return `False` to veto; return `None` or `True` to allow.
97
+ padding: Inner padding for the content frame.
98
+ gap: Spacing between children.
99
+ horizontal_items: Horizontal alignment of children — `'left'`,
100
+ `'center'`, `'right'`, or `'stretch'` (fill the width). Default
101
+ `'center'`.
102
+ vertical_items: How children are arranged top to bottom — `'top'`,
103
+ `'center'`, `'bottom'`, or a `'space-*'` mode. Default `'top'`.
104
+ grow_items: When `True`, children grow equally to fill the height.
105
+ surface: Surface token for the content frame background.
106
+ """
107
+
108
+ _auto_place = False # top-level window — no parent manages its position
109
+
110
+ def __init__(
111
+ self,
112
+ *,
113
+ title: str = "",
114
+ size: tuple[int, int] | None = None,
115
+ icon: "str | Image | AppIcon | None" = None,
116
+ position: tuple[int, int] | None = None,
117
+ min_size: tuple[int, int] | None = None,
118
+ max_size: tuple[int, int] | None = None,
119
+ resizable: tuple[bool, bool] | None = None,
120
+ modal: Literal[False, True, "window", "app"] = False,
121
+ parent: Any = None,
122
+ center_on_parent: bool = False,
123
+ center_on_screen: bool = False,
124
+ topmost: bool = False,
125
+ undecorated: bool = False,
126
+ window_controls: bool = True,
127
+ window_style: WindowStyle | str | None = None,
128
+ on_close: Callable[[], bool | None] | None = None,
129
+ # Content frame layout
130
+ padding: Padding | None = None,
131
+ gap: int = 0,
132
+ horizontal_items: HAlign = "center",
133
+ vertical_items: VArrange = "top",
134
+ grow_items: bool = False,
135
+ surface: SurfaceToken | str | None = None,
136
+ **kwargs: Any,
137
+ ) -> None:
138
+ from bootstack._runtime.toplevel import Toplevel as _InternalToplevel
139
+
140
+ self._parent = None
141
+ # overrideredirect has no effect on macOS — so the borderless treatment
142
+ # (custom border + title bar) is Windows/Linux only.
143
+ self._undecorated = undecorated and sys.platform != "darwin"
144
+ self._window_controls = window_controls
145
+
146
+ init_kwargs: dict[str, Any] = {
147
+ "title": title,
148
+ "modal": modal,
149
+ "center_on_parent": center_on_parent,
150
+ "center_on_screen": center_on_screen,
151
+ "topmost": topmost,
152
+ "overrideredirect": undecorated,
153
+ }
154
+ if size is not None:
155
+ init_kwargs["size"] = size
156
+ if position is not None:
157
+ init_kwargs["position"] = position
158
+ if min_size is not None:
159
+ init_kwargs["minsize"] = min_size
160
+ if max_size is not None:
161
+ init_kwargs["maxsize"] = max_size
162
+ if resizable is not None:
163
+ init_kwargs["resizable"] = resizable
164
+ if on_close is not None:
165
+ init_kwargs["on_close"] = on_close
166
+ if window_style is not None:
167
+ init_kwargs["window_style"] = window_style
168
+
169
+ parent_widget = _resolve_window_parent(parent)
170
+ self._parent_window = parent_widget
171
+ if parent_widget is not None:
172
+ init_kwargs["transient"] = parent_widget
173
+
174
+ from bootstack.widgets._core.image_binding import resolve_window_icon
175
+
176
+ icon_path, icon_image = resolve_window_icon(icon)
177
+ if icon_path is not None:
178
+ init_kwargs["icon"] = icon_path
179
+ init_kwargs.update(kwargs)
180
+
181
+ self._tk_toplevel = _InternalToplevel(**init_kwargs)
182
+
183
+ # An Image handle needs the window to exist before it can be rendered.
184
+ self._window_icon_photo = None
185
+ if icon_image is not None:
186
+ self._window_icon_photo = icon_image._materialize()
187
+ self._tk_toplevel._setup_icon(self._window_icon_photo)
188
+
189
+ frame_kwargs: dict[str, Any] = {
190
+ "direction": "vertical",
191
+ "gap": gap,
192
+ "horizontal_items": horizontal_items,
193
+ "vertical_items": vertical_items,
194
+ "grow_items": grow_items,
195
+ }
196
+ if padding is not None:
197
+ frame_kwargs["padding"] = padding
198
+ if surface is not None:
199
+ frame_kwargs["surface"] = surface
200
+
201
+ # In undecorated mode the OS border is gone; a 1px themed border frame
202
+ # substitutes it and hosts both the chrome stack and the content. A
203
+ # chromeless window (`window_controls=False`, e.g. a splash) keeps no
204
+ # border either.
205
+ if self._undecorated and self._window_controls:
206
+ from bootstack.widgets._impl.primitives.frame import Frame
207
+
208
+ self._region_root = Frame(self._tk_toplevel, show_border=True, padding=1)
209
+ self._region_root.pack(fill="both", expand=True)
210
+ else:
211
+ self._region_root = self._tk_toplevel
212
+
213
+ self._content_frame = FlexFrame(self._region_root, **frame_kwargs)
214
+ self._content_frame.pack(fill="both", expand=True)
215
+
216
+ self._internal = self._tk_toplevel
217
+
218
+ def _toolbar_stack_parent(self) -> Any:
219
+ # The chrome stack lives inside the (bordered) region root, above content.
220
+ return getattr(self, "_region_root", self._tk_toplevel)
221
+
222
+ @property
223
+ def _flex_frame(self) -> Any:
224
+ return self._content_frame
225
+
226
+ # ----- Lifecycle -----
227
+
228
+ def show(
229
+ self,
230
+ *,
231
+ anchor_to: Any = None,
232
+ anchor_point: Anchor = "center",
233
+ window_point: Anchor = "center",
234
+ offset: tuple[int, int] = (0, 0),
235
+ auto_flip: bool = True,
236
+ ) -> "Window":
237
+ """Show the window, optionally positioned relative to a widget.
238
+
239
+ With no arguments the window appears at its configured position (or
240
+ centered on its `parent`). Pass `anchor_to` to place it relative to a
241
+ widget instead — for example, to the right of a field.
242
+
243
+ Args:
244
+ anchor_to: A widget to position this window against, or one of
245
+ `'screen'`, `'cursor'`, or `'parent'`. When given, this overrides
246
+ centering.
247
+ anchor_point: The point on the anchor target to align to — one of
248
+ `'n'`, `'s'`, `'e'`, `'w'`, `'ne'`, `'nw'`, `'se'`, `'sw'`, or
249
+ `'center'`. For example, `'e'` is the target's right edge.
250
+ window_point: The matching point on this window placed at the anchor
251
+ (same value set). For example, `anchor_point='e'` with
252
+ `window_point='w'` puts this window's left edge at the target's
253
+ right edge — i.e. to its right.
254
+ offset: Extra `(x, y)` pixel offset from the anchored position.
255
+ auto_flip: Flip to the opposite side if the window would otherwise go
256
+ off-screen. Defaults to `True`.
257
+
258
+ Returns:
259
+ `self` — allows chaining: `win = Window(...).show()`.
260
+ """
261
+ self._ensure_default_titlebar()
262
+ if anchor_to is not None:
263
+ from bootstack._runtime.window_utilities import WindowPositioning
264
+
265
+ toplevel = self._tk_toplevel
266
+ toplevel.update_idletasks()
267
+ WindowPositioning.position_anchored(
268
+ window=toplevel,
269
+ anchor_to=_resolve_anchor_widget(anchor_to),
270
+ parent=self._parent_window,
271
+ anchor_point=anchor_point,
272
+ window_point=window_point,
273
+ offset=offset,
274
+ auto_flip=auto_flip,
275
+ ensure_visible=True,
276
+ )
277
+ self._tk_toplevel.show()
278
+ return self
279
+
280
+ def block_until_closed(self) -> Any:
281
+ """Show the window and block until it is destroyed.
282
+
283
+ Returns:
284
+ The value of `result` at the time the window was closed.
285
+ """
286
+ self._ensure_default_titlebar()
287
+ return self._tk_toplevel.block_until_closed()
288
+
289
+ # ----- Properties -----
290
+
291
+ @property
292
+ def title(self) -> str:
293
+ """The window's title bar text. Assigning to it updates the title live."""
294
+ return self._tk_toplevel.title()
295
+
296
+ @title.setter
297
+ def title(self, value: str) -> None:
298
+ self._tk_toplevel.title(value)
299
+
300
+ @property
301
+ def result(self) -> Any:
302
+ """Value set before closing, returned by `block_until_closed()`."""
303
+ return self._tk_toplevel.result
304
+
305
+ @result.setter
306
+ def result(self, value: Any) -> None:
307
+ self._tk_toplevel.result = value