bootstack 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. bootstack/__init__.py +249 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/api/__init__.py +127 -0
  4. bootstack/api/app.py +30 -0
  5. bootstack/api/constants.py +3 -0
  6. bootstack/api/data.py +23 -0
  7. bootstack/api/dialogs.py +44 -0
  8. bootstack/api/i18n.py +17 -0
  9. bootstack/api/localization.py +16 -0
  10. bootstack/api/menu.py +7 -0
  11. bootstack/api/style.py +23 -0
  12. bootstack/api/utils.py +24 -0
  13. bootstack/api/widgets.py +137 -0
  14. bootstack/assets/__init__.py +24 -0
  15. bootstack/assets/bootstack-transparent.png +0 -0
  16. bootstack/assets/bootstack.ico +0 -0
  17. bootstack/assets/bootstack.png +0 -0
  18. bootstack/assets/elements/__init__.py +0 -0
  19. bootstack/assets/elements/badge-pill.png +0 -0
  20. bootstack/assets/elements/badge-square.png +0 -0
  21. bootstack/assets/elements/border.png +0 -0
  22. bootstack/assets/elements/button-compact.png +0 -0
  23. bootstack/assets/elements/button-default.png +0 -0
  24. bootstack/assets/elements/button-group-horizontal-after-compact.png +0 -0
  25. bootstack/assets/elements/button-group-horizontal-after-default.png +0 -0
  26. bootstack/assets/elements/button-group-horizontal-before-compact.png +0 -0
  27. bootstack/assets/elements/button-group-horizontal-before-default.png +0 -0
  28. bootstack/assets/elements/button-group-horizontal-center-compact.png +0 -0
  29. bootstack/assets/elements/button-group-horizontal-center-default.png +0 -0
  30. bootstack/assets/elements/button-group-vertical-after-compact.png +0 -0
  31. bootstack/assets/elements/button-group-vertical-after-default.png +0 -0
  32. bootstack/assets/elements/button-group-vertical-before-compact.png +0 -0
  33. bootstack/assets/elements/button-group-vertical-before-default.png +0 -0
  34. bootstack/assets/elements/button-group-vertical-center-compact.png +0 -0
  35. bootstack/assets/elements/button-group-vertical-center-default.png +0 -0
  36. bootstack/assets/elements/checkbox-checked.png +0 -0
  37. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  38. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  39. bootstack/assets/elements/field.png +0 -0
  40. bootstack/assets/elements/input-after-compact.png +0 -0
  41. bootstack/assets/elements/input-after-default.png +0 -0
  42. bootstack/assets/elements/input-before-compact.png +0 -0
  43. bootstack/assets/elements/input-before-default.png +0 -0
  44. bootstack/assets/elements/input-compact.png +0 -0
  45. bootstack/assets/elements/input-default.png +0 -0
  46. bootstack/assets/elements/list-item-separated.png +0 -0
  47. bootstack/assets/elements/list-item.png +0 -0
  48. bootstack/assets/elements/manifest.toml +480 -0
  49. bootstack/assets/elements/menu-item.png +0 -0
  50. bootstack/assets/elements/nav-button-compact.png +0 -0
  51. bootstack/assets/elements/nav-button-default.png +0 -0
  52. bootstack/assets/elements/nav-icon-button-compact.png +0 -0
  53. bootstack/assets/elements/nav-icon-button-default.png +0 -0
  54. bootstack/assets/elements/notebook-client-border.png +0 -0
  55. bootstack/assets/elements/notebook-tab-active.png +0 -0
  56. bootstack/assets/elements/notebook-tab-bar.png +0 -0
  57. bootstack/assets/elements/notebook-tab-normal.png +0 -0
  58. bootstack/assets/elements/notebook-tab-pill.png +0 -0
  59. bootstack/assets/elements/progress-bar-horizontal-striped.png +0 -0
  60. bootstack/assets/elements/progress-bar-solid.png +0 -0
  61. bootstack/assets/elements/progress-bar-thin.png +0 -0
  62. bootstack/assets/elements/progress-bar-vertical-striped.png +0 -0
  63. bootstack/assets/elements/radio-selected.png +0 -0
  64. bootstack/assets/elements/radio-unselected.png +0 -0
  65. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  66. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  67. bootstack/assets/elements/slider-handle-focus.png +0 -0
  68. bootstack/assets/elements/slider-handle.png +0 -0
  69. bootstack/assets/elements/slider-track-horizontal.png +0 -0
  70. bootstack/assets/elements/slider-track-vertical.png +0 -0
  71. bootstack/assets/elements/switch-off.png +0 -0
  72. bootstack/assets/elements/switch-on.png +0 -0
  73. bootstack/assets/elements/tabs-bar-horizontal.png +0 -0
  74. bootstack/assets/elements/tabs-bar-vertical.png +0 -0
  75. bootstack/assets/elements/tabs-pill.png +0 -0
  76. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  77. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +853 -0
  78. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +875 -0
  79. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  80. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +853 -0
  81. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  82. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +853 -0
  83. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  84. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +853 -0
  85. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  86. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +875 -0
  87. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  88. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +853 -0
  89. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  90. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +853 -0
  91. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  92. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +851 -0
  93. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  94. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +842 -0
  95. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  96. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +841 -0
  97. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  98. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +914 -0
  99. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  100. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +842 -0
  101. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  102. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +841 -0
  103. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  104. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +841 -0
  105. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  106. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +842 -0
  107. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  108. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +842 -0
  109. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  110. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +842 -0
  111. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  112. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +842 -0
  113. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  114. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +842 -0
  115. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  116. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +842 -0
  117. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  118. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +842 -0
  119. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  120. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +842 -0
  121. bootstack/assets/themes/__init__.py +0 -0
  122. bootstack/assets/themes/amber-dark.json +32 -0
  123. bootstack/assets/themes/amber-light.json +32 -0
  124. bootstack/assets/themes/aurora-dark.json +32 -0
  125. bootstack/assets/themes/aurora-light.json +32 -0
  126. bootstack/assets/themes/bootstrap-dark.json +32 -0
  127. bootstack/assets/themes/bootstrap-light.json +32 -0
  128. bootstack/assets/themes/classic-dark.json +32 -0
  129. bootstack/assets/themes/classic-light.json +32 -0
  130. bootstack/assets/themes/docs-dark.json +32 -0
  131. bootstack/assets/themes/docs-light.json +32 -0
  132. bootstack/assets/themes/forest-dark.json +32 -0
  133. bootstack/assets/themes/forest-light.json +32 -0
  134. bootstack/assets/themes/ocean-dark.json +32 -0
  135. bootstack/assets/themes/ocean-light.json +32 -0
  136. bootstack/assets/themes/rose-dark.json +32 -0
  137. bootstack/assets/themes/rose-light.json +32 -0
  138. bootstack/assets/widgets/__init__.py +0 -0
  139. bootstack/assets/widgets/badge-default.png +0 -0
  140. bootstack/assets/widgets/badge-pill.png +0 -0
  141. bootstack/assets/widgets/border.png +0 -0
  142. bootstack/assets/widgets/button-group-horizontal-after.png +0 -0
  143. bootstack/assets/widgets/button-group-horizontal-before.png +0 -0
  144. bootstack/assets/widgets/button-group-horizontal-center.png +0 -0
  145. bootstack/assets/widgets/button-group-vertical-after.png +0 -0
  146. bootstack/assets/widgets/button-group-vertical-before.png +0 -0
  147. bootstack/assets/widgets/button-group-vertical-center.png +0 -0
  148. bootstack/assets/widgets/button.png +0 -0
  149. bootstack/assets/widgets/checkbox-checked.png +0 -0
  150. bootstack/assets/widgets/checkbox-indeterminate.png +0 -0
  151. bootstack/assets/widgets/checkbox-unchecked.png +0 -0
  152. bootstack/assets/widgets/field.png +0 -0
  153. bootstack/assets/widgets/icon-button.png +0 -0
  154. bootstack/assets/widgets/input-inner.png +0 -0
  155. bootstack/assets/widgets/input-prefix.png +0 -0
  156. bootstack/assets/widgets/input-suffix.png +0 -0
  157. bootstack/assets/widgets/input.png +0 -0
  158. bootstack/assets/widgets/list-item-focus.png +0 -0
  159. bootstack/assets/widgets/list-item-separated.png +0 -0
  160. bootstack/assets/widgets/menu-item-separated.png +0 -0
  161. bootstack/assets/widgets/notebook-client-border.png +0 -0
  162. bootstack/assets/widgets/notebook-pill-active.png +0 -0
  163. bootstack/assets/widgets/notebook-pill-inactive.png +0 -0
  164. bootstack/assets/widgets/notebook-tab-active.png +0 -0
  165. bootstack/assets/widgets/notebook-tab-border.png +0 -0
  166. bootstack/assets/widgets/notebook-tab-normal.png +0 -0
  167. bootstack/assets/widgets/notebook-underline.png +0 -0
  168. bootstack/assets/widgets/progress-bar-horizontal-default.png +0 -0
  169. bootstack/assets/widgets/progress-bar-horizontal-striped.png +0 -0
  170. bootstack/assets/widgets/progress-bar-vertical-default.png +0 -0
  171. bootstack/assets/widgets/progress-bar-vertical-striped.png +0 -0
  172. bootstack/assets/widgets/progress-trough-horizontal.png +0 -0
  173. bootstack/assets/widgets/progress-trough-vertical.png +0 -0
  174. bootstack/assets/widgets/radio-selected.png +0 -0
  175. bootstack/assets/widgets/radio-unselected.png +0 -0
  176. bootstack/assets/widgets/scrollbar-horizontal-rounded.png +0 -0
  177. bootstack/assets/widgets/scrollbar-vertical-rounded.png +0 -0
  178. bootstack/assets/widgets/separator-horizontal.png +0 -0
  179. bootstack/assets/widgets/separator-vertical.png +0 -0
  180. bootstack/assets/widgets/slider-handle-focus.png +0 -0
  181. bootstack/assets/widgets/slider-handle.png +0 -0
  182. bootstack/assets/widgets/slider-track-horizontal.png +0 -0
  183. bootstack/assets/widgets/slider-track-vertical.png +0 -0
  184. bootstack/assets/widgets/switch-off.png +0 -0
  185. bootstack/assets/widgets/switch-on.png +0 -0
  186. bootstack/assets/widgets/tabs-bar-horizontal.png +0 -0
  187. bootstack/assets/widgets/tabs-bar-vertical.png +0 -0
  188. bootstack/assets/widgets/tabs-pill.png +0 -0
  189. bootstack/cli/__init__.py +124 -0
  190. bootstack/cli/__main__.py +6 -0
  191. bootstack/cli/add.py +439 -0
  192. bootstack/cli/build.py +115 -0
  193. bootstack/cli/config.py +287 -0
  194. bootstack/cli/demo.py +1267 -0
  195. bootstack/cli/doctor.py +195 -0
  196. bootstack/cli/list_cmd.py +71 -0
  197. bootstack/cli/promote.py +120 -0
  198. bootstack/cli/pyinstaller.py +246 -0
  199. bootstack/cli/run.py +99 -0
  200. bootstack/cli/start.py +105 -0
  201. bootstack/cli/templates/__init__.py +861 -0
  202. bootstack/constants.py +325 -0
  203. bootstack/core/__init__.py +34 -0
  204. bootstack/core/capabilities/__init__.py +45 -0
  205. bootstack/core/capabilities/after.py +103 -0
  206. bootstack/core/capabilities/bind.py +154 -0
  207. bootstack/core/capabilities/bindtags.py +112 -0
  208. bootstack/core/capabilities/busy.py +61 -0
  209. bootstack/core/capabilities/clipboard.py +88 -0
  210. bootstack/core/capabilities/focus.py +118 -0
  211. bootstack/core/capabilities/grab.py +65 -0
  212. bootstack/core/capabilities/grid.py +188 -0
  213. bootstack/core/capabilities/localization.py +231 -0
  214. bootstack/core/capabilities/pack.py +119 -0
  215. bootstack/core/capabilities/place.py +92 -0
  216. bootstack/core/capabilities/selection.py +136 -0
  217. bootstack/core/capabilities/signals.py +242 -0
  218. bootstack/core/capabilities/winfo.py +315 -0
  219. bootstack/core/colorutils.py +234 -0
  220. bootstack/core/exceptions.py +95 -0
  221. bootstack/core/images.py +283 -0
  222. bootstack/core/localization/README.md +90 -0
  223. bootstack/core/localization/__init__.py +13 -0
  224. bootstack/core/localization/intl_format.py +580 -0
  225. bootstack/core/localization/msgcat.py +425 -0
  226. bootstack/core/localization/specs.py +143 -0
  227. bootstack/core/mixins/__init__.py +1 -0
  228. bootstack/core/mixins/ttk_state.py +35 -0
  229. bootstack/core/mixins/widget.py +132 -0
  230. bootstack/core/publisher.py +147 -0
  231. bootstack/core/signals/README.md +112 -0
  232. bootstack/core/signals/__init__.py +8 -0
  233. bootstack/core/signals/integration.py +100 -0
  234. bootstack/core/signals/signal.py +317 -0
  235. bootstack/core/signals/types.py +4 -0
  236. bootstack/core/validation/__init__.py +5 -0
  237. bootstack/core/validation/types.py +13 -0
  238. bootstack/core/validation/validation_result.py +17 -0
  239. bootstack/core/validation/validation_rules.py +112 -0
  240. bootstack/core/variables.py +62 -0
  241. bootstack/datasource/README.md +607 -0
  242. bootstack/datasource/__init__.py +51 -0
  243. bootstack/datasource/base.py +474 -0
  244. bootstack/datasource/file_source.py +541 -0
  245. bootstack/datasource/memory_source.py +482 -0
  246. bootstack/datasource/sqlite_source.py +453 -0
  247. bootstack/datasource/types.py +259 -0
  248. bootstack/dialogs/__init__.py +56 -0
  249. bootstack/dialogs/colorchooser.py +674 -0
  250. bootstack/dialogs/colordropper.py +257 -0
  251. bootstack/dialogs/datedialog.py +404 -0
  252. bootstack/dialogs/dialog.py +514 -0
  253. bootstack/dialogs/filterdialog.py +358 -0
  254. bootstack/dialogs/fontdialog.py +339 -0
  255. bootstack/dialogs/formdialog.py +541 -0
  256. bootstack/dialogs/message.py +489 -0
  257. bootstack/dialogs/query.py +561 -0
  258. bootstack/py.typed +1 -0
  259. bootstack/runtime/__init__.py +3 -0
  260. bootstack/runtime/app.py +879 -0
  261. bootstack/runtime/base_window.py +786 -0
  262. bootstack/runtime/events.py +399 -0
  263. bootstack/runtime/menu.py +510 -0
  264. bootstack/runtime/shortcuts.py +423 -0
  265. bootstack/runtime/tk_patch.py +31 -0
  266. bootstack/runtime/toplevel.py +131 -0
  267. bootstack/runtime/utility.py +371 -0
  268. bootstack/runtime/visual_focus.py +228 -0
  269. bootstack/runtime/window_utilities.py +1043 -0
  270. bootstack/style/__init__.py +5498 -0
  271. bootstack/style/bootstyle.py +507 -0
  272. bootstack/style/bootstyle_builder_base.py +752 -0
  273. bootstack/style/bootstyle_builder_mixed.py +93 -0
  274. bootstack/style/bootstyle_builder_tk.py +109 -0
  275. bootstack/style/bootstyle_builder_ttk.py +354 -0
  276. bootstack/style/builders/__init__.py +51 -0
  277. bootstack/style/builders/badge.py +44 -0
  278. bootstack/style/builders/button.py +453 -0
  279. bootstack/style/builders/buttongroup.py +344 -0
  280. bootstack/style/builders/calendar.py +271 -0
  281. bootstack/style/builders/checkbutton.py +95 -0
  282. bootstack/style/builders/combobox.py +112 -0
  283. bootstack/style/builders/contextmenu.py +268 -0
  284. bootstack/style/builders/entry.py +83 -0
  285. bootstack/style/builders/expander.py +171 -0
  286. bootstack/style/builders/field.py +312 -0
  287. bootstack/style/builders/frame.py +27 -0
  288. bootstack/style/builders/label.py +28 -0
  289. bootstack/style/builders/labelframe.py +41 -0
  290. bootstack/style/builders/listview.py +267 -0
  291. bootstack/style/builders/menubar.py +74 -0
  292. bootstack/style/builders/menubutton.py +408 -0
  293. bootstack/style/builders/notebook.py +316 -0
  294. bootstack/style/builders/panedwindow.py +25 -0
  295. bootstack/style/builders/progressbar.py +71 -0
  296. bootstack/style/builders/radiobutton.py +68 -0
  297. bootstack/style/builders/scale.py +66 -0
  298. bootstack/style/builders/scrollbar.py +360 -0
  299. bootstack/style/builders/separator.py +45 -0
  300. bootstack/style/builders/sidenav.py +313 -0
  301. bootstack/style/builders/sizegrip.py +15 -0
  302. bootstack/style/builders/spinbox.py +119 -0
  303. bootstack/style/builders/switch.py +67 -0
  304. bootstack/style/builders/tabitem.py +205 -0
  305. bootstack/style/builders/toolbutton.py +260 -0
  306. bootstack/style/builders/tooltip.py +26 -0
  307. bootstack/style/builders/treeview.py +269 -0
  308. bootstack/style/builders/utils.py +404 -0
  309. bootstack/style/builders_tk/__init__.py +16 -0
  310. bootstack/style/builders_tk/defaults.py +229 -0
  311. bootstack/style/element.py +173 -0
  312. bootstack/style/style.py +499 -0
  313. bootstack/style/theme_provider.py +449 -0
  314. bootstack/style/tk_patch.py +5 -0
  315. bootstack/style/token_maps.py +42 -0
  316. bootstack/style/types.py +32 -0
  317. bootstack/style/typography.py +527 -0
  318. bootstack/style/utility.py +696 -0
  319. bootstack/themes/__init__.py +12 -0
  320. bootstack/themes/standard.py +415 -0
  321. bootstack/themes/user.py +45 -0
  322. bootstack/widgets/__init__.py +53 -0
  323. bootstack/widgets/composites/__init__.py +38 -0
  324. bootstack/widgets/composites/accordion.py +385 -0
  325. bootstack/widgets/composites/appshell.py +445 -0
  326. bootstack/widgets/composites/buttongroup.py +391 -0
  327. bootstack/widgets/composites/calendar.py +914 -0
  328. bootstack/widgets/composites/compositeframe.py +282 -0
  329. bootstack/widgets/composites/contextmenu.py +1754 -0
  330. bootstack/widgets/composites/dateentry.py +261 -0
  331. bootstack/widgets/composites/dropdownbutton.py +190 -0
  332. bootstack/widgets/composites/expander.py +508 -0
  333. bootstack/widgets/composites/field.py +448 -0
  334. bootstack/widgets/composites/floodgauge.py +434 -0
  335. bootstack/widgets/composites/form.py +983 -0
  336. bootstack/widgets/composites/labeledscale.py +209 -0
  337. bootstack/widgets/composites/list/__init__.py +15 -0
  338. bootstack/widgets/composites/list/listitem.py +733 -0
  339. bootstack/widgets/composites/list/listview.py +1507 -0
  340. bootstack/widgets/composites/menubar.py +303 -0
  341. bootstack/widgets/composites/meter.py +882 -0
  342. bootstack/widgets/composites/numericentry.py +183 -0
  343. bootstack/widgets/composites/pagestack.py +330 -0
  344. bootstack/widgets/composites/passwordentry.py +149 -0
  345. bootstack/widgets/composites/pathentry.py +223 -0
  346. bootstack/widgets/composites/radiogroup.py +466 -0
  347. bootstack/widgets/composites/scrolledtext.py +388 -0
  348. bootstack/widgets/composites/scrolledtext.pyi +186 -0
  349. bootstack/widgets/composites/scrollview.py +675 -0
  350. bootstack/widgets/composites/selectbox.py +544 -0
  351. bootstack/widgets/composites/sidenav/__init__.py +24 -0
  352. bootstack/widgets/composites/sidenav/group.py +485 -0
  353. bootstack/widgets/composites/sidenav/header.py +83 -0
  354. bootstack/widgets/composites/sidenav/item.py +413 -0
  355. bootstack/widgets/composites/sidenav/separator.py +51 -0
  356. bootstack/widgets/composites/sidenav/view.py +919 -0
  357. bootstack/widgets/composites/spinnerentry.py +232 -0
  358. bootstack/widgets/composites/tableview/__init__.py +5 -0
  359. bootstack/widgets/composites/tableview/tableview.py +2254 -0
  360. bootstack/widgets/composites/tableview/types.py +169 -0
  361. bootstack/widgets/composites/tabs/__init__.py +6 -0
  362. bootstack/widgets/composites/tabs/tabitem.py +372 -0
  363. bootstack/widgets/composites/tabs/tabs.py +478 -0
  364. bootstack/widgets/composites/tabs/tabview.py +352 -0
  365. bootstack/widgets/composites/textentry.py +90 -0
  366. bootstack/widgets/composites/timeentry.py +189 -0
  367. bootstack/widgets/composites/toast.py +364 -0
  368. bootstack/widgets/composites/togglegroup.py +382 -0
  369. bootstack/widgets/composites/toolbar.py +393 -0
  370. bootstack/widgets/composites/tooltip.py +404 -0
  371. bootstack/widgets/internal/__init__.py +0 -0
  372. bootstack/widgets/internal/wrapper_base.py +304 -0
  373. bootstack/widgets/mixins/__init__.py +25 -0
  374. bootstack/widgets/mixins/configure_mixin.py +186 -0
  375. bootstack/widgets/mixins/entry_mixin.py +70 -0
  376. bootstack/widgets/mixins/font_mixin.py +346 -0
  377. bootstack/widgets/mixins/icon_mixin.py +38 -0
  378. bootstack/widgets/mixins/localization_mixin.py +255 -0
  379. bootstack/widgets/mixins/signal_mixin.py +272 -0
  380. bootstack/widgets/mixins/validation_mixin.py +204 -0
  381. bootstack/widgets/parts/__init__.py +11 -0
  382. bootstack/widgets/parts/numberentry_part.py +345 -0
  383. bootstack/widgets/parts/spinnerentry_part.py +394 -0
  384. bootstack/widgets/parts/textentry_part.py +344 -0
  385. bootstack/widgets/primitives/__init__.py +55 -0
  386. bootstack/widgets/primitives/badge.py +44 -0
  387. bootstack/widgets/primitives/button.py +89 -0
  388. bootstack/widgets/primitives/card.py +66 -0
  389. bootstack/widgets/primitives/checkbutton.py +124 -0
  390. bootstack/widgets/primitives/checktoggle.py +53 -0
  391. bootstack/widgets/primitives/combobox.py +165 -0
  392. bootstack/widgets/primitives/entry.py +98 -0
  393. bootstack/widgets/primitives/frame.py +206 -0
  394. bootstack/widgets/primitives/gridframe.py +479 -0
  395. bootstack/widgets/primitives/label.py +95 -0
  396. bootstack/widgets/primitives/labelframe.py +63 -0
  397. bootstack/widgets/primitives/menubutton.py +118 -0
  398. bootstack/widgets/primitives/notebook.py +551 -0
  399. bootstack/widgets/primitives/optionmenu.py +248 -0
  400. bootstack/widgets/primitives/packframe.py +228 -0
  401. bootstack/widgets/primitives/panedwindow.py +58 -0
  402. bootstack/widgets/primitives/progressbar.py +95 -0
  403. bootstack/widgets/primitives/radiobutton.py +115 -0
  404. bootstack/widgets/primitives/radiotoggle.py +50 -0
  405. bootstack/widgets/primitives/scale.py +85 -0
  406. bootstack/widgets/primitives/scrollbar.py +56 -0
  407. bootstack/widgets/primitives/separator.py +56 -0
  408. bootstack/widgets/primitives/sizegrip.py +47 -0
  409. bootstack/widgets/primitives/spinbox.py +91 -0
  410. bootstack/widgets/primitives/switch.py +41 -0
  411. bootstack/widgets/primitives/treeview.py +77 -0
  412. bootstack/widgets/types.py +20 -0
  413. bootstack-0.1.0a1.dist-info/METADATA +196 -0
  414. bootstack-0.1.0a1.dist-info/RECORD +419 -0
  415. bootstack-0.1.0a1.dist-info/WHEEL +5 -0
  416. bootstack-0.1.0a1.dist-info/entry_points.txt +2 -0
  417. bootstack-0.1.0a1.dist-info/licenses/LICENSE +22 -0
  418. bootstack-0.1.0a1.dist-info/licenses/NOTICE +10 -0
  419. bootstack-0.1.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,231 @@
