sg-widgets-qt 0.1.0__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 (537) hide show
  1. sg_widgets_qt-0.1.0/.gitignore +12 -0
  2. sg_widgets_qt-0.1.0/CHANGELOG.md +30 -0
  3. sg_widgets_qt-0.1.0/LICENSE +21 -0
  4. sg_widgets_qt-0.1.0/PKG-INFO +137 -0
  5. sg_widgets_qt-0.1.0/README.md +106 -0
  6. sg_widgets_qt-0.1.0/docs/DESIGN.md +72 -0
  7. sg_widgets_qt-0.1.0/docs/README.md +74 -0
  8. sg_widgets_qt-0.1.0/docs/core/client.md +150 -0
  9. sg_widgets_qt-0.1.0/docs/core/context.md +86 -0
  10. sg_widgets_qt-0.1.0/docs/core/index.md +26 -0
  11. sg_widgets_qt-0.1.0/docs/design-rules.md +234 -0
  12. sg_widgets_qt-0.1.0/docs/porting-conventions.md +130 -0
  13. sg_widgets_qt-0.1.0/docs/screenshots/entity-grid-light.png +0 -0
  14. sg_widgets_qt-0.1.0/docs/screenshots/entity-multi-picker-light.png +0 -0
  15. sg_widgets_qt-0.1.0/docs/screenshots/entity-table-dark.png +0 -0
  16. sg_widgets_qt-0.1.0/docs/screenshots/entity-table-light.png +0 -0
  17. sg_widgets_qt-0.1.0/docs/screenshots/filter-editor-light.png +0 -0
  18. sg_widgets_qt-0.1.0/docs/screenshots/global-search-light.png +0 -0
  19. sg_widgets_qt-0.1.0/docs/screenshots/status-picker-light.png +0 -0
  20. sg_widgets_qt-0.1.0/docs/start/install.md +52 -0
  21. sg_widgets_qt-0.1.0/docs/start/introduction.md +23 -0
  22. sg_widgets_qt-0.1.0/docs/widgets/_index.json +79 -0
  23. sg_widgets_qt-0.1.0/docs/widgets/checkbox-editor.md +53 -0
  24. sg_widgets_qt-0.1.0/docs/widgets/checkbox-editor.props.json +100 -0
  25. sg_widgets_qt-0.1.0/docs/widgets/collection-control.md +124 -0
  26. sg_widgets_qt-0.1.0/docs/widgets/collection-control.props.json +85 -0
  27. sg_widgets_qt-0.1.0/docs/widgets/collection-footer.props.json +45 -0
  28. sg_widgets_qt-0.1.0/docs/widgets/collection-source.props.json +55 -0
  29. sg_widgets_qt-0.1.0/docs/widgets/color-editor.md +69 -0
  30. sg_widgets_qt-0.1.0/docs/widgets/color-editor.props.json +113 -0
  31. sg_widgets_qt-0.1.0/docs/widgets/column-picker.md +100 -0
  32. sg_widgets_qt-0.1.0/docs/widgets/column-picker.props.json +261 -0
  33. sg_widgets_qt-0.1.0/docs/widgets/context-selector.md +71 -0
  34. sg_widgets_qt-0.1.0/docs/widgets/context-selector.props.json +190 -0
  35. sg_widgets_qt-0.1.0/docs/widgets/date-editor.md +78 -0
  36. sg_widgets_qt-0.1.0/docs/widgets/date-editor.props.json +128 -0
  37. sg_widgets_qt-0.1.0/docs/widgets/date-time-editor.md +72 -0
  38. sg_widgets_qt-0.1.0/docs/widgets/date-time-editor.props.json +149 -0
  39. sg_widgets_qt-0.1.0/docs/widgets/editor-calendar.props.json +9 -0
  40. sg_widgets_qt-0.1.0/docs/widgets/entity-card.md +123 -0
  41. sg_widgets_qt-0.1.0/docs/widgets/entity-card.props.json +202 -0
  42. sg_widgets_qt-0.1.0/docs/widgets/entity-chip.md +90 -0
  43. sg_widgets_qt-0.1.0/docs/widgets/entity-chip.props.json +111 -0
  44. sg_widgets_qt-0.1.0/docs/widgets/entity-fields.props.json +9 -0
  45. sg_widgets_qt-0.1.0/docs/widgets/entity-glyphs.props.json +9 -0
  46. sg_widgets_qt-0.1.0/docs/widgets/entity-grid.md +92 -0
  47. sg_widgets_qt-0.1.0/docs/widgets/entity-grid.props.json +258 -0
  48. sg_widgets_qt-0.1.0/docs/widgets/entity-multi-picker.md +77 -0
  49. sg_widgets_qt-0.1.0/docs/widgets/entity-multi-picker.props.json +340 -0
  50. sg_widgets_qt-0.1.0/docs/widgets/entity-picker.md +103 -0
  51. sg_widgets_qt-0.1.0/docs/widgets/entity-picker.props.json +296 -0
  52. sg_widgets_qt-0.1.0/docs/widgets/entity-table.md +197 -0
  53. sg_widgets_qt-0.1.0/docs/widgets/entity-table.props.json +325 -0
  54. sg_widgets_qt-0.1.0/docs/widgets/entity-tree.md +118 -0
  55. sg_widgets_qt-0.1.0/docs/widgets/entity-tree.props.json +293 -0
  56. sg_widgets_qt-0.1.0/docs/widgets/entity-type-multi-picker.md +78 -0
  57. sg_widgets_qt-0.1.0/docs/widgets/entity-type-multi-picker.props.json +222 -0
  58. sg_widgets_qt-0.1.0/docs/widgets/entity-type-picker.md +74 -0
  59. sg_widgets_qt-0.1.0/docs/widgets/entity-type-picker.props.json +194 -0
  60. sg_widgets_qt-0.1.0/docs/widgets/field-editor.md +110 -0
  61. sg_widgets_qt-0.1.0/docs/widgets/field-editor.props.json +221 -0
  62. sg_widgets_qt-0.1.0/docs/widgets/field-error.props.json +24 -0
  63. sg_widgets_qt-0.1.0/docs/widgets/field-picker.md +109 -0
  64. sg_widgets_qt-0.1.0/docs/widgets/field-picker.props.json +237 -0
  65. sg_widgets_qt-0.1.0/docs/widgets/field-value.md +92 -0
  66. sg_widgets_qt-0.1.0/docs/widgets/field-value.props.json +145 -0
  67. sg_widgets_qt-0.1.0/docs/widgets/filter-bar.md +108 -0
  68. sg_widgets_qt-0.1.0/docs/widgets/filter-bar.props.json +121 -0
  69. sg_widgets_qt-0.1.0/docs/widgets/filter-dialog.md +50 -0
  70. sg_widgets_qt-0.1.0/docs/widgets/filter-dialog.props.json +113 -0
  71. sg_widgets_qt-0.1.0/docs/widgets/filter-editor.md +185 -0
  72. sg_widgets_qt-0.1.0/docs/widgets/filter-editor.props.json +118 -0
  73. sg_widgets_qt-0.1.0/docs/widgets/global-search.md +78 -0
  74. sg_widgets_qt-0.1.0/docs/widgets/global-search.props.json +218 -0
  75. sg_widgets_qt-0.1.0/docs/widgets/grouped-list.md +109 -0
  76. sg_widgets_qt-0.1.0/docs/widgets/grouped-list.props.json +300 -0
  77. sg_widgets_qt-0.1.0/docs/widgets/hierarchical-search.md +79 -0
  78. sg_widgets_qt-0.1.0/docs/widgets/hierarchical-search.props.json +161 -0
  79. sg_widgets_qt-0.1.0/docs/widgets/index.md +51 -0
  80. sg_widgets_qt-0.1.0/docs/widgets/list-multi-picker.md +93 -0
  81. sg_widgets_qt-0.1.0/docs/widgets/list-multi-picker.props.json +289 -0
  82. sg_widgets_qt-0.1.0/docs/widgets/list-multi-select.md +15 -0
  83. sg_widgets_qt-0.1.0/docs/widgets/list-picker.md +96 -0
  84. sg_widgets_qt-0.1.0/docs/widgets/list-picker.props.json +294 -0
  85. sg_widgets_qt-0.1.0/docs/widgets/list-select.md +15 -0
  86. sg_widgets_qt-0.1.0/docs/widgets/match-text.md +68 -0
  87. sg_widgets_qt-0.1.0/docs/widgets/match-text.props.json +24 -0
  88. sg_widgets_qt-0.1.0/docs/widgets/number-editor.md +107 -0
  89. sg_widgets_qt-0.1.0/docs/widgets/number-editor.props.json +195 -0
  90. sg_widgets_qt-0.1.0/docs/widgets/picker-control.md +203 -0
  91. sg_widgets_qt-0.1.0/docs/widgets/picker-control.props.json +357 -0
  92. sg_widgets_qt-0.1.0/docs/widgets/picker-row.props.json +125 -0
  93. sg_widgets_qt-0.1.0/docs/widgets/project-multi-picker.md +71 -0
  94. sg_widgets_qt-0.1.0/docs/widgets/project-multi-picker.props.json +347 -0
  95. sg_widgets_qt-0.1.0/docs/widgets/project-picker.md +66 -0
  96. sg_widgets_qt-0.1.0/docs/widgets/project-picker.props.json +331 -0
  97. sg_widgets_qt-0.1.0/docs/widgets/search-control.md +126 -0
  98. sg_widgets_qt-0.1.0/docs/widgets/search-control.props.json +200 -0
  99. sg_widgets_qt-0.1.0/docs/widgets/search-skeleton.props.json +38 -0
  100. sg_widgets_qt-0.1.0/docs/widgets/sort-picker.md +81 -0
  101. sg_widgets_qt-0.1.0/docs/widgets/sort-picker.props.json +129 -0
  102. sg_widgets_qt-0.1.0/docs/widgets/state-line.md +69 -0
  103. sg_widgets_qt-0.1.0/docs/widgets/state-line.props.json +45 -0
  104. sg_widgets_qt-0.1.0/docs/widgets/status-badge.md +101 -0
  105. sg_widgets_qt-0.1.0/docs/widgets/status-badge.props.json +96 -0
  106. sg_widgets_qt-0.1.0/docs/widgets/status-glyph.props.json +38 -0
  107. sg_widgets_qt-0.1.0/docs/widgets/status-multi-picker.md +107 -0
  108. sg_widgets_qt-0.1.0/docs/widgets/status-multi-picker.props.json +246 -0
  109. sg_widgets_qt-0.1.0/docs/widgets/status-picker.md +99 -0
  110. sg_widgets_qt-0.1.0/docs/widgets/status-picker.props.json +186 -0
  111. sg_widgets_qt-0.1.0/docs/widgets/text-editor.md +48 -0
  112. sg_widgets_qt-0.1.0/docs/widgets/text-editor.props.json +113 -0
  113. sg_widgets_qt-0.1.0/docs/widgets/thumbnail.md +64 -0
  114. sg_widgets_qt-0.1.0/docs/widgets/thumbnail.props.json +52 -0
  115. sg_widgets_qt-0.1.0/docs/widgets/url-editor.md +57 -0
  116. sg_widgets_qt-0.1.0/docs/widgets/url-editor.props.json +107 -0
  117. sg_widgets_qt-0.1.0/docs/widgets/user-avatar.md +65 -0
  118. sg_widgets_qt-0.1.0/docs/widgets/user-avatar.props.json +52 -0
  119. sg_widgets_qt-0.1.0/docs/widgets/user-multi-picker.md +81 -0
  120. sg_widgets_qt-0.1.0/docs/widgets/user-multi-picker.props.json +353 -0
  121. sg_widgets_qt-0.1.0/docs/widgets/user-picker.md +78 -0
  122. sg_widgets_qt-0.1.0/docs/widgets/user-picker.props.json +337 -0
  123. sg_widgets_qt-0.1.0/docs/widgets/value-editor.md +156 -0
  124. sg_widgets_qt-0.1.0/docs/widgets/value-editor.props.json +52 -0
  125. sg_widgets_qt-0.1.0/docs/writing-rules.md +47 -0
  126. sg_widgets_qt-0.1.0/pyproject.toml +110 -0
  127. sg_widgets_qt-0.1.0/src/sg_widgets_core/__init__.py +30 -0
  128. sg_widgets_qt-0.1.0/src/sg_widgets_core/client.py +589 -0
  129. sg_widgets_qt-0.1.0/src/sg_widgets_core/collection.py +699 -0
  130. sg_widgets_qt-0.1.0/src/sg_widgets_core/collection_state.py +303 -0
  131. sg_widgets_qt-0.1.0/src/sg_widgets_core/context.py +135 -0
  132. sg_widgets_qt-0.1.0/src/sg_widgets_core/edit.py +833 -0
  133. sg_widgets_qt-0.1.0/src/sg_widgets_core/entity_card.py +183 -0
  134. sg_widgets_qt-0.1.0/src/sg_widgets_core/field_icons.py +56 -0
  135. sg_widgets_qt-0.1.0/src/sg_widgets_core/field_types.py +179 -0
  136. sg_widgets_qt-0.1.0/src/sg_widgets_core/filter.py +236 -0
  137. sg_widgets_qt-0.1.0/src/sg_widgets_core/filter_ux.py +1600 -0
  138. sg_widgets_qt-0.1.0/src/sg_widgets_core/list_chrome.py +85 -0
  139. sg_widgets_qt-0.1.0/src/sg_widgets_core/mock.py +2923 -0
  140. sg_widgets_qt-0.1.0/src/sg_widgets_core/paging.py +171 -0
  141. sg_widgets_qt-0.1.0/src/sg_widgets_core/picker.py +920 -0
  142. sg_widgets_qt-0.1.0/src/sg_widgets_core/picker_keys.py +149 -0
  143. sg_widgets_qt-0.1.0/src/sg_widgets_core/pickers.py +426 -0
  144. sg_widgets_qt-0.1.0/src/sg_widgets_core/presentation.py +78 -0
  145. sg_widgets_qt-0.1.0/src/sg_widgets_core/py.typed +0 -0
  146. sg_widgets_qt-0.1.0/src/sg_widgets_core/query.py +274 -0
  147. sg_widgets_qt-0.1.0/src/sg_widgets_core/render.py +739 -0
  148. sg_widgets_qt-0.1.0/src/sg_widgets_core/row.py +155 -0
  149. sg_widgets_qt-0.1.0/src/sg_widgets_core/schema.py +239 -0
  150. sg_widgets_qt-0.1.0/src/sg_widgets_core/schema_service.py +194 -0
  151. sg_widgets_qt-0.1.0/src/sg_widgets_core/search.py +492 -0
  152. sg_widgets_qt-0.1.0/src/sg_widgets_core/shotgun_client.py +637 -0
  153. sg_widgets_qt-0.1.0/src/sg_widgets_core/sortable.py +259 -0
  154. sg_widgets_qt-0.1.0/src/sg_widgets_core/state.py +81 -0
  155. sg_widgets_qt-0.1.0/src/sg_widgets_core/status.py +249 -0
  156. sg_widgets_qt-0.1.0/src/sg_widgets_core/status_icons.py +613 -0
  157. sg_widgets_qt-0.1.0/src/sg_widgets_core/status_service.py +70 -0
  158. sg_widgets_qt-0.1.0/src/sg_widgets_core/tree.py +1104 -0
  159. sg_widgets_qt-0.1.0/src/sg_widgets_qt/__init__.py +0 -0
  160. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/LICENSE +43 -0
  161. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-down.svg +16 -0
  162. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-left-to-line.svg +17 -0
  163. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-up-down.svg +18 -0
  164. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-up.svg +16 -0
  165. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/bot.svg +20 -0
  166. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/box.svg +17 -0
  167. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/braces.svg +16 -0
  168. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/building-2.svg +19 -0
  169. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/calendar-clock.svg +20 -0
  170. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/calendar.svg +18 -0
  171. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/check.svg +15 -0
  172. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-down.svg +15 -0
  173. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-left.svg +15 -0
  174. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-right.svg +15 -0
  175. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-up.svg +15 -0
  176. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevrons-up-down.svg +16 -0
  177. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-alert.svg +17 -0
  178. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-check.svg +16 -0
  179. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-dollar-sign.svg +17 -0
  180. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-dot.svg +16 -0
  181. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-x.svg +17 -0
  182. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle.svg +15 -0
  183. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/clapperboard.svg +18 -0
  184. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/clock.svg +16 -0
  185. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/columns-3.svg +17 -0
  186. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/copy.svg +16 -0
  187. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/dot.svg +15 -0
  188. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/ellipsis-vertical.svg +17 -0
  189. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/external-link.svg +17 -0
  190. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/eye-off.svg +18 -0
  191. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/eye.svg +16 -0
  192. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/file-box.svg +19 -0
  193. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/file-text.svg +19 -0
  194. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/file.svg +16 -0
  195. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/film.svg +22 -0
  196. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/filter.svg +15 -0
  197. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/fingerprint.svg +23 -0
  198. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/folder-open.svg +15 -0
  199. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/folder.svg +15 -0
  200. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/git-branch.svg +17 -0
  201. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/globe.svg +17 -0
  202. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/grip-vertical.svg +20 -0
  203. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/hash.svg +18 -0
  204. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/history.svg +17 -0
  205. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/hourglass.svg +18 -0
  206. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/image.svg +17 -0
  207. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/inbox.svg +16 -0
  208. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/info.svg +17 -0
  209. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/key-round.svg +16 -0
  210. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/layers.svg +17 -0
  211. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/layout-grid.svg +18 -0
  212. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/link-2.svg +17 -0
  213. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/link.svg +16 -0
  214. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/list-checks.svg +19 -0
  215. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/list-filter.svg +17 -0
  216. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/list.svg +20 -0
  217. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/loader-circle.svg +15 -0
  218. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/loader.svg +22 -0
  219. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/message-square.svg +15 -0
  220. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/minus.svg +15 -0
  221. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/moon.svg +15 -0
  222. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/more-horizontal.svg +17 -0
  223. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/palette.svg +19 -0
  224. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/pencil.svg +16 -0
  225. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/percent.svg +17 -0
  226. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/pin-off.svg +18 -0
  227. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/play.svg +15 -0
  228. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/plus.svg +16 -0
  229. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/refresh-cw.svg +18 -0
  230. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/rotate-ccw.svg +16 -0
  231. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/rows-3.svg +17 -0
  232. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/ruler.svg +19 -0
  233. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/search-x.svg +18 -0
  234. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/search.svg +16 -0
  235. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/settings.svg +16 -0
  236. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/shapes.svg +17 -0
  237. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/sigma.svg +15 -0
  238. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/square-check.svg +16 -0
  239. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/square.svg +15 -0
  240. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/sun.svg +23 -0
  241. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/table.svg +18 -0
  242. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/tag.svg +16 -0
  243. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/timer.svg +17 -0
  244. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/toggle-left.svg +16 -0
  245. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/trash-2.svg +19 -0
  246. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/triangle-alert.svg +17 -0
  247. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/type.svg +17 -0
  248. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/user.svg +16 -0
  249. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/users.svg +18 -0
  250. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/video.svg +16 -0
  251. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/x.svg +16 -0
  252. sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons.py +129 -0
  253. sg_widgets_qt-0.1.0/src/sg_widgets_qt/images.py +318 -0
  254. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/__init__.py +78 -0
  255. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/accessible.py +124 -0
  256. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/badge.py +395 -0
  257. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/base.py +634 -0
  258. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/button.py +559 -0
  259. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/calendar.py +666 -0
  260. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/checkbox.py +718 -0
  261. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/command.py +314 -0
  262. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/dialog.py +515 -0
  263. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/dropdown_menu.py +641 -0
  264. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/hover_card.py +173 -0
  265. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/input.py +453 -0
  266. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/input_group.py +378 -0
  267. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/label.py +178 -0
  268. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/list_view.py +553 -0
  269. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/popover.py +757 -0
  270. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/remove_control.py +144 -0
  271. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/roles.py +62 -0
  272. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/row_delegate.py +713 -0
  273. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/scroll_latch.py +70 -0
  274. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/scrollbar.py +344 -0
  275. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/select.py +365 -0
  276. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/skeleton.py +144 -0
  277. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/table.py +372 -0
  278. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/tooltip.py +144 -0
  279. sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/type_scale.py +39 -0
  280. sg_widgets_qt-0.1.0/src/sg_widgets_qt/py.typed +0 -0
  281. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/__init__.py +33 -0
  282. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/__main__.py +76 -0
  283. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/chrome.py +248 -0
  284. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/context.py +223 -0
  285. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/__init__.py +16 -0
  286. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_editors.py +246 -0
  287. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_layout.py +251 -0
  288. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_leaf.py +176 -0
  289. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_pickers.py +183 -0
  290. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_results.py +471 -0
  291. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_rows.py +63 -0
  292. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/checkbox_editor.py +69 -0
  293. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/collection_control.py +371 -0
  294. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/color_editor.py +73 -0
  295. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/column_picker.py +124 -0
  296. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/context_selector.py +147 -0
  297. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/date_editor.py +87 -0
  298. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/date_time_editor.py +116 -0
  299. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_card.py +234 -0
  300. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_chip.py +262 -0
  301. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_grid.py +201 -0
  302. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_multi_picker.py +225 -0
  303. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_picker.py +203 -0
  304. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_table.py +345 -0
  305. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_table_infinite.py +115 -0
  306. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_tree.py +173 -0
  307. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_type_multi_picker.py +163 -0
  308. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_type_picker.py +116 -0
  309. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/field_editor.py +234 -0
  310. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/field_picker.py +155 -0
  311. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/field_value.py +312 -0
  312. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/filter_bar.py +199 -0
  313. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/filter_dialog.py +130 -0
  314. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/filter_editor.py +264 -0
  315. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/global_search.py +137 -0
  316. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/grouped_list.py +248 -0
  317. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/hello.py +155 -0
  318. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/hierarchical_search.py +89 -0
  319. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/list_multi_picker.py +76 -0
  320. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/list_picker.py +112 -0
  321. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/match_text.py +105 -0
  322. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/number_editor.py +135 -0
  323. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/picker_control.py +333 -0
  324. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/project_multi_picker.py +182 -0
  325. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/project_picker.py +123 -0
  326. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/search_control.py +183 -0
  327. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/sort_picker.py +98 -0
  328. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/state_line.py +149 -0
  329. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/status_badge.py +363 -0
  330. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/status_multi_picker.py +301 -0
  331. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/status_picker.py +230 -0
  332. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/text_editor.py +77 -0
  333. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/thumbnail.py +189 -0
  334. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/url_editor.py +71 -0
  335. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/user_avatar.py +210 -0
  336. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/user_multi_picker.py +191 -0
  337. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/user_picker.py +140 -0
  338. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/value_editor.py +163 -0
  339. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/markdown.py +257 -0
  340. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/page.py +494 -0
  341. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/paths.py +97 -0
  342. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/prefs.py +225 -0
  343. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/stage.py +368 -0
  344. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/toolbar.py +117 -0
  345. sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/window.py +558 -0
  346. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/__init__.py +715 -0
  347. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/GeistMono[wght].ttf +0 -0
  348. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/Geist[wght].ttf +0 -0
  349. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/Montserrat[wght].ttf +0 -0
  350. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-geist.txt +93 -0
  351. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-geistmono.txt +93 -0
  352. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-montserrat.txt +93 -0
  353. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-opensans.txt +92 -0
  354. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-outfit.txt +93 -0
  355. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OpenSans[wdth,wght].ttf +0 -0
  356. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/Outfit[wght].ttf +0 -0
  357. sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/palettes.json +618 -0
  358. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/__init__.py +207 -0
  359. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/_sortable_rows.py +660 -0
  360. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/checkbox_editor.py +163 -0
  361. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/collection_control.py +676 -0
  362. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/collection_footer.py +297 -0
  363. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/collection_source.py +446 -0
  364. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/color_editor.py +536 -0
  365. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/column_picker.py +1541 -0
  366. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/context_selector.py +988 -0
  367. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/date_editor.py +434 -0
  368. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/date_time_editor.py +324 -0
  369. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/editor_calendar.py +34 -0
  370. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_card.py +1861 -0
  371. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_chip.py +492 -0
  372. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_glyphs.py +35 -0
  373. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_grid.py +899 -0
  374. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_multi_picker.py +129 -0
  375. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_picker.py +761 -0
  376. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_table.py +1996 -0
  377. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_tree.py +1216 -0
  378. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_type_multi_picker.py +100 -0
  379. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_type_picker.py +413 -0
  380. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_editor.py +1185 -0
  381. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_error.py +154 -0
  382. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_picker.py +1465 -0
  383. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_value.py +1361 -0
  384. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/filter_bar.py +1057 -0
  385. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/filter_dialog.py +357 -0
  386. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/filter_editor.py +2100 -0
  387. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/global_search.py +770 -0
  388. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/grouped_list.py +1127 -0
  389. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/hierarchical_search.py +605 -0
  390. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_multi_picker.py +178 -0
  391. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_multi_select.py +13 -0
  392. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_picker.py +789 -0
  393. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_select.py +12 -0
  394. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/match_text.py +159 -0
  395. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/number_editor.py +640 -0
  396. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/picker_control.py +1899 -0
  397. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/picker_row.py +881 -0
  398. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/project_multi_picker.py +44 -0
  399. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/project_picker.py +99 -0
  400. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/search_control.py +882 -0
  401. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/search_skeleton.py +219 -0
  402. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/sort_picker.py +630 -0
  403. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/state_line.py +198 -0
  404. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_badge.py +397 -0
  405. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_glyph.py +313 -0
  406. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_multi_picker.py +176 -0
  407. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_picker.py +587 -0
  408. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/text_editor.py +162 -0
  409. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/thumbnail.py +363 -0
  410. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/url_editor.py +188 -0
  411. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/user_avatar.py +317 -0
  412. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/user_multi_picker.py +54 -0
  413. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/user_picker.py +141 -0
  414. sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/value_editor.py +717 -0
  415. sg_widgets_qt-0.1.0/src/sg_widgets_qt/workers.py +485 -0
  416. sg_widgets_qt-0.1.0/sync/manifest.json +2503 -0
  417. sg_widgets_qt-0.1.0/tests/__init__.py +0 -0
  418. sg_widgets_qt-0.1.0/tests/conftest.py +6 -0
  419. sg_widgets_qt-0.1.0/tests/core/__init__.py +0 -0
  420. sg_widgets_qt-0.1.0/tests/core/fake_client.py +623 -0
  421. sg_widgets_qt-0.1.0/tests/core/test_client.py +46 -0
  422. sg_widgets_qt-0.1.0/tests/core/test_collection.py +523 -0
  423. sg_widgets_qt-0.1.0/tests/core/test_collection_state.py +241 -0
  424. sg_widgets_qt-0.1.0/tests/core/test_context.py +99 -0
  425. sg_widgets_qt-0.1.0/tests/core/test_edit.py +518 -0
  426. sg_widgets_qt-0.1.0/tests/core/test_entity_card.py +144 -0
  427. sg_widgets_qt-0.1.0/tests/core/test_field_icons.py +45 -0
  428. sg_widgets_qt-0.1.0/tests/core/test_field_types.py +37 -0
  429. sg_widgets_qt-0.1.0/tests/core/test_filter.py +92 -0
  430. sg_widgets_qt-0.1.0/tests/core/test_filter_ux.py +1053 -0
  431. sg_widgets_qt-0.1.0/tests/core/test_hierarchy.py +189 -0
  432. sg_widgets_qt-0.1.0/tests/core/test_list_chrome.py +59 -0
  433. sg_widgets_qt-0.1.0/tests/core/test_mock.py +1218 -0
  434. sg_widgets_qt-0.1.0/tests/core/test_paging.py +253 -0
  435. sg_widgets_qt-0.1.0/tests/core/test_picker.py +613 -0
  436. sg_widgets_qt-0.1.0/tests/core/test_picker_keys.py +125 -0
  437. sg_widgets_qt-0.1.0/tests/core/test_pickers.py +365 -0
  438. sg_widgets_qt-0.1.0/tests/core/test_presentation.py +80 -0
  439. sg_widgets_qt-0.1.0/tests/core/test_query.py +258 -0
  440. sg_widgets_qt-0.1.0/tests/core/test_render.py +400 -0
  441. sg_widgets_qt-0.1.0/tests/core/test_row.py +120 -0
  442. sg_widgets_qt-0.1.0/tests/core/test_schema.py +158 -0
  443. sg_widgets_qt-0.1.0/tests/core/test_schema_service.py +155 -0
  444. sg_widgets_qt-0.1.0/tests/core/test_search.py +186 -0
  445. sg_widgets_qt-0.1.0/tests/core/test_shotgun_client.py +874 -0
  446. sg_widgets_qt-0.1.0/tests/core/test_sortable.py +132 -0
  447. sg_widgets_qt-0.1.0/tests/core/test_state.py +55 -0
  448. sg_widgets_qt-0.1.0/tests/core/test_status.py +108 -0
  449. sg_widgets_qt-0.1.0/tests/core/test_status_icons.py +43 -0
  450. sg_widgets_qt-0.1.0/tests/core/test_status_service.py +63 -0
  451. sg_widgets_qt-0.1.0/tests/core/test_tree.py +632 -0
  452. sg_widgets_qt-0.1.0/tests/qt/__init__.py +0 -0
  453. sg_widgets_qt-0.1.0/tests/qt/collections.py +140 -0
  454. sg_widgets_qt-0.1.0/tests/qt/editors.py +46 -0
  455. sg_widgets_qt-0.1.0/tests/qt/pickers.py +104 -0
  456. sg_widgets_qt-0.1.0/tests/qt/test_accessibility.py +247 -0
  457. sg_widgets_qt-0.1.0/tests/qt/test_checkbox_editor.py +95 -0
  458. sg_widgets_qt-0.1.0/tests/qt/test_collection_control.py +190 -0
  459. sg_widgets_qt-0.1.0/tests/qt/test_collection_source.py +135 -0
  460. sg_widgets_qt-0.1.0/tests/qt/test_color_editor.py +168 -0
  461. sg_widgets_qt-0.1.0/tests/qt/test_column_picker.py +602 -0
  462. sg_widgets_qt-0.1.0/tests/qt/test_context_selector.py +310 -0
  463. sg_widgets_qt-0.1.0/tests/qt/test_dark_grounds.py +208 -0
  464. sg_widgets_qt-0.1.0/tests/qt/test_dark_ink.py +245 -0
  465. sg_widgets_qt-0.1.0/tests/qt/test_date_editor.py +133 -0
  466. sg_widgets_qt-0.1.0/tests/qt/test_date_time_editor.py +120 -0
  467. sg_widgets_qt-0.1.0/tests/qt/test_entity_card.py +388 -0
  468. sg_widgets_qt-0.1.0/tests/qt/test_entity_chip.py +209 -0
  469. sg_widgets_qt-0.1.0/tests/qt/test_entity_glyphs.py +90 -0
  470. sg_widgets_qt-0.1.0/tests/qt/test_entity_grid.py +301 -0
  471. sg_widgets_qt-0.1.0/tests/qt/test_entity_multi_picker.py +206 -0
  472. sg_widgets_qt-0.1.0/tests/qt/test_entity_picker.py +299 -0
  473. sg_widgets_qt-0.1.0/tests/qt/test_entity_table.py +684 -0
  474. sg_widgets_qt-0.1.0/tests/qt/test_entity_tree.py +220 -0
  475. sg_widgets_qt-0.1.0/tests/qt/test_entity_type_multi_picker.py +152 -0
  476. sg_widgets_qt-0.1.0/tests/qt/test_entity_type_picker.py +141 -0
  477. sg_widgets_qt-0.1.0/tests/qt/test_field_editor.py +493 -0
  478. sg_widgets_qt-0.1.0/tests/qt/test_field_picker.py +553 -0
  479. sg_widgets_qt-0.1.0/tests/qt/test_field_value.py +576 -0
  480. sg_widgets_qt-0.1.0/tests/qt/test_filter_bar.py +175 -0
  481. sg_widgets_qt-0.1.0/tests/qt/test_filter_dialog.py +159 -0
  482. sg_widgets_qt-0.1.0/tests/qt/test_filter_editor.py +559 -0
  483. sg_widgets_qt-0.1.0/tests/qt/test_global_search.py +233 -0
  484. sg_widgets_qt-0.1.0/tests/qt/test_grouped_list.py +299 -0
  485. sg_widgets_qt-0.1.0/tests/qt/test_hierarchical_search.py +289 -0
  486. sg_widgets_qt-0.1.0/tests/qt/test_icons.py +99 -0
  487. sg_widgets_qt-0.1.0/tests/qt/test_images.py +184 -0
  488. sg_widgets_qt-0.1.0/tests/qt/test_list_multi_picker.py +105 -0
  489. sg_widgets_qt-0.1.0/tests/qt/test_list_picker.py +136 -0
  490. sg_widgets_qt-0.1.0/tests/qt/test_match_text.py +159 -0
  491. sg_widgets_qt-0.1.0/tests/qt/test_number_editor.py +121 -0
  492. sg_widgets_qt-0.1.0/tests/qt/test_picker_contract.py +379 -0
  493. sg_widgets_qt-0.1.0/tests/qt/test_picker_control.py +427 -0
  494. sg_widgets_qt-0.1.0/tests/qt/test_picker_row.py +325 -0
  495. sg_widgets_qt-0.1.0/tests/qt/test_primitives_floating.py +489 -0
  496. sg_widgets_qt-0.1.0/tests/qt/test_primitives_leaf.py +564 -0
  497. sg_widgets_qt-0.1.0/tests/qt/test_primitives_lists.py +556 -0
  498. sg_widgets_qt-0.1.0/tests/qt/test_project_multi_picker.py +138 -0
  499. sg_widgets_qt-0.1.0/tests/qt/test_project_picker.py +129 -0
  500. sg_widgets_qt-0.1.0/tests/qt/test_scroll_latch.py +101 -0
  501. sg_widgets_qt-0.1.0/tests/qt/test_scrollbar.py +52 -0
  502. sg_widgets_qt-0.1.0/tests/qt/test_search_control.py +283 -0
  503. sg_widgets_qt-0.1.0/tests/qt/test_search_skeleton.py +76 -0
  504. sg_widgets_qt-0.1.0/tests/qt/test_showcase.py +461 -0
  505. sg_widgets_qt-0.1.0/tests/qt/test_showcase_collection_demos.py +216 -0
  506. sg_widgets_qt-0.1.0/tests/qt/test_showcase_demo_rows.py +65 -0
  507. sg_widgets_qt-0.1.0/tests/qt/test_showcase_docs.py +159 -0
  508. sg_widgets_qt-0.1.0/tests/qt/test_sort_picker.py +317 -0
  509. sg_widgets_qt-0.1.0/tests/qt/test_sortable_rows.py +178 -0
  510. sg_widgets_qt-0.1.0/tests/qt/test_state_line.py +140 -0
  511. sg_widgets_qt-0.1.0/tests/qt/test_status_badge.py +223 -0
  512. sg_widgets_qt-0.1.0/tests/qt/test_status_glyph.py +193 -0
  513. sg_widgets_qt-0.1.0/tests/qt/test_status_multi_picker.py +148 -0
  514. sg_widgets_qt-0.1.0/tests/qt/test_status_picker.py +183 -0
  515. sg_widgets_qt-0.1.0/tests/qt/test_text_editor.py +130 -0
  516. sg_widgets_qt-0.1.0/tests/qt/test_theme.py +233 -0
  517. sg_widgets_qt-0.1.0/tests/qt/test_theme_switch.py +225 -0
  518. sg_widgets_qt-0.1.0/tests/qt/test_thumbnail.py +163 -0
  519. sg_widgets_qt-0.1.0/tests/qt/test_url_editor.py +113 -0
  520. sg_widgets_qt-0.1.0/tests/qt/test_user_avatar.py +174 -0
  521. sg_widgets_qt-0.1.0/tests/qt/test_user_multi_picker.py +146 -0
  522. sg_widgets_qt-0.1.0/tests/qt/test_user_picker.py +170 -0
  523. sg_widgets_qt-0.1.0/tests/qt/test_value_editor.py +242 -0
  524. sg_widgets_qt-0.1.0/tests/qt/test_workers.py +323 -0
  525. sg_widgets_qt-0.1.0/tests/test_packaging.py +120 -0
  526. sg_widgets_qt-0.1.0/tests/test_sync.py +222 -0
  527. sg_widgets_qt-0.1.0/tools/export_docs.py +266 -0
  528. sg_widgets_qt-0.1.0/tools/export_palettes.py +404 -0
  529. sg_widgets_qt-0.1.0/tools/export_props.mjs +199 -0
  530. sg_widgets_qt-0.1.0/tools/lucide.py +202 -0
  531. sg_widgets_qt-0.1.0/tools/measure_diff.py +275 -0
  532. sg_widgets_qt-0.1.0/tools/measure_split.py +45 -0
  533. sg_widgets_qt-0.1.0/tools/props_types.py +252 -0
  534. sg_widgets_qt-0.1.0/tools/qa.py +277 -0
  535. sg_widgets_qt-0.1.0/tools/status.py +73 -0
  536. sg_widgets_qt-0.1.0/tools/sync_record.py +101 -0
  537. sg_widgets_qt-0.1.0/tools/sync_status.py +139 -0
@@ -0,0 +1,12 @@
1
+ .env.local
2
+ .venv*
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ shots/**/*.png
10
+ .qa/
11
+ .idea/
12
+ .DS_Store
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows
4
+ [semantic versioning](https://semver.org/spec/v2.0.0.html). While the version is 0.x, a minor
5
+ release may change a name, a prop or a signal.
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-09-20
10
+
11
+ First release, from the port of [sg-widgets](https://github.com/ksallee/sg-widgets).
12
+
13
+ ### Added
14
+
15
+ - `sg_widgets_core`: field data types and their operators, the filter tree and its serialisation,
16
+ status logic, formatters, parsers, the query cache, the `SgClient` protocol, `ShotgunClient` on
17
+ shotgun_api3 and `MockClient` over generated fixtures. No Qt.
18
+ - `sg_widgets_qt`: the theme with light and dark palettes, the painted primitives, and the widgets:
19
+ thumbnails, avatars, the field editors, the pickers for entities, fields, statuses and columns,
20
+ the entity table, grid, tree and card, the collection and search controls, and the filter editor.
21
+ - The showcase, `python -m sg_widgets_qt.showcase`: one page per widget with a demo, the props,
22
+ signals, slots and keyboard tables, and the prose. It runs on the mock site, and on a live site
23
+ through `.env.local`.
24
+ - `py.typed` in both packages.
25
+ - Gates on every pull request and on pushes to `dev` and `main`: ruff, and pytest offscreen on
26
+ PySide6 and on PyQt5, on Python 3.9.
27
+ - Release to PyPI by trusted publishing when a GitHub release is published.
28
+
29
+ [Unreleased]: https://github.com/ksallee/sg-widgets-qt/compare/v0.1.0...HEAD
30
+ [0.1.0]: https://github.com/ksallee/sg-widgets-qt/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kevin Sallee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.5
2
+ Name: sg-widgets-qt
3
+ Version: 0.1.0
4
+ Summary: Flow Production Tracking widgets for Qt, a port of sg-widgets on qtpy and shotgun_api3
5
+ Project-URL: Homepage, https://github.com/ksallee/sg-widgets-qt
6
+ Project-URL: Documentation, https://github.com/ksallee/sg-widgets-qt/tree/main/docs
7
+ Project-URL: Issues, https://github.com/ksallee/sg-widgets-qt/issues
8
+ Project-URL: Changelog, https://github.com/ksallee/sg-widgets-qt/blob/main/CHANGELOG.md
9
+ Project-URL: Source, https://github.com/ksallee/sg-widgets-qt
10
+ Author: Kevin Sallee
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: flow-production-tracking,pyqt,pyside,qt,shotgrid,shotgun,vfx
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Multimedia :: Graphics
22
+ Classifier: Topic :: Software Development :: User Interfaces
23
+ Requires-Python: >=3.9
24
+ Requires-Dist: qtpy>=2.4
25
+ Requires-Dist: shotgun-api3>=3.5
26
+ Provides-Extra: pyqt5
27
+ Requires-Dist: pyqt5; extra == 'pyqt5'
28
+ Provides-Extra: pyside6
29
+ Requires-Dist: pyside6; extra == 'pyside6'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # sg-widgets-qt
33
+
34
+ Flow Production Tracking (formerly ShotGrid) widgets for Qt: pickers, editors, tables, trees, grids
35
+ and search. For pipeline developers writing tools inside Maya, Houdini, Nuke, RV or a standalone
36
+ app.
37
+
38
+ ![An entity table grouped by status, with status badges and thumbnails](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-table-light.png)
39
+
40
+ ## Install
41
+
42
+ ```sh
43
+ pip install sg-widgets-qt
44
+ uv add sg-widgets-qt
45
+ ```
46
+
47
+ Python 3.9 and up. The package brings `shotgun_api3` and `qtpy` and no Qt binding, because a DCC
48
+ imports its own before your code runs. Outside a DCC, name a binding as an extra.
49
+
50
+ ```sh
51
+ pip install "sg-widgets-qt[pyside6]"
52
+ pip install "sg-widgets-qt[pyqt5]"
53
+ ```
54
+
55
+ Every Qt import here goes through [qtpy](https://github.com/spyder-ide/qtpy), so one widget runs on
56
+ PySide2, PySide6, PyQt5 and PyQt6, and on whichever of them the host imported first.
57
+
58
+ ## A first widget
59
+
60
+ Three environment values point at a site: `FPT_API_SITE_URL`, `FPT_API_SCRIPT_NAME` and
61
+ `FPT_API_API_KEY`.
62
+
63
+ ```python
64
+ from qtpy.QtWidgets import QApplication
65
+ from sg_widgets_core import ShotgunClient, create_sg_context
66
+ from sg_widgets_qt.widgets.entity_picker import EntityPicker
67
+
68
+ app = QApplication([])
69
+ context = create_sg_context(ShotgunClient.from_env())
70
+ picker = EntityPicker(entity_types=["Shot"], context=context)
71
+ picker.value_changed.connect(lambda ref, row: print(ref))
72
+ picker.show()
73
+ app.exec_()
74
+ ```
75
+
76
+ The context is built once and handed to every widget. The same picker runs on a generated site,
77
+ with no credentials and no network.
78
+
79
+ ```python
80
+ from sg_widgets_core import MockClient, create_sg_context
81
+
82
+ context = create_sg_context(MockClient())
83
+ picker = EntityPicker(entity_types=["Shot"], context=context)
84
+ ```
85
+
86
+ ## The showcase
87
+
88
+ ```sh
89
+ python -m sg_widgets_qt.showcase
90
+ ```
91
+
92
+ One page per widget, with a live demo, the props, signals, slots and keyboard tables, and the docs
93
+ prose. The pages ship inside the package. The demos run on the mock, so the showcase needs no
94
+ site; its toolbar offers Live where the three values above are set.
95
+
96
+ ## The widgets
97
+
98
+ | | |
99
+ |---|---|
100
+ | ![An entity multi picker open on its results](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-multi-picker-light.png) | A picker searches the site, holds what was ticked as chips, and emits references. |
101
+ | ![A filter editor holding one status condition](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/filter-editor-light.png) | The filter editor builds a condition tree and serialises it for the API. |
102
+ | ![A status picker open on the statuses of one project](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/status-picker-light.png) | Statuses carry the site's own names, codes, colours and icons, per project. |
103
+ | ![Global search, its results grouped by entity type](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/global-search-light.png) | Global search reads across entity types and marks what matched. |
104
+ | ![An entity grid of thumbnails](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-grid-light.png) | A table, a grid and a tree page a set, sort it, group it and edit a cell. |
105
+ | ![The entity table in the dark theme](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-table-dark.png) | Every widget wears a light and a dark theme, or the host application's palette. |
106
+
107
+ Every shot above reads a live site. [One page per
108
+ widget](https://github.com/ksallee/sg-widgets-qt/tree/main/docs/widgets) says what each one takes
109
+ and emits, beside
110
+ [the introduction](https://github.com/ksallee/sg-widgets-qt/blob/main/docs/start/introduction.md),
111
+ [install](https://github.com/ksallee/sg-widgets-qt/blob/main/docs/start/install.md) and
112
+ [the core](https://github.com/ksallee/sg-widgets-qt/blob/main/docs/core/index.md).
113
+
114
+ ## How it relates to sg-widgets
115
+
116
+ This is a port of [sg-widgets](https://github.com/ksallee/sg-widgets), whose React and Svelte
117
+ widgets carry the same names, props and behaviour, and whose
118
+ [documentation site](https://sg-widgets.vercel.app) is the reference for what a widget does; the
119
+ pages here say where Qt or Python forced a difference. The framework-neutral half comes with it as
120
+ `sg_widgets_core`, which holds the field data types, the operator vocabularies, the filter tree,
121
+ status logic, the formatters, the parsers, the client protocol and a generated mock site, and
122
+ imports no Qt, so it runs in a farm job as well as in a window. What either repo claims about the
123
+ API is measured in [sg-groundtruth](https://github.com/ksallee/sg-groundtruth) and cited where it
124
+ is relied on.
125
+
126
+ ## Status
127
+
128
+ Alpha. 52 widgets, 27 core modules and 55 documentation pages are complete, on Python 3.9 through
129
+ 3.13 and on Qt 5.15 and Qt 6. Both packages carry `py.typed`. Names, props and signals can still
130
+ change between 0.x releases, and the
131
+ [changelog](https://github.com/ksallee/sg-widgets-qt/blob/main/CHANGELOG.md) records what changed.
132
+ Ask for a widget, report a defect or say what reads wrong in the
133
+ [issues](https://github.com/ksallee/sg-widgets-qt/issues).
134
+
135
+ ## Licence
136
+
137
+ MIT. See [LICENSE](https://github.com/ksallee/sg-widgets-qt/blob/main/LICENSE).
@@ -0,0 +1,106 @@
1
+ # sg-widgets-qt
2
+
3
+ Flow Production Tracking (formerly ShotGrid) widgets for Qt: pickers, editors, tables, trees, grids
4
+ and search. For pipeline developers writing tools inside Maya, Houdini, Nuke, RV or a standalone
5
+ app.
6
+
7
+ ![An entity table grouped by status, with status badges and thumbnails](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-table-light.png)
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ pip install sg-widgets-qt
13
+ uv add sg-widgets-qt
14
+ ```
15
+
16
+ Python 3.9 and up. The package brings `shotgun_api3` and `qtpy` and no Qt binding, because a DCC
17
+ imports its own before your code runs. Outside a DCC, name a binding as an extra.
18
+
19
+ ```sh
20
+ pip install "sg-widgets-qt[pyside6]"
21
+ pip install "sg-widgets-qt[pyqt5]"
22
+ ```
23
+
24
+ Every Qt import here goes through [qtpy](https://github.com/spyder-ide/qtpy), so one widget runs on
25
+ PySide2, PySide6, PyQt5 and PyQt6, and on whichever of them the host imported first.
26
+
27
+ ## A first widget
28
+
29
+ Three environment values point at a site: `FPT_API_SITE_URL`, `FPT_API_SCRIPT_NAME` and
30
+ `FPT_API_API_KEY`.
31
+
32
+ ```python
33
+ from qtpy.QtWidgets import QApplication
34
+ from sg_widgets_core import ShotgunClient, create_sg_context
35
+ from sg_widgets_qt.widgets.entity_picker import EntityPicker
36
+
37
+ app = QApplication([])
38
+ context = create_sg_context(ShotgunClient.from_env())
39
+ picker = EntityPicker(entity_types=["Shot"], context=context)
40
+ picker.value_changed.connect(lambda ref, row: print(ref))
41
+ picker.show()
42
+ app.exec_()
43
+ ```
44
+
45
+ The context is built once and handed to every widget. The same picker runs on a generated site,
46
+ with no credentials and no network.
47
+
48
+ ```python
49
+ from sg_widgets_core import MockClient, create_sg_context
50
+
51
+ context = create_sg_context(MockClient())
52
+ picker = EntityPicker(entity_types=["Shot"], context=context)
53
+ ```
54
+
55
+ ## The showcase
56
+
57
+ ```sh
58
+ python -m sg_widgets_qt.showcase
59
+ ```
60
+
61
+ One page per widget, with a live demo, the props, signals, slots and keyboard tables, and the docs
62
+ prose. The pages ship inside the package. The demos run on the mock, so the showcase needs no
63
+ site; its toolbar offers Live where the three values above are set.
64
+
65
+ ## The widgets
66
+
67
+ | | |
68
+ |---|---|
69
+ | ![An entity multi picker open on its results](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-multi-picker-light.png) | A picker searches the site, holds what was ticked as chips, and emits references. |
70
+ | ![A filter editor holding one status condition](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/filter-editor-light.png) | The filter editor builds a condition tree and serialises it for the API. |
71
+ | ![A status picker open on the statuses of one project](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/status-picker-light.png) | Statuses carry the site's own names, codes, colours and icons, per project. |
72
+ | ![Global search, its results grouped by entity type](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/global-search-light.png) | Global search reads across entity types and marks what matched. |
73
+ | ![An entity grid of thumbnails](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-grid-light.png) | A table, a grid and a tree page a set, sort it, group it and edit a cell. |
74
+ | ![The entity table in the dark theme](https://raw.githubusercontent.com/ksallee/sg-widgets-qt/main/docs/screenshots/entity-table-dark.png) | Every widget wears a light and a dark theme, or the host application's palette. |
75
+
76
+ Every shot above reads a live site. [One page per
77
+ widget](https://github.com/ksallee/sg-widgets-qt/tree/main/docs/widgets) says what each one takes
78
+ and emits, beside
79
+ [the introduction](https://github.com/ksallee/sg-widgets-qt/blob/main/docs/start/introduction.md),
80
+ [install](https://github.com/ksallee/sg-widgets-qt/blob/main/docs/start/install.md) and
81
+ [the core](https://github.com/ksallee/sg-widgets-qt/blob/main/docs/core/index.md).
82
+
83
+ ## How it relates to sg-widgets
84
+
85
+ This is a port of [sg-widgets](https://github.com/ksallee/sg-widgets), whose React and Svelte
86
+ widgets carry the same names, props and behaviour, and whose
87
+ [documentation site](https://sg-widgets.vercel.app) is the reference for what a widget does; the
88
+ pages here say where Qt or Python forced a difference. The framework-neutral half comes with it as
89
+ `sg_widgets_core`, which holds the field data types, the operator vocabularies, the filter tree,
90
+ status logic, the formatters, the parsers, the client protocol and a generated mock site, and
91
+ imports no Qt, so it runs in a farm job as well as in a window. What either repo claims about the
92
+ API is measured in [sg-groundtruth](https://github.com/ksallee/sg-groundtruth) and cited where it
93
+ is relied on.
94
+
95
+ ## Status
96
+
97
+ Alpha. 52 widgets, 27 core modules and 55 documentation pages are complete, on Python 3.9 through
98
+ 3.13 and on Qt 5.15 and Qt 6. Both packages carry `py.typed`. Names, props and signals can still
99
+ change between 0.x releases, and the
100
+ [changelog](https://github.com/ksallee/sg-widgets-qt/blob/main/CHANGELOG.md) records what changed.
101
+ Ask for a widget, report a defect or say what reads wrong in the
102
+ [issues](https://github.com/ksallee/sg-widgets-qt/issues).
103
+
104
+ ## Licence
105
+
106
+ MIT. See [LICENSE](https://github.com/ksallee/sg-widgets-qt/blob/main/LICENSE).
@@ -0,0 +1,72 @@
1
+ # Design
2
+
3
+ ## Why a port
4
+
5
+ The widgets in `~/dev/sg-widgets` encode what the Flow Production Tracking API does, measured by
6
+ the sg-groundtruth corpus, behind one set of design rules. Pipeline tools in Maya, Houdini and
7
+ Nuke need the same widgets, in the Python and Qt those hosts ship.
8
+
9
+ ## Stack
10
+
11
+ Python 3.9 as the floor: Maya 2023, Houdini 19.5 and Nuke 14 ship it. `qtpy` so one source runs
12
+ on PySide2 5.15, PySide6, PyQt5 and PyQt6. `shotgun_api3` because it is BSD licensed and runs on
13
+ every host Python; `fpt-api` is AGPL and stays out. Those two are the whole runtime: annotations
14
+ are strings under `from __future__ import annotations`, so nothing here needs `typing_extensions`.
15
+
16
+ Dev: `uv`, `pytest`, `pytest-qt`, `pytest-timeout`, `ruff`. PySide6 6.7 is the last release for
17
+ 3.9. PyQt5 stands in for PySide2 in the second environment because PySide2 ships no arm64 wheel.
18
+ `pytest-timeout` carries the two-minute per-test timeout in `pyproject.toml`: a widget waiting on
19
+ a signal that never comes fails rather than hanging a run.
20
+
21
+ ## Publishing
22
+
23
+ `py.typed` in both packages, so a consumer's type checker reads the annotations. The wheel carries
24
+ the two packages, the icons and the fonts. The sdist carries what builds and checks that wheel and
25
+ nothing else: the screenshots under `shots/` and the qa drives under `tools/drives/` are most of
26
+ the tree and none of them is needed to build.
27
+
28
+ `.github/workflows/gates.yml` runs ruff and the suite on both bindings on every pull request and on
29
+ pushes to `dev` and `main`. It asks fontconfig for grayscale antialiasing first: where
30
+ fontconfig asks for subpixel rendering, a widget painting itself and the delegate painting the same
31
+ value rasterise one string two ways, and the face parity test reads that as drift. A Linux checkout
32
+ wants the same setting. `.github/workflows/release.yml` builds, installs the wheel into a fresh
33
+ environment, imports both packages offscreen and uploads to PyPI by trusted publishing when a
34
+ GitHub release is published. No token is stored anywhere.
35
+
36
+ ## Two packages, one distribution
37
+
38
+ `sg_widgets_core` has no Qt import, so a farm script or a test can use the filter tree, the
39
+ formatters and the client. `sg_widgets_qt` holds the theme, the primitives, the widgets and the
40
+ showcase. One wheel, because a DCC install is one `pip install`.
41
+
42
+ The showcase draws its pages from `docs/`, which is where they are written and where
43
+ `tools/export_docs.py` writes them. The wheel copies `docs/widgets`, `docs/core` and `docs/start`
44
+ to `sg_widgets_qt/_docs`, so an installed showcase opens the sidebar a checkout opens.
45
+ `sg_widgets_qt.showcase.paths` reads the package copy through `importlib.resources` and falls back
46
+ to the checkout's `docs/`. It also resolves `.env.local` from the working directory upward, because
47
+ nothing above `site-packages` belongs to the person running the showcase.
48
+
49
+ ## Threads
50
+
51
+ `shotgun_api3.Shotgun` is not thread-safe. `ShotgunClient` keeps one connection per thread. The Qt
52
+ layer runs every read on `QThreadPool` and hands the answer back through a signal; a ticket per
53
+ query drops an answer a newer query replaced.
54
+
55
+ Three pools, each four threads, so work of one kind never waits out work of another. Each stays
56
+ small because a site rate limits, and none of them is `QThreadPool.globalInstance()`, so a host
57
+ application's own work is untouched.
58
+
59
+ | pool | carries |
60
+ |---|---|
61
+ | `workers.default_pool()` | Schema reads, facet counts, field writes, the demos. |
62
+ | `entity_picker.search_pool()` | What a picker or a search types into. |
63
+ | `images.image_pool()` | Thumbnails, avatars and the status sprite. |
64
+
65
+ A page of rows asks for more pictures than any pool has threads, so the pictures read in a lane
66
+ of their own: a field write submitted behind a table of thumbnails still lands at once.
67
+
68
+ ## Sync
69
+
70
+ `sync/manifest.json` is the ledger: per item, the upstream files it ports and their content hash
71
+ at the upstream commit last synced. `tools/sync_status.py` diffs it against the checkout;
72
+ `/sync` ports what drifted.
@@ -0,0 +1,74 @@
1
+ # docs
2
+
3
+ The widget, core and start pages, and the tables the showcase draws beside them. Three scripts
4
+ produce them from `~/dev/sg-widgets`. Nothing under `docs/widgets/`, `docs/core/` or `docs/start/`
5
+ is written by hand, with one exception named below.
6
+
7
+ ## What produces what
8
+
9
+ | script | writes |
10
+ |---|---|
11
+ | `tools/export_props.mjs` | `docs/widgets/<name>.props.json`, `docs/widgets/_index.json` |
12
+ | `tools/export_docs.py` | `docs/widgets/<name>.md`, `docs/core/<name>.md`, `docs/start/<name>.md` |
13
+ | `tools/props_types.py` | the `py_type` of every prop row in `docs/widgets/*.props.json` |
14
+
15
+ ## The commands
16
+
17
+ cd ~/dev/sg-widgets && node ~/dev/sg-widgets-qt/tools/export_props.mjs
18
+ cd ~/dev/sg-widgets && ~/dev/sg-widgets-qt/.venv/bin/python ~/dev/sg-widgets-qt/tools/export_docs.py
19
+ .venv/bin/python tools/props_types.py
20
+
21
+ The type pass runs after the props export, and reruns over whatever is on disk. Either exporter
22
+ finds the upstream checkout in `SG_WIDGETS`, in the directory it was run from, or at
23
+ `~/dev/sg-widgets`.
24
+
25
+ ## The props JSON
26
+
27
+ One file per upstream props file, the `extends` chain resolved by the upstream's own `_resolve.ts`:
28
+
29
+ { "name", "page", "declares", "props": [], "events": [], "slots": [], "keyboard": [] }
30
+
31
+ `page` is the page the rows are drawn on, which differs from `name` for an item that shares a page
32
+ with another. A row carries `owner` where it comes from the item's base. Two names are changed for
33
+ Python: a prop name is snake_case (`labelField` is `label_field`) and an event name is a Qt signal
34
+ name (`onValueChange` is `value_changed`, `onOpenChange` is `open_changed`, `onError` is `error`).
35
+ A `class / className` row is dropped, a Svelte-only row is dropped, and a React-only row is kept
36
+ without the flag. Everything else is the upstream cell, verbatim.
37
+
38
+ `py_type` sits beside `type` and is a mechanical translation, not a decision: `string` is `str`,
39
+ `X[]` is `list[X]`, `X | null` is `Optional[X]`, `Record<K, V>` is `dict[K, V]`, a literal union is
40
+ `Literal[...]`, a function is `Callable[...]`, and `EntityRef`, `SgContext`, `FilterGroup`,
41
+ `WireGroup`, `CollectionColumn` and `PickerRow` stay as they are. `number` is `int` where the
42
+ meaning counts something, `float` where it is a fraction, and `int | float` otherwise. A callback
43
+ parameter with no type of its own is `Any`, except `row`, `query` and `open`.
44
+
45
+ `_index.json` is the sidebar: `start` and `core` page names, the widgets `overview` page, and
46
+ `widgets` as `[{ "category": "Foundations", "items": ["thumbnail", ...] }, ...]` in the order
47
+ `apps/site/astro.config.mjs` gives. A page outside the sidebar, such as a page that names a
48
+ renamed item, is exported but not listed.
49
+
50
+ ## The pages
51
+
52
+ A `.md` page keeps its `title` and `description` as YAML, and its prose verbatim, including the
53
+ API behaviour section and its corpus citations. The Astro islands become directives the showcase
54
+ reads:
55
+
56
+ ::demo{name="entity-picker" title="…"}
57
+ ::props{name="entity-picker" kind="props"}
58
+
59
+ `kind` is one of `props`, `events`, `slots` and `keyboard`. The install block becomes the import
60
+ line, and a site link becomes a link to the page beside it.
61
+
62
+ A paragraph that speaks of React, Svelte, Base UI, Bits UI, shadcn or the registry is followed by
63
+ a line reading `::qt-note`. The prose is left as the upstream wrote it; the marker is where the Qt
64
+ docs pass writes what differs here.
65
+
66
+ ## Editing, and what a rerun does
67
+
68
+ The `.md` pages are the exception to "generated, never edited": each one is generated once and then
69
+ edited, by the Qt docs pass that answers every `::qt-note`. A rerun therefore never overwrites a
70
+ page that is already there. Where the conversion differs from the page on disk, it is written to
71
+ `<name>.md.new` beside it and named on stdout, so the two are merged by hand and a Qt note survives
72
+ a sync.
73
+
74
+ The JSON files carry no hand edits and are overwritten on every run.
@@ -0,0 +1,150 @@
1
+ ---
2
+ title: Client
3
+ description: The one interface every widget reads through, and what it writes.
4
+ ---
5
+
6
+ A client is an `SgClient`, a protocol with one synchronous method per call. `ShotgunClient` speaks to
7
+ a site through shotgun_api3, and `MockClient` answers from a generated site. The upstream
8
+ `RestClient` and `ProxyClient` are not ported: they carry a token and a proxy endpoint through a
9
+ browser, and a Qt application holds its own credentials and calls the Python API directly.
10
+
11
+ ```python
12
+ from sg_widgets_core import ShotgunClient
13
+
14
+ client = ShotgunClient.from_env()
15
+ ```
16
+
17
+ `from_env` reads `FPT_API_SITE_URL`, `FPT_API_SCRIPT_NAME` and `FPT_API_API_KEY`. One
18
+ `shotgun_api3.Shotgun` is built per thread, because a connection is not thread-safe.
19
+
20
+ Every example below runs against the mock instead, so the writes land nowhere.
21
+
22
+ ```python
23
+ from sg_widgets_core import MOCK_NOW, MockClient, create_query_cache
24
+
25
+ client = create_query_cache(MockClient(seed=1, now=MOCK_NOW))
26
+ ```
27
+
28
+ The cache remembers reads for `ttl_ms` and drops what a write makes stale: a row read of the type the
29
+ write touched, and every note thread.
30
+
31
+ ## Reads
32
+
33
+ ### A note thread
34
+
35
+ `thread_contents` answers a Note, its Attachments and its Replies as one list in time order. The
36
+ author sits under `created_by` on a Note and an Attachment and under `user` on a Reply, and the
37
+ row exposes it as `author` whichever key it came from. A Reply's author carries an avatar the other
38
+ two do not.
39
+
40
+ ```python
41
+ thread = client.thread_contents(11030, {"Note": ["subject", "sg_status_list"]})
42
+ for row in thread:
43
+ print(row.type, row.created_at, row.author.name if row.author else None, row.content or "")
44
+ ```
45
+
46
+ The second argument widens a row type by extra fields. It works on Note and Attachment; the Reply
47
+ entry is accepted and changes nothing, so extra Reply fields come from a search on replies
48
+ (`get_entity_notes_id_thread_contents`).
49
+
50
+ ### The event log
51
+
52
+ `event_log` answers what changed, newest first. It is never cached. The cut is made on the project,
53
+ the entity, the event type, the attribute and a date window; `meta` holds the old and new values
54
+ and takes no filter, so the client lifts them out of each row.
55
+
56
+ ```python
57
+ from sg_widgets_core import EntityRef, EventLogOptions
58
+
59
+ result = client.event_log(
60
+ EventLogOptions(
61
+ entity=EntityRef(type="Shot", id=862),
62
+ attribute_name="sg_status_list",
63
+ page={"size": 5},
64
+ )
65
+ )
66
+ for event in result.data:
67
+ print(event.created_at, event.old_value, "->", event.new_value)
68
+ ```
69
+
70
+ `event_log_filters` builds the same cut as a filter group, for a search of your own.
71
+
72
+ ```python
73
+ from sg_widgets_core import event_log_filters
74
+
75
+ filters = event_log_filters(
76
+ EventLogOptions(project_id=70, event_type=["Shotgun_Shot_Change", "Shotgun_Version_Change"])
77
+ )
78
+ ```
79
+
80
+ Ids at the head of the log are sparse and fill in later, so a cursor on the highest id seen drops
81
+ events: re-scan a window behind the head or drive the feed from `created_at` and deduplicate on
82
+ `id` (`025_event_log`).
83
+
84
+ ### What a person follows
85
+
86
+ `following` answers every row one person follows, as a type and an id each, in one unpaged body.
87
+ It takes a type to keep and a project to cut on. The person is a HumanUser: a script cannot ask
88
+ what it follows (`get_entity_human_users_id_following`).
89
+
90
+ ```python
91
+ from sg_widgets_core import FollowingOptions, SearchOptions
92
+
93
+ followed = client.following(20, FollowingOptions(entity="Task", project_id=70))
94
+ rows = client.search(
95
+ "Task",
96
+ SearchOptions(
97
+ filters={"logical_operator": "and", "conditions": [["id", "in", [ref.id for ref in followed]]]},
98
+ fields=["content", "sg_status_list"],
99
+ ),
100
+ )
101
+ ```
102
+
103
+ ## Writes
104
+
105
+ ### A row
106
+
107
+ `create` posts one row and answers it. `project` is the whole contract on a project-scoped type; the
108
+ field the schema flags mandatory is optional, and the server fills the identity field when it is
109
+ left out. An entity link is a `{type, id}` hash, never a bare id (`012_create_version`).
110
+
111
+ ```python
112
+ note = client.create(
113
+ "Note",
114
+ {
115
+ "project": {"type": "Project", "id": 70},
116
+ "subject": "Key light reads flat",
117
+ "content": "Lift the fill on the left side.",
118
+ "note_links": [{"type": "Shot", "id": 862}],
119
+ },
120
+ )
121
+ reply = client.create("Reply", {"entity": {"type": "Note", "id": note.id}, "content": "On it."})
122
+ ```
123
+
124
+ The answer echoes the server's defaults, so read them off `note.values`: a fresh Note is `unread` and
125
+ `published` (`entity_types/Note`). A create takes `created_at` although the schema flags it
126
+ read-only; a later update refuses it (`070_authored_timestamps`).
127
+
128
+ ### A file
129
+
130
+ `upload` puts a file on a row in the three calls the API takes: a ticket, a PUT of the bytes to
131
+ storage, and a completing POST. The field in the path picks the kind: `image` is a Thumbnail,
132
+ another field an Attachment on that field, and no field a generic Attachment on the row
133
+ (`recipes/001`).
134
+
135
+ ```python
136
+ from sg_widgets_core import UploadFile
137
+
138
+ uploaded = client.upload(
139
+ "Note",
140
+ note.id,
141
+ UploadFile(filename="key-light.txt", data=b"Lift the fill on the left side.\n", field="attachments"),
142
+ )
143
+ print(uploaded.upload_type, uploaded.etag)
144
+ ```
145
+
146
+ `data` is the bytes themselves; a file on disk is `Path(name).read_bytes()`.
147
+
148
+ The status of the PUT is the receipt; `etag` is present when the storage exposes one. A media field
149
+ is not readable straight after: it answers a placeholder under `/images/status/transient/` on the
150
+ site root until the transcode lands (`013_upload_media`).