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,140 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Callable, Literal, overload, TYPE_CHECKING
5
+
6
+ from bootstack.events import Event, Subscription
7
+ from bootstack.streams import Stream
8
+ from bootstack.widgets._core.base import PublicWidgetBase
9
+ from bootstack.widgets._core.events import register_widget_events
10
+ from bootstack.widgets._impl.composites.avatar import Avatar as _InternalAvatar
11
+ from bootstack.widgets.types import AccentToken
12
+
13
+ if TYPE_CHECKING:
14
+ from bootstack.images import Image
15
+
16
+ AvatarShape = Literal["circle", "rounded", "square"]
17
+
18
+
19
+ class Avatar(PublicWidgetBase):
20
+ """A small identity badge — a picture or initials on a filled tile.
21
+
22
+ Shows `image` cover-fit and clipped to the avatar shape; when no image is
23
+ given (or one fails to load), it falls back to initials on a `background`
24
+ tile. Initials come from `initials` if given, otherwise from `name` (the
25
+ first letters of the first and last words).
26
+
27
+ Args:
28
+ image: The picture to show — an `Image` handle, a file path, or a PIL
29
+ image. Omit to show initials instead.
30
+ name: A name to derive initials from, e.g. `'Ada Lovelace'` → `'AL'`.
31
+ Used when `image` is absent and `initials` is not given.
32
+ initials: Explicit initials (1–2 characters), overriding `name`.
33
+ size: The avatar's edge length in pixels (it is square). Default `40`.
34
+ shape: `'circle'` (default), `'rounded'`, or `'square'`.
35
+ background: Tile color behind initials (and the fallback when an image
36
+ can't load) — a theme color token or a hex string. Default
37
+ `'primary'`.
38
+ foreground: Initials text color — a theme color token or hex string.
39
+ Default `'white'`.
40
+ parent: Override the context-stack parent.
41
+ **kwargs: Layout placement options applied by the parent container —
42
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
43
+ See :doc:`/tasks/layout`.
44
+ """
45
+
46
+ def __init__(
47
+ self,
48
+ image: "Image | str | Path | None" = None,
49
+ *,
50
+ name: str | None = None,
51
+ initials: str | None = None,
52
+ size: int = 40,
53
+ shape: AvatarShape = "circle",
54
+ background: AccentToken | str = "primary",
55
+ foreground: str = "white",
56
+ parent: Any = None,
57
+ **kwargs: Any,
58
+ ) -> None:
59
+ self._parent = self._resolve_parent(parent)
60
+ layout_kw = self._split_layout_kwargs(kwargs)
61
+ tk_master = self._parent._child_master() if self._parent else None
62
+
63
+ self._source = self._coerce_image(image)
64
+ self._internal = _InternalAvatar(
65
+ tk_master, source=self._source, name=name, initials=initials,
66
+ size=size, shape=shape, background=background, foreground=foreground,
67
+ )
68
+ self._attach_to_parent(layout_kw)
69
+
70
+ @staticmethod
71
+ def _coerce_image(image: "Image | str | Path | None") -> Any:
72
+ if image is None:
73
+ return None
74
+ from bootstack.images import Image as _ImageHandle
75
+
76
+ if isinstance(image, _ImageHandle):
77
+ return image
78
+ if isinstance(image, (str, Path)):
79
+ return _ImageHandle.open(image)
80
+ try:
81
+ from PIL.Image import Image as _PILImage
82
+
83
+ if isinstance(image, _PILImage):
84
+ return _ImageHandle.from_pil(image)
85
+ except Exception:
86
+ pass
87
+ raise TypeError(
88
+ "Avatar image must be an Image handle, a file path, or a PIL image; "
89
+ f"got {type(image).__name__}"
90
+ )
91
+
92
+ # ----- Properties -----
93
+
94
+ @property
95
+ def image(self) -> "Image | None":
96
+ """The displayed image handle, or `None` when showing initials.
97
+
98
+ Assign an `Image`, a file path, or `None` to change what is shown.
99
+ """
100
+ return self._source
101
+
102
+ @image.setter
103
+ def image(self, value: "Image | str | Path | None") -> None:
104
+ self._source = self._coerce_image(value)
105
+ self._internal.set_source(self._source)
106
+
107
+ def set_initials(self, *, name: str | None = None, initials: str | None = None) -> None:
108
+ """Update the initials shown (when no image is set).
109
+
110
+ Args:
111
+ name: A name to derive initials from.
112
+ initials: Explicit initials, overriding `name`.
113
+ """
114
+ self._internal.set_text(name=name, initials=initials)
115
+
116
+ # ----- Events -----
117
+
118
+ @overload
119
+ def on_click(self) -> Stream: ...
120
+ @overload
121
+ def on_click(self, handler: Callable[[Event], Any]) -> Subscription: ...
122
+ def on_click(
123
+ self, handler: Callable[[Event], Any] | None = None
124
+ ) -> Stream | Subscription:
125
+ """Register a callback for clicks on the avatar.
126
+
127
+ The handler receives a curated :class:`~bootstack.events.Event`.
128
+
129
+ Args:
130
+ handler: Called with the click `Event`. Omit to get a composable
131
+ :class:`~bootstack.streams.Stream`.
132
+
133
+ Returns:
134
+ A cancellable :class:`~bootstack.events.Subscription` when a handler
135
+ is given, otherwise a :class:`~bootstack.streams.Stream`.
136
+ """
137
+ return self.on("click", handler)
138
+
139
+
140
+ register_widget_events(Avatar, {"click": "<<AvatarClick>>"})
@@ -0,0 +1,455 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import overload, Any, Callable, TYPE_CHECKING
4
+
5
+ from bootstack.widgets._impl.primitives.checkbutton import CheckButton as _InternalCheckButton
6
+ from bootstack.widgets._impl.primitives.switch import Switch as _InternalSwitch
7
+ from bootstack.widgets._impl.primitives.checktoggle import CheckToggle as _InternalCheckToggle
8
+ from bootstack.widgets._core.base import PublicWidgetBase
9
+ from bootstack.widgets._core.events import register_widget_events
10
+ from bootstack.events import Subscription, ChangeEvent
11
+ from bootstack.streams import Stream
12
+ from bootstack.widgets.types import AccentToken, Event, WidgetDensity, ButtonVariant, LocalizeMode
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.signals import Signal
16
+
17
+ _BOOLEAN_EVENTS: dict[str, str] = {
18
+ "change": "<<Change>>",
19
+ "check": "<<ToggleOn>>",
20
+ "uncheck": "<<ToggleOff>>",
21
+ }
22
+
23
+
24
+ class _BooleanControlBase(PublicWidgetBase):
25
+ """Shared base for Checkbox, Switch, and ToggleButton."""
26
+
27
+ _internal_class: type # set by subclass
28
+
29
+ def __init__(
30
+ self,
31
+ label: str = "",
32
+ *,
33
+ signal: "Signal | None" = None,
34
+ value: Any = None,
35
+ checked_value: Any = True,
36
+ unchecked_value: Any = False,
37
+ on_change: Callable[[], Any] | None = None,
38
+ disabled: bool = False,
39
+ accent: AccentToken | str | None = None,
40
+ localize: LocalizeMode | None = None,
41
+ _tristate: bool = False,
42
+ _internal_options: dict[str, Any] | None = None,
43
+ parent: Any = None,
44
+ **kwargs: Any,
45
+ ) -> None:
46
+ self._parent = self._resolve_parent(parent)
47
+ layout_kw = self._split_layout_kwargs(kwargs)
48
+ if kwargs:
49
+ raise TypeError(
50
+ f"{type(self).__name__}() got unexpected keyword argument(s): "
51
+ f"{', '.join(sorted(kwargs))}"
52
+ )
53
+ self._checked_value = checked_value
54
+ self._unchecked_value = unchecked_value
55
+ self._tristate = _tristate
56
+
57
+ tk_master = self._parent._child_master() if self._parent else None
58
+
59
+ # Ctor on_change callback — stored so the command wrapper can call it.
60
+ _ctor_callback = on_change
61
+
62
+ internal_kwargs: dict[str, Any] = {}
63
+ if label:
64
+ internal_kwargs["text"] = label
65
+ if signal is not None:
66
+ internal_kwargs["signal"] = signal
67
+ if checked_value is not True:
68
+ internal_kwargs["onvalue"] = checked_value
69
+ if unchecked_value is not False:
70
+ internal_kwargs["offvalue"] = unchecked_value
71
+ if disabled:
72
+ internal_kwargs["state"] = "disabled"
73
+ if accent is not None:
74
+ internal_kwargs["accent"] = accent
75
+ if localize is not None:
76
+ internal_kwargs["localize"] = localize
77
+ # Per-subclass styling options (icons, variant, density, …) — only the
78
+ # ones a given control actually supports are passed in by the subclass.
79
+ if _internal_options:
80
+ internal_kwargs.update(_internal_options)
81
+
82
+ self._internal = self._internal_class(tk_master, **internal_kwargs)
83
+
84
+ # Seed initial value when no signal was passed.
85
+ # tristate=False: default to unchecked_value so the box never shows the
86
+ # indeterminate dash unexpectedly. tristate=True: leave unseeded so the
87
+ # initial state is None (indeterminate) unless value= was explicitly given.
88
+ if signal is None:
89
+ if value is not None:
90
+ self._internal.set(value)
91
+ elif not _tristate:
92
+ self._internal.set(unchecked_value)
93
+
94
+ # Track the previous value so on_change can report it. The control may be
95
+ # tristate (checked / unchecked / indeterminate), so prev cannot be derived
96
+ # from the new value alone — and the command fires after Tk updates the var.
97
+ self._prev_value = self._internal.get()
98
+
99
+ # Wire command → virtual events so on_change() / on_check() subscriptions work.
100
+ def _command():
101
+ v = self._internal.get()
102
+ prev, self._prev_value = self._prev_value, v
103
+ self._internal.event_generate(
104
+ "<<Change>>", data=ChangeEvent(value=v, prev_value=prev)
105
+ )
106
+ if v == self._checked_value:
107
+ self._internal.event_generate("<<ToggleOn>>")
108
+ else:
109
+ self._internal.event_generate("<<ToggleOff>>")
110
+ if _ctor_callback is not None:
111
+ _ctor_callback()
112
+
113
+ self._internal.configure(command=_command)
114
+ self._attach_to_parent(layout_kw)
115
+
116
+ # ----- Properties -----
117
+
118
+ @property
119
+ def value(self) -> Any:
120
+ """The current value.
121
+
122
+ Returns `checked_value` when checked, `unchecked_value` when
123
+ unchecked, or `None` when in the indeterminate state (only possible
124
+ when `tristate=True`).
125
+ """
126
+ v = self._internal.get()
127
+ if v == self._checked_value:
128
+ return self._checked_value
129
+ if v == self._unchecked_value:
130
+ return self._unchecked_value
131
+ return None
132
+
133
+ @value.setter
134
+ def value(self, v: Any) -> None:
135
+ self._internal.set(v)
136
+
137
+ @property
138
+ def checked(self) -> bool:
139
+ """Whether the control is in the checked/on state."""
140
+ return self._internal.get() == self._checked_value
141
+
142
+ @checked.setter
143
+ def checked(self, v: bool) -> None:
144
+ self._internal.set(self._checked_value if v else self._internal.cget("offvalue"))
145
+
146
+ @property
147
+ def signal(self) -> "Signal | None":
148
+ """The reactive `Signal` linked to this control, or `None`."""
149
+ return getattr(self._internal, 'signal', None)
150
+
151
+ @property
152
+ def disabled(self) -> bool:
153
+ """Whether the control is non-interactive."""
154
+ return str(self._internal.cget("state")) == "disabled"
155
+
156
+ @disabled.setter
157
+ def disabled(self, v: bool) -> None:
158
+ self._internal.configure(state="disabled" if v else "normal")
159
+
160
+ # ----- Methods -----
161
+
162
+ def toggle(self) -> None:
163
+ """Toggle the control's state programmatically."""
164
+ self._internal.invoke()
165
+
166
+ # ----- Event shorthands -----
167
+
168
+ @overload
169
+ def on_change(self) -> Stream: ...
170
+ @overload
171
+ def on_change(self, handler: Callable[[ChangeEvent], Any]) -> Subscription: ...
172
+ def on_change(self, handler: Callable[[ChangeEvent], Any] | None = None) -> Stream | Subscription:
173
+ """Register a callback fired whenever the value changes.
174
+
175
+ Args:
176
+ handler: Called with a :class:`~bootstack.events.ChangeEvent`
177
+ carrying the new `value` and the `prev_value` (useful for
178
+ tristate controls). Omit to get a composable
179
+ :class:`~bootstack.streams.Stream` instead.
180
+
181
+ Returns:
182
+ A cancellable :class:`~bootstack.events.Subscription` when a
183
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
184
+ """
185
+ return self.on("change", handler)
186
+
187
+ @overload
188
+ def on_check(self) -> Stream: ...
189
+ @overload
190
+ def on_check(self, handler: Callable[[Event], Any]) -> Subscription: ...
191
+ def on_check(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
192
+ """Register a callback fired when the control becomes checked/selected.
193
+
194
+ Args:
195
+ handler: Called with the :class:`~bootstack.events.Event`. Omit to
196
+ get a composable :class:`~bootstack.streams.Stream` instead.
197
+
198
+ Returns:
199
+ A cancellable :class:`~bootstack.events.Subscription` when a
200
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
201
+ """
202
+ return self.on("check", handler)
203
+
204
+ @overload
205
+ def on_uncheck(self) -> Stream: ...
206
+ @overload
207
+ def on_uncheck(self, handler: Callable[[Event], Any]) -> Subscription: ...
208
+ def on_uncheck(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
209
+ """Register a callback fired when the control becomes unchecked/deselected.
210
+
211
+ Args:
212
+ handler: Called with the :class:`~bootstack.events.Event`. Omit to
213
+ get a composable :class:`~bootstack.streams.Stream` instead.
214
+
215
+ Returns:
216
+ A cancellable :class:`~bootstack.events.Subscription` when a
217
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
218
+ """
219
+ return self.on("uncheck", handler)
220
+
221
+
222
+ class Checkbox(_BooleanControlBase):
223
+ """A labeled checkbox — checked or unchecked.
224
+
225
+ The label is the first positional argument. All options are keyword-only.
226
+
227
+ Args:
228
+ label: Label text displayed beside the checkbox.
229
+ signal: Reactive `Signal` controlling the checked state. When
230
+ provided, `value=` is ignored — seed the Signal directly.
231
+ value: Initial value. Ignored when `signal=` is passed.
232
+ checked_value: Value representing the checked state. Defaults to
233
+ `True`.
234
+ unchecked_value: Value representing the unchecked state. Defaults
235
+ to `False`.
236
+ tristate: If `True`, enables a third indeterminate state. When
237
+ indeterminate the box shows a dash indicator and `value`
238
+ returns `None`. If no `value=` or `signal=` is provided,
239
+ the checkbox starts in the indeterminate state. Defaults to
240
+ `False`.
241
+ on_change: Shorthand callback fired on every toggle. Equivalent to
242
+ `checkbox.on_change(fn)`.
243
+ on_icon: Bootstrap Icons name shown when the checkbox is checked.
244
+ Pair with `off_icon=` to display different icons per state,
245
+ e.g. `on_icon="check-circle-fill", off_icon="circle"`.
246
+ off_icon: Bootstrap Icons name shown when the checkbox is unchecked.
247
+ icon_only: If `True`, hides the label text and shows only the icon.
248
+ Combine with `on_icon=`/`off_icon=` and
249
+ `show_indicator=False` for fully icon-driven checkboxes.
250
+ show_indicator: If `False`, hides the checkbox box indicator.
251
+ Useful when `on_icon=`/`off_icon=` serve as the visual cue.
252
+ disabled: If `True`, widget is non-interactive and dimmed.
253
+ Defaults to `False`.
254
+ accent: Accent token applied to the box and check mark.
255
+ parent: Explicit parent widget. If omitted, the current
256
+ context-stack container is used.
257
+ **kwargs: Layout placement options applied by the parent container —
258
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
259
+ See :doc:`/tasks/layout`.
260
+ """
261
+ _internal_class = _InternalCheckButton
262
+
263
+ def __init__(
264
+ self,
265
+ label: str = "",
266
+ *,
267
+ signal: "Signal | None" = None,
268
+ value: Any = None,
269
+ checked_value: Any = True,
270
+ unchecked_value: Any = False,
271
+ tristate: bool = False,
272
+ on_change: Callable[[], Any] | None = None,
273
+ on_icon: str | None = None,
274
+ off_icon: str | None = None,
275
+ icon_only: bool = False,
276
+ show_indicator: bool = True,
277
+ disabled: bool = False,
278
+ accent: AccentToken | str | None = None,
279
+ parent: Any = None,
280
+ **kwargs: Any,
281
+ ) -> None:
282
+ options: dict[str, Any] = {}
283
+ if on_icon is not None:
284
+ options["on_icon"] = on_icon
285
+ if off_icon is not None:
286
+ options["off_icon"] = off_icon
287
+ if icon_only:
288
+ options["icon_only"] = True
289
+ if not show_indicator:
290
+ options["show_indicator"] = False
291
+ super().__init__(
292
+ label,
293
+ signal=signal,
294
+ value=value,
295
+ checked_value=checked_value,
296
+ unchecked_value=unchecked_value,
297
+ _tristate=tristate,
298
+ on_change=on_change,
299
+ disabled=disabled,
300
+ accent=accent,
301
+ _internal_options=options,
302
+ parent=parent,
303
+ **kwargs,
304
+ )
305
+
306
+
307
+ class Switch(_BooleanControlBase):
308
+ """A toggle switch — on or off.
309
+
310
+ Renders as a sliding track-and-thumb control. Use in place of a checkbox
311
+ when the action takes effect immediately (e.g. enable/disable a setting).
312
+
313
+ Args:
314
+ label: Label text displayed beside the switch.
315
+ signal: Reactive `Signal` controlling the on/off state. When
316
+ provided, `value=` is ignored — seed the Signal directly.
317
+ value: Initial value. Ignored when `signal=` is passed.
318
+ checked_value: Value representing the on state. Defaults to
319
+ `True`.
320
+ unchecked_value: Value representing the off state. Defaults to
321
+ `False`.
322
+ on_change: Shorthand callback fired on every toggle. Equivalent to
323
+ `switch.on_change(fn)`.
324
+ disabled: If `True`, widget is non-interactive and dimmed.
325
+ Defaults to `False`.
326
+ accent: Accent token applied to the track when on.
327
+ parent: Explicit parent widget. If omitted, the current
328
+ context-stack container is used.
329
+ **kwargs: Layout placement options applied by the parent container —
330
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
331
+ See :doc:`/tasks/layout`.
332
+ """
333
+ _internal_class = _InternalSwitch
334
+
335
+ def __init__(
336
+ self,
337
+ label: str = "",
338
+ *,
339
+ signal: "Signal | None" = None,
340
+ value: Any = None,
341
+ checked_value: Any = True,
342
+ unchecked_value: Any = False,
343
+ on_change: Callable[[], Any] | None = None,
344
+ disabled: bool = False,
345
+ accent: AccentToken | str | None = None,
346
+ parent: Any = None,
347
+ **kwargs: Any,
348
+ ) -> None:
349
+ super().__init__(
350
+ label,
351
+ signal=signal,
352
+ value=value,
353
+ checked_value=checked_value,
354
+ unchecked_value=unchecked_value,
355
+ on_change=on_change,
356
+ disabled=disabled,
357
+ accent=accent,
358
+ parent=parent,
359
+ **kwargs,
360
+ )
361
+
362
+
363
+ class ToggleButton(_BooleanControlBase):
364
+ """A button that stays pressed when active — toolbar-style toggle.
365
+
366
+ Renders as a depressed button rather than a checkbox or switch. Commonly
367
+ used in toolbars and button groups to represent a persistent on/off state.
368
+
369
+ Args:
370
+ text: Button text.
371
+ signal: Reactive `Signal` controlling the pressed state. When
372
+ provided, `value=` is ignored — seed the Signal directly.
373
+ value: Initial value. Ignored when `signal=` is passed.
374
+ checked_value: Value representing the pressed/active state. Defaults
375
+ to `True`.
376
+ unchecked_value: Value representing the unpressed/inactive state.
377
+ Defaults to `False`.
378
+ on_change: Shorthand callback fired on every toggle. Equivalent to
379
+ `btn.on_change(fn)`.
380
+ icon: Bootstrap Icons name shown in both states — the fallback for
381
+ `on_icon`/`off_icon` when those are not given. Pass `on_icon`/
382
+ `off_icon` to override the icon per state.
383
+ on_icon: Bootstrap Icons name shown when the button is active/pressed.
384
+ Use alone to swap icon on activation, or pair with `off_icon=`
385
+ to show different icons per state,
386
+ e.g. `on_icon="star-fill", off_icon="star"`. Falls back to `icon`.
387
+ off_icon: Bootstrap Icons name shown when the button is inactive.
388
+ Can be used alone or paired with `on_icon=`. Falls back to `icon`.
389
+ icon_only: If `True`, shows only the icon with no label text.
390
+ Requires `icon=`, `on_icon=`, or `off_icon=` to be set.
391
+ disabled: If `True`, widget is non-interactive and dimmed.
392
+ Defaults to `False`.
393
+ accent: Accent token applied to the button when active.
394
+ variant: Button style variant. Default `'solid'`.
395
+ density: Padding density.
396
+ parent: Explicit parent widget. If omitted, the current
397
+ context-stack container is used.
398
+ **kwargs: Layout placement options applied by the parent container —
399
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
400
+ See :doc:`/tasks/layout`.
401
+ """
402
+ _internal_class = _InternalCheckToggle
403
+
404
+ def __init__(
405
+ self,
406
+ text: str = "",
407
+ *,
408
+ signal: "Signal | None" = None,
409
+ value: Any = None,
410
+ checked_value: Any = True,
411
+ unchecked_value: Any = False,
412
+ on_change: Callable[[], Any] | None = None,
413
+ icon: str | None = None,
414
+ on_icon: str | None = None,
415
+ off_icon: str | None = None,
416
+ icon_only: bool = False,
417
+ disabled: bool = False,
418
+ accent: AccentToken | str | None = None,
419
+ variant: ButtonVariant = "default",
420
+ density: WidgetDensity | None = None,
421
+ parent: Any = None,
422
+ **kwargs: Any,
423
+ ) -> None:
424
+ options: dict[str, Any] = {}
425
+ # `icon` is the fallback for both states; on_icon/off_icon override it.
426
+ resolved_on = on_icon if on_icon is not None else icon
427
+ resolved_off = off_icon if off_icon is not None else icon
428
+ if resolved_on is not None:
429
+ options["on_icon"] = resolved_on
430
+ if resolved_off is not None:
431
+ options["off_icon"] = resolved_off
432
+ if icon_only:
433
+ options["icon_only"] = True
434
+ if variant is not None:
435
+ options["variant"] = variant
436
+ if density is not None:
437
+ options["density"] = density
438
+ super().__init__(
439
+ text,
440
+ signal=signal,
441
+ value=value,
442
+ checked_value=checked_value,
443
+ unchecked_value=unchecked_value,
444
+ on_change=on_change,
445
+ disabled=disabled,
446
+ accent=accent,
447
+ _internal_options=options,
448
+ parent=parent,
449
+ **kwargs,
450
+ )
451
+
452
+
453
+ register_widget_events(Checkbox, _BOOLEAN_EVENTS)
454
+ register_widget_events(Switch, _BOOLEAN_EVENTS)
455
+ register_widget_events(ToggleButton, _BOOLEAN_EVENTS)