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,385 @@
1
+ """Numeric entry widget with manual stepping and validation.
2
+
3
+ This module provides a number entry widget that extends TextEntryPart with
4
+ numeric-specific features like min/max bounds, stepping, and keyboard/mouse
5
+ wheel support.
6
+ """
7
+
8
+
9
+ from bootstack.events import ChangeEvent
10
+ from bootstack.widgets._impl.mixins.configure_mixin import configure_delegate
11
+ from bootstack.widgets._impl._parts.textentry_part import TextEntryPart
12
+
13
+
14
+ class NumberEntryPart(TextEntryPart):
15
+ """Numeric entry widget with stepping and bounds validation.
16
+
17
+ Extends TextEntryPart to provide numeric input with constraints and
18
+ stepping functionality. Supports min/max bounds, increment/decrement
19
+ via keyboard and mouse wheel, and optional wrapping.
20
+
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ master=None,
26
+ *,
27
+ value: int | float | str = 0,
28
+ value_format: str = None,
29
+ minvalue: int | float | None = None,
30
+ maxvalue: int | float | None = None,
31
+ increment: int | float = 1,
32
+ wrap: bool = False,
33
+ initial_focus: bool = False,
34
+ allow_blank: bool = True,
35
+ **kwargs
36
+ ):
37
+ """Initialize a NumberEntryPart widget.
38
+
39
+ Args:
40
+ master: Parent widget
41
+ value: Initial numeric value (int, float, string, or None)
42
+ value_format: Number format specification for IntlFormatter.
43
+ Examples: 'decimal', 'percent', 'currency', '#,##0.00', etc.
44
+ minvalue: Minimum allowed value (inclusive), or None for no lower bound
45
+ maxvalue: Maximum allowed value (inclusive), or None for no upper bound
46
+ increment: Step size for increment/decrement operations
47
+ wrap: If True, values wrap around at min/max boundaries.
48
+ If False, values are clamped at boundaries.
49
+ initial_focus: If True, widget receives focus on creation
50
+ allow_blank: If True, empty input is allowed (sets value to None)
51
+ locale: Locale identifier for number formatting (e.g., 'en_US')
52
+ **kwargs: Additional keyword arguments passed to TextEntryPart
53
+ """
54
+ # Store numeric configuration
55
+ self._minvalue = minvalue
56
+ self._maxvalue = maxvalue
57
+ self._increment = increment
58
+ self._wrap = wrap
59
+
60
+ # Determine numeric type (float if any parameter is float)
61
+ def _has_fractional(x: int | float | None) -> bool:
62
+ if x is None:
63
+ return False
64
+ if isinstance(x, float):
65
+ return True
66
+ if isinstance(x, (int, float)) and float(x) != int(x):
67
+ return True
68
+ return False
69
+
70
+ self._num_type = float if any(
71
+ _has_fractional(x) for x in (
72
+ minvalue, maxvalue, increment,
73
+ value if not isinstance(value, str) else 0
74
+ )
75
+ ) else int
76
+
77
+ # Initialize base TextEntryPart
78
+ # Convert initial value to appropriate type
79
+ if isinstance(value, str):
80
+ initial_value = value
81
+ else:
82
+ initial_value = None if value is None else self._num_type(value)
83
+
84
+ super().__init__(
85
+ master=master,
86
+ value=initial_value,
87
+ value_format=value_format,
88
+ initial_focus=initial_focus,
89
+ allow_blank=allow_blank,
90
+ **kwargs
91
+ )
92
+
93
+ # Apply bounds to the initial value. An empty/blank field has no numeric
94
+ # value — it arrives here as '' (a number field with no format stores its
95
+ # text verbatim) — so normalize it to None and skip bounds, mirroring how
96
+ # clear()/commit represent an empty field. (Without this, float('') raises
97
+ # at construction for NumberField(value=None) or value="".)
98
+ if self._value is None or self._value == "":
99
+ self._value = None
100
+ self._prev_changed_value = None
101
+ else:
102
+ self._value = self._apply_bounds(float(self._value))
103
+ if self._num_type is int:
104
+ self._value = int(round(self._value))
105
+ # Update display with bounded value
106
+ formatted_text = self._format_value(self._value)
107
+ self.textsignal.set(formatted_text)
108
+ self._prev_changed_value = self._value
109
+
110
+ # Bind keyboard stepping (Up/Down arrows)
111
+ self.bind('<Up>', self._handle_up_key, add=True)
112
+ self.bind('<Down>', self._handle_down_key, add=True)
113
+
114
+ # Bind mouse wheel (Windows/macOS)
115
+ self.bind('<MouseWheel>', self._handle_mouse_wheel, add=True)
116
+
117
+ # Bind mouse wheel (Linux/X11)
118
+ self.bind('<Button-4>', self._handle_wheel_up, add=True)
119
+ self.bind('<Button-5>', self._handle_wheel_down, add=True)
120
+
121
+ # Listen for increment/decrement events to invoke step
122
+ self.bind('<<Increment>>', self._handle_increment_event, add=True)
123
+ self.bind('<<Decrement>>', self._handle_decrement_event, add=True)
124
+
125
+ def _handle_up_key(self, event):
126
+ """Handle Up arrow key press - emit increment event."""
127
+ if not self._is_interactive():
128
+ return 'break'
129
+ self.event_generate('<<Increment>>', data={'value': self._value})
130
+ return 'break' # Prevent default behavior
131
+
132
+ def _handle_down_key(self, event):
133
+ """Handle Down arrow key press - emit decrement event."""
134
+ if not self._is_interactive():
135
+ return 'break'
136
+ self.event_generate('<<Decrement>>', data={'value': self._value})
137
+ return 'break' # Prevent default behavior
138
+
139
+ def _handle_mouse_wheel(self, event):
140
+ """Handle mouse wheel on Windows/macOS."""
141
+ if not self._is_interactive():
142
+ return 'break'
143
+ try:
144
+ delta = int(event.delta)
145
+ except (AttributeError, ValueError):
146
+ delta = 0
147
+
148
+ if delta != 0:
149
+ if delta > 0:
150
+ self.event_generate('<<Increment>>', data={'value': self._value})
151
+ else:
152
+ self.event_generate('<<Decrement>>', data={'value': self._value})
153
+ return 'break'
154
+
155
+ def _handle_wheel_up(self, event):
156
+ """Handle mouse wheel up on Linux/X11."""
157
+ if not self._is_interactive():
158
+ return 'break'
159
+ self.event_generate('<<Increment>>', data={'value': self._value})
160
+ return 'break'
161
+
162
+ def _handle_wheel_down(self, event):
163
+ """Handle mouse wheel down on Linux/X11."""
164
+ if not self._is_interactive():
165
+ return 'break'
166
+ self.event_generate('<<Decrement>>', data={'value': self._value})
167
+ return 'break'
168
+
169
+ def _handle_increment_event(self, event):
170
+ """Handle <<Increment>> event by stepping up."""
171
+ if not self._is_interactive():
172
+ return 'break'
173
+ self.step(+1)
174
+
175
+ def _handle_decrement_event(self, event):
176
+ """Handle <<Decrement>> event by stepping down."""
177
+ if not self._is_interactive():
178
+ return 'break'
179
+ self.step(-1)
180
+
181
+ def _increment_decimals(self) -> int:
182
+ """Number of decimal places implied by the increment.
183
+
184
+ Used to quantize stepped values to the step grid so floating-point
185
+ error does not accumulate across repeated steps.
186
+ """
187
+ from decimal import Decimal
188
+
189
+ try:
190
+ exponent = Decimal(str(self._increment)).as_tuple().exponent
191
+ except Exception:
192
+ return 0
193
+ return max(0, -exponent) if isinstance(exponent, int) else 0
194
+
195
+ def _apply_bounds(self, x: float) -> float:
196
+ """Apply min/max bounds with optional wrapping."""
197
+ lo = float(self._minvalue) if self._minvalue is not None else None
198
+ hi = float(self._maxvalue) if self._maxvalue is not None else None
199
+
200
+ if self._wrap and lo is not None and hi is not None:
201
+ if hi <= lo:
202
+ return lo
203
+
204
+ span = hi - lo
205
+ while x < lo:
206
+ x += span
207
+ while x > hi:
208
+ x -= span
209
+ return x
210
+
211
+ if lo is not None and x < lo:
212
+ x = lo
213
+ if hi is not None and x > hi:
214
+ x = hi
215
+
216
+ return x
217
+
218
+ def _is_interactive(self) -> bool:
219
+ """Return True if the widget is not readonly or disabled."""
220
+ current_states = self.state()
221
+ return 'disabled' not in current_states and 'readonly' not in current_states
222
+
223
+ def step(self, n: int = 1):
224
+ """Increment or decrement value by n steps."""
225
+ if not self._is_interactive():
226
+ return self
227
+ # Get current value (default to min if None)
228
+ current = self._value
229
+ if current is None:
230
+ base = float(self._minvalue) if self._minvalue is not None else 0.0
231
+ else:
232
+ base = float(current)
233
+
234
+ # Calculate new value
235
+ new_value = base + float(self._increment) * float(n)
236
+
237
+ # Apply bounds/wrapping
238
+ new_value = self._apply_bounds(new_value)
239
+
240
+ # Coerce to desired type. Snap floats to the increment's decimal
241
+ # precision so repeated stepping doesn't accumulate float error (e.g.
242
+ # 0.05 + 0.05 + 0.05 → 0.15000000000000002).
243
+ if self._num_type is float:
244
+ coerced = round(new_value, self._increment_decimals())
245
+ else:
246
+ coerced = int(round(new_value))
247
+
248
+ # Store previous value for change detection
249
+ prev_value = self._value
250
+
251
+ # Update internal value
252
+ self._value = coerced
253
+
254
+ # Update display
255
+ self._normalize_display_from_value()
256
+
257
+ # Emit changed event if value actually changed
258
+ if self._value != prev_value:
259
+ self._prev_changed_value = self._value
260
+ self.event_generate(
261
+ '<<Change>>', data=ChangeEvent(
262
+ value=self._value,
263
+ prev_value=prev_value,
264
+ text=self.textsignal(),
265
+ ))
266
+
267
+ return self
268
+
269
+ def _get_validation_value(self):
270
+ """Return the current input coerced to its numeric type, for validation.
271
+
272
+ A plain numeric field parses to a string when no display format is set,
273
+ so coerce it the same way the public value does — validation rules and a
274
+ `custom` func receive a real `int`/`float` (or `None` for empty/invalid
275
+ input), never the display string.
276
+ """
277
+ text = self.get()
278
+ try:
279
+ raw = self._parse_or_none(text)
280
+ except Exception:
281
+ raw = text
282
+ if raw is None or raw == "":
283
+ return None
284
+ try:
285
+ number = float(raw)
286
+ except (TypeError, ValueError):
287
+ return None
288
+ return int(round(number)) if self._num_type is int else number
289
+
290
+ def _normalize_display_from_value(self):
291
+ """Update display text from internal value without triggering input events."""
292
+ # Format the value
293
+ new_text = self._format_value(self._value)
294
+
295
+ # Only update if text changed
296
+ if new_text != self.textsignal():
297
+ # Temporarily unsubscribe from input signal to avoid spurious events
298
+ fid = getattr(self, '_on_input_fid', None)
299
+ if fid:
300
+ try:
301
+ fid.cancel()
302
+ except Exception:
303
+ pass
304
+
305
+ # Update display
306
+ self.textsignal.set(new_text)
307
+
308
+ # Re-subscribe to input signal
309
+ if fid:
310
+ self._on_input_fid = self.textsignal.subscribe(self._handle_change)
311
+
312
+ def commit(self):
313
+ """Override commit to apply bounds validation after parsing.
314
+
315
+ This ensures user-entered values are constrained to valid range.
316
+ """
317
+ # Call parent commit to parse and format
318
+ super().commit()
319
+
320
+ # Apply bounds to the parsed value
321
+ if self._value is not None:
322
+ bounded_value = self._apply_bounds(float(self._value))
323
+
324
+ # Coerce to appropriate type
325
+ if self._num_type is float:
326
+ self._value = float(bounded_value)
327
+ else:
328
+ self._value = int(round(bounded_value))
329
+
330
+ # Update display if value changed due to bounds
331
+ self._normalize_display_from_value()
332
+
333
+ def on_increment(self, callback) -> str:
334
+ """Bind to `<<Increment>>`. Callback receives `event.data = {'value': current_value}`."""
335
+ return self.bind('<<Increment>>', callback, add=True)
336
+
337
+ def off_increment(self, bind_id: str | None = None) -> None:
338
+ """Unbind from `<<Increment>>`."""
339
+ self.unbind('<<Increment>>', bind_id)
340
+
341
+ def on_decrement(self, callback) -> str:
342
+ """Bind to `<<Decrement>>`. Callback receives `event.data = {'value': current_value}`."""
343
+ return self.bind('<<Decrement>>', callback, add=True)
344
+
345
+ def off_decrement(self, bind_id: str | None = None) -> None:
346
+ """Unbind from `<<Decrement>>`."""
347
+ self.unbind('<<Decrement>>', bind_id)
348
+
349
+ @configure_delegate('minvalue')
350
+ def _delegate_minvalue(self, value: int | float):
351
+ """Get or set the minimum allowed value and re-validate current value."""
352
+ if value is None:
353
+ return self._minvalue
354
+
355
+ self._minvalue = value
356
+ if self._value is not None:
357
+ self._value = self._apply_bounds(float(self._value))
358
+ self._normalize_display_from_value()
359
+
360
+ @configure_delegate('maxvalue')
361
+ def _delegate_maxvalue(self, value: int | float):
362
+ """Get or set the maximum allowed value and re-validate current value."""
363
+ if value is None:
364
+ return self._maxvalue
365
+
366
+ self._maxvalue = value
367
+ if self._value is not None:
368
+ self._value = self._apply_bounds(float(self._value))
369
+ self._normalize_display_from_value()
370
+
371
+ @configure_delegate('increment')
372
+ def _delegate_increment(self, value: int | float):
373
+ """Get or set the step increment value."""
374
+ if value is None:
375
+ return self._increment
376
+
377
+ self._increment = value
378
+
379
+ @configure_delegate('wrap')
380
+ def _delegate_wrap(self, value: bool):
381
+ """Get or set the wrap setting."""
382
+ if value is None:
383
+ return self._wrap
384
+
385
+ self._wrap = bool(value)