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.
- sg_widgets_qt-0.1.0/.gitignore +12 -0
- sg_widgets_qt-0.1.0/CHANGELOG.md +30 -0
- sg_widgets_qt-0.1.0/LICENSE +21 -0
- sg_widgets_qt-0.1.0/PKG-INFO +137 -0
- sg_widgets_qt-0.1.0/README.md +106 -0
- sg_widgets_qt-0.1.0/docs/DESIGN.md +72 -0
- sg_widgets_qt-0.1.0/docs/README.md +74 -0
- sg_widgets_qt-0.1.0/docs/core/client.md +150 -0
- sg_widgets_qt-0.1.0/docs/core/context.md +86 -0
- sg_widgets_qt-0.1.0/docs/core/index.md +26 -0
- sg_widgets_qt-0.1.0/docs/design-rules.md +234 -0
- sg_widgets_qt-0.1.0/docs/porting-conventions.md +130 -0
- sg_widgets_qt-0.1.0/docs/screenshots/entity-grid-light.png +0 -0
- sg_widgets_qt-0.1.0/docs/screenshots/entity-multi-picker-light.png +0 -0
- sg_widgets_qt-0.1.0/docs/screenshots/entity-table-dark.png +0 -0
- sg_widgets_qt-0.1.0/docs/screenshots/entity-table-light.png +0 -0
- sg_widgets_qt-0.1.0/docs/screenshots/filter-editor-light.png +0 -0
- sg_widgets_qt-0.1.0/docs/screenshots/global-search-light.png +0 -0
- sg_widgets_qt-0.1.0/docs/screenshots/status-picker-light.png +0 -0
- sg_widgets_qt-0.1.0/docs/start/install.md +52 -0
- sg_widgets_qt-0.1.0/docs/start/introduction.md +23 -0
- sg_widgets_qt-0.1.0/docs/widgets/_index.json +79 -0
- sg_widgets_qt-0.1.0/docs/widgets/checkbox-editor.md +53 -0
- sg_widgets_qt-0.1.0/docs/widgets/checkbox-editor.props.json +100 -0
- sg_widgets_qt-0.1.0/docs/widgets/collection-control.md +124 -0
- sg_widgets_qt-0.1.0/docs/widgets/collection-control.props.json +85 -0
- sg_widgets_qt-0.1.0/docs/widgets/collection-footer.props.json +45 -0
- sg_widgets_qt-0.1.0/docs/widgets/collection-source.props.json +55 -0
- sg_widgets_qt-0.1.0/docs/widgets/color-editor.md +69 -0
- sg_widgets_qt-0.1.0/docs/widgets/color-editor.props.json +113 -0
- sg_widgets_qt-0.1.0/docs/widgets/column-picker.md +100 -0
- sg_widgets_qt-0.1.0/docs/widgets/column-picker.props.json +261 -0
- sg_widgets_qt-0.1.0/docs/widgets/context-selector.md +71 -0
- sg_widgets_qt-0.1.0/docs/widgets/context-selector.props.json +190 -0
- sg_widgets_qt-0.1.0/docs/widgets/date-editor.md +78 -0
- sg_widgets_qt-0.1.0/docs/widgets/date-editor.props.json +128 -0
- sg_widgets_qt-0.1.0/docs/widgets/date-time-editor.md +72 -0
- sg_widgets_qt-0.1.0/docs/widgets/date-time-editor.props.json +149 -0
- sg_widgets_qt-0.1.0/docs/widgets/editor-calendar.props.json +9 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-card.md +123 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-card.props.json +202 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-chip.md +90 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-chip.props.json +111 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-fields.props.json +9 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-glyphs.props.json +9 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-grid.md +92 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-grid.props.json +258 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-multi-picker.md +77 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-multi-picker.props.json +340 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-picker.md +103 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-picker.props.json +296 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-table.md +197 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-table.props.json +325 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-tree.md +118 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-tree.props.json +293 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-type-multi-picker.md +78 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-type-multi-picker.props.json +222 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-type-picker.md +74 -0
- sg_widgets_qt-0.1.0/docs/widgets/entity-type-picker.props.json +194 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-editor.md +110 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-editor.props.json +221 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-error.props.json +24 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-picker.md +109 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-picker.props.json +237 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-value.md +92 -0
- sg_widgets_qt-0.1.0/docs/widgets/field-value.props.json +145 -0
- sg_widgets_qt-0.1.0/docs/widgets/filter-bar.md +108 -0
- sg_widgets_qt-0.1.0/docs/widgets/filter-bar.props.json +121 -0
- sg_widgets_qt-0.1.0/docs/widgets/filter-dialog.md +50 -0
- sg_widgets_qt-0.1.0/docs/widgets/filter-dialog.props.json +113 -0
- sg_widgets_qt-0.1.0/docs/widgets/filter-editor.md +185 -0
- sg_widgets_qt-0.1.0/docs/widgets/filter-editor.props.json +118 -0
- sg_widgets_qt-0.1.0/docs/widgets/global-search.md +78 -0
- sg_widgets_qt-0.1.0/docs/widgets/global-search.props.json +218 -0
- sg_widgets_qt-0.1.0/docs/widgets/grouped-list.md +109 -0
- sg_widgets_qt-0.1.0/docs/widgets/grouped-list.props.json +300 -0
- sg_widgets_qt-0.1.0/docs/widgets/hierarchical-search.md +79 -0
- sg_widgets_qt-0.1.0/docs/widgets/hierarchical-search.props.json +161 -0
- sg_widgets_qt-0.1.0/docs/widgets/index.md +51 -0
- sg_widgets_qt-0.1.0/docs/widgets/list-multi-picker.md +93 -0
- sg_widgets_qt-0.1.0/docs/widgets/list-multi-picker.props.json +289 -0
- sg_widgets_qt-0.1.0/docs/widgets/list-multi-select.md +15 -0
- sg_widgets_qt-0.1.0/docs/widgets/list-picker.md +96 -0
- sg_widgets_qt-0.1.0/docs/widgets/list-picker.props.json +294 -0
- sg_widgets_qt-0.1.0/docs/widgets/list-select.md +15 -0
- sg_widgets_qt-0.1.0/docs/widgets/match-text.md +68 -0
- sg_widgets_qt-0.1.0/docs/widgets/match-text.props.json +24 -0
- sg_widgets_qt-0.1.0/docs/widgets/number-editor.md +107 -0
- sg_widgets_qt-0.1.0/docs/widgets/number-editor.props.json +195 -0
- sg_widgets_qt-0.1.0/docs/widgets/picker-control.md +203 -0
- sg_widgets_qt-0.1.0/docs/widgets/picker-control.props.json +357 -0
- sg_widgets_qt-0.1.0/docs/widgets/picker-row.props.json +125 -0
- sg_widgets_qt-0.1.0/docs/widgets/project-multi-picker.md +71 -0
- sg_widgets_qt-0.1.0/docs/widgets/project-multi-picker.props.json +347 -0
- sg_widgets_qt-0.1.0/docs/widgets/project-picker.md +66 -0
- sg_widgets_qt-0.1.0/docs/widgets/project-picker.props.json +331 -0
- sg_widgets_qt-0.1.0/docs/widgets/search-control.md +126 -0
- sg_widgets_qt-0.1.0/docs/widgets/search-control.props.json +200 -0
- sg_widgets_qt-0.1.0/docs/widgets/search-skeleton.props.json +38 -0
- sg_widgets_qt-0.1.0/docs/widgets/sort-picker.md +81 -0
- sg_widgets_qt-0.1.0/docs/widgets/sort-picker.props.json +129 -0
- sg_widgets_qt-0.1.0/docs/widgets/state-line.md +69 -0
- sg_widgets_qt-0.1.0/docs/widgets/state-line.props.json +45 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-badge.md +101 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-badge.props.json +96 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-glyph.props.json +38 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-multi-picker.md +107 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-multi-picker.props.json +246 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-picker.md +99 -0
- sg_widgets_qt-0.1.0/docs/widgets/status-picker.props.json +186 -0
- sg_widgets_qt-0.1.0/docs/widgets/text-editor.md +48 -0
- sg_widgets_qt-0.1.0/docs/widgets/text-editor.props.json +113 -0
- sg_widgets_qt-0.1.0/docs/widgets/thumbnail.md +64 -0
- sg_widgets_qt-0.1.0/docs/widgets/thumbnail.props.json +52 -0
- sg_widgets_qt-0.1.0/docs/widgets/url-editor.md +57 -0
- sg_widgets_qt-0.1.0/docs/widgets/url-editor.props.json +107 -0
- sg_widgets_qt-0.1.0/docs/widgets/user-avatar.md +65 -0
- sg_widgets_qt-0.1.0/docs/widgets/user-avatar.props.json +52 -0
- sg_widgets_qt-0.1.0/docs/widgets/user-multi-picker.md +81 -0
- sg_widgets_qt-0.1.0/docs/widgets/user-multi-picker.props.json +353 -0
- sg_widgets_qt-0.1.0/docs/widgets/user-picker.md +78 -0
- sg_widgets_qt-0.1.0/docs/widgets/user-picker.props.json +337 -0
- sg_widgets_qt-0.1.0/docs/widgets/value-editor.md +156 -0
- sg_widgets_qt-0.1.0/docs/widgets/value-editor.props.json +52 -0
- sg_widgets_qt-0.1.0/docs/writing-rules.md +47 -0
- sg_widgets_qt-0.1.0/pyproject.toml +110 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/__init__.py +30 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/client.py +589 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/collection.py +699 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/collection_state.py +303 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/context.py +135 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/edit.py +833 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/entity_card.py +183 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/field_icons.py +56 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/field_types.py +179 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/filter.py +236 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/filter_ux.py +1600 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/list_chrome.py +85 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/mock.py +2923 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/paging.py +171 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/picker.py +920 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/picker_keys.py +149 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/pickers.py +426 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/presentation.py +78 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/py.typed +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/query.py +274 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/render.py +739 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/row.py +155 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/schema.py +239 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/schema_service.py +194 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/search.py +492 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/shotgun_client.py +637 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/sortable.py +259 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/state.py +81 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/status.py +249 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/status_icons.py +613 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/status_service.py +70 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_core/tree.py +1104 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/__init__.py +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/LICENSE +43 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-down.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-left-to-line.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-up-down.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/arrow-up.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/bot.svg +20 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/box.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/braces.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/building-2.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/calendar-clock.svg +20 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/calendar.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/check.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-down.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-left.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-right.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevron-up.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/chevrons-up-down.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-alert.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-check.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-dollar-sign.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-dot.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle-x.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/circle.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/clapperboard.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/clock.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/columns-3.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/copy.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/dot.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/ellipsis-vertical.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/external-link.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/eye-off.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/eye.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/file-box.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/file-text.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/file.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/film.svg +22 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/filter.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/fingerprint.svg +23 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/folder-open.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/folder.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/git-branch.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/globe.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/grip-vertical.svg +20 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/hash.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/history.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/hourglass.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/image.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/inbox.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/info.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/key-round.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/layers.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/layout-grid.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/link-2.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/link.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/list-checks.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/list-filter.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/list.svg +20 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/loader-circle.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/loader.svg +22 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/message-square.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/minus.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/moon.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/more-horizontal.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/palette.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/pencil.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/percent.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/pin-off.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/play.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/plus.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/refresh-cw.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/rotate-ccw.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/rows-3.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/ruler.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/search-x.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/search.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/settings.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/shapes.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/sigma.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/square-check.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/square.svg +15 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/sun.svg +23 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/table.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/tag.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/timer.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/toggle-left.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/trash-2.svg +19 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/triangle-alert.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/type.svg +17 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/user.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/users.svg +18 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/video.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons/lucide/x.svg +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/icons.py +129 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/images.py +318 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/__init__.py +78 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/accessible.py +124 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/badge.py +395 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/base.py +634 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/button.py +559 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/calendar.py +666 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/checkbox.py +718 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/command.py +314 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/dialog.py +515 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/dropdown_menu.py +641 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/hover_card.py +173 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/input.py +453 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/input_group.py +378 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/label.py +178 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/list_view.py +553 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/popover.py +757 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/remove_control.py +144 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/roles.py +62 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/row_delegate.py +713 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/scroll_latch.py +70 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/scrollbar.py +344 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/select.py +365 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/skeleton.py +144 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/table.py +372 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/tooltip.py +144 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/primitives/type_scale.py +39 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/py.typed +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/__init__.py +33 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/__main__.py +76 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/chrome.py +248 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/context.py +223 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/__init__.py +16 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_editors.py +246 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_layout.py +251 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_leaf.py +176 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_pickers.py +183 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_results.py +471 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/_rows.py +63 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/checkbox_editor.py +69 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/collection_control.py +371 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/color_editor.py +73 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/column_picker.py +124 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/context_selector.py +147 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/date_editor.py +87 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/date_time_editor.py +116 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_card.py +234 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_chip.py +262 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_grid.py +201 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_multi_picker.py +225 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_picker.py +203 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_table.py +345 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_table_infinite.py +115 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_tree.py +173 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_type_multi_picker.py +163 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/entity_type_picker.py +116 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/field_editor.py +234 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/field_picker.py +155 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/field_value.py +312 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/filter_bar.py +199 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/filter_dialog.py +130 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/filter_editor.py +264 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/global_search.py +137 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/grouped_list.py +248 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/hello.py +155 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/hierarchical_search.py +89 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/list_multi_picker.py +76 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/list_picker.py +112 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/match_text.py +105 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/number_editor.py +135 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/picker_control.py +333 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/project_multi_picker.py +182 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/project_picker.py +123 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/search_control.py +183 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/sort_picker.py +98 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/state_line.py +149 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/status_badge.py +363 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/status_multi_picker.py +301 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/status_picker.py +230 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/text_editor.py +77 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/thumbnail.py +189 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/url_editor.py +71 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/user_avatar.py +210 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/user_multi_picker.py +191 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/user_picker.py +140 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/demos/value_editor.py +163 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/markdown.py +257 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/page.py +494 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/paths.py +97 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/prefs.py +225 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/stage.py +368 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/toolbar.py +117 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/showcase/window.py +558 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/__init__.py +715 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/GeistMono[wght].ttf +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/Geist[wght].ttf +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/Montserrat[wght].ttf +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-geist.txt +93 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-geistmono.txt +93 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-montserrat.txt +93 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-opensans.txt +92 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OFL-outfit.txt +93 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/OpenSans[wdth,wght].ttf +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/fonts/Outfit[wght].ttf +0 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/theme/palettes.json +618 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/__init__.py +207 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/_sortable_rows.py +660 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/checkbox_editor.py +163 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/collection_control.py +676 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/collection_footer.py +297 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/collection_source.py +446 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/color_editor.py +536 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/column_picker.py +1541 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/context_selector.py +988 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/date_editor.py +434 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/date_time_editor.py +324 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/editor_calendar.py +34 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_card.py +1861 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_chip.py +492 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_glyphs.py +35 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_grid.py +899 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_multi_picker.py +129 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_picker.py +761 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_table.py +1996 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_tree.py +1216 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_type_multi_picker.py +100 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/entity_type_picker.py +413 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_editor.py +1185 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_error.py +154 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_picker.py +1465 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/field_value.py +1361 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/filter_bar.py +1057 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/filter_dialog.py +357 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/filter_editor.py +2100 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/global_search.py +770 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/grouped_list.py +1127 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/hierarchical_search.py +605 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_multi_picker.py +178 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_multi_select.py +13 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_picker.py +789 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/list_select.py +12 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/match_text.py +159 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/number_editor.py +640 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/picker_control.py +1899 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/picker_row.py +881 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/project_multi_picker.py +44 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/project_picker.py +99 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/search_control.py +882 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/search_skeleton.py +219 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/sort_picker.py +630 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/state_line.py +198 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_badge.py +397 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_glyph.py +313 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_multi_picker.py +176 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/status_picker.py +587 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/text_editor.py +162 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/thumbnail.py +363 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/url_editor.py +188 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/user_avatar.py +317 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/user_multi_picker.py +54 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/user_picker.py +141 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/widgets/value_editor.py +717 -0
- sg_widgets_qt-0.1.0/src/sg_widgets_qt/workers.py +485 -0
- sg_widgets_qt-0.1.0/sync/manifest.json +2503 -0
- sg_widgets_qt-0.1.0/tests/__init__.py +0 -0
- sg_widgets_qt-0.1.0/tests/conftest.py +6 -0
- sg_widgets_qt-0.1.0/tests/core/__init__.py +0 -0
- sg_widgets_qt-0.1.0/tests/core/fake_client.py +623 -0
- sg_widgets_qt-0.1.0/tests/core/test_client.py +46 -0
- sg_widgets_qt-0.1.0/tests/core/test_collection.py +523 -0
- sg_widgets_qt-0.1.0/tests/core/test_collection_state.py +241 -0
- sg_widgets_qt-0.1.0/tests/core/test_context.py +99 -0
- sg_widgets_qt-0.1.0/tests/core/test_edit.py +518 -0
- sg_widgets_qt-0.1.0/tests/core/test_entity_card.py +144 -0
- sg_widgets_qt-0.1.0/tests/core/test_field_icons.py +45 -0
- sg_widgets_qt-0.1.0/tests/core/test_field_types.py +37 -0
- sg_widgets_qt-0.1.0/tests/core/test_filter.py +92 -0
- sg_widgets_qt-0.1.0/tests/core/test_filter_ux.py +1053 -0
- sg_widgets_qt-0.1.0/tests/core/test_hierarchy.py +189 -0
- sg_widgets_qt-0.1.0/tests/core/test_list_chrome.py +59 -0
- sg_widgets_qt-0.1.0/tests/core/test_mock.py +1218 -0
- sg_widgets_qt-0.1.0/tests/core/test_paging.py +253 -0
- sg_widgets_qt-0.1.0/tests/core/test_picker.py +613 -0
- sg_widgets_qt-0.1.0/tests/core/test_picker_keys.py +125 -0
- sg_widgets_qt-0.1.0/tests/core/test_pickers.py +365 -0
- sg_widgets_qt-0.1.0/tests/core/test_presentation.py +80 -0
- sg_widgets_qt-0.1.0/tests/core/test_query.py +258 -0
- sg_widgets_qt-0.1.0/tests/core/test_render.py +400 -0
- sg_widgets_qt-0.1.0/tests/core/test_row.py +120 -0
- sg_widgets_qt-0.1.0/tests/core/test_schema.py +158 -0
- sg_widgets_qt-0.1.0/tests/core/test_schema_service.py +155 -0
- sg_widgets_qt-0.1.0/tests/core/test_search.py +186 -0
- sg_widgets_qt-0.1.0/tests/core/test_shotgun_client.py +874 -0
- sg_widgets_qt-0.1.0/tests/core/test_sortable.py +132 -0
- sg_widgets_qt-0.1.0/tests/core/test_state.py +55 -0
- sg_widgets_qt-0.1.0/tests/core/test_status.py +108 -0
- sg_widgets_qt-0.1.0/tests/core/test_status_icons.py +43 -0
- sg_widgets_qt-0.1.0/tests/core/test_status_service.py +63 -0
- sg_widgets_qt-0.1.0/tests/core/test_tree.py +632 -0
- sg_widgets_qt-0.1.0/tests/qt/__init__.py +0 -0
- sg_widgets_qt-0.1.0/tests/qt/collections.py +140 -0
- sg_widgets_qt-0.1.0/tests/qt/editors.py +46 -0
- sg_widgets_qt-0.1.0/tests/qt/pickers.py +104 -0
- sg_widgets_qt-0.1.0/tests/qt/test_accessibility.py +247 -0
- sg_widgets_qt-0.1.0/tests/qt/test_checkbox_editor.py +95 -0
- sg_widgets_qt-0.1.0/tests/qt/test_collection_control.py +190 -0
- sg_widgets_qt-0.1.0/tests/qt/test_collection_source.py +135 -0
- sg_widgets_qt-0.1.0/tests/qt/test_color_editor.py +168 -0
- sg_widgets_qt-0.1.0/tests/qt/test_column_picker.py +602 -0
- sg_widgets_qt-0.1.0/tests/qt/test_context_selector.py +310 -0
- sg_widgets_qt-0.1.0/tests/qt/test_dark_grounds.py +208 -0
- sg_widgets_qt-0.1.0/tests/qt/test_dark_ink.py +245 -0
- sg_widgets_qt-0.1.0/tests/qt/test_date_editor.py +133 -0
- sg_widgets_qt-0.1.0/tests/qt/test_date_time_editor.py +120 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_card.py +388 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_chip.py +209 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_glyphs.py +90 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_grid.py +301 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_multi_picker.py +206 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_picker.py +299 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_table.py +684 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_tree.py +220 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_type_multi_picker.py +152 -0
- sg_widgets_qt-0.1.0/tests/qt/test_entity_type_picker.py +141 -0
- sg_widgets_qt-0.1.0/tests/qt/test_field_editor.py +493 -0
- sg_widgets_qt-0.1.0/tests/qt/test_field_picker.py +553 -0
- sg_widgets_qt-0.1.0/tests/qt/test_field_value.py +576 -0
- sg_widgets_qt-0.1.0/tests/qt/test_filter_bar.py +175 -0
- sg_widgets_qt-0.1.0/tests/qt/test_filter_dialog.py +159 -0
- sg_widgets_qt-0.1.0/tests/qt/test_filter_editor.py +559 -0
- sg_widgets_qt-0.1.0/tests/qt/test_global_search.py +233 -0
- sg_widgets_qt-0.1.0/tests/qt/test_grouped_list.py +299 -0
- sg_widgets_qt-0.1.0/tests/qt/test_hierarchical_search.py +289 -0
- sg_widgets_qt-0.1.0/tests/qt/test_icons.py +99 -0
- sg_widgets_qt-0.1.0/tests/qt/test_images.py +184 -0
- sg_widgets_qt-0.1.0/tests/qt/test_list_multi_picker.py +105 -0
- sg_widgets_qt-0.1.0/tests/qt/test_list_picker.py +136 -0
- sg_widgets_qt-0.1.0/tests/qt/test_match_text.py +159 -0
- sg_widgets_qt-0.1.0/tests/qt/test_number_editor.py +121 -0
- sg_widgets_qt-0.1.0/tests/qt/test_picker_contract.py +379 -0
- sg_widgets_qt-0.1.0/tests/qt/test_picker_control.py +427 -0
- sg_widgets_qt-0.1.0/tests/qt/test_picker_row.py +325 -0
- sg_widgets_qt-0.1.0/tests/qt/test_primitives_floating.py +489 -0
- sg_widgets_qt-0.1.0/tests/qt/test_primitives_leaf.py +564 -0
- sg_widgets_qt-0.1.0/tests/qt/test_primitives_lists.py +556 -0
- sg_widgets_qt-0.1.0/tests/qt/test_project_multi_picker.py +138 -0
- sg_widgets_qt-0.1.0/tests/qt/test_project_picker.py +129 -0
- sg_widgets_qt-0.1.0/tests/qt/test_scroll_latch.py +101 -0
- sg_widgets_qt-0.1.0/tests/qt/test_scrollbar.py +52 -0
- sg_widgets_qt-0.1.0/tests/qt/test_search_control.py +283 -0
- sg_widgets_qt-0.1.0/tests/qt/test_search_skeleton.py +76 -0
- sg_widgets_qt-0.1.0/tests/qt/test_showcase.py +461 -0
- sg_widgets_qt-0.1.0/tests/qt/test_showcase_collection_demos.py +216 -0
- sg_widgets_qt-0.1.0/tests/qt/test_showcase_demo_rows.py +65 -0
- sg_widgets_qt-0.1.0/tests/qt/test_showcase_docs.py +159 -0
- sg_widgets_qt-0.1.0/tests/qt/test_sort_picker.py +317 -0
- sg_widgets_qt-0.1.0/tests/qt/test_sortable_rows.py +178 -0
- sg_widgets_qt-0.1.0/tests/qt/test_state_line.py +140 -0
- sg_widgets_qt-0.1.0/tests/qt/test_status_badge.py +223 -0
- sg_widgets_qt-0.1.0/tests/qt/test_status_glyph.py +193 -0
- sg_widgets_qt-0.1.0/tests/qt/test_status_multi_picker.py +148 -0
- sg_widgets_qt-0.1.0/tests/qt/test_status_picker.py +183 -0
- sg_widgets_qt-0.1.0/tests/qt/test_text_editor.py +130 -0
- sg_widgets_qt-0.1.0/tests/qt/test_theme.py +233 -0
- sg_widgets_qt-0.1.0/tests/qt/test_theme_switch.py +225 -0
- sg_widgets_qt-0.1.0/tests/qt/test_thumbnail.py +163 -0
- sg_widgets_qt-0.1.0/tests/qt/test_url_editor.py +113 -0
- sg_widgets_qt-0.1.0/tests/qt/test_user_avatar.py +174 -0
- sg_widgets_qt-0.1.0/tests/qt/test_user_multi_picker.py +146 -0
- sg_widgets_qt-0.1.0/tests/qt/test_user_picker.py +170 -0
- sg_widgets_qt-0.1.0/tests/qt/test_value_editor.py +242 -0
- sg_widgets_qt-0.1.0/tests/qt/test_workers.py +323 -0
- sg_widgets_qt-0.1.0/tests/test_packaging.py +120 -0
- sg_widgets_qt-0.1.0/tests/test_sync.py +222 -0
- sg_widgets_qt-0.1.0/tools/export_docs.py +266 -0
- sg_widgets_qt-0.1.0/tools/export_palettes.py +404 -0
- sg_widgets_qt-0.1.0/tools/export_props.mjs +199 -0
- sg_widgets_qt-0.1.0/tools/lucide.py +202 -0
- sg_widgets_qt-0.1.0/tools/measure_diff.py +275 -0
- sg_widgets_qt-0.1.0/tools/measure_split.py +45 -0
- sg_widgets_qt-0.1.0/tools/props_types.py +252 -0
- sg_widgets_qt-0.1.0/tools/qa.py +277 -0
- sg_widgets_qt-0.1.0/tools/status.py +73 -0
- sg_widgets_qt-0.1.0/tools/sync_record.py +101 -0
- sg_widgets_qt-0.1.0/tools/sync_status.py +139 -0
|
@@ -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
|
+

|
|
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
|
+
|  | A picker searches the site, holds what was ticked as chips, and emits references. |
|
|
101
|
+
|  | The filter editor builds a condition tree and serialises it for the API. |
|
|
102
|
+
|  | Statuses carry the site's own names, codes, colours and icons, per project. |
|
|
103
|
+
|  | Global search reads across entity types and marks what matched. |
|
|
104
|
+
|  | A table, a grid and a tree page a set, sort it, group it and edit a cell. |
|
|
105
|
+
|  | 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
|
+

|
|
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
|
+
|  | A picker searches the site, holds what was ticked as chips, and emits references. |
|
|
70
|
+
|  | The filter editor builds a condition tree and serialises it for the API. |
|
|
71
|
+
|  | Statuses carry the site's own names, codes, colours and icons, per project. |
|
|
72
|
+
|  | Global search reads across entity types and marks what matched. |
|
|
73
|
+
|  | A table, a grid and a tree page a set, sort it, group it and edit a cell. |
|
|
74
|
+
|  | 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`).
|