bootstack 0.1.5__tar.gz → 0.1.7__tar.gz

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 (491) hide show
  1. {bootstack-0.1.5/src/bootstack.egg-info → bootstack-0.1.7}/PKG-INFO +4 -5
  2. {bootstack-0.1.5 → bootstack-0.1.7}/README.md +3 -4
  3. {bootstack-0.1.5 → bootstack-0.1.7}/pyproject.toml +2 -2
  4. bootstack-0.1.7/src/bootstack/_runtime/wheel.py +152 -0
  5. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/i18n/intl_format.py +7 -3
  6. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/validation/validation_rules.py +20 -2
  7. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/base.py +24 -0
  8. bootstack-0.1.7/src/bootstack/widgets/_core/kwargs.py +85 -0
  9. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/selection_group.py +7 -0
  10. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/_parts/numberentry_part.py +29 -28
  11. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/_parts/textentry_part.py +8 -2
  12. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/dropdownbutton.py +15 -2
  13. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/field.py +7 -2
  14. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/form.py +71 -29
  15. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/gallery.py +22 -10
  16. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/list/listview.py +46 -32
  17. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/scrolledtext.py +34 -36
  18. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/scrollview.py +41 -36
  19. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/selectbox.py +89 -12
  20. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tabs/tabs.py +23 -18
  21. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/core.py +18 -19
  22. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tree/treeview.py +33 -16
  23. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/spinbox.py +24 -7
  24. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/buttongroup.py +23 -9
  25. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/menubutton.py +4 -1
  26. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/passwordfield.py +3 -1
  27. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/pathfield.py +3 -1
  28. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/radiogroup.py +9 -2
  29. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/select.py +14 -3
  30. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/statusbar.py +5 -1
  31. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/textfield.py +3 -1
  32. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/togglegroup.py +9 -2
  33. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/toolbar.py +8 -3
  34. {bootstack-0.1.5 → bootstack-0.1.7/src/bootstack.egg-info}/PKG-INFO +4 -5
  35. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack.egg-info/SOURCES.txt +2 -0
  36. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_intl_format.py +25 -0
  37. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_validation_rules.py +61 -0
  38. {bootstack-0.1.5 → bootstack-0.1.7}/LICENSE +0 -0
  39. {bootstack-0.1.5 → bootstack-0.1.7}/MANIFEST.in +0 -0
  40. {bootstack-0.1.5 → bootstack-0.1.7}/NOTICE +0 -0
  41. {bootstack-0.1.5 → bootstack-0.1.7}/setup.cfg +0 -0
  42. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/__init__.py +0 -0
  43. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/__main__.py +0 -0
  44. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/__init__.py +0 -0
  45. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/__init__.py +0 -0
  46. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/after.py +0 -0
  47. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/bind.py +0 -0
  48. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/bindtags.py +0 -0
  49. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/busy.py +0 -0
  50. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/clipboard.py +0 -0
  51. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/focus.py +0 -0
  52. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/grab.py +0 -0
  53. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/grid.py +0 -0
  54. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/localization.py +0 -0
  55. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/pack.py +0 -0
  56. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/place.py +0 -0
  57. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/selection.py +0 -0
  58. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/signals.py +0 -0
  59. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/capabilities/winfo.py +0 -0
  60. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/colorutils.py +0 -0
  61. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/exceptions.py +0 -0
  62. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/images.py +0 -0
  63. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/mixins/__init__.py +0 -0
  64. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/mixins/ttk_state.py +0 -0
  65. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/mixins/widget.py +0 -0
  66. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/paths.py +0 -0
  67. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/publisher.py +0 -0
  68. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_core/variables.py +0 -0
  69. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/__init__.py +0 -0
  70. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/app.py +0 -0
  71. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/base_window.py +0 -0
  72. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/events.py +0 -0
  73. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/shortcuts.py +0 -0
  74. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/tk_patch.py +0 -0
  75. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/toplevel.py +0 -0
  76. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/utility.py +0 -0
  77. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/visual_focus.py +0 -0
  78. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/_runtime/window_utilities.py +0 -0
  79. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/__init__.py +0 -0
  80. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/bootstack.ico +0 -0
  81. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/bootstack.png +0 -0
  82. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/__init__.py +0 -0
  83. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/badge-pill.png +0 -0
  84. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/badge-square.png +0 -0
  85. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/button-compact.png +0 -0
  86. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/button-default.png +0 -0
  87. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
  88. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
  89. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
  90. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
  91. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
  92. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
  93. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
  94. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
  95. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
  96. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
  97. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
  98. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
  99. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/card.png +0 -0
  100. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/checkbox-checked.png +0 -0
  101. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  102. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/checkbox-unchecked.png +0 -0
  103. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/field.png +0 -0
  104. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/input-addon-compact.png +0 -0
  105. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/input-addon-default.png +0 -0
  106. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/input-compact.png +0 -0
  107. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/input-default.png +0 -0
  108. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/list-item-separated.png +0 -0
  109. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/list-item.png +0 -0
  110. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/listrow-compact.png +0 -0
  111. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/listrow-default.png +0 -0
  112. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/manifest.toml +0 -0
  113. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/menu-item.png +0 -0
  114. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/navitem-compact.png +0 -0
  115. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/navitem-default.png +0 -0
  116. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/progressbar-h-compact.png +0 -0
  117. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/progressbar-h-default.png +0 -0
  118. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/progressbar-v-compact.png +0 -0
  119. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/progressbar-v-default.png +0 -0
  120. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/radiobutton.png +0 -0
  121. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  122. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/scrollbar-vertical.png +0 -0
  123. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/slider-handle.png +0 -0
  124. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/slider-track-h.png +0 -0
  125. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/slider-track-v.png +0 -0
  126. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/switch-off.png +0 -0
  127. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/switch-on.png +0 -0
  128. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/tab-h.png +0 -0
  129. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/elements/tab-v.png +0 -0
  130. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/icons/bootstrap.ttf +0 -0
  131. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/icons/glyphmap.json +0 -0
  132. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/icons/icon_metrics.json +0 -0
  133. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  134. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +0 -0
  135. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
  136. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +0 -0
  137. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  138. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +0 -0
  139. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  140. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +0 -0
  141. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  142. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +0 -0
  143. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  144. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +0 -0
  145. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  146. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +0 -0
  147. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  148. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +0 -0
  149. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  150. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +0 -0
  151. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  152. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +0 -0
  153. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  154. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +0 -0
  155. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  156. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +0 -0
  157. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  158. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +0 -0
  159. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  160. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +0 -0
  161. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  162. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +0 -0
  163. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  164. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +0 -0
  165. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  166. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +0 -0
  167. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  168. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +0 -0
  169. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  170. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +0 -0
  171. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  172. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +0 -0
  173. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  174. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +0 -0
  175. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  176. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +0 -0
  177. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  178. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +0 -0
  179. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/__init__.py +0 -0
  180. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/__main__.py +0 -0
  181. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/add.py +0 -0
  182. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/appicon.py +0 -0
  183. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/build.py +0 -0
  184. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/config.py +0 -0
  185. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/demo.py +0 -0
  186. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/dev.py +0 -0
  187. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/doctor.py +0 -0
  188. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/icons.py +0 -0
  189. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/promote.py +0 -0
  190. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/pyinstaller.py +0 -0
  191. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/run.py +0 -0
  192. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/start.py +0 -0
  193. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/cli/templates/__init__.py +0 -0
  194. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/clipboard.py +0 -0
  195. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/constants.py +0 -0
  196. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/README.md +0 -0
  197. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/__init__.py +0 -0
  198. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/_observable.py +0 -0
  199. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/base.py +0 -0
  200. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/file_source.py +0 -0
  201. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/memory_source.py +0 -0
  202. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/query.py +0 -0
  203. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/readers.py +0 -0
  204. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/sqlite_source.py +0 -0
  205. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/types.py +0 -0
  206. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/data/writers.py +0 -0
  207. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/__init__.py +0 -0
  208. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/_capture.py +0 -0
  209. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/_env.py +0 -0
  210. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/_registry.py +0 -0
  211. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/_reloader.py +0 -0
  212. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/_reset.py +0 -0
  213. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dev/_watcher.py +0 -0
  214. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/__init__.py +0 -0
  215. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/__init__.py +0 -0
  216. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/colorchooser.py +0 -0
  217. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/datedialog.py +0 -0
  218. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/dialog.py +0 -0
  219. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/filterdialog.py +0 -0
  220. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/fontdialog.py +0 -0
  221. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/formdialog.py +0 -0
  222. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/message.py +0 -0
  223. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/dialogs/_impl/query.py +0 -0
  224. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/errors.py +0 -0
  225. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/events/__init__.py +0 -0
  226. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/events/_event.py +0 -0
  227. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/events/_payloads.py +0 -0
  228. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/events/_subscription.py +0 -0
  229. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/i18n/README.md +0 -0
  230. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/i18n/__init__.py +0 -0
  231. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/i18n/catalog.py +0 -0
  232. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/i18n/msgcat.py +0 -0
  233. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/i18n/specs.py +0 -0
  234. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/images.py +0 -0
  235. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/py.typed +0 -0
  236. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/scheduling/__init__.py +0 -0
  237. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/scheduling/_schedule.py +0 -0
  238. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/shortcuts.py +0 -0
  239. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/signals/README.md +0 -0
  240. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/signals/__init__.py +0 -0
  241. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/signals/integration.py +0 -0
  242. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/signals/signal.py +0 -0
  243. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/signals/types.py +0 -0
  244. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/store.py +0 -0
  245. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/streams/__init__.py +0 -0
  246. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/streams/_stream.py +0 -0
  247. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/__init__.py +0 -0
  248. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/__init__.py +0 -0
  249. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/badge.py +0 -0
  250. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/button.py +0 -0
  251. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/buttongroup.py +0 -0
  252. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/calendar.py +0 -0
  253. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/checkbutton.py +0 -0
  254. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/combobox.py +0 -0
  255. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/contextmenu.py +0 -0
  256. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/entry.py +0 -0
  257. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/expander.py +0 -0
  258. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/field.py +0 -0
  259. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/frame.py +0 -0
  260. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/label.py +0 -0
  261. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/labelframe.py +0 -0
  262. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/listview.py +0 -0
  263. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/menubar.py +0 -0
  264. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/menubutton.py +0 -0
  265. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/panedwindow.py +0 -0
  266. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/progressbar.py +0 -0
  267. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/radiobutton.py +0 -0
  268. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/scale.py +0 -0
  269. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/scrollbar.py +0 -0
  270. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/separator.py +0 -0
  271. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/sidenav.py +0 -0
  272. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/sizegrip.py +0 -0
  273. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/spinbox.py +0 -0
  274. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/switch.py +0 -0
  275. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/tabitem.py +0 -0
  276. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/togglegroup.py +0 -0
  277. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/toolbutton.py +0 -0
  278. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/tooltip.py +0 -0
  279. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/treeview.py +0 -0
  280. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders/utils.py +0 -0
  281. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders_tk/__init__.py +0 -0
  282. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/builders_tk/defaults.py +0 -0
  283. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/element.py +0 -0
  284. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/fonts.py +0 -0
  285. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/style.py +0 -0
  286. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/style_builder_base.py +0 -0
  287. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/style_builder_mixed.py +0 -0
  288. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/style_builder_tk.py +0 -0
  289. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/style_builder_ttk.py +0 -0
  290. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/style_resolver.py +0 -0
  291. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/theme.py +0 -0
  292. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/theme_provider.py +0 -0
  293. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/themes/__init__.py +0 -0
  294. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/tk_patch.py +0 -0
  295. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/token_maps.py +0 -0
  296. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/types.py +0 -0
  297. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/typography.py +0 -0
  298. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/style/utility.py +0 -0
  299. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/types.py +0 -0
  300. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/validation/__init__.py +0 -0
  301. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/validation/types.py +0 -0
  302. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/validation/validation_result.py +0 -0
  303. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/__init__.py +0 -0
  304. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/__init__.py +0 -0
  305. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/app_config.py +0 -0
  306. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/container.py +0 -0
  307. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/context.py +0 -0
  308. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/events.py +0 -0
  309. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/field_mixin.py +0 -0
  310. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/icon_image_props.py +0 -0
  311. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/image_binding.py +0 -0
  312. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/navmodel.py +0 -0
  313. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/options.py +0 -0
  314. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/window_controls.py +0 -0
  315. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_core/window_menu.py +0 -0
  316. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/__init__.py +0 -0
  317. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/_internal/__init__.py +0 -0
  318. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/_internal/wrapper_base.py +0 -0
  319. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/_parts/__init__.py +0 -0
  320. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/_parts/spinnerentry_part.py +0 -0
  321. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/__init__.py +0 -0
  322. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/_dateutils.py +0 -0
  323. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/_image_fit.py +0 -0
  324. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/accordion.py +0 -0
  325. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/avatar.py +0 -0
  326. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/buttongroup.py +0 -0
  327. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/calendar.py +0 -0
  328. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/carousel.py +0 -0
  329. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/chart.py +0 -0
  330. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/compositeframe.py +0 -0
  331. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/contextmenu.py +0 -0
  332. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/dateentry.py +0 -0
  333. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/expander.py +0 -0
  334. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/list/__init__.py +0 -0
  335. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/list/listitem.py +0 -0
  336. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/menu/__init__.py +0 -0
  337. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/menu/model.py +0 -0
  338. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/menu/render_native.py +0 -0
  339. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/menu/render_themed.py +0 -0
  340. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/meter.py +0 -0
  341. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/numericentry.py +0 -0
  342. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/pagestack.py +0 -0
  343. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/passwordentry.py +0 -0
  344. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/pathentry.py +0 -0
  345. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/picture.py +0 -0
  346. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/radiogroup.py +0 -0
  347. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/scrolledtext.pyi +0 -0
  348. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/__init__.py +0 -0
  349. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/content_host.py +0 -0
  350. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/layout.py +0 -0
  351. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/nav_panel.py +0 -0
  352. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/providers.py +0 -0
  353. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/rail.py +0 -0
  354. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/shell.py +0 -0
  355. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/shell/workspace.py +0 -0
  356. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/sidenav/__init__.py +0 -0
  357. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/sidenav/header.py +0 -0
  358. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/sidenav/separator.py +0 -0
  359. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/slider/__init__.py +0 -0
  360. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/slider/_shared.py +0 -0
  361. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/slider/rangeslider.py +0 -0
  362. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/slider/slider.py +0 -0
  363. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/spinnerentry.py +0 -0
  364. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tableview/__init__.py +0 -0
  365. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tableview/tableview.py +0 -0
  366. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tableview/types.py +0 -0
  367. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tabs/__init__.py +0 -0
  368. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tabs/tabitem.py +0 -0
  369. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tabs/tabview.py +0 -0
  370. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/__init__.py +0 -0
  371. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/change.py +0 -0
  372. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/codeeditor.py +0 -0
  373. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/decoration.py +0 -0
  374. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/diff.py +0 -0
  375. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +0 -0
  376. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +0 -0
  377. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +0 -0
  378. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +0 -0
  379. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +0 -0
  380. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +0 -0
  381. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/filter.py +0 -0
  382. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/search_overlay.py +0 -0
  383. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/sidebar.py +0 -0
  384. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/style_registry.py +0 -0
  385. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/textarea.py +0 -0
  386. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textarea/undo.py +0 -0
  387. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/textentry.py +0 -0
  388. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/timeentry.py +0 -0
  389. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/toast.py +0 -0
  390. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/toast_stack.py +0 -0
  391. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/togglegroup.py +0 -0
  392. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/toolbar.py +0 -0
  393. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tooltip.py +0 -0
  394. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tree/__init__.py +0 -0
  395. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tree/source_binding.py +0 -0
  396. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tree/treeitem.py +0 -0
  397. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/composites/tree/treenode.py +0 -0
  398. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/__init__.py +0 -0
  399. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/configure_mixin.py +0 -0
  400. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/entry_mixin.py +0 -0
  401. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/font_mixin.py +0 -0
  402. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/icon_mixin.py +0 -0
  403. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/localization_mixin.py +0 -0
  404. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/signal_mixin.py +0 -0
  405. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/mixins/validation_mixin.py +0 -0
  406. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/__init__.py +0 -0
  407. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/_menubutton.py +0 -0
  408. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/badge.py +0 -0
  409. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/button.py +0 -0
  410. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/card.py +0 -0
  411. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/checkbutton.py +0 -0
  412. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/checktoggle.py +0 -0
  413. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/combobox.py +0 -0
  414. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/entry.py +0 -0
  415. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/flexframe.py +0 -0
  416. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/frame.py +0 -0
  417. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/gridframe.py +0 -0
  418. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/label.py +0 -0
  419. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/labelframe.py +0 -0
  420. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/optionmenu.py +0 -0
  421. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/packframe.py +0 -0
  422. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/panedwindow.py +0 -0
  423. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/progressbar.py +0 -0
  424. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/radiobutton.py +0 -0
  425. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/radiotoggle.py +0 -0
  426. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/scrollbar.py +0 -0
  427. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/separator.py +0 -0
  428. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/sizegrip.py +0 -0
  429. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/switch.py +0 -0
  430. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/_impl/primitives/treeview.py +0 -0
  431. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/app.py +0 -0
  432. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/appshell.py +0 -0
  433. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/avatar.py +0 -0
  434. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/boolean_controls.py +0 -0
  435. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/button.py +0 -0
  436. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/calendar.py +0 -0
  437. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/card.py +0 -0
  438. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/carousel.py +0 -0
  439. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/chart.py +0 -0
  440. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/codeeditor.py +0 -0
  441. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/contextmenu.py +0 -0
  442. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/datatable.py +0 -0
  443. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/datefield.py +0 -0
  444. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/divider.py +0 -0
  445. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/expander.py +0 -0
  446. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/form.py +0 -0
  447. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/gallery.py +0 -0
  448. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/gauge.py +0 -0
  449. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/grid.py +0 -0
  450. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/groupbox.py +0 -0
  451. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/label.py +0 -0
  452. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/listview.py +0 -0
  453. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/numberfield.py +0 -0
  454. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/pagestack.py +0 -0
  455. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/picture.py +0 -0
  456. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/progressbar.py +0 -0
  457. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/radio_variants.py +0 -0
  458. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/scrollbar.py +0 -0
  459. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/scrollview.py +0 -0
  460. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/selectbutton.py +0 -0
  461. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/sidebar_toggle.py +0 -0
  462. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/sizegrip.py +0 -0
  463. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/slider.py +0 -0
  464. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/spinbox.py +0 -0
  465. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/spinnerfield.py +0 -0
  466. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/splash.py +0 -0
  467. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/splitview.py +0 -0
  468. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/stacks.py +0 -0
  469. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/tabs.py +0 -0
  470. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/textarea.py +0 -0
  471. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/theme_toggle.py +0 -0
  472. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/timefield.py +0 -0
  473. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/toast.py +0 -0
  474. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/tooltip.py +0 -0
  475. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/tree.py +0 -0
  476. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/types.py +0 -0
  477. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack/widgets/window.py +0 -0
  478. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack.egg-info/dependency_links.txt +0 -0
  479. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack.egg-info/entry_points.txt +0 -0
  480. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack.egg-info/requires.txt +0 -0
  481. {bootstack-0.1.5 → bootstack-0.1.7}/src/bootstack.egg-info/top_level.txt +0 -0
  482. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_dialog_anchor.py +0 -0
  483. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_events_doc_coverage.py +0 -0
  484. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_hot_reload.py +0 -0
  485. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_images.py +0 -0
  486. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_images_gui.py +0 -0
  487. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_navmodel.py +0 -0
  488. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_on_color_contrast.py +0 -0
  489. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_public_surface.py +0 -0
  490. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_store.py +0 -0
  491. {bootstack-0.1.5 → bootstack-0.1.7}/tests/test_theme_from_existing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bootstack
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate.
5
5
  Author-email: Israel Dryer <israel.dryer@gmail.com>
6
6
  License-Expression: MIT
@@ -66,10 +66,9 @@ Dynamic: license-file
66
66
 
67
67
  ### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
68
68
 
69
- bootstack is built on Tk, so the install is light, there's no Qt license, and
70
- your app ships as a small standalone executable. But you'll never write a
71
- `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state,
72
- and a CLI that scaffolds and packages the whole thing.
69
+ bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
70
+ write a `StringVar` or call `.pack()` the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
71
+ packages the whole thing.
73
72
 
74
73
  <p align="center">
75
74
  <picture>
@@ -13,10 +13,9 @@
13
13
 
14
14
  ### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
15
15
 
16
- bootstack is built on Tk, so the install is light, there's no Qt license, and
17
- your app ships as a small standalone executable. But you'll never write a
18
- `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state,
19
- and a CLI that scaffolds and packages the whole thing.
16
+ bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
17
+ write a `StringVar` or call `.pack()` the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
18
+ packages the whole thing.
20
19
 
21
20
  <p align="center">
22
21
  <picture>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "bootstack"
7
- version = "0.1.5"
7
+ version = "0.1.7"
8
8
  description = "Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -114,7 +114,7 @@ where = ["src"]
114
114
  ]
115
115
 
116
116
  [tool.bumpversion]
117
- current_version = "0.1.5"
117
+ current_version = "0.1.7"
118
118
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)((?P<pre>a|b|rc)(?P<pre_n>\\d+))?"
119
119
  serialize = [
120
120
  "{major}.{minor}.{patch}{pre}{pre_n}",
@@ -0,0 +1,152 @@
1
+ """Scroll-gesture normalization across Tk 8.6 and Tk 9.
2
+
3
+ Tk 9 changed the scroll-event contract in two ways that break code written
4
+ against Tk 8.6:
5
+
6
+ * A precise-delta device — every Apple trackpad, Magic Mouse and Magic
7
+ Trackpad — now fires `<TouchpadScroll>` and **never** `<MouseWheel>`.
8
+ Binding only `<MouseWheel>` leaves those devices completely dead.
9
+ * Wheel deltas are normalized to multiples of 120 on every windowing
10
+ system. On Aqua a notch used to report 1; it now reports 120.
11
+
12
+ On X11, `<Button-4>`/`<Button-5>` are no longer delivered to scripts at
13
+ all — Tk translates them to `<MouseWheel>` internally.
14
+
15
+ This module hides all of that behind one vocabulary. Callers ask for the
16
+ sequences to bind, then convert an incoming event to either wheel
17
+ *notches* or precise *pixels*.
18
+
19
+ Sign convention (matching Tk's own bindings): a positive value means the
20
+ wheel rolled away from the user, i.e. the view should move toward the
21
+ *start* of the content. Callers therefore negate to get a scroll amount.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import tkinter as tk
27
+
28
+ TOUCHPAD_SCROLL = "<TouchpadScroll>"
29
+ """Sequence for precise-delta scroll gestures. Tk 8.7+ only."""
30
+
31
+ _WHEEL_UNITS = 120.0
32
+ """Delta reported for one wheel notch on a normalized (Tk 8.7+) build."""
33
+
34
+ _TOUCHPAD_TK = 8.7
35
+ """First Tk release generating `<TouchpadScroll>` and normalized deltas."""
36
+
37
+
38
+ def _windowingsystem(widget: tk.Misc) -> str:
39
+ try:
40
+ return str(widget.tk.call("tk", "windowingsystem")).lower()
41
+ except Exception:
42
+ return ""
43
+
44
+
45
+ def has_touchpad_scroll() -> bool:
46
+ """Whether the running Tk generates `<TouchpadScroll>` events."""
47
+ return tk.TkVersion >= _TOUCHPAD_TK
48
+
49
+
50
+ def uses_x11_buttons(widget: tk.Misc) -> bool:
51
+ """Whether wheel input arrives as `<Button-4>`/`<Button-5>` here.
52
+
53
+ True only on legacy X11 builds. Tk 8.7+ translates those buttons to
54
+ `<MouseWheel>` and stops delivering them to scripts.
55
+ """
56
+ return not has_touchpad_scroll() and _windowingsystem(widget) == "x11"
57
+
58
+
59
+ def wheel_sequences(widget: tk.Misc, *, shift: bool = False) -> tuple[str, ...]:
60
+ """Event sequences carrying wheel notches for `widget`.
61
+
62
+ Args:
63
+ widget: Any widget; used to resolve the windowing system.
64
+ shift: Request the horizontal (Shift-modified) sequences.
65
+ """
66
+ if uses_x11_buttons(widget):
67
+ if shift:
68
+ return ("<Shift-Button-4>", "<Shift-Button-5>")
69
+ return ("<Button-4>", "<Button-5>")
70
+ return ("<Shift-MouseWheel>",) if shift else ("<MouseWheel>",)
71
+
72
+
73
+ def wheel_notches(widget: tk.Misc, event: tk.Event) -> float:
74
+ """Signed notch count for a wheel event.
75
+
76
+ Returns a positive value when the wheel rolled away from the user.
77
+ One physical notch is 1.0 on every platform and Tk version.
78
+ """
79
+ num = getattr(event, "num", None)
80
+ if num in (4, 6):
81
+ return 1.0
82
+ if num in (5, 7):
83
+ return -1.0
84
+
85
+ try:
86
+ delta = float(event.delta)
87
+ except (AttributeError, TypeError, ValueError):
88
+ return 0.0
89
+ if not delta:
90
+ return 0.0
91
+
92
+ # Tk 8.6 on Aqua reported one notch as 1; everything else uses 120.
93
+ if not has_touchpad_scroll() and _windowingsystem(widget) == "aqua":
94
+ return delta
95
+ return delta / _WHEEL_UNITS
96
+
97
+
98
+ def precise_deltas(event: tk.Event) -> tuple[int, int]:
99
+ """Unpack a `<TouchpadScroll>` event into `(dx, dy)` pixels.
100
+
101
+ Tk packs both axes into the delta field as two signed 16-bit values.
102
+ This mirrors Tcl's `::tk::PreciseScrollDeltas`.
103
+ """
104
+ try:
105
+ packed = int(event.delta)
106
+ except (AttributeError, TypeError, ValueError):
107
+ return (0, 0)
108
+ dx = packed >> 16
109
+ low = packed & 0xFFFF
110
+ dy = low if low < 0x8000 else low - 0x10000
111
+ return (dx, dy)
112
+
113
+
114
+ def scale_num(widget: tk.Misc, value: float) -> int:
115
+ """Scale a pixel amount for display density, like `::tk::ScaleNum`."""
116
+ try:
117
+ scaling = float(widget.tk.call("tk", "scaling"))
118
+ except Exception:
119
+ scaling = 1.0
120
+ return round(value * scaling * 0.75)
121
+
122
+
123
+ class PixelAccumulator:
124
+ """Converts precise pixel deltas into whole discrete scroll steps.
125
+
126
+ A touchpad reports small deltas roughly sixty times a second. Widgets
127
+ that scroll by rows or canvas units cannot act on each one, so the
128
+ fractional remainder is carried forward until it adds up to a step.
129
+ """
130
+
131
+ __slots__ = ("_x", "_y")
132
+
133
+ def __init__(self) -> None:
134
+ self._x = 0.0
135
+ self._y = 0.0
136
+
137
+ def add(self, dx: float, dy: float, step_x: float, step_y: float) -> tuple[int, int]:
138
+ """Add a delta and return the whole `(x, y)` steps it completes."""
139
+ step_x = step_x if step_x and step_x > 0 else 1.0
140
+ step_y = step_y if step_y and step_y > 0 else 1.0
141
+ self._x += dx
142
+ self._y += dy
143
+ out_x = int(self._x / step_x)
144
+ out_y = int(self._y / step_y)
145
+ self._x -= out_x * step_x
146
+ self._y -= out_y * step_y
147
+ return (out_x, out_y)
148
+
149
+ def reset(self) -> None:
150
+ """Drop any carried remainder."""
151
+ self._x = 0.0
152
+ self._y = 0.0
@@ -12,6 +12,7 @@ import locale
12
12
  import re
13
13
  import warnings
14
14
  from dataclasses import dataclass
15
+ from decimal import Decimal
15
16
  from datetime import date, datetime, time
16
17
  from typing import Any, Literal, Mapping, Optional, TypedDict, Union, cast
17
18
 
@@ -148,7 +149,10 @@ SUFFIXES_EN = (
148
149
  Suffix(1_000, "K"),
149
150
  )
150
151
  _SUFFIX_TO_FACTOR = {"K": 1_000, "M": 1_000_000, "B": 1_000_000_000, "T": 1_000_000_000_000}
151
- _NUMBERISH = (int, float)
152
+ # Values formatted as numbers. `Decimal` is passed to Babel as-is rather than
153
+ # coerced: Babel formats it natively, and going through `float` would round
154
+ # away the precision a caller chose `Decimal` to keep.
155
+ _NUMBERISH = (int, float, Decimal)
152
156
 
153
157
 
154
158
  def _locale_to_languages(loc: str) -> list[str]:
@@ -208,7 +212,7 @@ class IntlFormatter:
208
212
  if value is None:
209
213
  return ""
210
214
  if isinstance(value, _NUMBERISH):
211
- return self._format_number(float(value), spec)
215
+ return self._format_number(value if isinstance(value, Decimal) else float(value), spec)
212
216
  if isinstance(value, datetime):
213
217
  return self._format_datetime(value, spec)
214
218
  if isinstance(value, date):
@@ -238,7 +242,7 @@ class IntlFormatter:
238
242
  return self._parse_temporal(s, spec)
239
243
 
240
244
  # ---------- Numbers ----------
241
- def _format_number(self, x: float, spec: LooseSpec) -> str:
245
+ def _format_number(self, x: float | Decimal, spec: LooseSpec) -> str:
242
246
  opt = self._normalize_number_spec(spec)
243
247
 
244
248
  if opt["type"] == "custom":
@@ -33,6 +33,16 @@ def rule_applies_to_kind(rule_type: str, kind: str) -> bool:
33
33
  return True
34
34
 
35
35
 
36
+ def _is_empty(value: object) -> bool:
37
+ """Whether a field holds nothing, for rules that only shape a value.
38
+
39
+ Matches the emptiness test `range` uses: `None` or the empty string. A
40
+ whitespace-only entry is real input — `stringLength` should still measure
41
+ it — so only `required` treats blank text as absent.
42
+ """
43
+ return value is None or value == ""
44
+
45
+
36
46
  def _as_text(value: object) -> str:
37
47
  """Coerce a value to text for the string rules.
38
48
 
@@ -104,7 +114,15 @@ class ValidationRule:
104
114
  # Everything else is valid (non-empty string, number, date, etc.)
105
115
  return ValidationResult(True, "")
106
116
 
107
- elif self.type == "email":
117
+ # A rule other than `required` describes what a value must look like,
118
+ # not that one must be present. An untouched optional field has nothing
119
+ # to check, so it passes — otherwise leaving it blank would block a
120
+ # submit with no way forward. Use `required` for presence, the same
121
+ # contract `range` states below.
122
+ if self.type in TEXT_RULES and _is_empty(value):
123
+ return ValidationResult(True, "")
124
+
125
+ if self.type == "email":
108
126
  if not re.match(r"[^@]+@[^@]+\.[^@]+", _as_text(value)):
109
127
  return ValidationResult(False, msg)
110
128
  elif self.type == "stringLength":
@@ -119,7 +137,7 @@ class ValidationRule:
119
137
  elif self.type == "range":
120
138
  # Bounds on an ordered value (number/date/time). An empty field is
121
139
  # not out of range — use 'required' for presence.
122
- if value is None or value == "":
140
+ if _is_empty(value):
123
141
  return ValidationResult(True)
124
142
  lo = self.params.get("min")
125
143
  hi = self.params.get("max")
@@ -355,6 +355,7 @@ class PublicWidgetBase:
355
355
  options.update(_flex_child_opts(self, kwargs))
356
356
  master.add_child(self._internal, options, index=index)
357
357
  placement.options = options
358
+ self._recolor_on_attach()
358
359
  return
359
360
 
360
361
  if kwargs:
@@ -376,6 +377,29 @@ class PublicWidgetBase:
376
377
  options.update({k: v for k, v in kwargs.items() if k in PLACE_KEYS})
377
378
  self._internal.place(in_=master, **options)
378
379
  placement.options = options
380
+ self._recolor_on_attach()
381
+
382
+ def _recolor_on_attach(self) -> None:
383
+ """Recolor after a theme change that arrived while detached.
384
+
385
+ The theme walk skips off-screen widgets, so a widget detached across a
386
+ theme change comes back carrying the old palette. Attaching is the
387
+ genuine "now visible" trigger, matching PageStack navigation and
388
+ Expander expansion. Deferred to idle so the widget is mapped first.
389
+ """
390
+ widget = self._internal
391
+
392
+ def _recolor() -> None:
393
+ from bootstack.style.style import get_style
394
+ try:
395
+ get_style().apply_theme_walk(widget, only_stale=True)
396
+ except tkinter.TclError:
397
+ pass # destroyed between attach and the idle callback
398
+
399
+ try:
400
+ widget.after_idle(_recolor)
401
+ except tkinter.TclError:
402
+ pass
379
403
 
380
404
  @overload
381
405
  def on_destroy(self) -> "Stream": ...
@@ -0,0 +1,85 @@
1
+ """Merging a caller's options dict over framework-built keyword arguments.
2
+
3
+ Several widgets accept a bag of options aimed at a widget they build for you —
4
+ `Form`'s `editor_options`, `MenuButton`'s `menu_options`, the keyword
5
+ passthrough on `ButtonGroup.add` / `RadioGroup.add` / `Toolbar.add_widget`.
6
+ Those bags name the built widget's own public keyword arguments, so a caller
7
+ may name a parameter the framework also fills.
8
+
9
+ Splatting both into one call raises `TypeError: got multiple values for
10
+ keyword argument`, which names an internal class the caller never wrote.
11
+ `merge_kwargs` gives that meeting point one rule instead:
12
+
13
+ - The caller's options WIN over the framework's defaults. Naming a parameter
14
+ the framework also fills is how you override it.
15
+ - A short list of keys is structural — the widget cannot do its job if they
16
+ are replaced (it would be parented elsewhere, or lose the command that emits
17
+ its events). Supplying one raises `BootstackError` naming the API you called
18
+ and what to use instead.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ from typing import Any, Mapping
23
+
24
+ from bootstack.errors import BootstackError
25
+
26
+
27
+ def reject_reserved(
28
+ user: Mapping[str, Any] | None,
29
+ reserved: Mapping[str, str] | None,
30
+ context: str,
31
+ ) -> None:
32
+ """Raise if the caller set a key the framework owns.
33
+
34
+ Args:
35
+ user: The caller's options. `None` is treated as empty.
36
+ reserved: Structural keys the caller may not set, mapped to the
37
+ guidance shown when they try.
38
+ context: The API the caller invoked, e.g. `'ButtonGroup.add()'`.
39
+
40
+ Raises:
41
+ BootstackError: If `user` contains a key listed in `reserved`.
42
+ """
43
+ if not user or not reserved:
44
+ return
45
+ for key in user:
46
+ if key in reserved:
47
+ raise BootstackError(f"{context} does not accept {key}= — {reserved[key]}")
48
+
49
+
50
+ def merge_kwargs(
51
+ defaults: Mapping[str, Any],
52
+ user: Mapping[str, Any] | None,
53
+ *,
54
+ reserved: Mapping[str, str] | None = None,
55
+ context: str = "this call",
56
+ ) -> dict[str, Any]:
57
+ """Merge a caller's options over framework-built keyword arguments.
58
+
59
+ Args:
60
+ defaults: Keyword arguments the framework derived for the call. Any
61
+ key also present in `user` is overridden.
62
+ reserved: Structural keys the caller may not set, mapped to the
63
+ guidance shown when they try.
64
+ context: The API the caller invoked, used in the error message.
65
+ user: The caller's options. `None` is treated as empty.
66
+
67
+ Returns:
68
+ The merged keyword arguments.
69
+
70
+ Raises:
71
+ BootstackError: If `user` contains a key listed in `reserved`.
72
+ """
73
+ merged = dict(defaults)
74
+ if not user:
75
+ return merged
76
+ reject_reserved(user, reserved, context)
77
+ merged.update(user)
78
+ return merged
79
+
80
+
81
+ # Structural keys a bar's widget-options passthrough may not set — a toolbar or
82
+ # status bar places every widget it builds.
83
+ RESERVED_BAR_KWARGS = {
84
+ 'parent': 'the bar places the widgets it builds.',
85
+ }
@@ -4,6 +4,13 @@ from typing import Any
4
4
 
5
5
  from bootstack.widgets._core.options import OptionRecord, record_to_dict, option_localize
6
6
 
7
+ # Structural keys a per-option kwargs passthrough may not set — the group owns
8
+ # each option's identity and tracks its own selection.
9
+ RESERVED_OPTION_KWARGS = {
10
+ 'text': 'set the caption with the label argument.',
11
+ 'variable': 'the group tracks its own selection.',
12
+ }
13
+
7
14
 
8
15
  class SelectionGroupMixin:
9
16
  """Shared item-management surface for the option-group widgets.
@@ -6,10 +6,14 @@ wheel support.
6
6
  """
7
7
 
8
8
 
9
+ from bootstack._runtime import wheel
9
10
  from bootstack.events import ChangeEvent
10
11
  from bootstack.widgets._impl.mixins.configure_mixin import configure_delegate
11
12
  from bootstack.widgets._impl._parts.textentry_part import TextEntryPart
12
13
 
14
+ _TOUCHPAD_STEP_PX = 40
15
+ """Trackpad travel, in pixels, that advances a stepper by one increment."""
16
+
13
17
 
14
18
  class NumberEntryPart(TextEntryPart):
15
19
  """Numeric entry widget with stepping and bounds validation.
@@ -111,12 +115,13 @@ class NumberEntryPart(TextEntryPart):
111
115
  self.bind('<Up>', self._handle_up_key, add=True)
112
116
  self.bind('<Down>', self._handle_down_key, add=True)
113
117
 
114
- # Bind mouse wheel (Windows/macOS)
115
- self.bind('<MouseWheel>', self._handle_mouse_wheel, add=True)
116
-
117
- # Bind mouse wheel (Linux/X11)
118
- self.bind('<Button-4>', self._handle_wheel_up, add=True)
119
- self.bind('<Button-5>', self._handle_wheel_down, add=True)
118
+ # Bind wheel stepping. A wheel arrives as <MouseWheel> everywhere
119
+ # except legacy X11; a trackpad fires <TouchpadScroll> on Tk 8.7+.
120
+ for seq in wheel.wheel_sequences(self):
121
+ self.bind(seq, self._handle_mouse_wheel, add=True)
122
+ if wheel.has_touchpad_scroll():
123
+ self._touchpad = wheel.PixelAccumulator()
124
+ self.bind(wheel.TOUCHPAD_SCROLL, self._handle_touchpad_scroll, add=True)
120
125
 
121
126
  # Listen for increment/decrement events to invoke step
122
127
  self.bind('<<Increment>>', self._handle_increment_event, add=True)
@@ -137,33 +142,28 @@ class NumberEntryPart(TextEntryPart):
137
142
  return 'break' # Prevent default behavior
138
143
 
139
144
  def _handle_mouse_wheel(self, event):
140
- """Handle mouse wheel on Windows/macOS."""
145
+ """Handle a wheel notch by stepping the value once."""
141
146
  if not self._is_interactive():
142
147
  return 'break'
143
- try:
144
- delta = int(event.delta)
145
- except (AttributeError, ValueError):
146
- delta = 0
147
-
148
- if delta != 0:
149
- if delta > 0:
150
- self.event_generate('<<Increment>>', data={'value': self._value})
151
- else:
152
- self.event_generate('<<Decrement>>', data={'value': self._value})
148
+ notches = wheel.wheel_notches(self, event)
149
+ if notches:
150
+ name = '<<Increment>>' if notches > 0 else '<<Decrement>>'
151
+ self.event_generate(name, data={'value': self._value})
153
152
  return 'break'
154
153
 
155
- def _handle_wheel_up(self, event):
156
- """Handle mouse wheel up on Linux/X11."""
157
- if not self._is_interactive():
158
- return 'break'
159
- self.event_generate('<<Increment>>', data={'value': self._value})
160
- return 'break'
154
+ def _handle_touchpad_scroll(self, event):
155
+ """Step once per `_TOUCHPAD_STEP_PX` of trackpad travel.
161
156
 
162
- def _handle_wheel_down(self, event):
163
- """Handle mouse wheel down on Linux/X11."""
157
+ A trackpad reports around sixty events a second; stepping on each
158
+ one would run the value away from the user.
159
+ """
164
160
  if not self._is_interactive():
165
161
  return 'break'
166
- self.event_generate('<<Decrement>>', data={'value': self._value})
162
+ _dx, dy = wheel.precise_deltas(event)
163
+ _sx, steps = self._touchpad.add(0, dy, 1, _TOUCHPAD_STEP_PX)
164
+ name = '<<Increment>>' if steps > 0 else '<<Decrement>>'
165
+ for _ in range(abs(steps)):
166
+ self.event_generate(name, data={'value': self._value})
167
167
  return 'break'
168
168
 
169
169
  def _handle_increment_event(self, event):
@@ -272,9 +272,10 @@ class NumberEntryPart(TextEntryPart):
272
272
  A plain numeric field parses to a string when no display format is set,
273
273
  so coerce it the same way the public value does — validation rules and a
274
274
  `custom` func receive a real `int`/`float` (or `None` for empty/invalid
275
- input), never the display string.
275
+ input), never the display string. A visible placeholder is not input,
276
+ so it reads as empty here — same rule as the text field this overrides.
276
277
  """
277
- text = self.get()
278
+ text = '' if self._showing_placeholder else self.get()
278
279
  try:
279
280
  raw = self._parse_or_none(text)
280
281
  except Exception:
@@ -288,11 +288,17 @@ class TextEntryPart(ValidationMixin, Entry):
288
288
  last-committed value. This keeps a manual `validate()`, the automatic
289
289
  blur/key validation, and a form-level validate in agreement on the same
290
290
  live, typed input.
291
+
292
+ A visible placeholder is not input. It is inserted into the entry to
293
+ render it, so reading the raw text would hand the placeholder string to
294
+ the rules and `required` would pass on an untouched field — the field
295
+ reads as empty here, exactly as it does through `value`.
291
296
  """
297
+ text = "" if self._showing_placeholder else self.get()
292
298
  try:
293
- return self._parse_or_none(self.get())
299
+ return self._parse_or_none(text)
294
300
  except Exception:
295
- return self.get()
301
+ return text
296
302
 
297
303
  def text(self, value=None):
298
304
  """Get or set the raw display text without committing.
@@ -7,8 +7,18 @@ from typing_extensions import Unpack
7
7
  from bootstack.widgets._impl.composites.contextmenu import ContextMenu, ContextMenuItem, ContextMenuItemResult
8
8
  from bootstack.widgets._impl.primitives._menubutton import MenuButton
9
9
  from bootstack.widgets._impl.mixins import configure_delegate
10
+ from bootstack.widgets._core.kwargs import merge_kwargs
10
11
  from bootstack.widgets.types import Master, StyledKwargs, CompoundMode, WidgetState, WidgetDensity
11
12
 
13
+ # Structural keys a menu_options bag may not set — the button owns the menu's
14
+ # contents and the callback that emits its selection events.
15
+ _RESERVED_MENU_OPTIONS = {
16
+ 'items': 'pass the menu items to the button itself.',
17
+ 'command': "use the button's on_select event.",
18
+ 'trigger': 'the button opens its own menu when clicked.',
19
+ 'target': 'the menu belongs to the button that opens it.',
20
+ }
21
+
12
22
  if TYPE_CHECKING:
13
23
  from bootstack.signals import Signal
14
24
 
@@ -122,10 +132,13 @@ class DropdownButton(MenuButton):
122
132
  "offset": (offset_x, 0),
123
133
  "density": density,
124
134
  }
125
- options.update(self._popdown_options)
126
135
  # DropdownButton manages its own activation (left-click, Return/
127
136
  # KP_Enter via show_menu), so opt out of ContextMenu's auto-trigger.
128
- cm = ContextMenu(self, target=self, items=self._items, trigger=None, command=self._command, **options)
137
+ options["trigger"] = None
138
+ options = merge_kwargs(options, self._popdown_options,
139
+ reserved=_RESERVED_MENU_OPTIONS,
140
+ context='MenuButton menu_options')
141
+ cm = ContextMenu(self, target=self, items=self._items, command=self._command, **options)
129
142
  return cm
130
143
 
131
144
  @property
@@ -273,8 +273,13 @@ class Field(EntryMixin, Frame):
273
273
  self._entry.value(value)
274
274
 
275
275
  def get(self) -> str:
276
- """Return the raw text from the underlying entry widget."""
277
- return self._entry.get()
276
+ """Return the display text from the underlying entry widget.
277
+
278
+ Reads the entry's own text rather than its raw contents, so a field
279
+ showing only its placeholder reports an empty string — `text` and
280
+ `value` are a pair and must agree on whether the field is empty.
281
+ """
282
+ return self._entry.text()
278
283
 
279
284
  @property
280
285
  def entry_widget(self) -> EntryWidget: