bootstack 0.1.0a1__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 (419) hide show
  1. bootstack/__init__.py +249 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/api/__init__.py +127 -0
  4. bootstack/api/app.py +30 -0
  5. bootstack/api/constants.py +3 -0
  6. bootstack/api/data.py +23 -0
  7. bootstack/api/dialogs.py +44 -0
  8. bootstack/api/i18n.py +17 -0
  9. bootstack/api/localization.py +16 -0
  10. bootstack/api/menu.py +7 -0
  11. bootstack/api/style.py +23 -0
  12. bootstack/api/utils.py +24 -0
  13. bootstack/api/widgets.py +137 -0
  14. bootstack/assets/__init__.py +24 -0
  15. bootstack/assets/bootstack-transparent.png +0 -0
  16. bootstack/assets/bootstack.ico +0 -0
  17. bootstack/assets/bootstack.png +0 -0
  18. bootstack/assets/elements/__init__.py +0 -0
  19. bootstack/assets/elements/badge-pill.png +0 -0
  20. bootstack/assets/elements/badge-square.png +0 -0
  21. bootstack/assets/elements/border.png +0 -0
  22. bootstack/assets/elements/button-compact.png +0 -0
  23. bootstack/assets/elements/button-default.png +0 -0
  24. bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
  25. bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
  26. bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
  27. bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
  28. bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
  29. bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
  30. bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
  31. bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
  32. bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
  33. bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
  34. bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
  35. bootstack/assets/elements/button-group-vertical-center-default.png +0 -0
  36. bootstack/assets/elements/checkbox-checked.png +0 -0
  37. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  38. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  39. bootstack/assets/elements/field.png +0 -0
  40. bootstack/assets/elements/input-after-compact.png +0 -0
  41. bootstack/assets/elements/input-after-default.png +0 -0
  42. bootstack/assets/elements/input-before-compact.png +0 -0
  43. bootstack/assets/elements/input-before-default.png +0 -0
  44. bootstack/assets/elements/input-compact.png +0 -0
  45. bootstack/assets/elements/input-default.png +0 -0
  46. bootstack/assets/elements/list-item-separated.png +0 -0
  47. bootstack/assets/elements/list-item.png +0 -0
  48. bootstack/assets/elements/manifest.toml +480 -0
  49. bootstack/assets/elements/menu-item.png +0 -0
  50. bootstack/assets/elements/nav-button-compact.png +0 -0
  51. bootstack/assets/elements/nav-button-default.png +0 -0
  52. bootstack/assets/elements/nav-icon-button-compact.png +0 -0
  53. bootstack/assets/elements/nav-icon-button-default.png +0 -0
  54. bootstack/assets/elements/notebook-client-border.png +0 -0
  55. bootstack/assets/elements/notebook-tab-active.png +0 -0
  56. bootstack/assets/elements/notebook-tab-bar.png +0 -0
  57. bootstack/assets/elements/notebook-tab-normal.png +0 -0
  58. bootstack/assets/elements/notebook-tab-pill.png +0 -0
  59. bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
  60. bootstack/assets/elements/progress-bar-solid.png +0 -0
  61. bootstack/assets/elements/progress-bar-thin.png +0 -0
  62. bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
  63. bootstack/assets/elements/radio-selected.png +0 -0
  64. bootstack/assets/elements/radio-unselected.png +0 -0
  65. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  66. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  67. bootstack/assets/elements/slider-handle-focus.png +0 -0
  68. bootstack/assets/elements/slider-handle.png +0 -0
  69. bootstack/assets/elements/slider-track-horizontal.png +0 -0
  70. bootstack/assets/elements/slider-track-vertical.png +0 -0
  71. bootstack/assets/elements/switch-off.png +0 -0
  72. bootstack/assets/elements/switch-on.png +0 -0
  73. bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
  74. bootstack/assets/elements/tabs-bar-vertical.png +0 -0
  75. bootstack/assets/elements/tabs-pill.png +0 -0
  76. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  77. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
  78. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
  79. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  80. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
  81. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  82. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
  83. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  84. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
  85. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  86. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
  87. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  88. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
  89. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  90. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
  91. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  92. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
  93. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  94. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
  95. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  96. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
  97. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  98. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
  99. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  100. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
  101. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  102. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
  103. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  104. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
  105. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  106. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
  107. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  108. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
  109. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  110. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
  111. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  112. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
  113. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  114. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
  115. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  116. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
  117. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  118. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
  119. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  120. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
  121. bootstack/assets/themes/__init__.py +0 -0
  122. bootstack/assets/themes/amber-dark.json +32 -0
  123. bootstack/assets/themes/amber-light.json +32 -0
  124. bootstack/assets/themes/aurora-dark.json +32 -0
  125. bootstack/assets/themes/aurora-light.json +32 -0
  126. bootstack/assets/themes/bootstrap-dark.json +32 -0
  127. bootstack/assets/themes/bootstrap-light.json +32 -0
  128. bootstack/assets/themes/classic-dark.json +32 -0
  129. bootstack/assets/themes/classic-light.json +32 -0
  130. bootstack/assets/themes/docs-dark.json +32 -0
  131. bootstack/assets/themes/docs-light.json +32 -0
  132. bootstack/assets/themes/forest-dark.json +32 -0
  133. bootstack/assets/themes/forest-light.json +32 -0
  134. bootstack/assets/themes/ocean-dark.json +32 -0
  135. bootstack/assets/themes/ocean-light.json +32 -0
  136. bootstack/assets/themes/rose-dark.json +32 -0
  137. bootstack/assets/themes/rose-light.json +32 -0
  138. bootstack/assets/widgets/__init__.py +0 -0
  139. bootstack/assets/widgets/badge-default.png +0 -0
  140. bootstack/assets/widgets/badge-pill.png +0 -0
  141. bootstack/assets/widgets/border.png +0 -0
  142. bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
  143. bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
  144. bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
  145. bootstack/assets/widgets/button-group-vertical-after.png +0 -0
  146. bootstack/assets/widgets/button-group-vertical-before.png +0 -0
  147. bootstack/assets/widgets/button-group-vertical-center.png +0 -0
  148. bootstack/assets/widgets/button.png +0 -0
  149. bootstack/assets/widgets/checkbox-checked.png +0 -0
  150. bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
  151. bootstack/assets/widgets/checkbox-unchecked.png +0 -0
  152. bootstack/assets/widgets/field.png +0 -0
  153. bootstack/assets/widgets/icon-button.png +0 -0
  154. bootstack/assets/widgets/input-inner.png +0 -0
  155. bootstack/assets/widgets/input-prefix.png +0 -0
  156. bootstack/assets/widgets/input-suffix.png +0 -0
  157. bootstack/assets/widgets/input.png +0 -0
  158. bootstack/assets/widgets/list-item-focus.png +0 -0
  159. bootstack/assets/widgets/list-item-separated.png +0 -0
  160. bootstack/assets/widgets/menu-item-separated.png +0 -0
  161. bootstack/assets/widgets/notebook-client-border.png +0 -0
  162. bootstack/assets/widgets/notebook-pill-active.png +0 -0
  163. bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
  164. bootstack/assets/widgets/notebook-tab-active.png +0 -0
  165. bootstack/assets/widgets/notebook-tab-border.png +0 -0
  166. bootstack/assets/widgets/notebook-tab-normal.png +0 -0
  167. bootstack/assets/widgets/notebook-underline.png +0 -0
  168. bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
  169. bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
  170. bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
  171. bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
  172. bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
  173. bootstack/assets/widgets/progress-trough-vertical.png +0 -0
  174. bootstack/assets/widgets/radio-selected.png +0 -0
  175. bootstack/assets/widgets/radio-unselected.png +0 -0
  176. bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
  177. bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
  178. bootstack/assets/widgets/separator-horizontal.png +0 -0
  179. bootstack/assets/widgets/separator-vertical.png +0 -0
  180. bootstack/assets/widgets/slider-handle-focus.png +0 -0
  181. bootstack/assets/widgets/slider-handle.png +0 -0
  182. bootstack/assets/widgets/slider-track-horizontal.png +0 -0
  183. bootstack/assets/widgets/slider-track-vertical.png +0 -0
  184. bootstack/assets/widgets/switch-off.png +0 -0
  185. bootstack/assets/widgets/switch-on.png +0 -0
  186. bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
  187. bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
  188. bootstack/assets/widgets/tabs-pill.png +0 -0
  189. bootstack/cli/__init__.py +124 -0
  190. bootstack/cli/__main__.py +6 -0
  191. bootstack/cli/add.py +439 -0
  192. bootstack/cli/build.py +115 -0
  193. bootstack/cli/config.py +287 -0
  194. bootstack/cli/demo.py +1267 -0
  195. bootstack/cli/doctor.py +195 -0
  196. bootstack/cli/list_cmd.py +71 -0
  197. bootstack/cli/promote.py +120 -0
  198. bootstack/cli/pyinstaller.py +246 -0
  199. bootstack/cli/run.py +99 -0
  200. bootstack/cli/start.py +105 -0
  201. bootstack/cli/templates/__init__.py +861 -0
  202. bootstack/constants.py +325 -0
  203. bootstack/core/__init__.py +34 -0
  204. bootstack/core/capabilities/__init__.py +45 -0
  205. bootstack/core/capabilities/after.py +103 -0
  206. bootstack/core/capabilities/bind.py +154 -0
  207. bootstack/core/capabilities/bindtags.py +112 -0
  208. bootstack/core/capabilities/busy.py +61 -0
  209. bootstack/core/capabilities/clipboard.py +88 -0
  210. bootstack/core/capabilities/focus.py +118 -0
  211. bootstack/core/capabilities/grab.py +65 -0
  212. bootstack/core/capabilities/grid.py +188 -0
  213. bootstack/core/capabilities/localization.py +231 -0
  214. bootstack/core/capabilities/pack.py +119 -0
  215. bootstack/core/capabilities/place.py +92 -0
  216. bootstack/core/capabilities/selection.py +136 -0
  217. bootstack/core/capabilities/signals.py +242 -0
  218. bootstack/core/capabilities/winfo.py +315 -0
  219. bootstack/core/colorutils.py +234 -0
  220. bootstack/core/exceptions.py +95 -0
  221. bootstack/core/images.py +283 -0
  222. bootstack/core/localization/README.md +90 -0
  223. bootstack/core/localization/__init__.py +13 -0
  224. bootstack/core/localization/intl_format.py +580 -0
  225. bootstack/core/localization/msgcat.py +425 -0
  226. bootstack/core/localization/specs.py +143 -0
  227. bootstack/core/mixins/__init__.py +1 -0
  228. bootstack/core/mixins/ttk_state.py +35 -0
  229. bootstack/core/mixins/widget.py +132 -0
  230. bootstack/core/publisher.py +147 -0
  231. bootstack/core/signals/README.md +112 -0
  232. bootstack/core/signals/__init__.py +8 -0
  233. bootstack/core/signals/integration.py +100 -0
  234. bootstack/core/signals/signal.py +317 -0
  235. bootstack/core/signals/types.py +4 -0
  236. bootstack/core/validation/__init__.py +5 -0
  237. bootstack/core/validation/types.py +13 -0
  238. bootstack/core/validation/validation_result.py +17 -0
  239. bootstack/core/validation/validation_rules.py +112 -0
  240. bootstack/core/variables.py +62 -0
  241. bootstack/datasource/README.md +607 -0
  242. bootstack/datasource/__init__.py +51 -0
  243. bootstack/datasource/base.py +474 -0
  244. bootstack/datasource/file_source.py +541 -0
  245. bootstack/datasource/memory_source.py +482 -0
  246. bootstack/datasource/sqlite_source.py +453 -0
  247. bootstack/datasource/types.py +259 -0
  248. bootstack/dialogs/__init__.py +56 -0
  249. bootstack/dialogs/colorchooser.py +674 -0
  250. bootstack/dialogs/colordropper.py +257 -0
  251. bootstack/dialogs/datedialog.py +404 -0
  252. bootstack/dialogs/dialog.py +514 -0
  253. bootstack/dialogs/filterdialog.py +358 -0
  254. bootstack/dialogs/fontdialog.py +339 -0
  255. bootstack/dialogs/formdialog.py +541 -0
  256. bootstack/dialogs/message.py +489 -0
  257. bootstack/dialogs/query.py +561 -0
  258. bootstack/py.typed +1 -0
  259. bootstack/runtime/__init__.py +3 -0
  260. bootstack/runtime/app.py +879 -0
  261. bootstack/runtime/base_window.py +786 -0
  262. bootstack/runtime/events.py +399 -0
  263. bootstack/runtime/menu.py +510 -0
  264. bootstack/runtime/shortcuts.py +423 -0
  265. bootstack/runtime/tk_patch.py +31 -0
  266. bootstack/runtime/toplevel.py +131 -0
  267. bootstack/runtime/utility.py +371 -0
  268. bootstack/runtime/visual_focus.py +228 -0
  269. bootstack/runtime/window_utilities.py +1043 -0
  270. bootstack/style/__init__.py +5498 -0
  271. bootstack/style/bootstyle.py +507 -0
  272. bootstack/style/bootstyle_builder_base.py +752 -0
  273. bootstack/style/bootstyle_builder_mixed.py +93 -0
  274. bootstack/style/bootstyle_builder_tk.py +109 -0
  275. bootstack/style/bootstyle_builder_ttk.py +354 -0
  276. bootstack/style/builders/__init__.py +51 -0
  277. bootstack/style/builders/badge.py +44 -0
  278. bootstack/style/builders/button.py +453 -0
  279. bootstack/style/builders/buttongroup.py +344 -0
  280. bootstack/style/builders/calendar.py +271 -0
  281. bootstack/style/builders/checkbutton.py +95 -0
  282. bootstack/style/builders/combobox.py +112 -0
  283. bootstack/style/builders/contextmenu.py +268 -0
  284. bootstack/style/builders/entry.py +83 -0
  285. bootstack/style/builders/expander.py +171 -0
  286. bootstack/style/builders/field.py +312 -0
  287. bootstack/style/builders/frame.py +27 -0
  288. bootstack/style/builders/label.py +28 -0
  289. bootstack/style/builders/labelframe.py +41 -0
  290. bootstack/style/builders/listview.py +267 -0
  291. bootstack/style/builders/menubar.py +74 -0
  292. bootstack/style/builders/menubutton.py +408 -0
  293. bootstack/style/builders/notebook.py +316 -0
  294. bootstack/style/builders/panedwindow.py +25 -0
  295. bootstack/style/builders/progressbar.py +71 -0
  296. bootstack/style/builders/radiobutton.py +68 -0
  297. bootstack/style/builders/scale.py +66 -0
  298. bootstack/style/builders/scrollbar.py +360 -0
  299. bootstack/style/builders/separator.py +45 -0
  300. bootstack/style/builders/sidenav.py +313 -0
  301. bootstack/style/builders/sizegrip.py +15 -0
  302. bootstack/style/builders/spinbox.py +119 -0
  303. bootstack/style/builders/switch.py +67 -0
  304. bootstack/style/builders/tabitem.py +205 -0
  305. bootstack/style/builders/toolbutton.py +260 -0
  306. bootstack/style/builders/tooltip.py +26 -0
  307. bootstack/style/builders/treeview.py +269 -0
  308. bootstack/style/builders/utils.py +404 -0
  309. bootstack/style/builders_tk/__init__.py +16 -0
  310. bootstack/style/builders_tk/defaults.py +229 -0
  311. bootstack/style/element.py +173 -0
  312. bootstack/style/style.py +499 -0
  313. bootstack/style/theme_provider.py +449 -0
  314. bootstack/style/tk_patch.py +5 -0
  315. bootstack/style/token_maps.py +42 -0
  316. bootstack/style/types.py +32 -0
  317. bootstack/style/typography.py +527 -0
  318. bootstack/style/utility.py +696 -0
  319. bootstack/themes/__init__.py +12 -0
  320. bootstack/themes/standard.py +415 -0
  321. bootstack/themes/user.py +45 -0
  322. bootstack/widgets/__init__.py +53 -0
  323. bootstack/widgets/composites/__init__.py +38 -0
  324. bootstack/widgets/composites/accordion.py +385 -0
  325. bootstack/widgets/composites/appshell.py +445 -0
  326. bootstack/widgets/composites/buttongroup.py +391 -0
  327. bootstack/widgets/composites/calendar.py +914 -0
  328. bootstack/widgets/composites/compositeframe.py +282 -0
  329. bootstack/widgets/composites/contextmenu.py +1754 -0
  330. bootstack/widgets/composites/dateentry.py +261 -0
  331. bootstack/widgets/composites/dropdownbutton.py +190 -0
  332. bootstack/widgets/composites/expander.py +508 -0
  333. bootstack/widgets/composites/field.py +448 -0
  334. bootstack/widgets/composites/floodgauge.py +434 -0
  335. bootstack/widgets/composites/form.py +983 -0
  336. bootstack/widgets/composites/labeledscale.py +209 -0
  337. bootstack/widgets/composites/list/__init__.py +15 -0
  338. bootstack/widgets/composites/list/listitem.py +733 -0
  339. bootstack/widgets/composites/list/listview.py +1507 -0
  340. bootstack/widgets/composites/menubar.py +303 -0
  341. bootstack/widgets/composites/meter.py +882 -0
  342. bootstack/widgets/composites/numericentry.py +183 -0
  343. bootstack/widgets/composites/pagestack.py +330 -0
  344. bootstack/widgets/composites/passwordentry.py +149 -0
  345. bootstack/widgets/composites/pathentry.py +223 -0
  346. bootstack/widgets/composites/radiogroup.py +466 -0
  347. bootstack/widgets/composites/scrolledtext.py +388 -0
  348. bootstack/widgets/composites/scrolledtext.pyi +186 -0
  349. bootstack/widgets/composites/scrollview.py +675 -0
  350. bootstack/widgets/composites/selectbox.py +544 -0
  351. bootstack/widgets/composites/sidenav/__init__.py +24 -0
  352. bootstack/widgets/composites/sidenav/group.py +485 -0
  353. bootstack/widgets/composites/sidenav/header.py +83 -0
  354. bootstack/widgets/composites/sidenav/item.py +413 -0
  355. bootstack/widgets/composites/sidenav/separator.py +51 -0
  356. bootstack/widgets/composites/sidenav/view.py +919 -0
  357. bootstack/widgets/composites/spinnerentry.py +232 -0
  358. bootstack/widgets/composites/tableview/__init__.py +5 -0
  359. bootstack/widgets/composites/tableview/tableview.py +2254 -0
  360. bootstack/widgets/composites/tableview/types.py +169 -0
  361. bootstack/widgets/composites/tabs/__init__.py +6 -0
  362. bootstack/widgets/composites/tabs/tabitem.py +372 -0
  363. bootstack/widgets/composites/tabs/tabs.py +478 -0
  364. bootstack/widgets/composites/tabs/tabview.py +352 -0
  365. bootstack/widgets/composites/textentry.py +90 -0
  366. bootstack/widgets/composites/timeentry.py +189 -0
  367. bootstack/widgets/composites/toast.py +364 -0
  368. bootstack/widgets/composites/togglegroup.py +382 -0
  369. bootstack/widgets/composites/toolbar.py +393 -0
  370. bootstack/widgets/composites/tooltip.py +404 -0
  371. bootstack/widgets/internal/__init__.py +0 -0
  372. bootstack/widgets/internal/wrapper_base.py +304 -0
  373. bootstack/widgets/mixins/__init__.py +25 -0
  374. bootstack/widgets/mixins/configure_mixin.py +186 -0
  375. bootstack/widgets/mixins/entry_mixin.py +70 -0
  376. bootstack/widgets/mixins/font_mixin.py +346 -0
  377. bootstack/widgets/mixins/icon_mixin.py +38 -0
  378. bootstack/widgets/mixins/localization_mixin.py +255 -0
  379. bootstack/widgets/mixins/signal_mixin.py +272 -0
  380. bootstack/widgets/mixins/validation_mixin.py +204 -0
  381. bootstack/widgets/parts/__init__.py +11 -0
  382. bootstack/widgets/parts/numberentry_part.py +345 -0
  383. bootstack/widgets/parts/spinnerentry_part.py +394 -0
  384. bootstack/widgets/parts/textentry_part.py +344 -0
  385. bootstack/widgets/primitives/__init__.py +55 -0
  386. bootstack/widgets/primitives/badge.py +44 -0
  387. bootstack/widgets/primitives/button.py +89 -0
  388. bootstack/widgets/primitives/card.py +66 -0
  389. bootstack/widgets/primitives/checkbutton.py +124 -0
  390. bootstack/widgets/primitives/checktoggle.py +53 -0
  391. bootstack/widgets/primitives/combobox.py +165 -0
  392. bootstack/widgets/primitives/entry.py +98 -0
  393. bootstack/widgets/primitives/frame.py +206 -0
  394. bootstack/widgets/primitives/gridframe.py +479 -0
  395. bootstack/widgets/primitives/label.py +95 -0
  396. bootstack/widgets/primitives/labelframe.py +63 -0
  397. bootstack/widgets/primitives/menubutton.py +118 -0
  398. bootstack/widgets/primitives/notebook.py +551 -0
  399. bootstack/widgets/primitives/optionmenu.py +248 -0
  400. bootstack/widgets/primitives/packframe.py +228 -0
  401. bootstack/widgets/primitives/panedwindow.py +58 -0
  402. bootstack/widgets/primitives/progressbar.py +95 -0
  403. bootstack/widgets/primitives/radiobutton.py +115 -0
  404. bootstack/widgets/primitives/radiotoggle.py +50 -0
  405. bootstack/widgets/primitives/scale.py +85 -0
  406. bootstack/widgets/primitives/scrollbar.py +56 -0
  407. bootstack/widgets/primitives/separator.py +56 -0
  408. bootstack/widgets/primitives/sizegrip.py +47 -0
  409. bootstack/widgets/primitives/spinbox.py +91 -0
  410. bootstack/widgets/primitives/switch.py +41 -0
  411. bootstack/widgets/primitives/treeview.py +77 -0
  412. bootstack/widgets/types.py +20 -0
  413. bootstack-0.1.0a1.dist-info/METADATA +196 -0
  414. bootstack-0.1.0a1.dist-info/RECORD +419 -0
  415. bootstack-0.1.0a1.dist-info/WHEEL +5 -0
  416. bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
  417. bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
  418. bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
  419. bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,561 @@
1
+ """Query dialogs and querybox facade for data input."""
2
+
3
+ import textwrap
4
+ import tkinter
5
+ from datetime import date
6
+ from types import SimpleNamespace
7
+ from typing import Any, Callable, List, Optional
8
+
9
+ from bootstack.widgets.primitives import Combobox, Frame, Label
10
+ from bootstack.constants import *
11
+
12
+ ttk = SimpleNamespace(
13
+ Combobox=Combobox,
14
+ Frame=Frame,
15
+ Label=Label,
16
+ )
17
+ from bootstack.core.localization import MessageCatalog
18
+ from bootstack.dialogs.datedialog import DateDialog
19
+ from bootstack.dialogs.dialog import Dialog, DialogButton
20
+ from bootstack.dialogs.fontdialog import FontDialog
21
+ from bootstack.dialogs.message import MessageBox
22
+ from bootstack.widgets.composites.textentry import TextEntry
23
+ from bootstack.widgets.composites.numericentry import NumericEntry
24
+ from bootstack.widgets.composites.dateentry import DateEntry
25
+
26
+ EntryWidget = TextEntry | NumericEntry | DateEntry
27
+
28
+ class QueryDialog:
29
+ """A modal dialog for collecting user input with validation.
30
+
31
+ !!! note "Events"
32
+
33
+ `<<DialogResult>>`: Fired when dialog closes.
34
+ Provides `event.data` with keys: `result` (Any), `confirmed` (bool).
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ prompt: str,
40
+ title: str = " ",
41
+ value: Any = "",
42
+ minvalue: Optional[Any] = None,
43
+ maxvalue: Optional[Any] = None,
44
+ width: int = 65,
45
+ datatype: Any = str,
46
+ padding: tuple[int, int] | int = (20, 20),
47
+ master: Optional[tkinter.Misc] = None,
48
+ items: Optional[List[str]] = None,
49
+ value_format: Optional[str] = None,
50
+ increment: Optional[int | float] = None,
51
+ ) -> None:
52
+ """Create a query dialog for collecting user input.
53
+
54
+ Args:
55
+ prompt: The prompt text to display above the input field. Supports multiline strings.
56
+ title: The dialog window title.
57
+ value: The initial value to populate in the input field.
58
+ value_format: Optional ICU format pattern for formatting/parsing values.
59
+ For numbers: e.g., '$#,##0.00' for currency, '#,##0.##' for decimals
60
+ For dates: e.g., 'shortDate', 'longDate', 'yyyy-MM-dd'
61
+ When provided, uses specialized Field widgets (TextEntry, NumericEntry, DateEntry).
62
+ minvalue: Minimum allowed value for numeric data types. Ignored for strings.
63
+ maxvalue: Maximum allowed value for numeric data types. Ignored for strings.
64
+ increment: Step size for numeric fields (passed to NumericEntry).
65
+ width: Maximum width in characters for text wrapping of the prompt.
66
+ datatype: Expected data type for validation (str, int, float, date, complex).
67
+ padding: Padding around the dialog content.
68
+ master: Parent widget for the dialog.
69
+ items: Optional list of items for dropdown selection. Shows a Combobox instead of Entry.
70
+ """
71
+ self._prompt = prompt
72
+ self._value = value
73
+ self._items = items
74
+ self._minvalue = minvalue
75
+ self._maxvalue = maxvalue
76
+ self._width = width
77
+ self._datatype = datatype
78
+ self._padding = padding
79
+ self._value_format = value_format
80
+ self._increment = increment
81
+ self._entry_widget: Optional[EntryWidget] = None
82
+ self._master = master
83
+
84
+ # Create the underlying dialog with inline button specifications
85
+ self._dialog = Dialog(
86
+ master=master,
87
+ title=title,
88
+ content_builder=self._create_content,
89
+ buttons=[
90
+ DialogButton(
91
+ text="button.cancel", # Use semantic key - built-in localization
92
+ role="cancel",
93
+ result=None,
94
+ ),
95
+ DialogButton(
96
+ text="button.submit", # Use semantic key - built-in localization
97
+ role="primary",
98
+ default=True,
99
+ command=lambda dlg: self._on_submit(),
100
+ closes=False, # Don't close yet - we need to validate first
101
+ ),
102
+ ],
103
+ minsize=(350, 120),
104
+ )
105
+
106
+ def _create_content(self, parent: tkinter.Widget) -> None:
107
+ """Create the dialog body with prompt and input field."""
108
+ frame = ttk.Frame(parent, padding=self._padding)
109
+
110
+ # Create prompt label(s)
111
+ if self._prompt:
112
+ for p in self._prompt.split("\n"):
113
+ prompt = "\n".join(textwrap.wrap(p, width=self._width))
114
+ prompt_label = ttk.Label(frame, text=prompt)
115
+ prompt_label.pack(pady=(0, 5), fill=X, anchor=N)
116
+
117
+ # Create appropriate input field based on datatype and options
118
+ if self._items is not None and len(self._items) > 0:
119
+ # Combobox for item selection
120
+ entry = ttk.Combobox(master=frame, values=self._items)
121
+ entry.bind("<KeyRelease>", self._on_filter_list)
122
+ if self._value:
123
+ entry.set(self._value)
124
+ elif self._datatype == date:
125
+ # DateEntry for date input
126
+ kwargs = {"value": self._value} if self._value else {}
127
+ if self._value_format:
128
+ kwargs["value_format"] = self._value_format
129
+ kwargs.setdefault("initial_focus", True)
130
+ entry = DateEntry(master=frame, label=None, show_message=False, **kwargs)
131
+ elif self._datatype in (int, float):
132
+ # NumericEntry for numeric input with validation
133
+ kwargs = {"value": self._value if self._value else 0}
134
+ if self._minvalue is not None:
135
+ kwargs["minvalue"] = self._minvalue
136
+ if self._maxvalue is not None:
137
+ kwargs["maxvalue"] = self._maxvalue
138
+ if self._value_format:
139
+ kwargs["value_format"] = self._value_format
140
+ if self._increment is not None:
141
+ kwargs["increment"] = self._increment
142
+ kwargs.setdefault("initial_focus", True)
143
+ entry = NumericEntry(master=frame, label=None, show_message=False, **kwargs)
144
+ else:
145
+ # TextEntry for string input
146
+ kwargs = {"value": str(self._value) if self._value else ""}
147
+ if self._value_format:
148
+ kwargs["value_format"] = self._value_format
149
+ kwargs.setdefault("initial_focus", True)
150
+ entry = TextEntry(master=frame, label=None, show_message=False, **kwargs)
151
+
152
+ entry.pack(pady=(0, 5), fill=X)
153
+ entry.bind("<Return>", self._on_submit)
154
+ entry.bind("<KP_Enter>", self._on_submit)
155
+
156
+ # Focus the entry field
157
+ def _focus():
158
+ if hasattr(entry, 'entry_widget'):
159
+ entry.entry_widget.focus_set()
160
+ else:
161
+ entry.focus_set()
162
+
163
+ _focus()
164
+ # Ensure focus after dialog buttons set their own focus
165
+ entry.after_idle(_focus)
166
+
167
+ frame.pack(fill=X, expand=True)
168
+ self._entry_widget = entry
169
+
170
+ def _on_submit(self, *_: Any) -> None:
171
+ """Handle submit (Enter key or button click)."""
172
+ if not self._entry_widget:
173
+ return
174
+
175
+ # Get value from widget - Field widgets use .value, Entry/Combobox use .get()
176
+ if hasattr(self._entry_widget, 'value'):
177
+ # Field widgets (TextEntry, NumericEntry, DateEntry)
178
+ result = self._entry_widget.value
179
+ # Field widgets handle their own validation, so we can use the value directly
180
+ if result is not None:
181
+ self._dialog.result = result
182
+ if self._dialog.toplevel:
183
+ self._dialog.toplevel.destroy()
184
+ else:
185
+ # Regular Entry/Combobox - use old validation logic
186
+ result = self._entry_widget.get()
187
+ if self._validate(result):
188
+ self._dialog.result = self._datatype(result) if self._datatype != str else result
189
+ if self._dialog.toplevel:
190
+ self._dialog.toplevel.destroy()
191
+
192
+ def _on_filter_list(self, event: tkinter.Event) -> None:
193
+ """Filter combobox items based on user input."""
194
+ value = event.widget.get().lower()
195
+ if not value:
196
+ event.widget["values"] = self._items
197
+ else:
198
+ data = [k for k in self._items if value in k.lower()]
199
+ event.widget["values"] = data
200
+
201
+ def _validate(self, result: str) -> bool:
202
+ """Validate the input data."""
203
+ # No validation for string data types unless there's a list of items
204
+ if self._datatype not in [float, int, complex] and (self._items is None or len(self._items) == 0):
205
+ return True
206
+
207
+ # Convert result to appropriate data type
208
+ try:
209
+ converted_result = self._datatype(result)
210
+ except ValueError:
211
+ msg = MessageCatalog.translate("validation.should_be_type")
212
+ MessageBox.ok(
213
+ message=f"{msg} `{self._datatype}`",
214
+ title=MessageCatalog.translate("validation.invalid_type"),
215
+ master=self._dialog.toplevel,
216
+ )
217
+ return False
218
+
219
+ # Check max value range
220
+ if self._maxvalue is not None and converted_result > self._maxvalue:
221
+ msg = MessageCatalog.translate("validation.greater_than")
222
+ MessageBox.ok(
223
+ message=f"{msg} {self._maxvalue}",
224
+ title=MessageCatalog.translate("validation.out_of_range"),
225
+ master=self._dialog.toplevel,
226
+ )
227
+ return False
228
+
229
+ # Check min value range
230
+ if self._minvalue is not None and converted_result < self._minvalue:
231
+ msg = MessageCatalog.translate("validation.less_than")
232
+ MessageBox.ok(
233
+ message=f"{msg} {self._minvalue}",
234
+ title=MessageCatalog.translate("validation.out_of_range"),
235
+ master=self._dialog.toplevel,
236
+ )
237
+ return False
238
+
239
+ # Check if item is in list
240
+ if self._items is not None and len(self._items) > 0 and result not in self._items:
241
+ msg = MessageCatalog.translate("validation.select_item")
242
+ MessageBox.ok(
243
+ message=msg,
244
+ title=MessageCatalog.translate("validation.out_of_range"),
245
+ master=self._dialog.toplevel,
246
+ )
247
+ return False
248
+
249
+ return True
250
+
251
+ def show(self, position: Optional[tuple[int, int]] = None) -> None:
252
+ """Show the dialog.
253
+
254
+ Args:
255
+ position: x and y coordinates to position the dialog. If None, centers on parent.
256
+ """
257
+ self._dialog.show(position=position, modal=True)
258
+ target = self._dialog.toplevel or self._master
259
+ if target:
260
+ payload = {"result": self._dialog.result, "confirmed": self._dialog.result is not None}
261
+ try:
262
+ target.event_generate("<<DialogResult>>", data=payload)
263
+ except Exception:
264
+ try:
265
+ target.event_generate("<<DialogResult>>")
266
+ except Exception:
267
+ pass
268
+
269
+ @property
270
+ def result(self) -> Any:
271
+ """The dialog result value."""
272
+ return self._dialog.result
273
+
274
+ def on_dialog_result(self, callback: Callable[[Any], None]) -> Optional[str]:
275
+ """Bind a callback fired when the dialog produces a result.
276
+
277
+ The callback receives `event.data["result"]` when available.
278
+
279
+ Args:
280
+ callback: Callable that receives the result payload.
281
+
282
+ Returns:
283
+ Binding identifier for use with `off_dialog_result`.
284
+ """
285
+ target = self._dialog.toplevel or self._master
286
+ if target is None:
287
+ return None
288
+
289
+ def handler(event):
290
+ callback(getattr(event, "data", None))
291
+
292
+ return target.bind("<<DialogResult>>", handler, add="+")
293
+
294
+ def off_dialog_result(self, funcid: str) -> None:
295
+ """Unbind a previously bound dialog result callback."""
296
+ target = self._dialog.toplevel or self._master
297
+ if target is None:
298
+ return
299
+ target.unbind("<<DialogResult>>", funcid)
300
+
301
+
302
+ class QueryBox:
303
+ """Static methods for displaying query dialogs."""
304
+
305
+ @staticmethod
306
+ def get_color(
307
+ master: Optional[tkinter.Misc] = None,
308
+ title: str = "Color Chooser",
309
+ value: Optional[str] = None,
310
+ **kwargs: Any,
311
+ ) -> Any:
312
+ """Show a color picker dialog.
313
+
314
+ Args:
315
+ master: Parent widget for the dialog.
316
+ title: The dialog window title.
317
+ value: Initial color to display.
318
+ **kwargs: Additional arguments including 'position'.
319
+
320
+ Returns:
321
+ Selected color or None if canceled.
322
+ """
323
+ from bootstack.dialogs.colorchooser import ColorChooserDialog
324
+
325
+ position = kwargs.pop("position", None)
326
+ dialog = ColorChooserDialog(master, title, value)
327
+ dialog.show(position)
328
+ return dialog.result
329
+
330
+ @staticmethod
331
+ def get_date(
332
+ master: Optional[tkinter.Misc] = None,
333
+ title: str = " ",
334
+ first_weekday: int = 6,
335
+ value: Optional[date] = None,
336
+ accent: str = None,
337
+ hide_window_chrome: bool = False,
338
+ on_result: Optional[Callable[[Any], None]] = None,
339
+ **kwargs: Any,
340
+ ) -> Optional[date]:
341
+ """Show a date picker dialog.
342
+
343
+ Args:
344
+ master: Parent widget for the dialog.
345
+ title: The dialog window title.
346
+ first_weekday: First day of the week (0=Monday, 6=Sunday).
347
+ value: Initial date to display.
348
+ accent: Accent token for the calendar (e.g., 'primary', 'success').
349
+ hide_window_chrome: If True, shows the dialog with override-redirect
350
+ to hide window decorations.
351
+ on_result: Optional callback receiving the dialog result payload.
352
+ **kwargs: Additional arguments including 'position'.
353
+
354
+ Returns:
355
+ Selected date or None if canceled.
356
+ """
357
+ position = kwargs.pop("position", None)
358
+ dialog = DateDialog(
359
+ master=master,
360
+ title=title,
361
+ first_weekday=first_weekday,
362
+ initial_date=value,
363
+ accent=accent or "primary",
364
+ hide_window_chrome=hide_window_chrome,
365
+ )
366
+ if on_result:
367
+ dialog.on_result(on_result)
368
+ dialog.show(position)
369
+ return dialog.result
370
+
371
+ @staticmethod
372
+ def get_string(
373
+ prompt: str = "",
374
+ title: str = " ",
375
+ value: Optional[str] = None,
376
+ master: Optional[tkinter.Misc] = None,
377
+ value_format: Optional[str] = None,
378
+ on_result: Optional[Callable[[Any], None]] = None,
379
+ **kwargs: Any,
380
+ ) -> Optional[str]:
381
+ """Show a string input dialog.
382
+
383
+ Args:
384
+ prompt: The prompt text to display.
385
+ title: The dialog window title.
386
+ value: Initial value for the input field.
387
+ master: Parent widget for the dialog.
388
+ value_format: Optional ICU format pattern for parsing/formatting.
389
+ on_result: Optional callback receiving the dialog result payload.
390
+ **kwargs: Additional arguments including 'position'.
391
+
392
+ Returns:
393
+ Input string or None if canceled.
394
+ """
395
+ value = value or ""
396
+ position = kwargs.pop("position", None)
397
+ dialog = QueryDialog(
398
+ prompt,
399
+ title,
400
+ value,
401
+ master=master,
402
+ value_format=value_format,
403
+ **kwargs,
404
+ )
405
+ if on_result:
406
+ dialog.on_dialog_result(on_result)
407
+ dialog.show(position)
408
+ return dialog.result
409
+
410
+ @staticmethod
411
+ def get_item(
412
+ prompt: str = "",
413
+ title: str = " ",
414
+ value: Optional[str] = None,
415
+ items: Optional[List[str]] = None,
416
+ master: Optional[tkinter.Misc] = None,
417
+ on_result: Optional[Callable[[Any], None]] = None,
418
+ **kwargs: Any,
419
+ ) -> Optional[str]:
420
+ """Show a dropdown selection dialog.
421
+
422
+ Args:
423
+ prompt: The prompt text to display.
424
+ title: The dialog window title.
425
+ value: Initial value for the input field.
426
+ items: List of items to choose from.
427
+ master: Parent widget for the dialog.
428
+ on_result: Optional callback receiving the dialog result payload.
429
+ **kwargs: Additional arguments including 'position'.
430
+
431
+ Returns:
432
+ Selected item or None if canceled.
433
+ """
434
+ value = value or ""
435
+ position = kwargs.pop("position", None)
436
+ dialog = QueryDialog(
437
+ prompt,
438
+ title,
439
+ value,
440
+ items=items,
441
+ master=master,
442
+ **kwargs,
443
+ )
444
+ if on_result:
445
+ dialog.on_dialog_result(on_result)
446
+ dialog.show(position)
447
+ return dialog.result
448
+
449
+ @staticmethod
450
+ def get_integer(
451
+ prompt: str = "",
452
+ title: str = " ",
453
+ value: Optional[int] = None,
454
+ minvalue: Optional[int] = None,
455
+ maxvalue: Optional[int] = None,
456
+ master: Optional[tkinter.Misc] = None,
457
+ value_format: Optional[str] = None,
458
+ increment: Optional[int] = None,
459
+ on_result: Optional[Callable[[Any], None]] = None,
460
+ **kwargs: Any,
461
+ ) -> Optional[int]:
462
+ """Show an integer input dialog with validation.
463
+
464
+ Args:
465
+ prompt: The prompt text to display.
466
+ title: The dialog window title.
467
+ value: Initial value for the input field.
468
+ minvalue: Minimum allowed value.
469
+ maxvalue: Maximum allowed value.
470
+ increment: Step size for increment/decrement buttons.
471
+ value_format: Optional ICU format pattern for parsing/formatting.
472
+ master: Parent widget for the dialog.
473
+ on_result: Optional callback receiving the dialog result payload.
474
+ **kwargs: Additional arguments including 'position'.
475
+
476
+ Returns:
477
+ Integer value or None if canceled.
478
+ """
479
+ value = value or ""
480
+ position = kwargs.pop("position", None)
481
+ dialog = QueryDialog(
482
+ prompt,
483
+ title,
484
+ value,
485
+ minvalue,
486
+ maxvalue,
487
+ datatype=int,
488
+ master=master,
489
+ value_format=value_format,
490
+ increment=increment,
491
+ **kwargs,
492
+ )
493
+ if on_result:
494
+ dialog.on_dialog_result(on_result)
495
+ dialog.show(position)
496
+ return dialog.result
497
+
498
+ @staticmethod
499
+ def get_float(
500
+ prompt: str = "",
501
+ title: str = " ",
502
+ value: Optional[float] = None,
503
+ minvalue: Optional[float] = None,
504
+ maxvalue: Optional[float] = None,
505
+ master: Optional[tkinter.Misc] = None,
506
+ value_format: Optional[str] = None,
507
+ increment: Optional[float] = None,
508
+ on_result: Optional[Callable[[Any], None]] = None,
509
+ **kwargs: Any,
510
+ ) -> Optional[float]:
511
+ """Show a float input dialog with validation.
512
+
513
+ Args:
514
+ prompt: The prompt text to display.
515
+ title: The dialog window title.
516
+ value: Initial value for the input field.
517
+ minvalue: Minimum allowed value.
518
+ maxvalue: Maximum allowed value.
519
+ master: Parent widget for the dialog.
520
+ value_format: Optional ICU format pattern for parsing/formatting.
521
+ increment: Step size for increment/decrement buttons.
522
+ on_result: Optional callback receiving the dialog result payload.
523
+ **kwargs: Additional arguments including 'position'.
524
+
525
+ Returns:
526
+ Float value or None if canceled.
527
+ """
528
+ value = value or ""
529
+ position = kwargs.pop("position", None)
530
+ dialog = QueryDialog(
531
+ prompt,
532
+ title,
533
+ value,
534
+ minvalue,
535
+ maxvalue,
536
+ datatype=float,
537
+ master=master,
538
+ value_format=value_format,
539
+ increment=increment,
540
+ **kwargs,
541
+ )
542
+ if on_result:
543
+ dialog.on_dialog_result(on_result)
544
+ dialog.show(position)
545
+ return dialog.result
546
+
547
+ @staticmethod
548
+ def get_font(master: Optional[tkinter.Misc] = None, **kwargs: Any) -> Any:
549
+ """Show a font selection dialog.
550
+
551
+ Args:
552
+ master: Parent widget for the dialog.
553
+ **kwargs: Additional arguments including 'position'.
554
+
555
+ Returns:
556
+ Selected font or None if canceled.
557
+ """
558
+ position = kwargs.pop("position", None)
559
+ dialog = FontDialog(master=master, **kwargs)
560
+ dialog.show(position=position)
561
+ return dialog.result
bootstack/py.typed ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,3 @@
1
+ """Runtime integration layer (Tk/tcl interop, assets, scaling)."""
2
+
3
+ # Placeholder for future runtime utilities.