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,786 @@
1
+ """Base window functionality shared between App (Tk) and Toplevel.
2
+
3
+ This module provides the BaseWindow mixin class that encapsulates common
4
+ window management functionality used by both the main App and Toplevel classes.
5
+ This eliminates code duplication and ensures consistent behavior across all
6
+ window types.
7
+
8
+ Standard widget APIs (events, scheduling, clipboard, geometry managers, winfo) are documented under capabilities and are
9
+ available through normal Tk/Ttk inheritance.”
10
+
11
+ The BaseWindow mixin provides:
12
+ - Window manager (wm) pass-throughs with modern docstrings
13
+ - Window configuration (size, position, constraints)
14
+ - Alpha transparency handling (platform-aware)
15
+ - Icon management
16
+ - Positioning utilities
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import tkinter
22
+ from typing import Literal, Optional, Tuple, Callable, Any
23
+
24
+ from bootstack.core.localization import MessageCatalog
25
+ from bootstack.runtime.window_utilities import AnchorPoint, WindowPositioning, WindowSizing
26
+
27
+
28
+ def on_visibility_alpha(event: tkinter.Event) -> None:
29
+ """Set Window or Toplevel alpha value on Visibility (X11).
30
+
31
+ X11 requires alpha to be set after the window is visible, so we bind
32
+ to the <Visibility> event and set alpha then, unbinding after first use.
33
+
34
+ Args:
35
+ event: The visibility event containing the widget.
36
+ """
37
+ widget = event.widget
38
+ if hasattr(widget, 'alpha') and hasattr(widget, 'alpha_bind'):
39
+ if widget.alpha_bind:
40
+ widget.unbind(widget.alpha_bind)
41
+ widget.attributes("-alpha", widget.alpha)
42
+
43
+
44
+ class BaseWindow:
45
+ """Base window behavior shared by bootstack windows.
46
+
47
+ This class is intended to be used as a mixin alongside `tkinter.Tk` or
48
+ `tkinter.Toplevel`, for example:
49
+
50
+ class App(BaseWindow, tkinter.Tk): ...
51
+ class Window(BaseWindow, tkinter.Toplevel): ...
52
+
53
+ The methods below are thin pass-throughs to Tk's window manager ("wm")
54
+ functionality, primarily to provide modern, consistent docstrings and a
55
+ curated, documented API surface.
56
+ """
57
+
58
+ _title_message_id: str | None = None
59
+
60
+ # -------------------------------------------------------------------------
61
+ # Setup methods (bootstack-specific)
62
+ # -------------------------------------------------------------------------
63
+
64
+ def _setup_window(
65
+ self,
66
+ title: str = "bootstack",
67
+ size: Optional[tuple[int, int]] = None,
68
+ position: Optional[tuple[int, int]] = None,
69
+ minsize: Optional[tuple[int, int]] = None,
70
+ maxsize: Optional[tuple[int, int]] = None,
71
+ resizable: Optional[tuple[bool, bool]] = None,
72
+ transient: Optional[tkinter.Misc] = None,
73
+ overrideredirect: bool = False,
74
+ alpha: float = 1.0,
75
+ window_style: Optional[str] = None,
76
+ ) -> None:
77
+ """Configure common window properties.
78
+
79
+ This method should be called during window initialization to set up
80
+ standard window properties. It handles platform differences automatically.
81
+ The window is temporarily hidden during setup so that sizing and
82
+ positioning are applied before it is shown.
83
+
84
+ Args:
85
+ title: Window title shown in titlebar.
86
+ size: Optional (width, height) in pixels.
87
+ position: Optional (x, y) position on screen.
88
+ minsize: Optional (width, height) minimum window size.
89
+ maxsize: Optional (width, height) maximum window size.
90
+ resizable: Optional (width, height) resizable flags.
91
+ transient: Optional master window for transient behavior.
92
+ overrideredirect: If True, removes window decorations.
93
+ alpha: Transparency level (0.0 to 1.0). Platform-aware.
94
+ window_style: Windows-only pywinstyles effect. Options include
95
+ 'mica', 'acrylic', 'aero', 'transparent', 'win7', etc.
96
+ If None, uses AppSettings.window_style (defaults to 'mica').
97
+
98
+ Note:
99
+ The window must already be initialized (tkinter.Tk.__init__ or
100
+ tkinter.Toplevel.__init__ called) before calling this method.
101
+ """
102
+ # Get window_style from AppSettings if not explicitly provided
103
+ if window_style is None:
104
+ try:
105
+ from bootstack.runtime.app import get_app_settings
106
+ window_style = get_app_settings().window_style
107
+ except (ImportError, RuntimeError):
108
+ # No app registered yet, use default
109
+ window_style = 'mica'
110
+
111
+ # Store window style for later application
112
+ self._window_style = window_style
113
+ # Hide window until we finish applying geometry/resizing to avoid flicker
114
+ self.withdraw()
115
+
116
+ # Store window system for platform-specific behavior
117
+ if not hasattr(self, 'winsys'):
118
+ self.winsys = self.tk.call('tk', 'windowingsystem')
119
+
120
+ # Basic configuration - localize title automatically
121
+ self.title(title)
122
+
123
+ # Bind locale changes
124
+ self.winfo_toplevel().bind("<<LocaleChanged>>", self._handle_locale_changed)
125
+
126
+ # Geometry
127
+ if size is not None:
128
+ width, height = size
129
+ self.geometry(f"{width}x{height}")
130
+
131
+ # Track whether we should center (defer until after constraints)
132
+ _should_center = (position is None)
133
+
134
+ if position is not None:
135
+ xpos, ypos = position
136
+ self.geometry(f"+{xpos}+{ypos}")
137
+
138
+ # Size constraints
139
+ if minsize is not None:
140
+ width, height = minsize
141
+ self.minsize(width, height)
142
+
143
+ if maxsize is not None:
144
+ width, height = maxsize
145
+ self.maxsize(width, height)
146
+
147
+ if resizable is not None:
148
+ width, height = resizable
149
+ self.resizable(width, height)
150
+
151
+ # Window attributes
152
+ if transient is not None:
153
+ self.transient(transient)
154
+
155
+ if overrideredirect:
156
+ # Skip overrideredirect on macOS - causes click handling issues and crashes
157
+ if self.winsys != 'aqua':
158
+ self.overrideredirect(1)
159
+
160
+ # Alpha transparency (platform-aware)
161
+ self._setup_alpha(alpha)
162
+
163
+ # Center window on screen if no explicit position was provided
164
+ if _should_center:
165
+ # Update geometry to ensure size is applied before centering
166
+ self.update_idletasks()
167
+ x, y = WindowPositioning.center_on_screen(self)
168
+ x, y = WindowPositioning.ensure_on_screen(self, x, y)
169
+ self.geometry(f'+{x}+{y}')
170
+
171
+ def _apply_window_style(self) -> None:
172
+ """Apply pywinstyles effect on Windows.
173
+
174
+ Uses the window_style set during initialization. Only applies on Windows
175
+ and only if the style hasn't already been applied.
176
+ """
177
+ if getattr(self, '_window_style_applied', False):
178
+ return
179
+ window_style = getattr(self, '_window_style', 'mica')
180
+ if window_style is None:
181
+ return
182
+ if not hasattr(self, 'winsys') or self.winsys != 'win32':
183
+ return
184
+ try:
185
+ import pywinstyles
186
+ pywinstyles.apply_style(self, window_style)
187
+ self._window_style_applied = True
188
+ except Exception:
189
+ pass
190
+
191
+ def _setup_alpha(self, alpha: float) -> None:
192
+ """Configure window alpha transparency in a platform-aware manner.
193
+
194
+ Handles platform differences in alpha transparency support:
195
+ - X11: Requires setting alpha after window is visible
196
+ - Windows/macOS: Can set alpha immediately
197
+
198
+ Args:
199
+ alpha: Transparency level (0.0 = fully transparent, 1.0 = opaque).
200
+
201
+ Note:
202
+ On X11, this binds to <Visibility> event to set alpha after
203
+ the window becomes visible. The binding is automatically
204
+ removed after first use.
205
+ """
206
+ if alpha is not None and alpha != 1.0:
207
+ if self.winsys == 'x11':
208
+ # X11 requires alpha to be set after window is visible
209
+ self.alpha = alpha
210
+ self.alpha_bind = self.bind("<Visibility>", on_visibility_alpha, '+')
211
+ else:
212
+ # Windows and macOS can set alpha immediately
213
+ self.attributes("-alpha", alpha)
214
+
215
+ def _setup_icon(self, iconphoto: Optional[str], default_icon_enabled: bool = True) -> None:
216
+ """Configure window icon from file path or use default.
217
+
218
+ Sets up the window icon, with support for:
219
+ - Custom icon from file path or PhotoImage object
220
+ - Default bootstack.png from package assets (when iconphoto is None and default_icon_enabled=True)
221
+ - No icon (when iconphoto is None and default_icon_enabled=False)
222
+
223
+ Args:
224
+ iconphoto: Path to icon image file, PhotoImage object, or None for default/no icon.
225
+ default_icon_enabled: Whether to use default icon when iconphoto is None.
226
+
227
+ Note:
228
+ The icon is stored in self._icon to prevent garbage collection (for PhotoImage icons).
229
+ On failure to load custom icon, falls back to default icon if enabled.
230
+ """
231
+ if iconphoto is None:
232
+ # No custom icon provided - use default if enabled
233
+ if default_icon_enabled:
234
+ try:
235
+ from pathlib import Path
236
+ import bootstack
237
+ icon_path = Path(bootstack.__file__).parent / 'assets' / 'bootstack.png'
238
+ self._icon = tkinter.PhotoImage(file=str(icon_path), master=self)
239
+ self.iconphoto(True, self._icon)
240
+ except (ImportError, FileNotFoundError, tkinter.TclError, Exception):
241
+ # Icon file not available or failed to load - silently continue
242
+ pass
243
+ return
244
+
245
+ # User provided a custom icon
246
+ try:
247
+ # Check if it's already a PhotoImage object
248
+ if isinstance(iconphoto, tkinter.PhotoImage):
249
+ self._icon = iconphoto
250
+ self.iconphoto(True, self._icon)
251
+ else:
252
+ # Assume it's a file path
253
+ self._icon = tkinter.PhotoImage(file=iconphoto, master=self)
254
+ self.iconphoto(True, self._icon)
255
+ except (tkinter.TclError, Exception) as e:
256
+ # Failed to load user icon
257
+ print(f'Failed to load icon: {iconphoto} - {e}')
258
+ if default_icon_enabled:
259
+ # Fall back to default bootstack.png
260
+ try:
261
+ from pathlib import Path
262
+ import bootstack
263
+ icon_path = Path(bootstack.__file__).parent / 'assets' / 'bootstack.png'
264
+ self._icon = tkinter.PhotoImage(file=str(icon_path), master=self)
265
+ self.iconphoto(True, self._icon)
266
+ except (ImportError, FileNotFoundError, tkinter.TclError, Exception):
267
+ pass
268
+
269
+ def _handle_locale_changed(self, *_):
270
+ """Handle locale change events by updating the localized title."""
271
+ if self._title_message_id:
272
+ self.title(self._title_message_id)
273
+
274
+ # -------------------------------------------------------------------------
275
+ # Window manager (wm) — pass-throughs with modern docstrings
276
+ # -------------------------------------------------------------------------
277
+
278
+ def show(self) -> None:
279
+ """Show the window after it has been fully initialized.
280
+
281
+ This forces a geometry/layout pass before mapping the window, which is
282
+ useful if you have performed setup that affects sizing.
283
+ """
284
+ # Apply Windows window style while still withdrawn to prevent flash.
285
+ # The update() flushes input/IO events so pywinstyles can attach to a
286
+ # fully realized HWND on Windows; on Aqua it can hang indefinitely
287
+ # processing children's pending events (see Dialog._position_dialog
288
+ # for the same pattern), so gate it on the platform that needs it.
289
+ self.update_idletasks()
290
+ self._apply_window_style()
291
+ if getattr(self, 'winsys', None) == 'win32':
292
+ self.update()
293
+ self.deiconify()
294
+
295
+ def title(self, value: str | None = None) -> str:
296
+ """Get or set the window title.
297
+
298
+ If you localize UI text (e.g., via a message catalog), the title is
299
+ automatically translated using the MessageCatalog.
300
+
301
+ Args:
302
+ value: The new title text. If None, return the current title.
303
+
304
+ Returns:
305
+ The current title string (getter) or the title string after setting.
306
+ """
307
+ if value is None:
308
+ return super().title()
309
+ self._title_message_id = value
310
+ return super().title(MessageCatalog.translate(self._title_message_id))
311
+
312
+ def geometry(self, new_geometry: str | None = None) -> str:
313
+ """Get or set the window geometry.
314
+
315
+ Geometry strings use the standard Tk format:
316
+
317
+ - "{width}x{height}" (size only)
318
+ - "+{x}+{y}" (position only)
319
+ - "{width}x{height}+{x}+{y}" (size + position)
320
+
321
+ Args:
322
+ new_geometry: The geometry string to apply. If None, return the
323
+ current geometry string.
324
+
325
+ Returns:
326
+ The current geometry string (getter) or the geometry after setting.
327
+ """
328
+ return super().geometry(new_geometry)
329
+
330
+ def state(self, newstate: str | None = None) -> str:
331
+ """Get or set the window manager state.
332
+
333
+ Common states include:
334
+
335
+ - "normal": displayed normally
336
+ - "iconic": minimized (iconified)
337
+ - "withdrawn": hidden (not shown)
338
+ - "zoomed": maximized (platform/window-manager dependent)
339
+
340
+ Args:
341
+ newstate: State to apply. If None, return the current state.
342
+
343
+ Returns:
344
+ The current state string.
345
+ """
346
+ return super().state(newstate)
347
+
348
+ def attributes(self, *args: Any) -> Any:
349
+ """Get or set platform-specific window attributes.
350
+
351
+ This method forwards to Tk's "wm attributes" command. Common attributes:
352
+
353
+ - "-alpha" (float 0.0-1.0): transparency
354
+ - "-fullscreen" (bool): fullscreen mode
355
+ - "-topmost" (bool): keep window above others
356
+
357
+ The exact supported attributes vary by platform/window manager.
358
+
359
+ Args:
360
+ *args: Arguments accepted by Tk's `wm attributes`. Common forms are:
361
+ - (name,) to query a single attribute
362
+ - (name, value) to set an attribute
363
+ - () to query all supported attributes (platform dependent)
364
+
365
+ Returns:
366
+ The queried attribute value(s), or an implementation-dependent
367
+ result when setting.
368
+ """
369
+ return super().attributes(*args)
370
+
371
+ def iconify(self) -> None:
372
+ """Minimize (iconify) the window."""
373
+ return super().iconify()
374
+
375
+ def deiconify(self) -> None:
376
+ """Show a minimized or withdrawn window.
377
+
378
+ This restores a window that has been hidden with `withdraw()` or
379
+ minimized with `iconify()`.
380
+ """
381
+ return super().deiconify()
382
+
383
+ def withdraw(self) -> None:
384
+ """Hide the window without destroying it.
385
+
386
+ A withdrawn window is unmapped and typically removed from
387
+ taskbar/window lists. Use `deiconify()` to show it again.
388
+ """
389
+ return super().withdraw()
390
+
391
+ def resizable(self, width: bool | None = None, height: bool | None = None) -> tuple[int, int] | None:
392
+ """Get or set whether the user can resize the window.
393
+
394
+ Args:
395
+ width: If provided, enable/disable horizontal resizing.
396
+ height: If provided, enable/disable vertical resizing.
397
+
398
+ Returns:
399
+ When called as a getter (both args None), returns `(width_flag, height_flag)`
400
+ where each flag is 0/1. When called as a setter, Tk returns None.
401
+ """
402
+ return super().resizable(width, height)
403
+
404
+ def minsize(self, width: int | None = None, height: int | None = None) -> tuple[int, int] | None:
405
+ """Get or set the minimum window size in pixels.
406
+
407
+ Args:
408
+ width: Minimum width in pixels. If None, act as a getter.
409
+ height: Minimum height in pixels. If None, act as a getter.
410
+
411
+ Returns:
412
+ When called as a getter (both args None), returns `(width, height)`.
413
+ When called as a setter, Tk returns None.
414
+ """
415
+ return super().minsize(width, height)
416
+
417
+ def maxsize(self, width: int | None = None, height: int | None = None) -> tuple[int, int] | None:
418
+ """Get or set the maximum window size in pixels.
419
+
420
+ Args:
421
+ width: Maximum width in pixels. If None, act as a getter.
422
+ height: Maximum height in pixels. If None, act as a getter.
423
+
424
+ Returns:
425
+ When called as a getter (both args None), returns `(width, height)`.
426
+ When called as a setter, Tk returns None.
427
+ """
428
+ return super().maxsize(width, height)
429
+
430
+ def transient(self, master: tkinter.Misc | None = None) -> tkinter.Misc | None:
431
+ """Get or set the transient parent (window relationship).
432
+
433
+ Transient windows typically stay on top of their parent and may be
434
+ omitted from the taskbar. This is commonly used for dialogs.
435
+
436
+ Args:
437
+ master: The parent window. If None, return the current transient parent.
438
+
439
+ Returns:
440
+ The current transient parent (getter) or the provided master (setter),
441
+ depending on Tk/platform behavior.
442
+ """
443
+ return super().transient(master)
444
+
445
+ def protocol(self, name: str, func: Callable[[], Any] | None = None) -> Any:
446
+ """Get or set a window manager protocol handler.
447
+
448
+ The most common protocol is "WM_DELETE_WINDOW" (close button).
449
+
450
+ Args:
451
+ name: Protocol name.
452
+ func: Handler to register. If None, return the current handler (if any).
453
+
454
+ Returns:
455
+ The current handler when queried, or an implementation-dependent result
456
+ when setting.
457
+ """
458
+ return super().protocol(name, func)
459
+
460
+ def overrideredirect(self, boolean: bool | None = None) -> bool | None:
461
+ """Get or set override-redirect mode.
462
+
463
+ When enabled, the window manager typically does not decorate or manage
464
+ the window (no title bar/borders). Useful for popups/menus; use with care.
465
+
466
+ Note:
467
+ On macOS (Aqua), overrideredirect is disabled due to Tk/Cocoa issues
468
+ with click handling and event processing that can cause crashes.
469
+
470
+ Args:
471
+ boolean: True to enable override-redirect, False to disable. If None,
472
+ return the current value.
473
+
474
+ Returns:
475
+ The current override-redirect value when queried, or None when set.
476
+ """
477
+ # Skip overrideredirect on macOS - causes click handling issues and crashes
478
+ if boolean and hasattr(self, 'winsys') and self.winsys == 'aqua':
479
+ return None
480
+ return super().overrideredirect(boolean)
481
+
482
+ # -------------------------------------------------------------------------
483
+ # Convenience wrappers: intent-based names for common tasks
484
+ # -------------------------------------------------------------------------
485
+
486
+ def on_close(self, handler: Callable[[], Any]) -> None:
487
+ """Register a handler for the window close button.
488
+
489
+ This is a convenience wrapper for:
490
+
491
+ protocol("WM_DELETE_WINDOW", handler)
492
+
493
+ Args:
494
+ handler: A callable invoked when the user requests to close the window.
495
+ """
496
+ self.protocol("WM_DELETE_WINDOW", handler)
497
+
498
+ def hide(self) -> None:
499
+ """Hide the window (alias for `withdraw()`)."""
500
+ self.withdraw()
501
+
502
+ def minimize(self) -> None:
503
+ """Minimize the window (alias for `iconify()`)."""
504
+ self.iconify()
505
+
506
+ def maximize(self) -> None:
507
+ """Maximize the window where supported.
508
+
509
+ Tk uses `state("zoomed")` to request maximized windows on some platforms.
510
+ On unsupported window managers this may raise `tkinter.TclError`.
511
+ """
512
+ try:
513
+ self.state("zoomed")
514
+ except tkinter.TclError:
515
+ pass
516
+
517
+ def set_topmost(self, value: bool = True) -> None:
518
+ """Enable/disable always-on-top behavior where supported.
519
+
520
+ Args:
521
+ value: True to keep the window above others; False to disable.
522
+ """
523
+ try:
524
+ self.attributes("-topmost", bool(value))
525
+ except tkinter.TclError:
526
+ pass
527
+
528
+ # Backward compatibility alias
529
+ keep_on_top = set_topmost
530
+
531
+ def set_fullscreen(self, value: bool = True) -> None:
532
+ """Enable/disable fullscreen where supported.
533
+
534
+ Args:
535
+ value: True to enter fullscreen; False to exit.
536
+ """
537
+ try:
538
+ self.attributes("-fullscreen", bool(value))
539
+ except tkinter.TclError:
540
+ pass
541
+
542
+ def set_alpha(self, value: float) -> None:
543
+ """Set window opacity where supported.
544
+
545
+ Args:
546
+ value: Opacity from 0.0 (transparent) to 1.0 (opaque).
547
+ """
548
+ try:
549
+ self.attributes("-alpha", float(value))
550
+ except tkinter.TclError:
551
+ pass
552
+
553
+ # -------------------------------------------------------------------------
554
+ # Positioning utilities
555
+ # -------------------------------------------------------------------------
556
+
557
+ def place_center(self) -> None:
558
+ """Position the window in the center of the screen.
559
+
560
+ Centers the window on the primary display. For multi-monitor setups,
561
+ this typically centers on the monitor containing the mouse pointer.
562
+
563
+ The window geometry is updated immediately.
564
+
565
+ Examples:
566
+ >>> app = App()
567
+ >>> app.place_center()
568
+ >>> app.mainloop()
569
+ """
570
+ x, y = WindowPositioning.center_on_screen(self)
571
+ x, y = WindowPositioning.ensure_on_screen(self, x, y)
572
+ self.geometry(f'+{x}+{y}')
573
+
574
+ def place_center_on(self, parent: tkinter.Misc) -> None:
575
+ """Position the window centered on a parent widget or window.
576
+
577
+ Centers this window on the specified parent widget or window.
578
+ Commonly used for dialogs to center them on their parent window.
579
+
580
+ Args:
581
+ parent: The parent widget or window to center on.
582
+
583
+ Examples:
584
+ >>> parent = App()
585
+ >>> dialog = Toplevel()
586
+ >>> dialog.place_center_on(parent)
587
+ """
588
+ x, y = WindowPositioning.center_on_parent(self, parent)
589
+ x, y = WindowPositioning.ensure_on_screen(self, x, y)
590
+ self.geometry(f'+{x}+{y}')
591
+
592
+ def place_at(self, x: int, y: int, ensure_visible: bool = True) -> None:
593
+ """Position the window at specific screen coordinates.
594
+
595
+ Places the window at the given (x, y) coordinates, optionally
596
+ adjusting the position to ensure the window remains fully visible
597
+ on screen.
598
+
599
+ Args:
600
+ x: X coordinate on screen (in pixels from left edge).
601
+ y: Y coordinate on screen (in pixels from top edge).
602
+ ensure_visible: If True, adjusts coordinates to keep window on screen.
603
+
604
+ Examples:
605
+ >>> window = App()
606
+ >>> window.place_at(100, 100)
607
+ """
608
+ if ensure_visible:
609
+ x, y = WindowPositioning.ensure_on_screen(self, x, y)
610
+ self.geometry(f'+{x}+{y}')
611
+
612
+ def place_anchor(
613
+ self,
614
+ anchor_to: tkinter.Misc,
615
+ anchor_point: AnchorPoint = 'sw',
616
+ window_point: AnchorPoint = 'nw',
617
+ offset: Tuple[int, int] = (0, 0),
618
+ ensure_visible: bool = True
619
+ ) -> None:
620
+ """Position window relative to another widget using anchor points.
621
+
622
+ Uses tkinter's standard anchor naming (n, s, e, w, ne, nw, se, sw, center).
623
+ This is useful for dropdowns, tooltips, context menus, and popovers.
624
+
625
+ Args:
626
+ anchor_to: The widget to anchor this window to.
627
+ anchor_point: Which point on the anchor widget to use (default 'sw').
628
+ window_point: Which point on this window to align (default 'nw').
629
+ offset: Additional (x, y) offset in pixels.
630
+ ensure_visible: If True, adjusts position to keep window on screen.
631
+
632
+ Examples:
633
+ >>> # Show dialog below button
634
+ >>> dialog = Toplevel()
635
+ >>> dialog.place_anchor(
636
+ ... anchor_to=button,
637
+ ... anchor_point='sw', # button's bottom-left
638
+ ... window_point='nw', # dialog's top-left
639
+ ... offset=(0, 5)
640
+ ... )
641
+ """
642
+ WindowPositioning.position_with_anchor(
643
+ window=self,
644
+ anchor_to=anchor_to,
645
+ anchor_point=anchor_point,
646
+ window_point=window_point,
647
+ offset=offset,
648
+ ensure_visible=ensure_visible
649
+ )
650
+
651
+ def place_dropdown(
652
+ self,
653
+ trigger_widget: tkinter.Misc,
654
+ prefer_below: bool = True,
655
+ align: Literal['left', 'right', 'center'] = 'left',
656
+ offset: Tuple[int, int] = (0, 2),
657
+ ensure_visible: bool = True,
658
+ auto_flip: bool = True
659
+ ) -> None:
660
+ """Position window as a dropdown relative to a trigger widget.
661
+
662
+ Smart positioning that automatically flips above/below based on
663
+ available space. Perfect for combobox dropdowns, autocomplete
664
+ suggestions, and dropdown menus.
665
+
666
+ Args:
667
+ trigger_widget: The widget that triggers the dropdown.
668
+ prefer_below: If True, tries to show below trigger; else tries above.
669
+ align: Horizontal alignment ('left', 'right', or 'center').
670
+ offset: Additional (x, y) offset in pixels.
671
+ ensure_visible: If True, adjusts position to keep window on screen.
672
+ auto_flip: If True, automatically flips above/below if no room.
673
+
674
+ Examples:
675
+ >>> # Dropdown menu below button
676
+ >>> menu = Toplevel()
677
+ >>> menu.place_dropdown(
678
+ ... trigger_widget=button,
679
+ ... prefer_below=True,
680
+ ... align='left'
681
+ ... )
682
+ """
683
+ WindowPositioning.position_dropdown(
684
+ window=self,
685
+ trigger_widget=trigger_widget,
686
+ prefer_below=prefer_below,
687
+ align=align,
688
+ offset=offset,
689
+ ensure_visible=ensure_visible,
690
+ auto_flip=auto_flip
691
+ )
692
+
693
+ def place_cursor(
694
+ self,
695
+ offset: Tuple[int, int] = (5, 5),
696
+ ensure_visible: bool = True
697
+ ) -> None:
698
+ """Position window at the current mouse cursor location.
699
+
700
+ Useful for context menus, tooltips that follow the cursor, or
701
+ click-to-show dialogs.
702
+
703
+ Args:
704
+ offset: Additional (x, y) offset from cursor in pixels.
705
+ ensure_visible: If True, adjusts position to keep window on screen.
706
+
707
+ Examples:
708
+ >>> # Show context menu at cursor
709
+ >>> menu = Toplevel()
710
+ >>> menu.place_cursor(offset=(2, 2))
711
+ """
712
+ WindowPositioning.position_at_cursor(
713
+ window=self,
714
+ offset=offset,
715
+ ensure_visible=ensure_visible
716
+ )
717
+
718
+ # Backward compatibility aliases
719
+ def place_window_center(self) -> None:
720
+ """Alias for place_center(). Deprecated, use place_center() instead."""
721
+ self.place_center()
722
+
723
+ position_center = place_center # Additional alias for compatibility
724
+
725
+ # -------------------------------------------------------------------------
726
+ # Sizing utilities
727
+ # -------------------------------------------------------------------------
728
+
729
+ def set_default_size(
730
+ self,
731
+ width_ratio: float = 0.6,
732
+ height_ratio: float = 0.7,
733
+ min_width: int = 400,
734
+ min_height: int = 300,
735
+ max_width: Optional[int] = None,
736
+ max_height: Optional[int] = None
737
+ ) -> None:
738
+ """Set window size as a percentage of screen size.
739
+
740
+ Calculates and applies a window size based on screen dimensions,
741
+ constrained by minimum and optional maximum sizes. Useful for
742
+ creating responsive windows that adapt to different screen sizes.
743
+
744
+ Args:
745
+ width_ratio: Proportion of screen width (0.0 to 1.0).
746
+ height_ratio: Proportion of screen height (0.0 to 1.0).
747
+ min_width: Minimum window width in pixels.
748
+ min_height: Minimum window height in pixels.
749
+ max_width: Optional maximum window width in pixels.
750
+ max_height: Optional maximum window height in pixels.
751
+
752
+ Examples:
753
+ >>> window = App()
754
+ >>> window.set_default_size(width_ratio=0.8, height_ratio=0.8)
755
+ >>> # Window will be 80% of screen size
756
+ """
757
+ width, height = WindowSizing.get_default_size(
758
+ self, width_ratio, height_ratio,
759
+ min_width, min_height, max_width, max_height
760
+ )
761
+ self.geometry(f"{width}x{height}")
762
+
763
+ def apply_size_constraints(
764
+ self,
765
+ minsize: Optional[tuple[int, int]] = None,
766
+ maxsize: Optional[tuple[int, int]] = None,
767
+ resizable: Optional[tuple[bool, bool]] = None
768
+ ) -> None:
769
+ """Apply multiple size constraints at once.
770
+
771
+ Convenience method to set minsize, maxsize, and resizable in one call.
772
+
773
+ Args:
774
+ minsize: Optional (width, height) minimum size.
775
+ maxsize: Optional (width, height) maximum size.
776
+ resizable: Optional (width, height) resizable flags.
777
+
778
+ Examples:
779
+ >>> window = App()
780
+ >>> window.apply_size_constraints(
781
+ ... minsize=(400, 300),
782
+ ... resizable=(True, False) # Width resizable, height fixed
783
+ ... )
784
+ """
785
+ WindowSizing.apply_size_constraints(self, minsize, maxsize, resizable)
786
+