mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge branch 'develop' into feature/item_types_value_type_validation
This commit is contained in:
commit
243b8941af
25 changed files with 2244 additions and 1188 deletions
|
|
@ -717,6 +717,9 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
if not self.ftrack_removed:
|
||||
return
|
||||
ent_infos = self.ftrack_removed
|
||||
self.log.debug(
|
||||
"Processing removed entities: {}".format(str(ent_infos))
|
||||
)
|
||||
removable_ids = []
|
||||
recreate_ents = []
|
||||
removed_names = []
|
||||
|
|
@ -878,8 +881,9 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
self.process_session.commit()
|
||||
|
||||
found_idx = None
|
||||
for idx, _entity in enumerate(self._avalon_ents):
|
||||
if _entity["_id"] == avalon_entity["_id"]:
|
||||
proj_doc, asset_docs = self._avalon_ents
|
||||
for idx, asset_doc in enumerate(asset_docs):
|
||||
if asset_doc["_id"] == avalon_entity["_id"]:
|
||||
found_idx = idx
|
||||
break
|
||||
|
||||
|
|
@ -894,7 +898,8 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
new_entity_id
|
||||
)
|
||||
# Update cached entities
|
||||
self._avalon_ents[found_idx] = avalon_entity
|
||||
asset_docs[found_idx] = avalon_entity
|
||||
self._avalon_ents = proj_doc, asset_docs
|
||||
|
||||
if self._avalon_ents_by_id is not None:
|
||||
mongo_id = avalon_entity["_id"]
|
||||
|
|
@ -1258,6 +1263,10 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
if not ent_infos:
|
||||
return
|
||||
|
||||
self.log.debug(
|
||||
"Processing renamed entities: {}".format(str(ent_infos))
|
||||
)
|
||||
|
||||
renamed_tasks = {}
|
||||
not_found = {}
|
||||
changeable_queue = queue.Queue()
|
||||
|
|
@ -1453,6 +1462,10 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
if not ent_infos:
|
||||
return
|
||||
|
||||
self.log.debug(
|
||||
"Processing added entities: {}".format(str(ent_infos))
|
||||
)
|
||||
|
||||
cust_attrs, hier_attrs = self.avalon_cust_attrs
|
||||
entity_type_conf_ids = {}
|
||||
# Skip if already exit in avalon db or tasks entities
|
||||
|
|
@ -1729,6 +1742,10 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
if not self.ftrack_moved:
|
||||
return
|
||||
|
||||
self.log.debug(
|
||||
"Processing moved entities: {}".format(str(self.ftrack_moved))
|
||||
)
|
||||
|
||||
ftrack_moved = {k: v for k, v in sorted(
|
||||
self.ftrack_moved.items(),
|
||||
key=(lambda line: len(
|
||||
|
|
@ -1859,6 +1876,10 @@ class SyncToAvalonEvent(BaseEvent):
|
|||
if not self.ftrack_updated:
|
||||
return
|
||||
|
||||
self.log.debug(
|
||||
"Processing updated entities: {}".format(str(self.ftrack_updated))
|
||||
)
|
||||
|
||||
ent_infos = self.ftrack_updated
|
||||
ftrack_mongo_mapping = {}
|
||||
not_found_ids = []
|
||||
|
|
|
|||
|
|
@ -2144,6 +2144,7 @@ class SyncEntitiesFactory:
|
|||
"name": _name,
|
||||
"parent": parent_entity
|
||||
})
|
||||
self.session.commit()
|
||||
|
||||
final_entity = {}
|
||||
for k, v in av_entity.items():
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import sys
|
|||
import six
|
||||
import pyblish.api
|
||||
from avalon import io
|
||||
from pprint import pformat
|
||||
|
||||
try:
|
||||
from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_AUTO_SYNC
|
||||
|
|
@ -40,9 +41,14 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin):
|
|||
|
||||
def process(self, context):
|
||||
self.context = context
|
||||
if "hierarchyContext" not in context.data:
|
||||
if "hierarchyContext" not in self.context.data:
|
||||
return
|
||||
|
||||
hierarchy_context = self.context.data["hierarchyContext"]
|
||||
|
||||
self.log.debug(
|
||||
f"__ hierarchy_context: `{pformat(hierarchy_context)}`")
|
||||
|
||||
self.session = self.context.data["ftrackSession"]
|
||||
project_name = self.context.data["projectEntity"]["name"]
|
||||
query = 'Project where full_name is "{}"'.format(project_name)
|
||||
|
|
@ -55,7 +61,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin):
|
|||
|
||||
self.ft_project = None
|
||||
|
||||
input_data = context.data["hierarchyContext"]
|
||||
input_data = hierarchy_context
|
||||
|
||||
# disable termporarily ftrack project's autosyncing
|
||||
if auto_sync_state:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin):
|
|||
families = ["clip", "shot"]
|
||||
|
||||
def process(self, context):
|
||||
# processing starts here
|
||||
if "hierarchyContext" not in context.data:
|
||||
self.log.info("skipping IntegrateHierarchyToAvalon")
|
||||
return
|
||||
|
|
@ -17,7 +18,29 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin):
|
|||
if not io.Session:
|
||||
io.install()
|
||||
|
||||
input_data = context.data["hierarchyContext"]
|
||||
active_assets = []
|
||||
hierarchy_context = context.data["hierarchyContext"]
|
||||
hierarchy_assets = self._get_assets(hierarchy_context)
|
||||
|
||||
# filter only the active publishing insatnces
|
||||
for instance in context:
|
||||
if instance.data.get("publish") is False:
|
||||
continue
|
||||
|
||||
if not instance.data.get("asset"):
|
||||
continue
|
||||
|
||||
active_assets.append(instance.data["asset"])
|
||||
|
||||
# filter out only assets which are activated as isntances
|
||||
new_hierarchy_assets = {k: v for k, v in hierarchy_assets.items()
|
||||
if k in active_assets}
|
||||
|
||||
# modify the hierarchy context so there are only fitred assets
|
||||
self._set_assets(hierarchy_context, new_hierarchy_assets)
|
||||
|
||||
input_data = context.data["hierarchyContext"] = hierarchy_context
|
||||
|
||||
self.project = None
|
||||
self.import_to_avalon(input_data)
|
||||
|
||||
|
|
@ -149,3 +172,41 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin):
|
|||
entity_id = io.insert_one(item).inserted_id
|
||||
|
||||
return io.find_one({"_id": entity_id})
|
||||
|
||||
def _get_assets(self, input_dict):
|
||||
""" Returns only asset dictionary.
|
||||
Usually the last part of deep dictionary which
|
||||
is not having any children
|
||||
"""
|
||||
for key in input_dict.keys():
|
||||
# check if child key is available
|
||||
if input_dict[key].get("childs"):
|
||||
# loop deeper
|
||||
return self._get_assets(input_dict[key]["childs"])
|
||||
else:
|
||||
# give the dictionary with assets
|
||||
return input_dict
|
||||
|
||||
def _set_assets(self, input_dict, new_assets=None):
|
||||
""" Modify the hierarchy context dictionary.
|
||||
It will replace the asset dictionary with only the filtred one.
|
||||
"""
|
||||
for key in input_dict.keys():
|
||||
# check if child key is available
|
||||
if input_dict[key].get("childs"):
|
||||
# return if this is just for testing purpose and no
|
||||
# new_assets property is avalable
|
||||
if not new_assets:
|
||||
return True
|
||||
|
||||
# test for deeper inner children availabelity
|
||||
if self._set_assets(input_dict[key]["childs"]):
|
||||
# if one level deeper is still children available
|
||||
# then process farther
|
||||
self._set_assets(input_dict[key]["childs"], new_assets)
|
||||
else:
|
||||
# or just assign the filtred asset ditionary
|
||||
input_dict[key]["childs"] = new_assets
|
||||
else:
|
||||
# test didnt find more childs in input dictionary
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class CollectEditorial(pyblish.api.InstancePlugin):
|
|||
actions = []
|
||||
|
||||
# presets
|
||||
extensions = [".mov"]
|
||||
extensions = [".mov", ".mp4"]
|
||||
|
||||
def process(self, instance):
|
||||
# remove context test attribute
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"Codec": {
|
||||
"compression": "jpg",
|
||||
"format": "image",
|
||||
"quality": 95
|
||||
},
|
||||
"Display Options": {
|
||||
"background": [
|
||||
0.714,
|
||||
0.714,
|
||||
0.714
|
||||
],
|
||||
"backgroundBottom": [
|
||||
0.714,
|
||||
0.714,
|
||||
0.714
|
||||
],
|
||||
"backgroundTop": [
|
||||
0.714,
|
||||
0.714,
|
||||
0.714
|
||||
],
|
||||
"override_display": true
|
||||
},
|
||||
"Generic": {
|
||||
"isolate_view": true,
|
||||
"off_screen": true
|
||||
},
|
||||
"IO": {
|
||||
"name": "",
|
||||
"open_finished": false,
|
||||
"raw_frame_numbers": false,
|
||||
"recent_playblasts": [],
|
||||
"save_file": false
|
||||
},
|
||||
"PanZoom": {
|
||||
"pan_zoom": true
|
||||
},
|
||||
"Renderer": {
|
||||
"rendererName": "vp2Renderer"
|
||||
},
|
||||
"Resolution": {
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"percent": 1.0,
|
||||
"mode": "Custom"
|
||||
},
|
||||
"Time Range": {
|
||||
"start_frame": 0,
|
||||
"end_frame": 25,
|
||||
"frame": "",
|
||||
"time": "Time Slider"
|
||||
},
|
||||
"Viewport Options": {
|
||||
"cameras": false,
|
||||
"clipGhosts": false,
|
||||
"controlVertices": false,
|
||||
"deformers": false,
|
||||
"dimensions": false,
|
||||
"displayLights": 0,
|
||||
"dynamicConstraints": false,
|
||||
"dynamics": false,
|
||||
"fluids": false,
|
||||
"follicles": false,
|
||||
"gpuCacheDisplayFilter": false,
|
||||
"greasePencils": false,
|
||||
"grid": false,
|
||||
"hairSystems": false,
|
||||
"handles": false,
|
||||
"high_quality": true,
|
||||
"hud": false,
|
||||
"hulls": false,
|
||||
"ikHandles": false,
|
||||
"imagePlane": false,
|
||||
"joints": false,
|
||||
"lights": false,
|
||||
"locators": false,
|
||||
"manipulators": false,
|
||||
"motionTrails": false,
|
||||
"nCloths": false,
|
||||
"nParticles": false,
|
||||
"nRigids": false,
|
||||
"nurbsCurves": false,
|
||||
"nurbsSurfaces": false,
|
||||
"override_viewport_options": true,
|
||||
"particleInstancers": false,
|
||||
"pivots": false,
|
||||
"planes": false,
|
||||
"pluginShapes": false,
|
||||
"polymeshes": true,
|
||||
"shadows": false,
|
||||
"strokes": false,
|
||||
"subdivSurfaces": false,
|
||||
"textures": false,
|
||||
"twoSidedLighting": true
|
||||
},
|
||||
"Camera Options": {
|
||||
"displayGateMask": false,
|
||||
"displayResolution": false,
|
||||
"displayFilmGate": false,
|
||||
"displayFieldChart": false,
|
||||
"displaySafeAction": false,
|
||||
"displaySafeTitle": false,
|
||||
"displayFilmPivot": false,
|
||||
"displayFilmOrigin": false,
|
||||
"overscan": 1.0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"ValidateModelName": {
|
||||
"enabled": true,
|
||||
"material_file": {
|
||||
"windows": "",
|
||||
"darwin": "",
|
||||
"linux": ""
|
||||
},
|
||||
"regex": ""
|
||||
},
|
||||
"ValidateAssemblyName": {
|
||||
"enabled": true
|
||||
},
|
||||
"ValidateShaderName": {
|
||||
"enabled": true,
|
||||
"regex": "(?P<asset>.*)_(.*)_SHD"
|
||||
},
|
||||
"ValidateMeshHasOverlappingUVs": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -1147,48 +1147,52 @@ class TerminalModel(QtGui.QStandardItemModel):
|
|||
|
||||
return prepared_records
|
||||
|
||||
def append(self, record_item):
|
||||
record_type = record_item["type"]
|
||||
def append(self, record_items):
|
||||
all_record_items = []
|
||||
for record_item in record_items:
|
||||
record_type = record_item["type"]
|
||||
|
||||
terminal_item_type = None
|
||||
if record_type == "record":
|
||||
for level, _type in self.level_to_record:
|
||||
if level > record_item["levelno"]:
|
||||
break
|
||||
terminal_item_type = _type
|
||||
terminal_item_type = None
|
||||
if record_type == "record":
|
||||
for level, _type in self.level_to_record:
|
||||
if level > record_item["levelno"]:
|
||||
break
|
||||
terminal_item_type = _type
|
||||
|
||||
else:
|
||||
terminal_item_type = record_type
|
||||
else:
|
||||
terminal_item_type = record_type
|
||||
|
||||
icon_color = self.item_icon_colors.get(terminal_item_type)
|
||||
icon_name = self.item_icon_name.get(record_type)
|
||||
icon_color = self.item_icon_colors.get(terminal_item_type)
|
||||
icon_name = self.item_icon_name.get(record_type)
|
||||
|
||||
top_item_icon = None
|
||||
if icon_color and icon_name:
|
||||
top_item_icon = QAwesomeIconFactory.icon(icon_name, icon_color)
|
||||
top_item_icon = None
|
||||
if icon_color and icon_name:
|
||||
top_item_icon = QAwesomeIconFactory.icon(icon_name, icon_color)
|
||||
|
||||
label = record_item["label"].split("\n")[0]
|
||||
label = record_item["label"].split("\n")[0]
|
||||
|
||||
top_item = QtGui.QStandardItem()
|
||||
top_item.setData(TerminalLabelType, Roles.TypeRole)
|
||||
top_item.setData(terminal_item_type, Roles.TerminalItemTypeRole)
|
||||
top_item.setData(label, QtCore.Qt.DisplayRole)
|
||||
top_item.setFlags(
|
||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
|
||||
)
|
||||
top_item = QtGui.QStandardItem()
|
||||
all_record_items.append(top_item)
|
||||
|
||||
if top_item_icon:
|
||||
top_item.setData(top_item_icon, QtCore.Qt.DecorationRole)
|
||||
detail_item = TerminalDetailItem(record_item)
|
||||
top_item.appendRow(detail_item)
|
||||
|
||||
self.appendRow(top_item)
|
||||
top_item.setData(TerminalLabelType, Roles.TypeRole)
|
||||
top_item.setData(terminal_item_type, Roles.TerminalItemTypeRole)
|
||||
top_item.setData(label, QtCore.Qt.DisplayRole)
|
||||
top_item.setFlags(
|
||||
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
|
||||
)
|
||||
|
||||
detail_item = TerminalDetailItem(record_item)
|
||||
detail_item.setData(TerminalDetailType, Roles.TypeRole)
|
||||
top_item.appendRow(detail_item)
|
||||
if top_item_icon:
|
||||
top_item.setData(top_item_icon, QtCore.Qt.DecorationRole)
|
||||
|
||||
detail_item.setData(TerminalDetailType, Roles.TypeRole)
|
||||
|
||||
self.invisibleRootItem().appendRows(all_record_items)
|
||||
|
||||
def update_with_result(self, result):
|
||||
for record in result["records"]:
|
||||
self.append(record)
|
||||
self.append(result["records"])
|
||||
|
||||
|
||||
class TerminalProxy(QtCore.QSortFilterProxyModel):
|
||||
|
|
|
|||
|
|
@ -1087,10 +1087,10 @@ class Window(QtWidgets.QDialog):
|
|||
info.setText(message)
|
||||
|
||||
# Include message in terminal
|
||||
self.terminal_model.append({
|
||||
self.terminal_model.append([{
|
||||
"label": message,
|
||||
"type": "info"
|
||||
})
|
||||
}])
|
||||
|
||||
self.animation_info_msg.stop()
|
||||
self.animation_info_msg.start()
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@
|
|||
"type": "list",
|
||||
"key": "profiles",
|
||||
"label": "Profiles",
|
||||
"object_type": "dict-item",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "dict-item",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
|
|
@ -168,6 +168,29 @@
|
|||
}
|
||||
```
|
||||
|
||||
### enum
|
||||
- returns value of single on multiple items from predefined values
|
||||
- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`)
|
||||
- values are defined under value of key `"enum_items"` as list
|
||||
- each item in list is simple dictionary where value is label and key is value which will be stored
|
||||
- should be possible to enter single dictionary if order of items doesn't matter
|
||||
|
||||
```
|
||||
{
|
||||
"key": "tags",
|
||||
"label": "Tags",
|
||||
"type": "enum",
|
||||
"multiselection": true,
|
||||
"enum_items": [
|
||||
{"burnin": "Add burnins"},
|
||||
{"ftrackreview": "Add to Ftrack"},
|
||||
{"delete": "Delete output"},
|
||||
{"slate-frame": "Add slate frame"},
|
||||
{"no-hnadles": "Skip handle frames"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Inputs for setting value using Pure inputs
|
||||
- these inputs also have required `"key"` and `"label"`
|
||||
- they use Pure inputs "as widgets"
|
||||
|
|
@ -176,37 +199,53 @@
|
|||
- output is list
|
||||
- items can be added and removed
|
||||
- items in list must be the same type
|
||||
- type of items is defined with key `"object_type"` where Pure input name is entered (e.g. `number`)
|
||||
- because Pure inputs may have modifiers (`number` input has `minimum`, `maximum` and `decimals`) you can set these in key `"input_modifiers"`
|
||||
- type of items is defined with key `"object_type"`
|
||||
- there are 2 possible ways how to set the type:
|
||||
1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below)
|
||||
2.) item type name as string without modifiers (e.g. `text`)
|
||||
|
||||
1.) with item modifiers
|
||||
```
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "number",
|
||||
"key": "exclude_ports",
|
||||
"label": "Exclude ports",
|
||||
"input_modifiers": {
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
"object_type": {
|
||||
"type": "number", # number item type
|
||||
"minimum": 1, # minimum modifier
|
||||
"maximum": 65535 # maximum modifier
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2.) without modifiers
|
||||
```
|
||||
{
|
||||
"type": "list",
|
||||
"key": "exclude_ports",
|
||||
"label": "Exclude ports",
|
||||
"object_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
### dict-modifiable
|
||||
- one of dictionary inputs, this is only used as value input
|
||||
- items in this input can be removed and added same way as in `list` input
|
||||
- value items in dictionary must be the same type
|
||||
- type of items is defined with key `"object_type"` where Pure input name is entered (e.g. `number`)
|
||||
- because Pure inputs may have modifiers (`number` input has `minimum`, `maximum` and `decimals`) you can set these in key `"input_modifiers"`
|
||||
- type of items is defined with key `"object_type"`
|
||||
- there are 2 possible ways how to set the type:
|
||||
1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below)
|
||||
2.) item type name as string without modifiers (e.g. `text`)
|
||||
- this input can be expandable
|
||||
- that can be set with key `"expandable"` as `True`/`False` (Default: `True`)
|
||||
- with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`)
|
||||
|
||||
1.) with item modifiers
|
||||
```
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": "number",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 300
|
||||
},
|
||||
|
|
@ -217,6 +256,18 @@
|
|||
}
|
||||
```
|
||||
|
||||
2.) without modifiers
|
||||
```
|
||||
{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": "text",
|
||||
"is_group": true,
|
||||
"key": "templates_mapping",
|
||||
"label": "Muster - Templates mapping",
|
||||
"is_file": true
|
||||
}
|
||||
```
|
||||
|
||||
### path-widget
|
||||
- input for paths, use `path-input` internally
|
||||
- has 2 input modifiers `"multiplatform"` and `"multipath"`
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,522 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "maya_capture",
|
||||
"label": "Maya Capture settings",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict-invisible",
|
||||
"key": "Codec",
|
||||
"label": "Codec",
|
||||
"collapsable": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Codec</b>"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "compression",
|
||||
"label": "Compression type"
|
||||
}, {
|
||||
"type": "text",
|
||||
"key": "format",
|
||||
"label": "Data format"
|
||||
}, {
|
||||
"type": "number",
|
||||
"key": "quality",
|
||||
"label": "Quality",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
|
||||
{
|
||||
"type": "splitter"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "dict-invisible",
|
||||
"key": "Display Options",
|
||||
"label": "Display Options",
|
||||
"collapsable": false,
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Display Options</b>"
|
||||
},
|
||||
{
|
||||
"type": "list-strict",
|
||||
"key": "background",
|
||||
"label": "Background Color: ",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}, {
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}, {
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "list-strict",
|
||||
"key": "backgroundBottom",
|
||||
"label": "Background Bottom: ",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}, {
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}, {
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "list-strict",
|
||||
"key": "backgroundTop",
|
||||
"label": "Background Top: ",
|
||||
"object_types": [
|
||||
{
|
||||
"label": "Red",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}, {
|
||||
"label": "Green",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}, {
|
||||
"label": "Blue",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"decimal": 3
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "boolean",
|
||||
"key": "override_display",
|
||||
"label": "Override display options"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
} ,
|
||||
{
|
||||
"type": "dict-invisible",
|
||||
"collapsable": true,
|
||||
"key": "Generic",
|
||||
"label": "Generic",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Generic</b>"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "isolate_view",
|
||||
"label": " Isolate view"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "off_screen",
|
||||
"label": " Off Screen"
|
||||
}
|
||||
]
|
||||
},{
|
||||
"type": "dict-invisible",
|
||||
"collapsable": true,
|
||||
"key": "IO",
|
||||
"label": "IO",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>IO</b>"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "name",
|
||||
"label": "Name"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "open_finished",
|
||||
"label": "Open finished"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "raw_frame_numbers",
|
||||
"label": "Raw frame numbers"
|
||||
},{
|
||||
"type": "list",
|
||||
"key": "recent_playblasts",
|
||||
"label": "Recent Playblasts",
|
||||
"object_type": "text"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "save_file",
|
||||
"label": "Save file"
|
||||
}
|
||||
]
|
||||
},{
|
||||
"type": "dict-invisible",
|
||||
"collapsable": true,
|
||||
"key": "PanZoom",
|
||||
"label": "Pan Zoom",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "pan_zoom",
|
||||
"label": " Pan Zoom"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},{
|
||||
"type": "dict-invisible",
|
||||
"collapsable": true,
|
||||
"key": "Renderer",
|
||||
"label": "Renderer",
|
||||
"children": [
|
||||
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Renderer</b>"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "rendererName",
|
||||
"label": " Renderer name"
|
||||
}
|
||||
]
|
||||
},{
|
||||
"type": "dict-invisible",
|
||||
"collapsable": true,
|
||||
"key": "Resolution",
|
||||
"label": "Resolution",
|
||||
"children": [
|
||||
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Resolution</b>"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "width",
|
||||
"label": " Width",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 99999
|
||||
},{
|
||||
"type": "number",
|
||||
"key": "height",
|
||||
"label": "Height",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 99999
|
||||
},{
|
||||
"type": "number",
|
||||
"key": "percent",
|
||||
"label": "percent",
|
||||
"decimal": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 200
|
||||
},{
|
||||
"type": "text",
|
||||
"key": "mode",
|
||||
"label": "Mode"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "splitter"
|
||||
},
|
||||
{
|
||||
"type": "dict-invisible",
|
||||
"collapsable": true,
|
||||
"key": "Time Range",
|
||||
"label": "Time Range",
|
||||
"children": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "<b>Time Range</b>"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"key": "start_frame",
|
||||
"label": " Start frame",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 999999
|
||||
},{
|
||||
"type": "number",
|
||||
"key": "end_frame",
|
||||
"label": "End frame",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 999999
|
||||
},{
|
||||
"type": "text",
|
||||
"key": "frame",
|
||||
"label": "Frame"
|
||||
},{
|
||||
"type": "text",
|
||||
"key": "time",
|
||||
"label": "Time"
|
||||
}
|
||||
]
|
||||
},{
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "Viewport Options",
|
||||
"label": "Viewport Options",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "cameras",
|
||||
"label": "cameras"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "clipGhosts",
|
||||
"label": "clipGhosts"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "controlVertices",
|
||||
"label": "controlVertices"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "deformers",
|
||||
"label": "deformers"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "dimensions",
|
||||
"label": "dimensions"
|
||||
},{
|
||||
"type": "number",
|
||||
"key": "displayLights",
|
||||
"label": "displayLights",
|
||||
"decimal": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 10
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "dynamicConstraints",
|
||||
"label": "dynamicConstraints"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "dynamics",
|
||||
"label": "dynamics"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "fluids",
|
||||
"label": "fluids"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "follicles",
|
||||
"label": "follicles"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "gpuCacheDisplayFilter",
|
||||
"label": "gpuCacheDisplayFilter"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "greasePencils",
|
||||
"label": "greasePencils"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "grid",
|
||||
"label": "grid"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "hairSystems",
|
||||
"label": "hairSystems"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "handles",
|
||||
"label": "handles"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "high_quality",
|
||||
"label": "high_quality"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "hud",
|
||||
"label": "hud"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "hulls",
|
||||
"label": "hulls"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "ikHandles",
|
||||
"label": "ikHandles"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "imagePlane",
|
||||
"label": "imagePlane"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "joints",
|
||||
"label": "joints"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "lights",
|
||||
"label": "lights"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "locators",
|
||||
"label": "locators"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "manipulators",
|
||||
"label": "manipulators"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "motionTrails",
|
||||
"label": "motionTrails"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "nCloths",
|
||||
"label": "nCloths"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "nParticles",
|
||||
"label": "nParticles"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "nRigids",
|
||||
"label": "nRigids"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "nurbsCurves",
|
||||
"label": "nurbsCurves"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "nurbsSurfaces",
|
||||
"label": "nurbsSurfaces"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "override_viewport_options",
|
||||
"label": "override_viewport_options"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "particleInstancers",
|
||||
"label": "particleInstancers"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "pivots",
|
||||
"label": "pivots"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "planes",
|
||||
"label": "planes"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "pluginShapes",
|
||||
"label": "pluginShapes"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "polymeshes",
|
||||
"label": "polymeshes"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "shadows",
|
||||
"label": "shadows"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "strokes",
|
||||
"label": "strokes"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "subdivSurfaces",
|
||||
"label": "subdivSurfaces"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "textures",
|
||||
"label": "textures"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "twoSidedLighting",
|
||||
"label": "twoSidedLighting"
|
||||
}
|
||||
]
|
||||
},{
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "Camera Options",
|
||||
"label": "Camera Options",
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "displayGateMask",
|
||||
"label": "displayGateMask"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displayResolution",
|
||||
"label": "displayResolution"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displayFilmGate",
|
||||
"label": "displayFilmGate"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displayFieldChart",
|
||||
"label": "displayFieldChart"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displaySafeAction",
|
||||
"label": "displaySafeAction"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displaySafeTitle",
|
||||
"label": "displaySafeTitle"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displayFilmPivot",
|
||||
"label": "displayFilmPivot"
|
||||
},{
|
||||
"type": "boolean",
|
||||
"key": "displayFilmOrigin",
|
||||
"label": "displayFilmOrigin"
|
||||
},{
|
||||
"type": "number",
|
||||
"key": "overscan",
|
||||
"label": "overscan",
|
||||
"decimal": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "publish",
|
||||
"label": "Publish plugins",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "ValidateModelName",
|
||||
"label": "Validate Model Name",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "Path to material file defining list of material names to check. This is material name per line simple text file.<br/>It will be checked against named group <b>shader</b> in your <em>Validation regex</em>.<p>For example: <br/> <code>^.*(?P=<shader>.+)_GEO</code></p>"
|
||||
},
|
||||
{
|
||||
"type": "path-widget",
|
||||
"key": "material_file",
|
||||
"label": "Material File",
|
||||
"multiplatform": true,
|
||||
"multipath": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "regex",
|
||||
"label": "Validation regex"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "ValidateAssemblyName",
|
||||
"label": "Validate Assembly Name",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "ValidateShaderName",
|
||||
"label": "ValidateShaderName",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}, {
|
||||
"type": "label",
|
||||
"label": "Shader name regex can use named capture group <b>asset</b> to validate against current asset name.<p><b>Example:</b><br/><code>^.*(?P=<asset>.+)_SHD</code></p>"
|
||||
|
||||
}, {
|
||||
"type": "text",
|
||||
"key": "regex",
|
||||
"label": "Validation regex"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "dict",
|
||||
"collapsable": true,
|
||||
"key": "ValidateMeshHasOverlappingUVs",
|
||||
"label": "ValidateMeshHasOverlappingUVs",
|
||||
"checkbox_key": "enabled",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"key": "enabled",
|
||||
"label": "Enabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"type": "raw-json",
|
||||
"key": "workfile_build",
|
||||
"label": "Workfile Build logic",
|
||||
"is_file": true
|
||||
}
|
||||
|
|
@ -9,6 +9,25 @@
|
|||
"type": "dict-invisible",
|
||||
"children": [
|
||||
{
|
||||
"type": "enum",
|
||||
"key": "test_enum_singleselection",
|
||||
"label": "Enum Single Selection",
|
||||
"enum_items": [
|
||||
{"value_1": "Label 1"},
|
||||
{"value_2": "Label 2"},
|
||||
{"value_3": "Label 3"}
|
||||
]
|
||||
}, {
|
||||
"type": "enum",
|
||||
"key": "test_enum_multiselection",
|
||||
"label": "Enum Multi Selection",
|
||||
"multiselection": true,
|
||||
"enum_items": [
|
||||
{"value_1": "Label 1"},
|
||||
{"value_2": "Label 2"},
|
||||
{"value_3": "Label 3"}
|
||||
]
|
||||
}, {
|
||||
"type": "boolean",
|
||||
"key": "bool",
|
||||
"label": "Boolean checkbox"
|
||||
|
|
@ -48,16 +67,16 @@
|
|||
"type": "list",
|
||||
"key": "list_item_of_multiline_texts",
|
||||
"label": "List of multiline texts",
|
||||
"object_type": "text",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"multiline": true
|
||||
}
|
||||
}, {
|
||||
"type": "list",
|
||||
"key": "list_item_of_floats",
|
||||
"label": "List of floats",
|
||||
"object_type": "number",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"decimal": 3,
|
||||
"minimum": 1000,
|
||||
"maximum": 2000
|
||||
|
|
@ -66,8 +85,8 @@
|
|||
"type": "dict-modifiable",
|
||||
"key": "modifiable_dict_of_integers",
|
||||
"label": "Modifiable dict of integers",
|
||||
"object_type": "number",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"decimal": 0,
|
||||
"minimum": 10,
|
||||
"maximum": 100
|
||||
|
|
@ -194,8 +213,8 @@
|
|||
"type": "list",
|
||||
"key": "dict_item",
|
||||
"label": "DictItem in List",
|
||||
"object_type": "dict-item",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "dict-item",
|
||||
"children": [
|
||||
{
|
||||
"key": "families",
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@
|
|||
"type": "list",
|
||||
"key": "statuses_name_change",
|
||||
"label": "Status name change",
|
||||
"object_type": "text",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "text",
|
||||
"multiline": false
|
||||
}
|
||||
}]
|
||||
|
|
@ -96,9 +96,9 @@
|
|||
"type": "dict-modifiable",
|
||||
"key": "status_update",
|
||||
"label": "Status Updates",
|
||||
"object_type": "list",
|
||||
"input_modifiers": {
|
||||
"object_type": "text"
|
||||
"object_type": {
|
||||
"type": "list",
|
||||
"object_type": "text"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -133,10 +133,10 @@
|
|||
},
|
||||
{
|
||||
"type": "list",
|
||||
"object_type": "number",
|
||||
"key": "exclude_ports",
|
||||
"label": "Exclude ports",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
|
|
@ -213,8 +213,8 @@
|
|||
"label": "Muster Resl URL"
|
||||
},{
|
||||
"type": "dict-modifiable",
|
||||
"object_type": "number",
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 300
|
||||
},
|
||||
|
|
|
|||
|
|
@ -38,6 +38,18 @@ QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:d
|
|||
QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus {
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
QComboBox {
|
||||
border: 1px solid #aaaaaa;
|
||||
border-radius: 3px;
|
||||
padding: 2px 2px 4px 4px;
|
||||
background: #1d272f;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView::item {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
QToolButton {
|
||||
background: transparent;
|
||||
}
|
||||
|
|
@ -102,6 +114,10 @@ QPushButton[btn-type="expand-toggle"] {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
#MultiSelectionComboBox {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#DictKey[state="studio"] {border-color: #bfccd6;}
|
||||
#DictKey[state="modified"] {border-color: #137cbd;}
|
||||
#DictKey[state="overriden"] {border-color: #00f;}
|
||||
|
|
@ -152,8 +168,10 @@ QPushButton[btn-type="expand-toggle"] {
|
|||
background: #141a1f;
|
||||
}
|
||||
|
||||
#DictAsWidgetBody{
|
||||
#DictAsWidgetBody {
|
||||
background: transparent;
|
||||
}
|
||||
#DictAsWidgetBody[show_borders="1"] {
|
||||
border: 2px solid #cccccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,9 +271,9 @@ class RootsWidget(QtWidgets.QWidget, SettingObject):
|
|||
)
|
||||
multiroot_data = {
|
||||
"key": self.key,
|
||||
"object_type": "path-widget",
|
||||
"expandable": False,
|
||||
"input_modifiers": {
|
||||
"object_type": {
|
||||
"type": "path-widget",
|
||||
"multiplatform": True
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ class SystemWidget(QtWidgets.QWidget):
|
|||
klass = lib.TypeToKlass.types.get(item_type)
|
||||
item = klass(child_configuration, self)
|
||||
self.input_fields.append(item)
|
||||
self.content_layout.addWidget(item)
|
||||
self.content_layout.addWidget(item, 0)
|
||||
|
||||
# Add spacer to stretch children guis
|
||||
spacer = QtWidgets.QWidget(self.content_widget)
|
||||
|
|
@ -532,7 +532,7 @@ class ProjectWidget(QtWidgets.QWidget):
|
|||
klass = lib.TypeToKlass.types.get(item_type)
|
||||
item = klass(child_configuration, self)
|
||||
self.input_fields.append(item)
|
||||
self.content_layout.addWidget(item)
|
||||
self.content_layout.addWidget(item, 0)
|
||||
|
||||
# Add spacer to stretch children guis
|
||||
spacer = QtWidgets.QWidget(self.content_widget)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -299,7 +299,11 @@ def gui_schema(subfolder, main_schema_name):
|
|||
|
||||
filepath = os.path.join(dirpath, filename)
|
||||
with open(filepath, "r") as json_stream:
|
||||
schema_data = json.load(json_stream)
|
||||
try:
|
||||
schema_data = json.load(json_stream)
|
||||
except Exception as e:
|
||||
raise Exception((f"Unable to parse JSON file {json_stream}\n "
|
||||
f" - {e}")) from e
|
||||
loaded_schemas[basename] = schema_data
|
||||
|
||||
main_schema = _fill_inner_schemas(
|
||||
|
|
|
|||
317
pype/tools/settings/settings/widgets/multiselection_combobox.py
Normal file
317
pype/tools/settings/settings/widgets/multiselection_combobox.py
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
from Qt import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class ComboItemDelegate(QtWidgets.QStyledItemDelegate):
|
||||
"""
|
||||
Helper styled delegate (mostly based on existing private Qt's
|
||||
delegate used by the QtWidgets.QComboBox). Used to style the popup like a
|
||||
list view (e.g windows style).
|
||||
"""
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
option = QtWidgets.QStyleOptionViewItem(option)
|
||||
option.showDecorationSelected = True
|
||||
|
||||
# option.state &= (
|
||||
# ~QtWidgets.QStyle.State_HasFocus
|
||||
# & ~QtWidgets.QStyle.State_MouseOver
|
||||
# )
|
||||
super(ComboItemDelegate, self).paint(painter, option, index)
|
||||
|
||||
|
||||
class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||
value_changed = QtCore.Signal()
|
||||
ignored_keys = {
|
||||
QtCore.Qt.Key_Up,
|
||||
QtCore.Qt.Key_Down,
|
||||
QtCore.Qt.Key_PageDown,
|
||||
QtCore.Qt.Key_PageUp,
|
||||
QtCore.Qt.Key_Home,
|
||||
QtCore.Qt.Key_End
|
||||
}
|
||||
|
||||
top_bottom_padding = 2
|
||||
left_right_padding = 3
|
||||
left_offset = 4
|
||||
top_bottom_margins = 2
|
||||
item_spacing = 5
|
||||
|
||||
item_bg_color = QtGui.QColor("#31424e")
|
||||
|
||||
def __init__(
|
||||
self, parent=None, placeholder="", separator=", ", **kwargs
|
||||
):
|
||||
super(MultiSelectionComboBox, self).__init__(parent=parent, **kwargs)
|
||||
self.setObjectName("MultiSelectionComboBox")
|
||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
|
||||
self._popup_is_shown = False
|
||||
self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True)
|
||||
self._initial_mouse_pos = None
|
||||
self._separator = separator
|
||||
self.placeholder_text = placeholder
|
||||
self.delegate = ComboItemDelegate(self)
|
||||
self.setItemDelegate(self.delegate)
|
||||
|
||||
self.lines = {}
|
||||
self.item_height = (
|
||||
self.fontMetrics().height()
|
||||
+ (2 * self.top_bottom_padding)
|
||||
+ (2 * self.top_bottom_margins)
|
||||
)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""Reimplemented."""
|
||||
self._popup_is_shown = False
|
||||
super(MultiSelectionComboBox, self).mousePressEvent(event)
|
||||
if self._popup_is_shown:
|
||||
self._initial_mouse_pos = self.mapToGlobal(event.pos())
|
||||
self._block_mouse_release_timer.start(
|
||||
QtWidgets.QApplication.doubleClickInterval()
|
||||
)
|
||||
|
||||
def showPopup(self):
|
||||
"""Reimplemented."""
|
||||
super(MultiSelectionComboBox, self).showPopup()
|
||||
view = self.view()
|
||||
view.installEventFilter(self)
|
||||
view.viewport().installEventFilter(self)
|
||||
self._popup_is_shown = True
|
||||
|
||||
def hidePopup(self):
|
||||
"""Reimplemented."""
|
||||
self.view().removeEventFilter(self)
|
||||
self.view().viewport().removeEventFilter(self)
|
||||
self._popup_is_shown = False
|
||||
self._initial_mouse_pos = None
|
||||
super(MultiSelectionComboBox, self).hidePopup()
|
||||
self.view().clearFocus()
|
||||
|
||||
def _event_popup_shown(self, obj, event):
|
||||
if not self._popup_is_shown:
|
||||
return
|
||||
|
||||
current_index = self.view().currentIndex()
|
||||
model = self.model()
|
||||
|
||||
if event.type() == QtCore.QEvent.MouseMove:
|
||||
if (
|
||||
self.view().isVisible()
|
||||
and self._initial_mouse_pos is not None
|
||||
and self._block_mouse_release_timer.isActive()
|
||||
):
|
||||
diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos
|
||||
if diff.manhattanLength() > 9:
|
||||
self._block_mouse_release_timer.stop()
|
||||
return
|
||||
|
||||
index_flags = current_index.flags()
|
||||
state = current_index.data(QtCore.Qt.CheckStateRole)
|
||||
new_state = None
|
||||
|
||||
if event.type() == QtCore.QEvent.MouseButtonRelease:
|
||||
if (
|
||||
self._block_mouse_release_timer.isActive()
|
||||
or not current_index.isValid()
|
||||
or not self.view().isVisible()
|
||||
or not self.view().rect().contains(event.pos())
|
||||
or not index_flags & QtCore.Qt.ItemIsSelectable
|
||||
or not index_flags & QtCore.Qt.ItemIsEnabled
|
||||
or not index_flags & QtCore.Qt.ItemIsUserCheckable
|
||||
):
|
||||
return
|
||||
|
||||
if state == QtCore.Qt.Unchecked:
|
||||
new_state = QtCore.Qt.Checked
|
||||
else:
|
||||
new_state = QtCore.Qt.Unchecked
|
||||
|
||||
elif event.type() == QtCore.QEvent.KeyPress:
|
||||
# TODO: handle QtCore.Qt.Key_Enter, Key_Return?
|
||||
if event.key() == QtCore.Qt.Key_Space:
|
||||
# toogle the current items check state
|
||||
if (
|
||||
index_flags & QtCore.Qt.ItemIsUserCheckable
|
||||
and index_flags & QtCore.Qt.ItemIsTristate
|
||||
):
|
||||
new_state = QtCore.Qt.CheckState((int(state) + 1) % 3)
|
||||
|
||||
elif index_flags & QtCore.Qt.ItemIsUserCheckable:
|
||||
if state != QtCore.Qt.Checked:
|
||||
new_state = QtCore.Qt.Checked
|
||||
else:
|
||||
new_state = QtCore.Qt.Unchecked
|
||||
|
||||
if new_state is not None:
|
||||
model.setData(current_index, new_state, QtCore.Qt.CheckStateRole)
|
||||
self.view().update(current_index)
|
||||
self.update_size_hint()
|
||||
self.value_changed.emit()
|
||||
return True
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
"""Reimplemented."""
|
||||
result = self._event_popup_shown(obj, event)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
return super(MultiSelectionComboBox, self).eventFilter(obj, event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""Reimplemented."""
|
||||
painter = QtWidgets.QStylePainter(self)
|
||||
option = QtWidgets.QStyleOptionComboBox()
|
||||
self.initStyleOption(option)
|
||||
painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option)
|
||||
|
||||
# draw the icon and text
|
||||
items = self.checked_items_text()
|
||||
if not items:
|
||||
option.currentText = self.placeholder_text
|
||||
option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled)
|
||||
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
|
||||
return
|
||||
|
||||
font_metricts = self.fontMetrics()
|
||||
for line, items in self.lines.items():
|
||||
top_y = (
|
||||
option.rect.top()
|
||||
+ (line * self.item_height)
|
||||
+ self.top_bottom_margins
|
||||
)
|
||||
left_x = option.rect.left() + self.left_offset
|
||||
for item in items:
|
||||
label_rect = font_metricts.boundingRect(item)
|
||||
label_height = label_rect.height()
|
||||
|
||||
label_rect.moveTop(top_y)
|
||||
label_rect.moveLeft(left_x)
|
||||
label_rect.setHeight(self.item_height)
|
||||
|
||||
bg_rect = QtCore.QRectF(label_rect)
|
||||
bg_rect.setWidth(
|
||||
label_rect.width()
|
||||
+ (2 * self.left_right_padding)
|
||||
)
|
||||
left_x = bg_rect.right() + self.item_spacing
|
||||
|
||||
label_rect.moveLeft(label_rect.x() + self.left_right_padding)
|
||||
|
||||
bg_rect.setHeight(label_height + (2 * self.top_bottom_padding))
|
||||
bg_rect.moveTop(bg_rect.top() + self.top_bottom_margins)
|
||||
|
||||
path = QtGui.QPainterPath()
|
||||
path.addRoundedRect(bg_rect, 5, 5)
|
||||
|
||||
painter.fillPath(path, self.item_bg_color)
|
||||
|
||||
painter.drawText(
|
||||
label_rect,
|
||||
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter,
|
||||
item
|
||||
)
|
||||
|
||||
def resizeEvent(self, *args, **kwargs):
|
||||
super(MultiSelectionComboBox, self).resizeEvent(*args, **kwargs)
|
||||
self.update_size_hint()
|
||||
|
||||
def update_size_hint(self):
|
||||
self.lines = {}
|
||||
|
||||
items = self.checked_items_text()
|
||||
if not items:
|
||||
self.update()
|
||||
return
|
||||
|
||||
option = QtWidgets.QStyleOptionComboBox()
|
||||
self.initStyleOption(option)
|
||||
btn_rect = self.style().subControlRect(
|
||||
QtWidgets.QStyle.CC_ComboBox,
|
||||
option,
|
||||
QtWidgets.QStyle.SC_ComboBoxArrow
|
||||
)
|
||||
total_width = option.rect.width() - btn_rect.width()
|
||||
font_metricts = self.fontMetrics()
|
||||
|
||||
line = 0
|
||||
self.lines = {line: []}
|
||||
|
||||
font_metricts = self.fontMetrics()
|
||||
default_left_x = 0 + self.left_offset
|
||||
left_x = int(default_left_x)
|
||||
for item in items:
|
||||
rect = font_metricts.boundingRect(item)
|
||||
width = rect.width() + (2 * self.left_right_padding)
|
||||
right_x = left_x + width
|
||||
if right_x > total_width:
|
||||
left_x = int(default_left_x)
|
||||
if self.lines.get(line):
|
||||
line += 1
|
||||
self.lines[line] = [item]
|
||||
left_x += width
|
||||
else:
|
||||
self.lines[line] = [item]
|
||||
line += 1
|
||||
else:
|
||||
self.lines[line].append(item)
|
||||
left_x = left_x + width + self.item_spacing
|
||||
|
||||
self.update()
|
||||
self.updateGeometry()
|
||||
|
||||
def sizeHint(self):
|
||||
value = super(MultiSelectionComboBox, self).sizeHint()
|
||||
lines = len(self.lines)
|
||||
if lines == 0:
|
||||
lines = 1
|
||||
value.setHeight(
|
||||
(lines * self.item_height)
|
||||
+ (2 * self.top_bottom_margins)
|
||||
)
|
||||
return value
|
||||
|
||||
def setItemCheckState(self, index, state):
|
||||
self.setItemData(index, state, QtCore.Qt.CheckStateRole)
|
||||
|
||||
def set_value(self, values):
|
||||
for idx in range(self.count()):
|
||||
value = self.itemData(idx, role=QtCore.Qt.UserRole)
|
||||
if value in values:
|
||||
check_state = QtCore.Qt.Checked
|
||||
else:
|
||||
check_state = QtCore.Qt.Unchecked
|
||||
self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole)
|
||||
self.update_size_hint()
|
||||
|
||||
def value(self):
|
||||
items = list()
|
||||
for idx in range(self.count()):
|
||||
state = self.itemData(idx, role=QtCore.Qt.CheckStateRole)
|
||||
if state == QtCore.Qt.Checked:
|
||||
items.append(
|
||||
self.itemData(idx, role=QtCore.Qt.UserRole)
|
||||
)
|
||||
return items
|
||||
|
||||
def checked_items_text(self):
|
||||
items = list()
|
||||
for idx in range(self.count()):
|
||||
state = self.itemData(idx, role=QtCore.Qt.CheckStateRole)
|
||||
if state == QtCore.Qt.Checked:
|
||||
items.append(self.itemText(idx))
|
||||
return items
|
||||
|
||||
def wheelEvent(self, event):
|
||||
event.ignore()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if (
|
||||
event.key() == QtCore.Qt.Key_Down
|
||||
and event.modifiers() & QtCore.Qt.AltModifier
|
||||
):
|
||||
return self.showPopup()
|
||||
|
||||
if event.key() in self.ignored_keys:
|
||||
return event.ignore()
|
||||
|
||||
return super(MultiSelectionComboBox, self).keyPressEvent(event)
|
||||
|
|
@ -25,6 +25,28 @@ class NumberSpinBox(QtWidgets.QDoubleSpinBox):
|
|||
return output
|
||||
|
||||
|
||||
class ComboBox(QtWidgets.QComboBox):
|
||||
value_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ComboBox, self).__init__(*args, **kwargs)
|
||||
|
||||
self.currentIndexChanged.connect(self._on_change)
|
||||
|
||||
def _on_change(self, *args, **kwargs):
|
||||
self.value_changed.emit()
|
||||
|
||||
def set_value(self, value):
|
||||
for idx in range(self.count()):
|
||||
_value = self.itemData(idx, role=QtCore.Qt.UserRole)
|
||||
if _value == value:
|
||||
self.setCurrentIndex(idx)
|
||||
break
|
||||
|
||||
def value(self):
|
||||
return self.itemData(self.currentIndex(), role=QtCore.Qt.UserRole)
|
||||
|
||||
|
||||
class PathInput(QtWidgets.QLineEdit):
|
||||
def clear_end_path(self):
|
||||
value = self.text().strip()
|
||||
|
|
@ -71,33 +93,51 @@ class ExpandingWidget(QtWidgets.QWidget):
|
|||
|
||||
top_part = ClickableWidget(parent=self)
|
||||
|
||||
side_line_widget = QtWidgets.QWidget(top_part)
|
||||
side_line_widget.setObjectName("SideLineWidget")
|
||||
|
||||
button_size = QtCore.QSize(5, 5)
|
||||
button_toggle = QtWidgets.QToolButton(parent=top_part)
|
||||
button_toggle = QtWidgets.QToolButton(parent=side_line_widget)
|
||||
button_toggle.setProperty("btn-type", "expand-toggle")
|
||||
button_toggle.setIconSize(button_size)
|
||||
button_toggle.setArrowType(QtCore.Qt.RightArrow)
|
||||
button_toggle.setCheckable(True)
|
||||
button_toggle.setChecked(False)
|
||||
|
||||
label_widget = QtWidgets.QLabel(label, parent=top_part)
|
||||
label_widget = QtWidgets.QLabel(label, parent=side_line_widget)
|
||||
label_widget.setObjectName("DictLabel")
|
||||
|
||||
side_line_widget = QtWidgets.QWidget(top_part)
|
||||
side_line_widget.setObjectName("SideLineWidget")
|
||||
before_label_widget = QtWidgets.QWidget(side_line_widget)
|
||||
before_label_layout = QtWidgets.QVBoxLayout(before_label_widget)
|
||||
before_label_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
after_label_widget = QtWidgets.QWidget(side_line_widget)
|
||||
after_label_layout = QtWidgets.QVBoxLayout(after_label_widget)
|
||||
after_label_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
spacer_widget = QtWidgets.QWidget(side_line_widget)
|
||||
|
||||
side_line_layout = QtWidgets.QHBoxLayout(side_line_widget)
|
||||
side_line_layout.setContentsMargins(5, 10, 0, 10)
|
||||
side_line_layout.addWidget(button_toggle)
|
||||
side_line_layout.addWidget(before_label_widget)
|
||||
side_line_layout.addWidget(label_widget)
|
||||
side_line_layout.addWidget(after_label_widget)
|
||||
side_line_layout.addWidget(spacer_widget, 1)
|
||||
|
||||
top_part_layout = QtWidgets.QHBoxLayout(top_part)
|
||||
top_part_layout.setContentsMargins(0, 0, 0, 0)
|
||||
top_part_layout.addWidget(side_line_widget)
|
||||
|
||||
before_label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
after_label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
||||
self.top_part_ending = None
|
||||
self.after_label_layout = None
|
||||
self.end_of_layout = None
|
||||
self.after_label_layout = after_label_layout
|
||||
self.before_label_layout = before_label_layout
|
||||
|
||||
self.side_line_widget = side_line_widget
|
||||
self.side_line_layout = side_line_layout
|
||||
|
|
@ -146,45 +186,10 @@ class ExpandingWidget(QtWidgets.QWidget):
|
|||
self.parent().updateGeometry()
|
||||
|
||||
def add_widget_after_label(self, widget):
|
||||
self._add_side_widget_subwidgets()
|
||||
self.after_label_layout.addWidget(widget)
|
||||
|
||||
def _add_side_widget_subwidgets(self):
|
||||
if self.top_part_ending is not None:
|
||||
return
|
||||
|
||||
top_part_ending = QtWidgets.QWidget(self.side_line_widget)
|
||||
top_part_ending.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
||||
top_part_ending_layout = QtWidgets.QHBoxLayout(top_part_ending)
|
||||
top_part_ending_layout.setContentsMargins(0, 0, 0, 0)
|
||||
top_part_ending_layout.setSpacing(0)
|
||||
top_part_ending_layout.setAlignment(QtCore.Qt.AlignVCenter)
|
||||
|
||||
after_label_widget = QtWidgets.QWidget(top_part_ending)
|
||||
spacer_item = QtWidgets.QWidget(top_part_ending)
|
||||
end_of_widget = QtWidgets.QWidget(top_part_ending)
|
||||
|
||||
self.after_label_layout = QtWidgets.QVBoxLayout(after_label_widget)
|
||||
self.after_label_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.end_of_layout = QtWidgets.QVBoxLayout(end_of_widget)
|
||||
self.end_of_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
spacer_layout = QtWidgets.QVBoxLayout(spacer_item)
|
||||
spacer_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
top_part_ending_layout.addWidget(after_label_widget, 0)
|
||||
top_part_ending_layout.addWidget(spacer_item, 1)
|
||||
top_part_ending_layout.addWidget(end_of_widget, 0)
|
||||
|
||||
top_part_ending.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
after_label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
spacer_item.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
end_of_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
||||
self.top_part_ending = top_part_ending
|
||||
self.side_line_layout.addWidget(top_part_ending)
|
||||
def add_widget_before_label(self, widget):
|
||||
self.before_label_layout.addWidget(widget)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
super(ExpandingWidget, self).resizeEvent(event)
|
||||
|
|
@ -243,10 +248,11 @@ class GridLabelWidget(QtWidgets.QWidget):
|
|||
self.properties = {}
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setContentsMargins(0, 2, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
|
||||
label_proxy = QtWidgets.QWidget(self)
|
||||
|
||||
label_proxy_layout = QtWidgets.QHBoxLayout(label_proxy)
|
||||
label_proxy_layout.setContentsMargins(0, 0, 0, 0)
|
||||
label_proxy_layout.setSpacing(0)
|
||||
|
|
@ -265,6 +271,9 @@ class GridLabelWidget(QtWidgets.QWidget):
|
|||
layout.addWidget(label_proxy, 0)
|
||||
layout.addWidget(spacer_widget_v, 1)
|
||||
|
||||
label_proxy.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
||||
self.label_widget = label_widget
|
||||
|
||||
def setProperty(self, name, value):
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = "2.12.0"
|
||||
__version__ = "2.12.1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue