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,570 @@
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._impl.primitives import Frame, Label
10
+ from bootstack.widgets._impl.composites.selectbox import SelectBox
11
+ from bootstack.constants import *
12
+
13
+ ttk = SimpleNamespace(
14
+ Frame=Frame,
15
+ Label=Label,
16
+ )
17
+ from bootstack.i18n import MessageCatalog
18
+ from bootstack.dialogs._impl.datedialog import DateDialog
19
+ from bootstack.dialogs._impl.dialog import Dialog, DialogButton
20
+ from bootstack.dialogs._impl.fontdialog import FontDialog
21
+ from bootstack.dialogs._impl.message import MessageBox
22
+ from bootstack.widgets._impl.composites.textentry import TextEntry
23
+ from bootstack.widgets._impl.composites.numericentry import NumericEntry
24
+ from bootstack.widgets._impl.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
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ prompt: str,
36
+ title: str = " ",
37
+ value: Any = "",
38
+ minvalue: Optional[Any] = None,
39
+ maxvalue: Optional[Any] = None,
40
+ width: int = 65,
41
+ datatype: Any = str,
42
+ padding: tuple[int, int] | int = (20, 20),
43
+ master: Optional[tkinter.Misc] = None,
44
+ items: Optional[List[str]] = None,
45
+ value_format: Optional[str] = None,
46
+ increment: Optional[int | float] = None,
47
+ ) -> None:
48
+ """Create a query dialog for collecting user input.
49
+
50
+ Args:
51
+ prompt: The prompt text to display above the input field. Supports multiline strings.
52
+ title: The dialog window title.
53
+ value: The initial value to populate in the input field.
54
+ value_format: Optional ICU format pattern for formatting/parsing values.
55
+ For numbers: e.g., '$#,##0.00' for currency, '#,##0.##' for decimals
56
+ For dates: e.g., 'shortDate', 'longDate', 'yyyy-MM-dd'
57
+ When provided, uses specialized Field widgets (TextEntry, NumericEntry, DateEntry).
58
+ minvalue: Minimum allowed value for numeric data types. Ignored for strings.
59
+ maxvalue: Maximum allowed value for numeric data types. Ignored for strings.
60
+ increment: Step size for numeric fields (passed to NumericEntry).
61
+ width: Maximum width in characters for text wrapping of the prompt.
62
+ datatype: Expected data type for validation (str, int, float, date, complex).
63
+ padding: Padding around the dialog content.
64
+ master: Parent widget for the dialog.
65
+ items: Optional list of items for dropdown selection. Shows a Combobox instead of Entry.
66
+ """
67
+ self._prompt = prompt
68
+ self._value = value
69
+ self._items = items
70
+ self._minvalue = minvalue
71
+ self._maxvalue = maxvalue
72
+ self._width = width
73
+ self._datatype = datatype
74
+ self._padding = padding
75
+ self._value_format = value_format
76
+ self._increment = increment
77
+ self._entry_widget: Optional[EntryWidget] = None
78
+ self._master = master
79
+
80
+ # Create the underlying dialog with inline button specifications
81
+ self._dialog = Dialog(
82
+ title=title,
83
+ content_builder=self._create_content,
84
+ _raw_content=True,
85
+ buttons=[
86
+ DialogButton(
87
+ text="button.cancel",
88
+ role="cancel",
89
+ result=None,
90
+ ),
91
+ DialogButton(
92
+ text="button.submit",
93
+ role="primary",
94
+ default=True,
95
+ command=lambda dlg: self._on_submit(),
96
+ closes=False,
97
+ ),
98
+ ],
99
+ min_size=(350, 120),
100
+ parent=master,
101
+ )
102
+
103
+ def _create_content(self, parent: tkinter.Widget) -> None:
104
+ """Create the dialog body with prompt and input field."""
105
+ frame = ttk.Frame(parent, padding=self._padding)
106
+
107
+ # Create prompt label(s)
108
+ if self._prompt:
109
+ for p in self._prompt.split("\n"):
110
+ prompt = "\n".join(textwrap.wrap(p, width=self._width))
111
+ prompt_label = ttk.Label(frame, text=prompt)
112
+ prompt_label.pack(pady=(0, 5), fill=X, anchor=N)
113
+
114
+ # Create appropriate input field based on datatype and options
115
+ if self._items is not None and len(self._items) > 0:
116
+ entry = SelectBox(
117
+ frame,
118
+ items=self._items,
119
+ value=self._value if self._value else None,
120
+ allow_custom_values=False,
121
+ enable_search=True,
122
+ initial_focus=True,
123
+ show_message=False,
124
+ label=None,
125
+ )
126
+ elif self._datatype == date:
127
+ # DateEntry for date input
128
+ kwargs = {"value": self._value} if self._value else {}
129
+ if self._value_format:
130
+ kwargs["value_format"] = self._value_format
131
+ kwargs.setdefault("initial_focus", True)
132
+ entry = DateEntry(master=frame, label=None, show_message=False, **kwargs)
133
+ elif self._datatype in (int, float):
134
+ # NumericEntry for numeric input with validation
135
+ kwargs = {"value": self._value if self._value else 0}
136
+ if self._minvalue is not None:
137
+ kwargs["minvalue"] = self._minvalue
138
+ if self._maxvalue is not None:
139
+ kwargs["maxvalue"] = self._maxvalue
140
+ if self._value_format:
141
+ kwargs["value_format"] = self._value_format
142
+ if self._increment is not None:
143
+ kwargs["increment"] = self._increment
144
+ kwargs.setdefault("initial_focus", True)
145
+ entry = NumericEntry(master=frame, label=None, show_message=False, **kwargs)
146
+ else:
147
+ # TextEntry for string input
148
+ kwargs = {"value": str(self._value) if self._value else ""}
149
+ if self._value_format:
150
+ kwargs["value_format"] = self._value_format
151
+ kwargs.setdefault("initial_focus", True)
152
+ entry = TextEntry(master=frame, label=None, show_message=False, **kwargs)
153
+
154
+ entry.pack(pady=(0, 5), fill=X)
155
+ entry.bind("<Return>", self._on_submit)
156
+ entry.bind("<KP_Enter>", self._on_submit)
157
+
158
+ # Focus the entry field
159
+ def _focus():
160
+ if hasattr(entry, 'entry_widget'):
161
+ entry.entry_widget.focus_set()
162
+ else:
163
+ entry.focus_set()
164
+
165
+ _focus()
166
+ # Ensure focus after dialog buttons set their own focus
167
+ entry.after_idle(_focus)
168
+
169
+ frame.pack(fill=X, expand=True)
170
+ self._entry_widget = entry
171
+
172
+ def _on_submit(self, *_: Any) -> None:
173
+ """Handle submit (Enter key or button click)."""
174
+ if not self._entry_widget:
175
+ return
176
+
177
+ # Get value from widget - Field widgets use .value, Entry/Combobox use .get()
178
+ if hasattr(self._entry_widget, 'value'):
179
+ result = self._entry_widget.value
180
+ # For item-selection dialogs, reject values not in the list
181
+ if self._items and result not in self._items:
182
+ msg = MessageCatalog.translate("validation.select_item")
183
+ MessageBox.ok(
184
+ message=msg,
185
+ title=MessageCatalog.translate("validation.out_of_range"),
186
+ master=self._dialog.toplevel,
187
+ )
188
+ return
189
+ if result is not None:
190
+ self._dialog.result = result
191
+ if self._dialog.toplevel:
192
+ self._dialog.toplevel.destroy()
193
+ else:
194
+ # Regular Entry/Combobox - use old validation logic
195
+ result = self._entry_widget.get()
196
+ if self._validate(result):
197
+ self._dialog.result = self._datatype(result) if self._datatype != str else result
198
+ if self._dialog.toplevel:
199
+ self._dialog.toplevel.destroy()
200
+
201
+ def _on_filter_list(self, event: tkinter.Event) -> None:
202
+ """Filter combobox items based on user input."""
203
+ value = event.widget.get().lower()
204
+ if not value:
205
+ event.widget["values"] = self._items
206
+ else:
207
+ data = [k for k in self._items if value in k.lower()]
208
+ event.widget["values"] = data
209
+
210
+ def _validate(self, result: str) -> bool:
211
+ """Validate the input data."""
212
+ # No validation for string data types unless there's a list of items
213
+ if self._datatype not in [float, int, complex] and (self._items is None or len(self._items) == 0):
214
+ return True
215
+
216
+ # Convert result to appropriate data type
217
+ try:
218
+ converted_result = self._datatype(result)
219
+ except ValueError:
220
+ msg = MessageCatalog.translate("validation.should_be_type")
221
+ MessageBox.ok(
222
+ message=f"{msg} `{self._datatype}`",
223
+ title=MessageCatalog.translate("validation.invalid_type"),
224
+ master=self._dialog.toplevel,
225
+ )
226
+ return False
227
+
228
+ # Check max value range
229
+ if self._maxvalue is not None and converted_result > self._maxvalue:
230
+ msg = MessageCatalog.translate("validation.greater_than")
231
+ MessageBox.ok(
232
+ message=f"{msg} {self._maxvalue}",
233
+ title=MessageCatalog.translate("validation.out_of_range"),
234
+ master=self._dialog.toplevel,
235
+ )
236
+ return False
237
+
238
+ # Check min value range
239
+ if self._minvalue is not None and converted_result < self._minvalue:
240
+ msg = MessageCatalog.translate("validation.less_than")
241
+ MessageBox.ok(
242
+ message=f"{msg} {self._minvalue}",
243
+ title=MessageCatalog.translate("validation.out_of_range"),
244
+ master=self._dialog.toplevel,
245
+ )
246
+ return False
247
+
248
+ # Check if item is in list
249
+ if self._items is not None and len(self._items) > 0 and result not in self._items:
250
+ msg = MessageCatalog.translate("validation.select_item")
251
+ MessageBox.ok(
252
+ message=msg,
253
+ title=MessageCatalog.translate("validation.out_of_range"),
254
+ master=self._dialog.toplevel,
255
+ )
256
+ return False
257
+
258
+ return True
259
+
260
+ def show(self, position: Optional[tuple[int, int]] = None) -> None:
261
+ """Show the dialog.
262
+
263
+ Args:
264
+ position: x and y coordinates to position the dialog. If None, centers on parent.
265
+ """
266
+ self._dialog.show(position=position, modal=True)
267
+ target = self._dialog.toplevel or self._master
268
+ if target:
269
+ payload = {"result": self._dialog.result, "confirmed": self._dialog.result is not None}
270
+ try:
271
+ target.event_generate("<<DialogResult>>", data=payload)
272
+ except Exception:
273
+ try:
274
+ target.event_generate("<<DialogResult>>")
275
+ except Exception:
276
+ pass
277
+
278
+ @property
279
+ def result(self) -> Any:
280
+ """The dialog result value."""
281
+ return self._dialog.result
282
+
283
+ def on_dialog_result(self, callback: Callable[[Any], None]) -> Optional[str]:
284
+ """Bind a callback fired when the dialog produces a result.
285
+
286
+ The callback receives `event.data["result"]` when available.
287
+
288
+ Args:
289
+ callback: Callable that receives the result payload.
290
+
291
+ Returns:
292
+ Binding identifier for use with `off_dialog_result`.
293
+ """
294
+ target = self._dialog.toplevel or self._master
295
+ if target is None:
296
+ return None
297
+
298
+ def handler(event):
299
+ callback(getattr(event, "data", None))
300
+
301
+ return target.bind("<<DialogResult>>", handler, add="+")
302
+
303
+ def off_dialog_result(self, funcid: str) -> None:
304
+ """Unbind a previously bound dialog result callback."""
305
+ target = self._dialog.toplevel or self._master
306
+ if target is None:
307
+ return
308
+ target.unbind("<<DialogResult>>", funcid)
309
+
310
+
311
+ class QueryBox:
312
+ """Static methods for displaying query dialogs."""
313
+
314
+ @staticmethod
315
+ def get_color(
316
+ master: Optional[tkinter.Misc] = None,
317
+ title: str = "Color Chooser",
318
+ value: Optional[str] = None,
319
+ **kwargs: Any,
320
+ ) -> Any:
321
+ """Show a color picker dialog.
322
+
323
+ Args:
324
+ master: Parent widget for the dialog.
325
+ title: The dialog window title.
326
+ value: Initial color to display.
327
+ **kwargs: Additional arguments including 'position'.
328
+
329
+ Returns:
330
+ Selected color or None if canceled.
331
+ """
332
+ from bootstack.dialogs._impl.colorchooser import ColorChooserDialog
333
+
334
+ position = kwargs.pop("position", None)
335
+ dialog = ColorChooserDialog(master, title, value)
336
+ dialog.show(position)
337
+ return dialog.result
338
+
339
+ @staticmethod
340
+ def get_date(
341
+ master: Optional[tkinter.Misc] = None,
342
+ title: str = " ",
343
+ first_weekday: int = 6,
344
+ value: Optional[date] = None,
345
+ accent: str = None,
346
+ hide_window_chrome: bool = False,
347
+ on_result: Optional[Callable[[Any], None]] = None,
348
+ **kwargs: Any,
349
+ ) -> Optional[date]:
350
+ """Show a date picker dialog.
351
+
352
+ Args:
353
+ master: Parent widget for the dialog.
354
+ title: The dialog window title.
355
+ first_weekday: First day of the week (0=Monday, 6=Sunday).
356
+ value: Initial date to display.
357
+ accent: Accent token for the calendar (e.g., 'primary', 'success').
358
+ hide_window_chrome: If True, shows the dialog with override-redirect
359
+ to hide window decorations.
360
+ on_result: Optional callback receiving the dialog result payload.
361
+ **kwargs: Additional arguments including 'position'.
362
+
363
+ Returns:
364
+ Selected date or None if canceled.
365
+ """
366
+ position = kwargs.pop("position", None)
367
+ dialog = DateDialog(
368
+ master=master,
369
+ title=title,
370
+ first_weekday=first_weekday,
371
+ initial_date=value,
372
+ accent=accent or "primary",
373
+ hide_window_chrome=hide_window_chrome,
374
+ )
375
+ if on_result:
376
+ dialog.on_result(on_result)
377
+ dialog.show(position)
378
+ return dialog.result
379
+
380
+ @staticmethod
381
+ def get_string(
382
+ prompt: str = "",
383
+ title: str = " ",
384
+ value: Optional[str] = None,
385
+ master: Optional[tkinter.Misc] = None,
386
+ value_format: Optional[str] = None,
387
+ on_result: Optional[Callable[[Any], None]] = None,
388
+ **kwargs: Any,
389
+ ) -> Optional[str]:
390
+ """Show a string input dialog.
391
+
392
+ Args:
393
+ prompt: The prompt text to display.
394
+ title: The dialog window title.
395
+ value: Initial value for the input field.
396
+ master: Parent widget for the dialog.
397
+ value_format: Optional ICU format pattern for parsing/formatting.
398
+ on_result: Optional callback receiving the dialog result payload.
399
+ **kwargs: Additional arguments including 'position'.
400
+
401
+ Returns:
402
+ Input string or None if canceled.
403
+ """
404
+ value = value or ""
405
+ position = kwargs.pop("position", None)
406
+ dialog = QueryDialog(
407
+ prompt,
408
+ title,
409
+ value,
410
+ master=master,
411
+ value_format=value_format,
412
+ **kwargs,
413
+ )
414
+ if on_result:
415
+ dialog.on_dialog_result(on_result)
416
+ dialog.show(position)
417
+ return dialog.result
418
+
419
+ @staticmethod
420
+ def get_item(
421
+ prompt: str = "",
422
+ title: str = " ",
423
+ value: Optional[str] = None,
424
+ items: Optional[List[str]] = None,
425
+ master: Optional[tkinter.Misc] = None,
426
+ on_result: Optional[Callable[[Any], None]] = None,
427
+ **kwargs: Any,
428
+ ) -> Optional[str]:
429
+ """Show a dropdown selection dialog.
430
+
431
+ Args:
432
+ prompt: The prompt text to display.
433
+ title: The dialog window title.
434
+ value: Initial value for the input field.
435
+ items: List of items to choose from.
436
+ master: Parent widget for the dialog.
437
+ on_result: Optional callback receiving the dialog result payload.
438
+ **kwargs: Additional arguments including 'position'.
439
+
440
+ Returns:
441
+ Selected item or None if canceled.
442
+ """
443
+ value = value or ""
444
+ position = kwargs.pop("position", None)
445
+ dialog = QueryDialog(
446
+ prompt,
447
+ title,
448
+ value,
449
+ items=items,
450
+ master=master,
451
+ **kwargs,
452
+ )
453
+ if on_result:
454
+ dialog.on_dialog_result(on_result)
455
+ dialog.show(position)
456
+ return dialog.result
457
+
458
+ @staticmethod
459
+ def get_integer(
460
+ prompt: str = "",
461
+ title: str = " ",
462
+ value: Optional[int] = None,
463
+ minvalue: Optional[int] = None,
464
+ maxvalue: Optional[int] = None,
465
+ master: Optional[tkinter.Misc] = None,
466
+ value_format: Optional[str] = None,
467
+ increment: Optional[int] = None,
468
+ on_result: Optional[Callable[[Any], None]] = None,
469
+ **kwargs: Any,
470
+ ) -> Optional[int]:
471
+ """Show an integer input dialog with validation.
472
+
473
+ Args:
474
+ prompt: The prompt text to display.
475
+ title: The dialog window title.
476
+ value: Initial value for the input field.
477
+ minvalue: Minimum allowed value.
478
+ maxvalue: Maximum allowed value.
479
+ increment: Step size for increment/decrement buttons.
480
+ value_format: Optional ICU format pattern for parsing/formatting.
481
+ master: Parent widget for the dialog.
482
+ on_result: Optional callback receiving the dialog result payload.
483
+ **kwargs: Additional arguments including 'position'.
484
+
485
+ Returns:
486
+ Integer value or None if canceled.
487
+ """
488
+ value = value or ""
489
+ position = kwargs.pop("position", None)
490
+ dialog = QueryDialog(
491
+ prompt,
492
+ title,
493
+ value,
494
+ minvalue,
495
+ maxvalue,
496
+ datatype=int,
497
+ master=master,
498
+ value_format=value_format,
499
+ increment=increment,
500
+ **kwargs,
501
+ )
502
+ if on_result:
503
+ dialog.on_dialog_result(on_result)
504
+ dialog.show(position)
505
+ return dialog.result
506
+
507
+ @staticmethod
508
+ def get_float(
509
+ prompt: str = "",
510
+ title: str = " ",
511
+ value: Optional[float] = None,
512
+ minvalue: Optional[float] = None,
513
+ maxvalue: Optional[float] = None,
514
+ master: Optional[tkinter.Misc] = None,
515
+ value_format: Optional[str] = None,
516
+ increment: Optional[float] = None,
517
+ on_result: Optional[Callable[[Any], None]] = None,
518
+ **kwargs: Any,
519
+ ) -> Optional[float]:
520
+ """Show a float input dialog with validation.
521
+
522
+ Args:
523
+ prompt: The prompt text to display.
524
+ title: The dialog window title.
525
+ value: Initial value for the input field.
526
+ minvalue: Minimum allowed value.
527
+ maxvalue: Maximum allowed value.
528
+ master: Parent widget for the dialog.
529
+ value_format: Optional ICU format pattern for parsing/formatting.
530
+ increment: Step size for increment/decrement buttons.
531
+ on_result: Optional callback receiving the dialog result payload.
532
+ **kwargs: Additional arguments including 'position'.
533
+
534
+ Returns:
535
+ Float value or None if canceled.
536
+ """
537
+ value = value or ""
538
+ position = kwargs.pop("position", None)
539
+ dialog = QueryDialog(
540
+ prompt,
541
+ title,
542
+ value,
543
+ minvalue,
544
+ maxvalue,
545
+ datatype=float,
546
+ master=master,
547
+ value_format=value_format,
548
+ increment=increment,
549
+ **kwargs,
550
+ )
551
+ if on_result:
552
+ dialog.on_dialog_result(on_result)
553
+ dialog.show(position)
554
+ return dialog.result
555
+
556
+ @staticmethod
557
+ def get_font(master: Optional[tkinter.Misc] = None, **kwargs: Any) -> Any:
558
+ """Show a font selection dialog.
559
+
560
+ Args:
561
+ master: Parent widget for the dialog.
562
+ **kwargs: Additional arguments including 'position'.
563
+
564
+ Returns:
565
+ Selected font or None if canceled.
566
+ """
567
+ position = kwargs.pop("position", None)
568
+ dialog = FontDialog(master=master, **kwargs)
569
+ dialog.show(position=position)
570
+ return dialog.result
bootstack/errors.py ADDED
@@ -0,0 +1,67 @@
1
+ """Public exception types raised by the bootstack API."""
2
+
3
+
4
+ class BootstackError(Exception):
5
+ """Base class for all public API errors."""
6
+
7
+
8
+ class UnknownEventError(BootstackError):
9
+ """Raised by `widget.on(name, ...)` when `name` cannot be resolved."""
10
+
11
+
12
+ class ParentResolutionError(BootstackError):
13
+ """Raised when a widget cannot resolve its parent."""
14
+
15
+
16
+ class DuplicateIdError(BootstackError):
17
+ """Raised when a data source receives a record whose id already exists.
18
+
19
+ Record ids must be unique — they identify rows for selection and events.
20
+ """
21
+
22
+
23
+ class SerializationError(BootstackError):
24
+ """Raised when a file-backed store or data source receives a value it
25
+ cannot persist.
26
+
27
+ File- and database-backed sources carry non-scalar fields as JSON, and
28
+ `Store` persists its values as JSON, so values must be JSON-serializable
29
+ (scalars, lists, dicts). Store arbitrary Python objects in an in-memory
30
+ source instead.
31
+ """
32
+
33
+
34
+ class NavigationError(BootstackError):
35
+ """Raised when a navigation operation references a wrong key.
36
+
37
+ Examples: adding a page, tab, or workspace whose key already exists, or
38
+ selecting, looking up, or removing one whose key does not exist.
39
+ """
40
+
41
+
42
+ class ThemeError(BootstackError):
43
+ """Raised when a theme-related operation fails.
44
+
45
+ Examples: requesting an unknown theme name, or loading a malformed theme
46
+ definition.
47
+ """
48
+
49
+
50
+ class StyleBuilderError(BootstackError):
51
+ """Raised when a widget style cannot be built.
52
+
53
+ Examples: an unsupported `variant` for a widget, or a missing required
54
+ theme color token.
55
+ """
56
+
57
+
58
+ __all__ = [
59
+ "BootstackError",
60
+ "DuplicateIdError",
61
+ "NavigationError",
62
+ "ParentResolutionError",
63
+ "SerializationError",
64
+ "StyleBuilderError",
65
+ "ThemeError",
66
+ "UnknownEventError",
67
+ ]