1
+ """Localization capability for bootstack widgets.
2
+
3
+ This module provides the core framework service for localizing widget text
4
+ and values. It handles text resolution, value formatting, and locale change
5
+ propagation.
6
+
7
+ The widget mixin (LocalizationMixin) delegates to these functions to remain
8
+ a thin glue layer.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import Any, TYPE_CHECKING
14
+
15
+ from bootstack.core.localization.msgcat import MessageCatalog
16
+ from bootstack.core.localization.specs import (
17
+ LocalizedSpec,
18
+ LocalizedTextSpec,
19
+ LocalizedValueSpec,
20
+ )
21
+
22
+ if TYPE_CHECKING:
23
+ from bootstack.core.signals import Signal
24
+
25
+
26
+ # =============================================================================
27
+ # Text Resolution
28
+ # =============================================================================
29
+
30
+ def resolve_text(
31
+ value: Any,
32
+ *,
33
+ localize_mode: bool | str = True,
34
+ ) -> LocalizedTextSpec | None:
35
+ """Resolve a text value into a LocalizedTextSpec.
36
+
37
+ This function handles the logic for creating localization specs from
38
+ string values based on the localization mode.
39
+
40
+ Args:
41
+ value: The value to resolve. Can be:
42
+ - A LocalizedSpec: returned as-is (if it's a LocalizedTextSpec)
43
+ - A string: wrapped in LocalizedTextSpec if localize_mode is truthy
44
+ - None or empty string: returns None
45
+ localize_mode: Controls auto-wrapping of literals:
46
+ - True or "auto": wrap strings in LocalizedTextSpec
47
+ - False: return None (no localization)
48
+
49
+ Returns:
50
+ A LocalizedTextSpec if the value should be localized, None otherwise.
51
+
52
+ Examples:
53
+ >>> spec = resolve_text("Hello World")
54
+ >>> spec.key
55
+ 'Hello World'
56
+
57
+ >>> spec = resolve_text("Hello", localize_mode=False)
58
+ >>> spec is None
59
+ True
60
+
61
+ >>> from bootstack.core.localization.specs import L
62
+ >>> spec = resolve_text(L("greeting"))
63
+ >>> spec.key
64
+ 'greeting'
65
+ """
66
+ if value is None:
67
+ return None
68
+
69
+ if isinstance(value, str) and value == "":
70
+ return None
71
+
72
+ # If already a LocalizedSpec, return as-is
73
+ if isinstance(value, LocalizedTextSpec):
74
+ return value
75
+ if isinstance(value, LocalizedSpec):
76
+ # Other spec types (like LocalizedValueSpec) - cannot use as text
77
+ return None
78
+
79
+ # Check localize mode
80
+ if localize_mode is False:
81
+ return None
82
+
83
+ # Wrap string in LocalizedTextSpec
84
+ if isinstance(value, str):
85
+ return LocalizedTextSpec(key=value, original=value)
86
+
87
+ return None
88
+
89
+
90
+ def resolve_variable_text(
91
+ value: Any,
92
+ *,
93
+ value_format: str | None = None,
94
+ default_format: str = "decimal",
95
+ ) -> LocalizedValueSpec | None:
96
+ """Resolve a non-string value into a LocalizedValueSpec for formatting.
97
+
98
+ This function handles the logic for creating value formatting specs from
99
+ numeric or other values.
100
+
101
+ Args:
102
+ value: The value to format. Should be a number, date, or other
103
+ formattable type.
104
+ value_format: The IntlFormatter spec (e.g., "currency", "decimal",
105
+ "percent"). If None, uses default_format.
106
+ default_format: Fallback format spec when value_format is None.
107
+
108
+ Returns:
109
+ A LocalizedValueSpec if the value can be formatted, None otherwise.
110
+
111
+ Examples:
112
+ >>> spec = resolve_variable_text(1234.56, value_format="currency")
113
+ >>> spec.value
114
+ 1234.56
115
+ >>> spec.format_spec
116
+ 'currency'
117
+
118
+ >>> spec = resolve_variable_text(0.5, value_format="percent")
119
+ >>> spec.format_spec
120
+ 'percent'
121
+ """
122
+ if value is None:
123
+ return None
124
+
125
+ if isinstance(value, LocalizedValueSpec):
126
+ return value
127
+
128
+ if isinstance(value, str):
129
+ # Strings are handled by resolve_text, not this function
130
+ return None
131
+
132
+ fmt = value_format or default_format
133
+ return LocalizedValueSpec(value=value, format_spec=fmt)
134
+
135
+
136
+ def apply_spec(spec: LocalizedSpec, locale: str | None = None) -> str:
137
+ """Apply a localization spec and return the resolved string.
138
+
139
+ Args:
140
+ spec: The LocalizedSpec to resolve.
141
+ locale: The locale to use. If None, uses the current locale from
142
+ MessageCatalog.
143
+
144
+ Returns:
145
+ The resolved, localized string value.
146
+
147
+ Examples:
148
+ >>> from bootstack.core.localization.specs import L, LV
149
+ >>> spec = L("hello")
150
+ >>> result = apply_spec(spec) # Uses current locale
151
+ >>> isinstance(result, str)
152
+ True
153
+
154
+ >>> spec = LV(1234.56, "decimal")
155
+ >>> result = apply_spec(spec)
156
+ >>> isinstance(result, str)
157
+ True
158
+ """
159
+ if not spec.enabled:
160
+ # Return original if possible, else empty
161
+ if isinstance(spec, LocalizedTextSpec):
162
+ return spec.original or spec.key
163
+ elif isinstance(spec, LocalizedValueSpec):
164
+ return str(spec.value)
165
+ return ""
166
+
167
+ current_locale = locale or MessageCatalog.locale()
168
+ return spec.resolve(current_locale)
169
+
170
+
171
+ def get_current_locale() -> str:
172
+ """Get the current locale from MessageCatalog.
173
+
174
+ Returns:
175
+ The current locale code (e.g., "en_US", "de_DE").
176
+ """
177
+ return MessageCatalog.locale()
178
+
179
+
180
+ # =============================================================================
181
+ # Signal Formatting
182
+ # =============================================================================
183
+
184
+ def create_formatted_signal(
185
+ source_signal: 'Signal[Any]',
186
+ value_format: str,
187
+ ) -> tuple['Signal[str]', Any]:
188
+ """Create a formatted signal that tracks a source signal.
189
+
190
+ This creates a new Signal for formatted display that subscribes to the
191
+ source signal and automatically formats values when they change.
192
+
193
+ Args:
194
+ source_signal: The source Signal to subscribe to.
195
+ value_format: The IntlFormatter spec for formatting values.
196
+
197
+ Returns:
198
+ A tuple of (formatted_signal, formatter_callback) where:
199
+ - formatted_signal: A new Signal[str] containing the formatted value
200
+ - formatter_callback: The callback function for locale change updates
201
+
202
+ Examples:
203
+ >>> from bootstack.core.signals import Signal
204
+ >>> price = Signal(1234.56)
205
+ >>> formatted, formatter = create_formatted_signal(price, "currency")
206
+ >>> # formatted.get() returns locale-formatted currency string
207
+ """
208
+ from bootstack.core.signals import Signal
209
+
210
+ formatted_signal: Signal[str] = Signal("")
211
+
212
+ def format_signal_value(value: Any) -> None:
213
+ """Format the signal value using the current locale."""
214
+ spec = LocalizedValueSpec(value=value, format_spec=value_format)
215
+ locale = MessageCatalog.locale()
216
+ formatted = spec.resolve(locale)
217
+ formatted_signal.set(formatted)
218
+
219
+ # Subscribe with immediate execution to format initial value
220
+ source_signal.subscribe(format_signal_value, immediate=True)
221
+
222
+ return formatted_signal, format_signal_value
223
+
224
+
225
+ __all__ = [
226
+ "resolve_text",
227
+ "resolve_variable_text",
228
+ "apply_spec",
229
+ "get_current_locale",
230
+ "create_formatted_signal",
231
+ ]
@@ -0,0 +1,119 @@
1
+ """Pack geometry manager capabilities mixin for bootstack widgets."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any, Literal, TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from typing_extensions import Self
8
+
9
+
10
+ class PackMixin:
11
+ """Pack geometry manager helpers (pack).
12
+
13
+ Tk's `pack` geometry manager places widgets relative to the sides of a container.
14
+
15
+ In bootstack v2 you may prefer higher-level layout containers (e.g. `PackFrame`)
16
+ for most UI layout. This mixin documents the underlying Tkinter `pack_*` API
17
+ as an escape hatch and for interoperability with existing Tk code.
18
+
19
+ Notes:
20
+ - `pack()` attaches a widget to a parent container that is using pack.
21
+ - `pack_propagate(False)` prevents a container from resizing to fit its children.
22
+ - `fill`, `expand`, and `side` control how a widget consumes available space.
23
+ - If the parent has a `_on_child_pack` hook (e.g. PackFrame), layout defaults
24
+ are applied automatically.
25
+ """
26
+
27
+ # -------------------------------------------------------------------------
28
+ # Core widget methods
29
+ # -------------------------------------------------------------------------
30
+
31
+ def pack(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
32
+ """Position this widget using the pack geometry manager.
33
+
34
+ Args:
35
+ cnf: Optional dict of pack options.
36
+ **kw: Pack options. Common options include:
37
+ - side: Which side to pack against ("top", "bottom", "left", "right").
38
+ - fill: How the widget should fill extra space ("x", "y", "both", "none").
39
+ - expand: Whether the widget expands to fill extra space (0/1 or False/True).
40
+ - anchor: Where to place the widget if it does not fill the space.
41
+ - padx, pady: External padding around the widget.
42
+ - ipadx, ipady: Internal padding inside the widget.
43
+ - before, after: Pack relative to another widget.
44
+
45
+ Returns:
46
+ Self for method chaining.
47
+ """
48
+ options = cnf or {}
49
+ options.update(kw)
50
+
51
+ parent = self.master # type: ignore[attr-defined]
52
+ if hasattr(parent, '_on_child_pack'):
53
+ parent._on_child_pack(self, **options)
54
+ else:
55
+ super().pack(**options) # type: ignore[misc]
56
+ return self # type: ignore[return-value]
57
+
58
+ def pack_configure(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
59
+ """Alias for `pack()`.
60
+
61
+ Args:
62
+ cnf: Optional dict of pack options.
63
+ **kw: Pack options (see `pack`).
64
+
65
+ Returns:
66
+ Self for method chaining.
67
+ """
68
+ return self.pack(cnf, **kw)
69
+
70
+ def pack_forget(self) -> Self:
71
+ """Unmap this widget and forget its pack configuration.
72
+
73
+ The widget is removed from the layout, and its previous pack options
74
+ are discarded.
75
+
76
+ Returns:
77
+ Self for method chaining.
78
+ """
79
+ parent = self.master # type: ignore[attr-defined]
80
+ if hasattr(parent, '_on_child_pack_forget'):
81
+ parent._on_child_pack_forget(self)
82
+ else:
83
+ super().pack_forget() # type: ignore[misc]
84
+ return self # type: ignore[return-value]
85
+
86
+ def pack_info(self) -> dict[str, Any]:
87
+ """Return this widget's current pack configuration.
88
+
89
+ Returns:
90
+ A dict containing the current pack options for this widget
91
+ (side, fill, expand, padx, pady, etc.).
92
+ """
93
+ return super().pack_info() # type: ignore[misc]
94
+
95
+ # -------------------------------------------------------------------------
96
+ # Container methods (applied to the pack parent container)
97
+ # -------------------------------------------------------------------------
98
+
99
+ def pack_propagate(self, flag: bool | None = None) -> bool | None:
100
+ """Get or set pack geometry propagation for this container.
101
+
102
+ When propagation is enabled (default), the container may resize itself
103
+ to fit the size requests of its children.
104
+
105
+ Args:
106
+ flag: True/False to enable/disable propagation. If None, acts as a getter.
107
+
108
+ Returns:
109
+ When queried, returns the current propagation flag. When set, returns None.
110
+ """
111
+ return super().pack_propagate(flag) # type: ignore[misc]
112
+
113
+ def pack_slaves(self) -> list[Any]:
114
+ """Return the widgets managed by pack in this container.
115
+
116
+ Returns:
117
+ A list of child widgets managed by pack (in packing order).
118
+ """
119
+ return super().pack_slaves() # type: ignore[misc]
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from typing_extensions import Self
7
+
8
+
9
+ class PlaceMixin:
10
+ """Place geometry manager helpers (place).
11
+
12
+ Tk's `place` geometry manager positions widgets using absolute coordinates
13
+ and/or relative fractions of the container size.
14
+
15
+ `place` is useful for:
16
+ - overlays (badges, floating buttons, popovers)
17
+ - precise positioning inside a fixed-size container
18
+ - small "anchor" adjustments that don't fit grid/pack well
19
+
20
+ Notes:
21
+ - `place` is generally less adaptive than `grid` or `pack` for resizable UIs.
22
+ - Relative coordinates (`relx`, `rely`, `relwidth`, `relheight`) are fractions
23
+ of the container size (0.0–1.0).
24
+ """
25
+
26
+ # -------------------------------------------------------------------------
27
+ # Core widget methods
28
+ # -------------------------------------------------------------------------
29
+
30
+ def place(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
31
+ """Position this widget using the place geometry manager.
32
+
33
+ Args:
34
+ cnf: Optional dict of place options.
35
+ **kw: Place options. Common options include:
36
+ - x, y: Absolute coordinates in pixels (relative to container).
37
+ - relx, rely: Relative coordinates (0.0–1.0) of the container size.
38
+ - width, height: Absolute size in pixels.
39
+ - relwidth, relheight: Relative size (0.0–1.0) of the container size.
40
+ - anchor: Which point of the widget is placed at (x, y) / (relx, rely)
41
+ (e.g. "nw", "center", "se").
42
+ - bordermode: How to interpret x/y relative to container borders.
43
+
44
+ Returns:
45
+ Self for method chaining.
46
+ """
47
+ options = cnf or {}
48
+ options.update(kw)
49
+ super().place(**options) # type: ignore[misc]
50
+ return self # type: ignore[return-value]
51
+
52
+ def place_configure(self, cnf: dict[str, Any] | None = None, **kw: Any) -> Self:
53
+ """Alias for `place()`.
54
+
55
+ Args:
56
+ cnf: Optional dict of place options.
57
+ **kw: Place options (see `place`).
58
+
59
+ Returns:
60
+ Self for method chaining.
61
+ """
62
+ return self.place(cnf, **kw)
63
+
64
+ def place_forget(self) -> Self:
65
+ """Unmap this widget and forget its place configuration.
66
+
67
+ Returns:
68
+ Self for method chaining.
69
+ """
70
+ super().place_forget() # type: ignore[misc]
71
+ return self # type: ignore[return-value]
72
+
73
+ def place_info(self) -> dict[str, Any]:
74
+ """Return this widget's current place configuration.
75
+
76
+ Returns:
77
+ A dict containing the current place options for this widget
78
+ (x, y, relx, rely, width, height, etc.).
79
+ """
80
+ return super().place_info() # type: ignore[misc]
81
+
82
+ # -------------------------------------------------------------------------
83
+ # Container methods
84
+ # -------------------------------------------------------------------------
85
+
86
+ def place_slaves(self) -> list[Any]:
87
+ """Return the widgets managed by place in this container.
88
+
89
+ Returns:
90
+ A list of child widgets managed by place.
91
+ """
92
+ return super().place_slaves() # type: ignore[misc]
@@ -0,0 +1,136 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable
4
+
5
+
6
+ class SelectionMixin:
7
+ """X selection helpers (selection).
8
+
9
+ Tk’s `selection` command provides access to the X selection mechanism (ICCCM),
10
+ most commonly the **PRIMARY** selection, and also supports **CLIPBOARD** and
11
+ other named selections.
12
+
13
+ Portability notes:
14
+ - On X11, PRIMARY is a system-wide selection shared across processes.
15
+ - On Windows, PRIMARY is provided by Tk (not the OS) and is shared only
16
+ within related interpreters, not across processes.
17
+ - For clipboard-style usage, Tk also provides the `clipboard_*` methods,
18
+ which are often a better cross-platform fit.
19
+
20
+ Intended usage:
21
+ class Widget(SelectionMixin, ttk.Widget): ...
22
+ class App(SelectionMixin, tkinter.Tk): ...
23
+ """
24
+
25
+ def selection_clear(self, **kw: Any) -> None:
26
+ """Clear a selection so that no window owns it.
27
+
28
+ This corresponds to `selection clear` and clears the specified selection
29
+ on the target display (if it exists).
30
+
31
+ Args:
32
+ **kw: Selection options forwarded to Tkinter. Common options include:
33
+ - selection: The selection name (e.g. "PRIMARY", "CLIPBOARD").
34
+ Defaults to "PRIMARY".
35
+ - displayof: A widget/window whose display should be targeted.
36
+ Defaults to "." (the application’s main display).
37
+ """
38
+ return super().selection_clear(**kw) # type: ignore[misc]
39
+
40
+ def selection_get(self, **kw: Any) -> str:
41
+ """Return the current contents of a selection.
42
+
43
+ This corresponds to `selection get` and retrieves a selection from the
44
+ target display. The default selection is "PRIMARY" and the default type
45
+ is "STRING".
46
+
47
+ Args:
48
+ **kw: Selection options forwarded to Tkinter. Common options include:
49
+ - selection: The selection name (e.g. "PRIMARY", "CLIPBOARD").
50
+ Defaults to "PRIMARY".
51
+ - type: The desired “target” type for conversion (e.g. "STRING",
52
+ "UTF8_STRING", "TARGETS", "FILE_NAME"). Defaults to "STRING".
53
+ - displayof: A widget/window whose display should be targeted.
54
+ Defaults to ".".
55
+
56
+ Returns:
57
+ The selection contents as a string.
58
+
59
+ Notes:
60
+ - If the owner returns a non-string representation (e.g. ATOM or INTEGER),
61
+ Tk converts it to a space-separated string representation.
62
+ - Tk will not retrieve UTF-8 formatted data unless you request
63
+ `type="UTF8_STRING"`.
64
+ """
65
+ return super().selection_get(**kw) # type: ignore[misc]
66
+
67
+ def selection_handle(self, command: str | None, **kw: Any) -> None:
68
+ """Register or remove a handler for selection retrieval requests.
69
+
70
+ This corresponds to `selection handle`. When this widget owns a selection,
71
+ Tk will execute *command* when another client attempts to retrieve the
72
+ selection in the requested type.
73
+
74
+ Args:
75
+ command: A Tcl command (string) to execute to supply selection data.
76
+ If an empty string or None, removes any existing handler for the
77
+ given selection/type combination.
78
+ **kw: Handler options forwarded to Tkinter. Common options include:
79
+ - selection: Selection name (defaults to "PRIMARY").
80
+ - type: Requested type (defaults to "STRING").
81
+ - format: Representation format used to transmit the selection
82
+ (defaults to "STRING"). Usually only needed for compatibility
83
+ with non-Tk requesters.
84
+
85
+ Notes:
86
+ - When handling type "STRING", Tk will also handle "UTF8_STRING"
87
+ automatically.
88
+ - The command is invoked with two additional arguments appended:
89
+ `offset` and `maxChars`. The command should return up to `maxChars`
90
+ characters starting at `offset`. Large selections are retrieved
91
+ in multiple chunks.
92
+ """
93
+ # Tkinter expects `command` to be a Tcl script; keep the pass-through shape.
94
+ if command is None:
95
+ command = ""
96
+ return super().selection_handle(command, **kw) # type: ignore[misc]
97
+
98
+ def selection_own(self, **kw: Any) -> str:
99
+ """Query the current selection owner within this application.
100
+
101
+ This corresponds to the *query* form of `selection own`, returning the
102
+ pathname of the window in this application that owns the selection on
103
+ the target display, or an empty string if none.
104
+
105
+ Args:
106
+ **kw: Query options forwarded to Tkinter. Common options include:
107
+ - selection: Selection name (defaults to "PRIMARY").
108
+ - displayof: A widget/window whose display should be targeted.
109
+ Defaults to ".".
110
+
111
+ Returns:
112
+ The pathname of the owner window in this application, or an empty
113
+ string if no window in this application owns the selection.
114
+ """
115
+ return super().selection_own(**kw) # type: ignore[misc]
116
+
117
+ def selection_own_set(
118
+ self,
119
+ owner: Any,
120
+ command: Callable[[], Any] | None = None,
121
+ *,
122
+ selection: str = "PRIMARY",
123
+ ) -> None:
124
+ """Make *owner* the selection owner (convenience helper).
125
+
126
+ Tk’s `selection own` *setter* form is easy to confuse with the query form.
127
+ This helper makes the intent explicit while still using Tk’s semantics.
128
+
129
+ Args:
130
+ owner: The widget/window that should own the selection.
131
+ command: Optional callback invoked when this widget loses ownership
132
+ of the selection (i.e., another window claims it).
133
+ selection: The selection name to claim (defaults to "PRIMARY").
134
+ """
135
+ # `selection_own` in Tkinter supports setting with `command` and `selection`.
136
+ return super().selection_own(owner, command=command, selection=selection) # type: ignore[misc]