From a896a3a9e9ac398625a47a6f4765723bf3c3cc02 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 11 Oct 2021 09:31:50 +0200 Subject: [PATCH 001/100] base func and files --- openpype/hosts/nuke/api/lib.py | 17 ++ .../hosts/nuke/plugins/create/create_geo.py | 53 +++++ .../hosts/nuke/plugins/load/load_geo_abc.py | 187 ++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 openpype/hosts/nuke/plugins/create/create_geo.py create mode 100644 openpype/hosts/nuke/plugins/load/load_geo_abc.py diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 6fe9af744b..40701605e5 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1823,3 +1823,20 @@ def recreate_instance(origin_node, avalon_data=None): dn.setInput(0, new_node) return new_node + + +def extract_alembic(file, + startFrame=None, + endFrame=None): + """Extract an Alembic Geo. + + This extracts an Alembic Geo .... what was Collected into the instance. + + Arguments: + + startFrame (float): Start frame of output. + + endFrame (float): End frame of output. + + """ + pass \ No newline at end of file diff --git a/openpype/hosts/nuke/plugins/create/create_geo.py b/openpype/hosts/nuke/plugins/create/create_geo.py new file mode 100644 index 0000000000..6aefe6d51a --- /dev/null +++ b/openpype/hosts/nuke/plugins/create/create_geo.py @@ -0,0 +1,53 @@ +from avalon.nuke import lib as anlib +from openpype.hosts.nuke.api import plugin +import nuke + + +class CreateGeo(plugin.PypeCreator): + """Add Publishable Geometry""" + + name = "geo" + label = "Create 3d Geo" + family = "model" + icon = "cube" + defaults = ["Main"] + + def __init__(self, *args, **kwargs): + super(CreateGeo, self).__init__(*args, **kwargs) + self.nodes = nuke.selectedNodes() + self.node_color = "0xff3200ff" + return + + def process(self): + nodes = list() + if (self.options or {}).get("useSelection"): + nodes = self.nodes + + if len(nodes) >= 1: + # loop selected nodes + for n in nodes: + data = self.data.copy() + if len(nodes) > 1: + # rename subset name only if more + # then one node are selected + subset = self.family + n["name"].value().capitalize() + data["subset"] = subset + + # change node color + n["tile_color"].setValue(int(self.node_color, 16)) + # add avalon knobs + anlib.set_avalon_knob_data(n, data) + return True + else: + msg = str("Please select nodes you " + "wish to add to a container") + self.log.error(msg) + nuke.message(msg) + return + else: + # if selected is off then create one node + geo_node = nuke.createNode("Geo2") + geo_node["tile_color"].setValue(int(self.node_color, 16)) + # add avalon knobs + instance = anlib.set_avalon_knob_data(geo_node, self.data) + return instance diff --git a/openpype/hosts/nuke/plugins/load/load_geo_abc.py b/openpype/hosts/nuke/plugins/load/load_geo_abc.py new file mode 100644 index 0000000000..faf63281cc --- /dev/null +++ b/openpype/hosts/nuke/plugins/load/load_geo_abc.py @@ -0,0 +1,187 @@ +from avalon import api, io +from avalon.nuke import lib as anlib +from avalon.nuke import containerise, update_container +import nuke + + +class AlembicGeoLoader(api.Loader): + """ + This will load alembic geo into script. + """ + + families = ["geo"] + representations = ["abc"] + + label = "Load Alembic Geo" + icon = "geo" + color = "orange" + node_color = "0xff3200ff" + + def load(self, context, name, namespace, data): + # get main variables + version = context['version'] + version_data = version.get("data", {}) + vname = version.get("name", None) + first = version_data.get("frameStart", None) + last = version_data.get("frameEnd", None) + fps = version_data.get("fps") or nuke.root()["fps"].getValue() + namespace = namespace or context['asset']['name'] + object_name = "{}_{}".format(name, namespace) + + # prepare data for imprinting + # add additional metadata from the version to imprint to Avalon knob + add_keys = ["source", "author", "fps"] + + data_imprint = {"frameStart": first, + "frameEnd": last, + "version": vname, + "objectName": object_name} + + for k in add_keys: + data_imprint.update({k: version_data[k]}) + + # getting file path + file = self.fname.replace("\\", "/") + + with anlib.maintained_selection(): + geo_node = nuke.createNode( + "Geo2", + "name {} file {} read_from_file True".format( + object_name, file), + inpanel=False + ) + geo_node.forceValidate() + geo_node["frame_rate"].setValue(float(fps)) + + # workaround because nuke's bug is not adding + # animation keys properly + xpos = geo_node.xpos() + ypos = geo_node.ypos() + nuke.nodeCopy("%clipboard%") + nuke.delete(geo_node) + nuke.nodePaste("%clipboard%") + geo_node = nuke.toNode(object_name) + geo_node.setXYpos(xpos, ypos) + + # color node by correct color by actual version + self.node_version_color(version, geo_node) + + return containerise( + node=geo_node, + name=name, + namespace=namespace, + context=context, + loader=self.__class__.__name__, + data=data_imprint) + + def update(self, container, representation): + """ + Called by Scene Inventory when look should be updated to current + version. + If any reference edits cannot be applied, eg. shader renamed and + material not present, reference is unloaded and cleaned. + All failed edits are highlighted to the user via message box. + + Args: + container: object that has look to be updated + representation: (dict): relationship data to get proper + representation from DB and persisted + data in .json + Returns: + None + """ + # Get version from io + version = io.find_one({ + "type": "version", + "_id": representation["parent"] + }) + object_name = container['objectName'] + # get corresponding node + geo_node = nuke.toNode(object_name) + + # get main variables + version_data = version.get("data", {}) + vname = version.get("name", None) + first = version_data.get("frameStart", None) + last = version_data.get("frameEnd", None) + fps = version_data.get("fps") or nuke.root()["fps"].getValue() + + # prepare data for imprinting + # add additional metadata from the version to imprint to Avalon knob + add_keys = ["source", "author", "fps"] + + data_imprint = {"representation": str(representation["_id"]), + "frameStart": first, + "frameEnd": last, + "version": vname, + "objectName": object_name} + + for k in add_keys: + data_imprint.update({k: version_data[k]}) + + # getting file path + file = api.get_representation_path(representation).replace("\\", "/") + + with anlib.maintained_selection(): + geo_node = nuke.toNode(object_name) + geo_node['selected'].setValue(True) + + # collect input output dependencies + dependencies = geo_node.dependencies() + dependent = geo_node.dependent() + + geo_node["frame_rate"].setValue(float(fps)) + geo_node["file"].setValue(file) + + # workaround because nuke's bug is + # not adding animation keys properly + xpos = geo_node.xpos() + ypos = geo_node.ypos() + nuke.nodeCopy("%clipboard%") + nuke.delete(geo_node) + nuke.nodePaste("%clipboard%") + geo_node = nuke.toNode(object_name) + geo_node.setXYpos(xpos, ypos) + + # link to original input nodes + for i, input in enumerate(dependencies): + geo_node.setInput(i, input) + # link to original output nodes + for d in dependent: + index = next((i for i, dpcy in enumerate( + d.dependencies()) + if geo_node is dpcy), 0) + d.setInput(index, geo_node) + + # color node by correct color by actual version + self.node_version_color(version, geo_node) + + self.log.info("udated to version: {}".format(version.get("name"))) + + return update_container(geo_node, data_imprint) + + def node_version_color(self, version, node): + """ Coloring a node by correct color by actual version + """ + # get all versions in list + versions = io.find({ + "type": "version", + "parent": version["parent"] + }).distinct('name') + + max_version = max(versions) + + # change color of node + if version.get("name") not in [max_version]: + node["tile_color"].setValue(int("0xd88467ff", 16)) + else: + node["tile_color"].setValue(int(self.node_color, 16)) + + def switch(self, container, representation): + self.update(container, representation) + + def remove(self, container): + from avalon.nuke import viewer_update_and_undo_stop + node = nuke.toNode(container['objectName']) + with viewer_update_and_undo_stop(): + nuke.delete(node) From a6c1037de2671b491df51a7fa8d33e1834685835 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Wed, 13 Oct 2021 11:41:56 +0200 Subject: [PATCH 002/100] model family name instead of geo --- .../create/{create_geo.py => create_model.py} | 16 +- .../load/{load_geo_abc.py => load_model.py} | 66 +++---- .../nuke/plugins/publish/collect_model.py | 50 +++++ .../nuke/plugins/publish/extract_model.py | 185 ++++++++++++++++++ .../nuke/plugins/publish/validate_model.py | 58 ++++++ 5 files changed, 334 insertions(+), 41 deletions(-) rename openpype/hosts/nuke/plugins/create/{create_geo.py => create_model.py} (79%) rename openpype/hosts/nuke/plugins/load/{load_geo_abc.py => load_model.py} (78%) create mode 100644 openpype/hosts/nuke/plugins/publish/collect_model.py create mode 100644 openpype/hosts/nuke/plugins/publish/extract_model.py create mode 100644 openpype/hosts/nuke/plugins/publish/validate_model.py diff --git a/openpype/hosts/nuke/plugins/create/create_geo.py b/openpype/hosts/nuke/plugins/create/create_model.py similarity index 79% rename from openpype/hosts/nuke/plugins/create/create_geo.py rename to openpype/hosts/nuke/plugins/create/create_model.py index 6aefe6d51a..26b80788ff 100644 --- a/openpype/hosts/nuke/plugins/create/create_geo.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -3,17 +3,17 @@ from openpype.hosts.nuke.api import plugin import nuke -class CreateGeo(plugin.PypeCreator): - """Add Publishable Geometry""" +class CreateModel(plugin.PypeCreator): + """Add Publishable Modelmetry""" - name = "geo" - label = "Create 3d Geo" + name = "model" + label = "Create 3d Model" family = "model" icon = "cube" defaults = ["Main"] def __init__(self, *args, **kwargs): - super(CreateGeo, self).__init__(*args, **kwargs) + super(CreateModel, self).__init__(*args, **kwargs) self.nodes = nuke.selectedNodes() self.node_color = "0xff3200ff" return @@ -46,8 +46,8 @@ class CreateGeo(plugin.PypeCreator): return else: # if selected is off then create one node - geo_node = nuke.createNode("Geo2") - geo_node["tile_color"].setValue(int(self.node_color, 16)) + model_node = nuke.createNode("Model2") + model_node["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs - instance = anlib.set_avalon_knob_data(geo_node, self.data) + instance = anlib.set_avalon_knob_data(model_node, self.data) return instance diff --git a/openpype/hosts/nuke/plugins/load/load_geo_abc.py b/openpype/hosts/nuke/plugins/load/load_model.py similarity index 78% rename from openpype/hosts/nuke/plugins/load/load_geo_abc.py rename to openpype/hosts/nuke/plugins/load/load_model.py index faf63281cc..4ff568214e 100644 --- a/openpype/hosts/nuke/plugins/load/load_geo_abc.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -4,16 +4,16 @@ from avalon.nuke import containerise, update_container import nuke -class AlembicGeoLoader(api.Loader): +class AlembicModelLoader(api.Loader): """ - This will load alembic geo into script. + This will load alembic model into script. """ - families = ["geo"] + families = ["model"] representations = ["abc"] - label = "Load Alembic Geo" - icon = "geo" + label = "Load Alembic Model" + icon = "model" color = "orange" node_color = "0xff3200ff" @@ -44,30 +44,30 @@ class AlembicGeoLoader(api.Loader): file = self.fname.replace("\\", "/") with anlib.maintained_selection(): - geo_node = nuke.createNode( - "Geo2", + model_node = nuke.createNode( + "Model2", "name {} file {} read_from_file True".format( object_name, file), inpanel=False ) - geo_node.forceValidate() - geo_node["frame_rate"].setValue(float(fps)) + model_node.forceValidate() + model_node["frame_rate"].setValue(float(fps)) # workaround because nuke's bug is not adding # animation keys properly - xpos = geo_node.xpos() - ypos = geo_node.ypos() + xpos = model_node.xpos() + ypos = model_node.ypos() nuke.nodeCopy("%clipboard%") - nuke.delete(geo_node) + nuke.delete(model_node) nuke.nodePaste("%clipboard%") - geo_node = nuke.toNode(object_name) - geo_node.setXYpos(xpos, ypos) + model_node = nuke.toNode(object_name) + model_node.setXYpos(xpos, ypos) # color node by correct color by actual version - self.node_version_color(version, geo_node) + self.node_version_color(version, model_node) return containerise( - node=geo_node, + node=model_node, name=name, namespace=namespace, context=context, @@ -97,7 +97,7 @@ class AlembicGeoLoader(api.Loader): }) object_name = container['objectName'] # get corresponding node - geo_node = nuke.toNode(object_name) + model_node = nuke.toNode(object_name) # get main variables version_data = version.get("data", {}) @@ -123,42 +123,42 @@ class AlembicGeoLoader(api.Loader): file = api.get_representation_path(representation).replace("\\", "/") with anlib.maintained_selection(): - geo_node = nuke.toNode(object_name) - geo_node['selected'].setValue(True) + model_node = nuke.toNode(object_name) + model_node['selected'].setValue(True) # collect input output dependencies - dependencies = geo_node.dependencies() - dependent = geo_node.dependent() + dependencies = model_node.dependencies() + dependent = model_node.dependent() - geo_node["frame_rate"].setValue(float(fps)) - geo_node["file"].setValue(file) + model_node["frame_rate"].setValue(float(fps)) + model_node["file"].setValue(file) # workaround because nuke's bug is # not adding animation keys properly - xpos = geo_node.xpos() - ypos = geo_node.ypos() + xpos = model_node.xpos() + ypos = model_node.ypos() nuke.nodeCopy("%clipboard%") - nuke.delete(geo_node) + nuke.delete(model_node) nuke.nodePaste("%clipboard%") - geo_node = nuke.toNode(object_name) - geo_node.setXYpos(xpos, ypos) + model_node = nuke.toNode(object_name) + model_node.setXYpos(xpos, ypos) # link to original input nodes for i, input in enumerate(dependencies): - geo_node.setInput(i, input) + model_node.setInput(i, input) # link to original output nodes for d in dependent: index = next((i for i, dpcy in enumerate( d.dependencies()) - if geo_node is dpcy), 0) - d.setInput(index, geo_node) + if model_node is dpcy), 0) + d.setInput(index, model_node) # color node by correct color by actual version - self.node_version_color(version, geo_node) + self.node_version_color(version, model_node) self.log.info("udated to version: {}".format(version.get("name"))) - return update_container(geo_node, data_imprint) + return update_container(model_node, data_imprint) def node_version_color(self, version, node): """ Coloring a node by correct color by actual version diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py new file mode 100644 index 0000000000..f764c9d9ac --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -0,0 +1,50 @@ +import pyblish.api +import nuke + + +@pyblish.api.log +class CollectModel(pyblish.api.InstancePlugin): + """Collect Model (group) node instance and its content + """ + + order = pyblish.api.CollectorOrder + 0.22 + label = "Collect Model (Group)" + hosts = ["nuke"] + families = ["model"] + + def process(self, instance): + + grpn = instance[0] + + # add family to familiess + instance.data["families"].insert(0, instance.data["family"]) + # make label nicer + instance.data["label"] = "{0} ({1} nodes)".format( + grpn.name(), len(instance) - 1) + + # Get frame range + handle_start = instance.context.data["handleStart"] + handle_end = instance.context.data["handleEnd"] + first_frame = int(nuke.root()["first_frame"].getValue()) + last_frame = int(nuke.root()["last_frame"].getValue()) + + # Add version data to instance + version_data = { + "handles": handle_start, + "handleStart": handle_start, + "handleEnd": handle_end, + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, + "colorspace": nuke.root().knob('workingSpaceLUT').value(), + "families": [instance.data["family"]] + instance.data["families"], + "subset": instance.data["subset"], + "fps": instance.context.data["fps"] + } + + instance.data.update({ + "versionData": version_data, + "frameStart": first_frame, + "frameEnd": last_frame + }) + self.log.info("Model content collected: `{}`".format(instance[:])) + self.log.info("Model instance collected: `{}`".format(instance)) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py new file mode 100644 index 0000000000..bd6fa1e337 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -0,0 +1,185 @@ +import nuke +import os +import math +import pyblish.api +import openpype.api +from avalon.nuke import lib as anlib +from pprint import pformat + + +class ExtractModel(openpype.api.Extractor): + """ 3D model exctractor + """ + label = 'Exctract Model' + order = pyblish.api.ExtractorOrder + families = ["model"] + hosts = ["nuke"] + + # presets + write_geo_knobs = [ + ("file_type", "abc"), + ("storageFormat", "Ogawa"), + ("writeGeometries", False), + ("writePointClouds", False), + ("writeAxes", False) + ] + + def process(self, instance): + handle_start = instance.context.data["handleStart"] + handle_end = instance.context.data["handleEnd"] + first_frame = int(nuke.root()["first_frame"].getValue()) + last_frame = int(nuke.root()["last_frame"].getValue()) + step = 1 + output_range = str(nuke.FrameRange(first_frame, last_frame, step)) + + self.log.info("instance.data: `{}`".format( + pformat(instance.data))) + + rm_nodes = list() + self.log.info("Crating additional nodes") + subset = instance.data["subset"] + staging_dir = self.staging_dir(instance) + + # get extension form preset + extension = next((k[1] for k in self.write_geo_knobs + if k[0] == "file_type"), None) + if not extension: + raise RuntimeError( + "Bad config for extension in presets. " + "Talk to your supervisor or pipeline admin") + + # create file name and path + filename = subset + ".{}".format(extension) + file_path = os.path.join(staging_dir, filename).replace("\\", "/") + + with anlib.maintained_selection(): + # bake model with axeses onto word coordinate XYZ + rm_n = bakeModelWithAxeses( + nuke.toNode(instance.data["name"]), output_range) + rm_nodes.append(rm_n) + + # create scene node + rm_n = nuke.createNode("Scene") + rm_nodes.append(rm_n) + + # create write geo node + wg_n = nuke.createNode("WriteGeo") + wg_n["file"].setValue(file_path) + # add path to write to + for k, v in self.write_geo_knobs: + wg_n[k].setValue(v) + rm_nodes.append(wg_n) + + # write out model + nuke.execute( + wg_n, + int(first_frame), + int(last_frame) + ) + # erase additional nodes + for n in rm_nodes: + nuke.delete(n) + + self.log.info(file_path) + + # create representation data + if "representations" not in instance.data: + instance.data["representations"] = [] + + representation = { + 'name': extension, + 'ext': extension, + 'files': filename, + "stagingDir": staging_dir, + "frameStart": first_frame, + "frameEnd": last_frame + } + instance.data["representations"].append(representation) + + instance.data.update({ + "path": file_path, + "outputDir": staging_dir, + "ext": extension, + "handleStart": handle_start, + "handleEnd": handle_end, + "frameStart": first_frame + handle_start, + "frameEnd": last_frame - handle_end, + "frameStartHandle": first_frame, + "frameEndHandle": last_frame, + }) + + self.log.info("Extracted instance '{0}' to: {1}".format( + instance.name, file_path)) + + +def bakeModelWithAxeses(model_node, output_range): + """ Baking all perent hiearchy of axeses into model + with transposition onto word XYZ coordinance + """ + bakeFocal = False + bakeHaperture = False + bakeVaperture = False + + model_matrix = model_node['world_matrix'] + + new_cam_n = nuke.createNode("Model2") + new_cam_n.setInput(0, None) + new_cam_n['rotate'].setAnimated() + new_cam_n['translate'].setAnimated() + + old_focal = model_node['focal'] + if old_focal.isAnimated() and not (old_focal.animation(0).constant()): + new_cam_n['focal'].setAnimated() + bakeFocal = True + else: + new_cam_n['focal'].setValue(old_focal.value()) + + old_haperture = model_node['haperture'] + if old_haperture.isAnimated() and not ( + old_haperture.animation(0).constant()): + new_cam_n['haperture'].setAnimated() + bakeHaperture = True + else: + new_cam_n['haperture'].setValue(old_haperture.value()) + + old_vaperture = model_node['vaperture'] + if old_vaperture.isAnimated() and not ( + old_vaperture.animation(0).constant()): + new_cam_n['vaperture'].setAnimated() + bakeVaperture = True + else: + new_cam_n['vaperture'].setValue(old_vaperture.value()) + + new_cam_n['win_translate'].setValue(model_node['win_translate'].value()) + new_cam_n['win_scale'].setValue(model_node['win_scale'].value()) + + for x in nuke.FrameRange(output_range): + math_matrix = nuke.math.Matrix4() + for y in range(model_matrix.height()): + for z in range(model_matrix.width()): + matrix_pointer = z + (y * model_matrix.width()) + math_matrix[matrix_pointer] = model_matrix.getValueAt( + x, (y + (z * model_matrix.width()))) + + rot_matrix = nuke.math.Matrix4(math_matrix) + rot_matrix.rotationOnly() + rot = rot_matrix.rotationsZXY() + + new_cam_n['rotate'].setValueAt(math.degrees(rot[0]), x, 0) + new_cam_n['rotate'].setValueAt(math.degrees(rot[1]), x, 1) + new_cam_n['rotate'].setValueAt(math.degrees(rot[2]), x, 2) + new_cam_n['translate'].setValueAt( + model_matrix.getValueAt(x, 3), x, 0) + new_cam_n['translate'].setValueAt( + model_matrix.getValueAt(x, 7), x, 1) + new_cam_n['translate'].setValueAt( + model_matrix.getValueAt(x, 11), x, 2) + + if bakeFocal: + new_cam_n['focal'].setValueAt(old_focal.getValueAt(x), x) + if bakeHaperture: + new_cam_n['haperture'].setValueAt(old_haperture.getValueAt(x), x) + if bakeVaperture: + new_cam_n['vaperture'].setValueAt(old_vaperture.getValueAt(x), x) + + return new_cam_n diff --git a/openpype/hosts/nuke/plugins/publish/validate_model.py b/openpype/hosts/nuke/plugins/publish/validate_model.py new file mode 100644 index 0000000000..03b7092767 --- /dev/null +++ b/openpype/hosts/nuke/plugins/publish/validate_model.py @@ -0,0 +1,58 @@ +import pyblish +from avalon.nuke import lib as anlib +import nuke + + +class OpenFailedGroupNode(pyblish.api.Action): + """ + Centering failed instance node in node grap + """ + + label = "Open Model in Node Graph" + icon = "wrench" + on = "failed" + + def process(self, context, plugin): + + # Get the errored instances + failed = [] + for result in context.data["results"]: + if (result["error"] is not None and result["instance"] is not None + and result["instance"] not in failed): + failed.append(result["instance"]) + + # Apply pyblish.logic to get the instances for the plug-in + instances = pyblish.api.instances_by_plugin(failed, plugin) + + # maintain selection + with anlib.maintained_selection(): + # collect all failed nodes xpos and ypos + for instance in instances: + grpn = instance[0] + nuke.showDag(grpn) + + +@pyblish.api.log +class ValidateModel(pyblish.api.InstancePlugin): + """Validate amount of output nodes in model (group) node""" + + order = pyblish.api.ValidatorOrder + optional = True + families = ["model"] + label = "Validate Model (Group)" + hosts = ["nuke"] + actions = [OpenFailedGroupNode] + + def process(self, instance): + grpn = instance[0] + + with grpn: + connections_out = nuke.allNodes('Output') + msg_multiple_outputs = "Only one outcoming connection from " + "\"{}\" is allowed".format(instance.data["name"]) + assert len(connections_out) <= 1, msg_multiple_outputs + + connections_in = nuke.allNodes('Input') + msg_missing_inputs = "At least one Input node has to be used in: " + "\"{}\"".format(instance.data["name"]) + assert len(connections_in) >= 1, msg_missing_inputs From 6c53bc172417843c4cea7012464f20777412b371 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Wed, 13 Oct 2021 11:45:36 +0200 Subject: [PATCH 003/100] add mode to nuke josn --- openpype/hosts/nuke/api/__init__.py | 3 ++- openpype/settings/defaults/project_settings/nuke.json | 1 + .../schemas/projects_schema/schemas/schema_nuke_publish.json | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/__init__.py b/openpype/hosts/nuke/api/__init__.py index e6dab5cfc9..e684b48fa3 100644 --- a/openpype/hosts/nuke/api/__init__.py +++ b/openpype/hosts/nuke/api/__init__.py @@ -70,7 +70,8 @@ def install(): family_states = [ "write", "review", - "nukenodes" + "nukenodes", + "model", "gizmo" ] diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index dd65df02e5..4085409e23 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -32,6 +32,7 @@ "PreCollectNukeInstances": { "sync_workfile_version_on_families": [ "nukenodes", + "model", "camera", "gizmo", "source", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json index 74b2592d29..8764435ed3 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json @@ -24,6 +24,9 @@ { "nukenodes": "nukenodes" }, + { + "model": "model" + }, { "camera": "camera" }, From bdcafe328e41098aef595f42c35944ca2879271c Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Wed, 13 Oct 2021 12:18:57 +0200 Subject: [PATCH 004/100] add write geo extension to jsons --- .../hosts/nuke/plugins/create/create_model.py | 2 +- .../hosts/nuke/plugins/load/load_model.py | 2 +- .../nuke/plugins/publish/extract_model.py | 101 ++---------------- .../defaults/project_settings/nuke.json | 3 + .../projects_schema/schema_project_nuke.json | 14 +++ 5 files changed, 30 insertions(+), 92 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 26b80788ff..e458e0677b 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -4,7 +4,7 @@ import nuke class CreateModel(plugin.PypeCreator): - """Add Publishable Modelmetry""" + """Add Publishable Model Geometry""" name = "model" label = "Create 3d Model" diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 4ff568214e..7e11abbae3 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -45,7 +45,7 @@ class AlembicModelLoader(api.Loader): with anlib.maintained_selection(): model_node = nuke.createNode( - "Model2", + "ReadGeo2", "name {} file {} read_from_file True".format( object_name, file), inpanel=False diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index bd6fa1e337..f050ec92bb 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -19,7 +19,7 @@ class ExtractModel(openpype.api.Extractor): write_geo_knobs = [ ("file_type", "abc"), ("storageFormat", "Ogawa"), - ("writeGeometries", False), + ("writeGeometries", True), ("writePointClouds", False), ("writeAxes", False) ] @@ -32,6 +32,7 @@ class ExtractModel(openpype.api.Extractor): step = 1 output_range = str(nuke.FrameRange(first_frame, last_frame, step)) + self.log.info("instance.data: `{}`".format( pformat(instance.data))) @@ -40,28 +41,21 @@ class ExtractModel(openpype.api.Extractor): subset = instance.data["subset"] staging_dir = self.staging_dir(instance) - # get extension form preset - extension = next((k[1] for k in self.write_geo_knobs - if k[0] == "file_type"), None) - if not extension: - raise RuntimeError( - "Bad config for extension in presets. " - "Talk to your supervisor or pipeline admin") + # get extension form setting or from preset + extension = instance.context.data["modelFormat"] + if not extension : + extension = next((k[1] for k in self.write_geo_knobs + if k[0] == "file_type"), None) + if not extension: + raise RuntimeError( + "Bad config for extension in presets. " + "Talk to your supervisor or pipeline admin") # create file name and path filename = subset + ".{}".format(extension) file_path = os.path.join(staging_dir, filename).replace("\\", "/") with anlib.maintained_selection(): - # bake model with axeses onto word coordinate XYZ - rm_n = bakeModelWithAxeses( - nuke.toNode(instance.data["name"]), output_range) - rm_nodes.append(rm_n) - - # create scene node - rm_n = nuke.createNode("Scene") - rm_nodes.append(rm_n) - # create write geo node wg_n = nuke.createNode("WriteGeo") wg_n["file"].setValue(file_path) @@ -110,76 +104,3 @@ class ExtractModel(openpype.api.Extractor): self.log.info("Extracted instance '{0}' to: {1}".format( instance.name, file_path)) - - -def bakeModelWithAxeses(model_node, output_range): - """ Baking all perent hiearchy of axeses into model - with transposition onto word XYZ coordinance - """ - bakeFocal = False - bakeHaperture = False - bakeVaperture = False - - model_matrix = model_node['world_matrix'] - - new_cam_n = nuke.createNode("Model2") - new_cam_n.setInput(0, None) - new_cam_n['rotate'].setAnimated() - new_cam_n['translate'].setAnimated() - - old_focal = model_node['focal'] - if old_focal.isAnimated() and not (old_focal.animation(0).constant()): - new_cam_n['focal'].setAnimated() - bakeFocal = True - else: - new_cam_n['focal'].setValue(old_focal.value()) - - old_haperture = model_node['haperture'] - if old_haperture.isAnimated() and not ( - old_haperture.animation(0).constant()): - new_cam_n['haperture'].setAnimated() - bakeHaperture = True - else: - new_cam_n['haperture'].setValue(old_haperture.value()) - - old_vaperture = model_node['vaperture'] - if old_vaperture.isAnimated() and not ( - old_vaperture.animation(0).constant()): - new_cam_n['vaperture'].setAnimated() - bakeVaperture = True - else: - new_cam_n['vaperture'].setValue(old_vaperture.value()) - - new_cam_n['win_translate'].setValue(model_node['win_translate'].value()) - new_cam_n['win_scale'].setValue(model_node['win_scale'].value()) - - for x in nuke.FrameRange(output_range): - math_matrix = nuke.math.Matrix4() - for y in range(model_matrix.height()): - for z in range(model_matrix.width()): - matrix_pointer = z + (y * model_matrix.width()) - math_matrix[matrix_pointer] = model_matrix.getValueAt( - x, (y + (z * model_matrix.width()))) - - rot_matrix = nuke.math.Matrix4(math_matrix) - rot_matrix.rotationOnly() - rot = rot_matrix.rotationsZXY() - - new_cam_n['rotate'].setValueAt(math.degrees(rot[0]), x, 0) - new_cam_n['rotate'].setValueAt(math.degrees(rot[1]), x, 1) - new_cam_n['rotate'].setValueAt(math.degrees(rot[2]), x, 2) - new_cam_n['translate'].setValueAt( - model_matrix.getValueAt(x, 3), x, 0) - new_cam_n['translate'].setValueAt( - model_matrix.getValueAt(x, 7), x, 1) - new_cam_n['translate'].setValueAt( - model_matrix.getValueAt(x, 11), x, 2) - - if bakeFocal: - new_cam_n['focal'].setValueAt(old_focal.getValueAt(x), x) - if bakeHaperture: - new_cam_n['haperture'].setValueAt(old_haperture.getValueAt(x), x) - if bakeVaperture: - new_cam_n['vaperture'].setValueAt(old_vaperture.getValueAt(x), x) - - return new_cam_n diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 4085409e23..0509d65fc7 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -26,6 +26,9 @@ "Branch01", "Part01" ] + }, + "CreateModel": { + "extension": ".abc" } }, "publish": { diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index e0b21f4037..10026e3e53 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -100,6 +100,20 @@ } } ] + }, + { + "type": "dict", + "collapsible": false, + "key": "CreateModel", + "label": "CreateModel", + "is_group": true, + "children": [ + { + "type": "text", + "key": "extension", + "label": "Extension" + } + ] } ] }, From aa5e6a2b557a2de17caf58c90194f0f8c2c13910 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 18 Oct 2021 03:08:26 +0200 Subject: [PATCH 005/100] WriteGeo create_model --- openpype/hosts/nuke/plugins/create/create_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index e458e0677b..c6368ddb0e 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -46,7 +46,7 @@ class CreateModel(plugin.PypeCreator): return else: # if selected is off then create one node - model_node = nuke.createNode("Model2") + model_node = nuke.createNode("WriteGeo") model_node["tile_color"].setValue(int(self.node_color, 16)) # add avalon knobs instance = anlib.set_avalon_knob_data(model_node, self.data) From 61dd3f419b64fbe206db1bb5bea25d4a3f044f0e Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 18 Oct 2021 03:10:53 +0200 Subject: [PATCH 006/100] del validatemodel. was in gizmo but not in cam --- .../nuke/plugins/publish/validate_model.py | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 openpype/hosts/nuke/plugins/publish/validate_model.py diff --git a/openpype/hosts/nuke/plugins/publish/validate_model.py b/openpype/hosts/nuke/plugins/publish/validate_model.py deleted file mode 100644 index 03b7092767..0000000000 --- a/openpype/hosts/nuke/plugins/publish/validate_model.py +++ /dev/null @@ -1,58 +0,0 @@ -import pyblish -from avalon.nuke import lib as anlib -import nuke - - -class OpenFailedGroupNode(pyblish.api.Action): - """ - Centering failed instance node in node grap - """ - - label = "Open Model in Node Graph" - icon = "wrench" - on = "failed" - - def process(self, context, plugin): - - # Get the errored instances - failed = [] - for result in context.data["results"]: - if (result["error"] is not None and result["instance"] is not None - and result["instance"] not in failed): - failed.append(result["instance"]) - - # Apply pyblish.logic to get the instances for the plug-in - instances = pyblish.api.instances_by_plugin(failed, plugin) - - # maintain selection - with anlib.maintained_selection(): - # collect all failed nodes xpos and ypos - for instance in instances: - grpn = instance[0] - nuke.showDag(grpn) - - -@pyblish.api.log -class ValidateModel(pyblish.api.InstancePlugin): - """Validate amount of output nodes in model (group) node""" - - order = pyblish.api.ValidatorOrder - optional = True - families = ["model"] - label = "Validate Model (Group)" - hosts = ["nuke"] - actions = [OpenFailedGroupNode] - - def process(self, instance): - grpn = instance[0] - - with grpn: - connections_out = nuke.allNodes('Output') - msg_multiple_outputs = "Only one outcoming connection from " - "\"{}\" is allowed".format(instance.data["name"]) - assert len(connections_out) <= 1, msg_multiple_outputs - - connections_in = nuke.allNodes('Input') - msg_missing_inputs = "At least one Input node has to be used in: " - "\"{}\"".format(instance.data["name"]) - assert len(connections_in) >= 1, msg_missing_inputs From 484c89ac4a0682085c68f37f9e5b2263b36e78eb Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 18 Oct 2021 03:53:48 +0200 Subject: [PATCH 007/100] clean attr-test 01 - with ext option parameter --- openpype/hosts/nuke/plugins/load/load_model.py | 2 +- openpype/hosts/nuke/plugins/publish/extract_model.py | 2 +- openpype/settings/defaults/project_settings/nuke.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index 7e11abbae3..c3312a8d31 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -46,7 +46,7 @@ class AlembicModelLoader(api.Loader): with anlib.maintained_selection(): model_node = nuke.createNode( "ReadGeo2", - "name {} file {} read_from_file True".format( + "name {} file {} ".format( object_name, file), inpanel=False ) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index f050ec92bb..293156a4c5 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -42,7 +42,7 @@ class ExtractModel(openpype.api.Extractor): staging_dir = self.staging_dir(instance) # get extension form setting or from preset - extension = instance.context.data["modelFormat"] + extension = instance.context.data["project_settings"]["nuke"]["create"]["CreateModel"]["extension"] if not extension : extension = next((k[1] for k in self.write_geo_knobs if k[0] == "file_type"), None) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 0509d65fc7..83ccd84755 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -28,7 +28,7 @@ ] }, "CreateModel": { - "extension": ".abc" + "extension": "abc" } }, "publish": { From be112112563548d1b519f9576e4267bb570c8625 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 18 Oct 2021 03:55:32 +0200 Subject: [PATCH 008/100] without ext option - work fine as abc --- .../hosts/nuke/plugins/publish/extract_model.py | 15 ++++++--------- .../settings/defaults/project_settings/nuke.json | 3 --- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 293156a4c5..7303e6cbbb 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -41,15 +41,12 @@ class ExtractModel(openpype.api.Extractor): subset = instance.data["subset"] staging_dir = self.staging_dir(instance) - # get extension form setting or from preset - extension = instance.context.data["project_settings"]["nuke"]["create"]["CreateModel"]["extension"] - if not extension : - extension = next((k[1] for k in self.write_geo_knobs - if k[0] == "file_type"), None) - if not extension: - raise RuntimeError( - "Bad config for extension in presets. " - "Talk to your supervisor or pipeline admin") + extension = next((k[1] for k in self.write_geo_knobs + if k[0] == "file_type"), None) + if not extension: + raise RuntimeError( + "Bad config for extension in presets. " + "Talk to your supervisor or pipeline admin") # create file name and path filename = subset + ".{}".format(extension) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 83ccd84755..4085409e23 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -26,9 +26,6 @@ "Branch01", "Part01" ] - }, - "CreateModel": { - "extension": "abc" } }, "publish": { From a46eb634556cc98b0161ef6484d0fca55d281198 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 18 Oct 2021 10:53:38 +0200 Subject: [PATCH 009/100] del extension text from schema --- openpype/hosts/nuke/api/lib.py | 17 ----------------- .../projects_schema/schema_project_nuke.json | 14 -------------- 2 files changed, 31 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 40701605e5..6fe9af744b 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1823,20 +1823,3 @@ def recreate_instance(origin_node, avalon_data=None): dn.setInput(0, new_node) return new_node - - -def extract_alembic(file, - startFrame=None, - endFrame=None): - """Extract an Alembic Geo. - - This extracts an Alembic Geo .... what was Collected into the instance. - - Arguments: - - startFrame (float): Start frame of output. - - endFrame (float): End frame of output. - - """ - pass \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index 10026e3e53..e0b21f4037 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -100,20 +100,6 @@ } } ] - }, - { - "type": "dict", - "collapsible": false, - "key": "CreateModel", - "label": "CreateModel", - "is_group": true, - "children": [ - { - "type": "text", - "key": "extension", - "label": "Extension" - } - ] } ] }, From 83a9c1e6e83042e32d6cee007207b8695db41088 Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Fri, 22 Oct 2021 10:41:40 +0200 Subject: [PATCH 010/100] Update openpype/hosts/nuke/plugins/load/load_model.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub JeΕΎek --- openpype/hosts/nuke/plugins/load/load_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index c3312a8d31..b6893066e3 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -15,7 +15,7 @@ class AlembicModelLoader(api.Loader): label = "Load Alembic Model" icon = "model" color = "orange" - node_color = "0xff3200ff" + node_color = "0x4ecd91ff" def load(self, context, name, namespace, data): # get main variables From e21249d8c4b1f79320763bde2194557dc4e272ae Mon Sep 17 00:00:00 2001 From: karimmozilla Date: Fri, 22 Oct 2021 10:41:58 +0200 Subject: [PATCH 011/100] Update openpype/hosts/nuke/plugins/load/load_model.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub JeΕΎek --- openpype/hosts/nuke/plugins/load/load_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/load/load_model.py b/openpype/hosts/nuke/plugins/load/load_model.py index b6893066e3..15fa4fa35c 100644 --- a/openpype/hosts/nuke/plugins/load/load_model.py +++ b/openpype/hosts/nuke/plugins/load/load_model.py @@ -13,7 +13,7 @@ class AlembicModelLoader(api.Loader): representations = ["abc"] label = "Load Alembic Model" - icon = "model" + icon = "cube" color = "orange" node_color = "0x4ecd91ff" From 02d08dfcb8f55603c97969719c92879a01f68a39 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Fri, 22 Oct 2021 10:46:13 +0200 Subject: [PATCH 012/100] update label --- openpype/hosts/nuke/plugins/publish/extract_model.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 7303e6cbbb..7753efc764 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -1,6 +1,5 @@ import nuke import os -import math import pyblish.api import openpype.api from avalon.nuke import lib as anlib @@ -31,7 +30,6 @@ class ExtractModel(openpype.api.Extractor): last_frame = int(nuke.root()["last_frame"].getValue()) step = 1 output_range = str(nuke.FrameRange(first_frame, last_frame, step)) - self.log.info("instance.data: `{}`".format( pformat(instance.data))) From 7f1e9569311098efbcf52cca37f48565fde265bb Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Fri, 22 Oct 2021 13:41:46 +0200 Subject: [PATCH 013/100] update label --- openpype/hosts/nuke/plugins/publish/collect_model.py | 4 ++-- openpype/settings/defaults/project_settings/nuke.json | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index f764c9d9ac..ade9f90987 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -4,11 +4,11 @@ import nuke @pyblish.api.log class CollectModel(pyblish.api.InstancePlugin): - """Collect Model (group) node instance and its content + """Collect Model node instance and its content """ order = pyblish.api.CollectorOrder + 0.22 - label = "Collect Model (Group)" + label = "Collect Model" hosts = ["nuke"] families = ["model"] diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 4085409e23..dd65df02e5 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -32,7 +32,6 @@ "PreCollectNukeInstances": { "sync_workfile_version_on_families": [ "nukenodes", - "model", "camera", "gizmo", "source", From 56850e6bd374571fd4cafeb6903cdd13a1609393 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Fri, 22 Oct 2021 14:29:58 +0200 Subject: [PATCH 014/100] del outputrnage --- openpype/hosts/nuke/plugins/publish/extract_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 7753efc764..1ad93a49e4 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -29,7 +29,6 @@ class ExtractModel(openpype.api.Extractor): first_frame = int(nuke.root()["first_frame"].getValue()) last_frame = int(nuke.root()["last_frame"].getValue()) step = 1 - output_range = str(nuke.FrameRange(first_frame, last_frame, step)) self.log.info("instance.data: `{}`".format( pformat(instance.data))) From aa5242ac48265df55f34f489d64fad8537623e06 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Fri, 22 Oct 2021 14:30:48 +0200 Subject: [PATCH 015/100] del step --- openpype/hosts/nuke/plugins/publish/extract_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 1ad93a49e4..8a7ecbe093 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -28,7 +28,6 @@ class ExtractModel(openpype.api.Extractor): handle_end = instance.context.data["handleEnd"] first_frame = int(nuke.root()["first_frame"].getValue()) last_frame = int(nuke.root()["last_frame"].getValue()) - step = 1 self.log.info("instance.data: `{}`".format( pformat(instance.data))) From 7be0dec7e202bbde778133586d5bbfd75c491c9b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:46:43 +0100 Subject: [PATCH 016/100] removed unused object name LabelWidget --- openpype/tools/settings/settings/base.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 92fffe6f9c..75a3427040 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -470,8 +470,6 @@ class GUIWidget(BaseWidget): self.entity_widget.add_widget_to_layout(self) def _create_label_ui(self): - self.setObjectName("LabelWidget") - label = self.entity["label"] label_widget = QtWidgets.QLabel(label, self) @@ -513,8 +511,6 @@ class MockUpWidget(BaseWidget): child_invalid = False def create_ui(self): - self.setObjectName("LabelWidget") - label = "Mockup widget for entity {}".format(self.entity.path) label_widget = QtWidgets.QLabel(label, self) From d8caf89097922685d554862e802f12798b406e93 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:47:58 +0100 Subject: [PATCH 017/100] replaced btn-type with object name SettingsToolBtn --- .../tools/settings/settings/dict_mutable_widget.py | 6 +++--- openpype/tools/settings/settings/list_item_widget.py | 12 ++++++------ openpype/tools/settings/settings/style/style.css | 9 ++++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index 9afce7259e..1c62ccb121 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -81,7 +81,7 @@ class PaintHelper: def create_add_btn(parent): add_btn = QtWidgets.QPushButton("+", parent) add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - add_btn.setProperty("btn-type", "tool-item") + add_btn.setObjectName("SettingsToolBtn") add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) return add_btn @@ -89,7 +89,7 @@ def create_add_btn(parent): def create_remove_btn(parent): remove_btn = QtWidgets.QPushButton("-", parent) remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - remove_btn.setProperty("btn-type", "tool-item") + remove_btn.setObjectName("SettingsToolBtn") remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) return remove_btn @@ -102,7 +102,7 @@ def create_confirm_btn(parent): ) confirm_btn.setIcon(icon) confirm_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - confirm_btn.setProperty("btn-type", "tool-item") + confirm_btn.setObjectName("SettingsToolBtn") confirm_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) return confirm_btn diff --git a/openpype/tools/settings/settings/list_item_widget.py b/openpype/tools/settings/settings/list_item_widget.py index 128af92631..cc539933ff 100644 --- a/openpype/tools/settings/settings/list_item_widget.py +++ b/openpype/tools/settings/settings/list_item_widget.py @@ -25,8 +25,8 @@ class EmptyListItem(QtWidgets.QWidget): add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - add_btn.setProperty("btn-type", "tool-item") - remove_btn.setProperty("btn-type", "tool-item") + add_btn.setObjectName("SettingsToolBtn") + remove_btn.setObjectName("SettingsToolBtn") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -74,10 +74,10 @@ class ListItem(QtWidgets.QWidget): up_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) down_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - add_btn.setProperty("btn-type", "tool-item") - remove_btn.setProperty("btn-type", "tool-item") - up_btn.setProperty("btn-type", "tool-item") - down_btn.setProperty("btn-type", "tool-item") + add_btn.setObjectName("SettingsToolBtn") + remove_btn.setObjectName("SettingsToolBtn") + up_btn.setObjectName("SettingsToolBtn") + down_btn.setObjectName("SettingsToolBtn") add_btn.clicked.connect(self._on_add_clicked) remove_btn.clicked.connect(self._on_remove_clicked) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index b77b575204..0a9dcfb232 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -94,16 +94,19 @@ QPushButton:hover { border: 1px solid #fff; color: #fff; } -QPushButton[btn-type="tool-item"] { +#SettingsToolBtn { + background: transparent; border: 1px solid #bfccd6; border-radius: 10px; } - -QPushButton[btn-type="tool-item"]:hover { +#SettingsToolBtn:hover { border-color: #189aea; color: #46b1f3; background-color: transparent; } +#SettingsToolBtn:disabled { + background-color: #464b54; +} QPushButton[btn-type="tool-item-icon"] { border: 0px solid #bfccd6; From debe423b2320d9bd5848576e6f4b45a4d74725a9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:49:07 +0100 Subject: [PATCH 018/100] replaced btn-type tool-item-icon with object name SettingsToolIconBtn --- openpype/tools/settings/settings/dict_mutable_widget.py | 2 +- openpype/tools/settings/settings/style/style.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index 1c62ccb121..07d64263ce 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -375,7 +375,7 @@ class ModifiableDictItem(QtWidgets.QWidget): "fa.edit", QtCore.Qt.lightGray, QtCore.Qt.white ) edit_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - edit_btn.setProperty("btn-type", "tool-item-icon") + edit_btn.setObjectName("SettingsToolIconBtn") edit_btn.setFixedHeight(BTN_FIXED_SIZE) confirm_btn = create_confirm_btn(self) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index 0a9dcfb232..cde3ed86e8 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -108,7 +108,7 @@ QPushButton:hover { background-color: #464b54; } -QPushButton[btn-type="tool-item-icon"] { +#SettingsToolIconBtn { border: 0px solid #bfccd6; background-color: transparent; } From bf82d1f76e4bc900cb327883c0785481f7668c75 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:49:53 +0100 Subject: [PATCH 019/100] replaced btn-type expand-toggle with object name ExpandToggleBtn --- openpype/tools/settings/settings/style/style.css | 4 ++-- openpype/tools/settings/settings/widgets.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index cde3ed86e8..99da3b2fed 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -113,8 +113,8 @@ QPushButton:hover { background-color: transparent; } -QPushButton[btn-type="expand-toggle"] { - background: #21252B; +#ExpandToggleBtn { + background: transparent; } /* SLider */ diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 710884e9e5..469c984a5e 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -180,7 +180,7 @@ class ExpandingWidget(QtWidgets.QWidget): button_size = QtCore.QSize(5, 5) button_toggle = QtWidgets.QToolButton(parent=side_line_widget) - button_toggle.setProperty("btn-type", "expand-toggle") + button_toggle.setObjectName("ExpandToggleBtn") button_toggle.setIconSize(button_size) button_toggle.setArrowType(QtCore.Qt.RightArrow) button_toggle.setCheckable(True) From 8c28fca43604a9b387eee7897e16e7d4cfdf7b08 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:50:14 +0100 Subject: [PATCH 020/100] renamed MainWidget object name to SettingsMainWidget --- openpype/tools/settings/settings/style/style.css | 2 +- openpype/tools/settings/settings/window.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index 99da3b2fed..e271eaf5ed 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -213,7 +213,7 @@ QSlider::handle:vertical { #SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} #SideLineWidget[state="child-overriden-modified"]:hover {border-color: #189aea;} -#MainWidget { +#SettingsMainWidget { background: #141a1f; } diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 4e88301349..3ee303cfe9 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -25,7 +25,7 @@ class MainWidget(QtWidgets.QWidget): self._password_dialog = None - self.setObjectName("MainWidget") + self.setObjectName("SettingsMainWidget") self.setWindowTitle("OpenPype Settings") self.resize(self.widget_width, self.widget_height) From 30400bbbda42fcd9ff0af38d8ed358ebd24fbc7b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:50:34 +0100 Subject: [PATCH 021/100] DictLabel renamed to ExpandLabel --- openpype/tools/settings/settings/style/style.css | 2 +- openpype/tools/settings/settings/widgets.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index e271eaf5ed..61299a3cc7 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -173,7 +173,7 @@ QSlider::handle:vertical { #DictKey[state="overriden-modified"] {border-color: #0f0;} #DictKey[state="invalid"] {border-color: #ad2e2e;} -#DictLabel { +#ExpandLabel { font-weight: bold; } diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 469c984a5e..05622764b4 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -187,7 +187,7 @@ class ExpandingWidget(QtWidgets.QWidget): button_toggle.setChecked(False) label_widget = QtWidgets.QLabel(label, parent=side_line_widget) - label_widget.setObjectName("DictLabel") + label_widget.setObjectName("ExpandLabel") before_label_widget = QtWidgets.QWidget(side_line_widget) before_label_layout = QtWidgets.QHBoxLayout(before_label_widget) From d9f9a0d01e38ffe8c7408b6480d719b4b10549d2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:51:22 +0100 Subject: [PATCH 022/100] all that should behave differently have object name SettingsLabel --- openpype/tools/settings/settings/base.py | 2 ++ .../settings/settings/dict_conditional.py | 1 + .../tools/settings/settings/item_widgets.py | 1 + .../tools/settings/settings/style/style.css | 28 +++++++++++-------- openpype/tools/settings/settings/widgets.py | 1 + 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 75a3427040..6e45c9b0c4 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -472,6 +472,7 @@ class GUIWidget(BaseWidget): def _create_label_ui(self): label = self.entity["label"] label_widget = QtWidgets.QLabel(label, self) + label_widget.setObjectName("SettingsLabel") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 5, 0, 5) @@ -513,6 +514,7 @@ class MockUpWidget(BaseWidget): def create_ui(self): label = "Mockup widget for entity {}".format(self.entity.path) label_widget = QtWidgets.QLabel(label, self) + label_widget.setObjectName("SettingsLabel") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 5, 0, 5) diff --git a/openpype/tools/settings/settings/dict_conditional.py b/openpype/tools/settings/settings/dict_conditional.py index 3e3270cac9..2e1617f505 100644 --- a/openpype/tools/settings/settings/dict_conditional.py +++ b/openpype/tools/settings/settings/dict_conditional.py @@ -164,6 +164,7 @@ class DictConditionalWidget(BaseWidget): content_widget.setProperty("show_borders", show_borders) label_widget = QtWidgets.QLabel(self.entity.label) + label_widget.setObjectName("SettingsLabel") content_layout = QtWidgets.QGridLayout(content_widget) content_layout.setContentsMargins(5, 5, 5, 5) diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index a28bee8d36..4d5840d7b7 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -129,6 +129,7 @@ class DictImmutableKeysWidget(BaseWidget): content_widget.setProperty("show_borders", show_borders) label_widget = QtWidgets.QLabel(self.entity.label) + label_widget.setObjectName("SettingsLabel") content_layout = QtWidgets.QGridLayout(content_widget) content_layout.setContentsMargins(5, 5, 5, 5) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index 61299a3cc7..0f5e97ec09 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -59,23 +59,27 @@ QComboBox QAbstractItemView::item { QToolButton { background: transparent; } - QLabel { background: transparent; color: #969b9e; } -QLabel:hover {color: #b8c1c5;} -QLabel[state="studio"] {color: #73C990;} -QLabel[state="studio"]:hover {color: #ffffff;} -QLabel[state="modified"] {color: #189aea;} -QLabel[state="modified"]:hover {color: #46b1f3;} -QLabel[state="overriden-modified"] {color: #189aea;} -QLabel[state="overriden-modified"]:hover {color: #46b1f3;} -QLabel[state="overriden"] {color: #ff8c1a;} -QLabel[state="overriden"]:hover {color: #ffa64d;} -QLabel[state="invalid"] {color: #ad2e2e;} -QLabel[state="invalid"]:hover {color: #ad2e2e;} +#SettingsLabel { + background: transparent; + color: #969b9e; +} +#SettingsLabel:hover {color: #b8c1c5;} + +#SettingsLabel[state="studio"] {color: #73C990;} +#SettingsLabel[state="studio"]:hover {color: #ffffff;} +#SettingsLabel[state="modified"] {color: #189aea;} +#SettingsLabel[state="modified"]:hover {color: #46b1f3;} +#SettingsLabel[state="overriden-modified"] {color: #189aea;} +#SettingsLabel[state="overriden-modified"]:hover {color: #46b1f3;} +#SettingsLabel[state="overriden"] {color: #ff8c1a;} +#SettingsLabel[state="overriden"]:hover {color: #ffa64d;} +#SettingsLabel[state="invalid"] {color: #ad2e2e;} +#SettingsLabel[state="invalid"]:hover {color: #ad2e2e;} QWidget[input-state="studio"] {border-color: #858a94;} diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 05622764b4..ab0dbfc4f4 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -381,6 +381,7 @@ class GridLabelWidget(QtWidgets.QWidget): self.properties = {} label_widget = QtWidgets.QLabel(label, self) + label_widget.setObjectName("SettingsLabel") label_proxy_layout = QtWidgets.QHBoxLayout() label_proxy_layout.setContentsMargins(0, 0, 0, 0) From 7a9529f33286020e739e7c172db63469d2775ae4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:51:38 +0100 Subject: [PATCH 023/100] renamed object name SplitterItem to Separator --- openpype/tools/settings/settings/base.py | 2 +- openpype/tools/settings/settings/style/style.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/settings/settings/base.py b/openpype/tools/settings/settings/base.py index 6e45c9b0c4..f8378ed18c 100644 --- a/openpype/tools/settings/settings/base.py +++ b/openpype/tools/settings/settings/base.py @@ -480,7 +480,7 @@ class GUIWidget(BaseWidget): def _create_separator_ui(self): splitter_item = QtWidgets.QWidget(self) - splitter_item.setObjectName("SplitterItem") + splitter_item.setObjectName("Separator") splitter_item.setMinimumHeight(self.separator_height) splitter_item.setMaximumHeight(self.separator_height) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index 0f5e97ec09..93bdf9b5bd 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -229,7 +229,7 @@ QSlider::handle:vertical { border-radius: 5px; } -#SplitterItem { +#Separator { background-color: #21252B; } From c9228d74a0419f8daddda59d178ecd3ad9c66371 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 10:57:47 +0100 Subject: [PATCH 024/100] fix epand label hover --- openpype/tools/settings/settings/style/style.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index 93bdf9b5bd..daf7cca822 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -180,6 +180,9 @@ QSlider::handle:vertical { #ExpandLabel { font-weight: bold; } +#ExpandLabel:hover { + color: #b8c1c5; +} #ContentWidget { background-color: transparent; From 5e2e818db287afc5b267956faee5f155f3ec059e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 11:06:36 +0100 Subject: [PATCH 025/100] add styled delegates to comboboxes --- openpype/tools/settings/local_settings/projects_widget.py | 3 +++ openpype/tools/settings/settings/widgets.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index 9cd3b9a38e..9b373ed3cd 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -456,6 +456,8 @@ class _SiteCombobox(QtWidgets.QWidget): self ) combobox_input = QtWidgets.QComboBox(self) + combobox_delegate = QtWidgets.QStyledItemDelegate() + combobox_input.setItemDelegate(combobox_delegate) main_layout = QtWidgets.QHBoxLayout(self) main_layout.addWidget(label_widget) @@ -464,6 +466,7 @@ class _SiteCombobox(QtWidgets.QWidget): combobox_input.currentIndexChanged.connect(self._on_index_change) self.label_widget = label_widget self.combobox_input = combobox_input + self._combobox_delegate = combobox_delegate def _set_current_text(self, text): index = None diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index ab0dbfc4f4..7ed6827139 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -132,9 +132,14 @@ class SettingsComboBox(QtWidgets.QComboBox): def __init__(self, *args, **kwargs): super(SettingsComboBox, self).__init__(*args, **kwargs) + delegate = QtWidgets.QStyledItemDelegate() + self.setItemDelegate(delegate) + self.currentIndexChanged.connect(self._on_change) self.setFocusPolicy(QtCore.Qt.StrongFocus) + self._delegate = delegate + def wheelEvent(self, event): if self.hasFocus(): return super(SettingsComboBox, self).wheelEvent(event) From 5532cd3f3244fb6ccd675b573f56ed828c368aab Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 11:20:39 +0100 Subject: [PATCH 026/100] check if layout item has widget before calling hide --- openpype/tools/settings/local_settings/apps_widget.py | 4 +++- openpype/tools/settings/local_settings/projects_widget.py | 4 +++- openpype/tools/settings/settings/categories.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/openpype/tools/settings/local_settings/apps_widget.py b/openpype/tools/settings/local_settings/apps_widget.py index e6a4132955..850e009937 100644 --- a/openpype/tools/settings/local_settings/apps_widget.py +++ b/openpype/tools/settings/local_settings/apps_widget.py @@ -172,7 +172,9 @@ class LocalApplicationsWidgets(QtWidgets.QWidget): def _reset_app_widgets(self): while self.content_layout.count() > 0: item = self.content_layout.itemAt(0) - item.widget().hide() + widget = item.widget() + if widget is not None: + widget.setVisible(False) self.content_layout.removeItem(item) self.widgets_by_group_name.clear() diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index 9b373ed3cd..4a7477dcd2 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -259,7 +259,9 @@ class SitesWidget(QtWidgets.QWidget): def _clear_widgets(self): while self.content_layout.count(): item = self.content_layout.itemAt(0) - item.widget().hide() + widget = item.widget() + if widget is not None: + widget.setVisible(False) self.content_layout.removeItem(item) self.input_objects = {} diff --git a/openpype/tools/settings/settings/categories.py b/openpype/tools/settings/settings/categories.py index 5f9051344d..a6e4154b2b 100644 --- a/openpype/tools/settings/settings/categories.py +++ b/openpype/tools/settings/settings/categories.py @@ -391,7 +391,9 @@ class SettingsCategoryWidget(QtWidgets.QWidget): while self.content_layout.count() != 0: widget = self.content_layout.itemAt(0).widget() - widget.hide() + if widget is not None: + widget.setVisible(False) + self.content_layout.removeWidget(widget) widget.deleteLater() From 4f178f18ff2e6d5b0b9183602d5ee86bf48f90e2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 11:21:01 +0100 Subject: [PATCH 027/100] replaced SpacerWidget with stretch --- .../settings/local_settings/projects_widget.py | 15 ++++++--------- openpype/tools/settings/local_settings/widgets.py | 5 +---- openpype/tools/settings/local_settings/window.py | 6 ++---- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index 4a7477dcd2..7e2ad661a0 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -6,10 +6,7 @@ from openpype.settings.constants import ( PROJECT_ANATOMY_KEY, DEFAULT_PROJECT_KEY ) -from .widgets import ( - SpacerWidget, - ProxyLabelWidget -) +from .widgets import ProxyLabelWidget from .constants import ( LABEL_REMOVE_DEFAULT, LABEL_ADD_DEFAULT, @@ -238,9 +235,9 @@ class SitesWidget(QtWidgets.QWidget): comboboxes_layout = QtWidgets.QHBoxLayout(comboboxes_widget) comboboxes_layout.setContentsMargins(0, 0, 0, 0) - comboboxes_layout.addWidget(active_site_widget) - comboboxes_layout.addWidget(remote_site_widget) - comboboxes_layout.addWidget(SpacerWidget(comboboxes_widget), 1) + comboboxes_layout.addWidget(active_site_widget, 0) + comboboxes_layout.addWidget(remote_site_widget, 0) + comboboxes_layout.addStretch(1) content_widget = QtWidgets.QWidget(self) content_layout = QtWidgets.QVBoxLayout(content_widget) @@ -385,7 +382,7 @@ class SitesWidget(QtWidgets.QWidget): self.input_objects[site_name] = site_input_objects # Add spacer so other widgets are squeezed to top - self.content_layout.addWidget(SpacerWidget(self), 1) + self.content_layout.addStretch(1) def _on_input_value_change(self, site_name, key): if ( @@ -782,7 +779,7 @@ class RootSiteWidget(QtWidgets.QWidget): main_layout = QtWidgets.QVBoxLayout(self) main_layout.addWidget(sites_widget) - main_layout.addWidget(SpacerWidget(self), 1) + main_layout.addStretch(1) self.sites_widget = sites_widget diff --git a/openpype/tools/settings/local_settings/widgets.py b/openpype/tools/settings/local_settings/widgets.py index b164f1b407..2733aef187 100644 --- a/openpype/tools/settings/local_settings/widgets.py +++ b/openpype/tools/settings/local_settings/widgets.py @@ -1,7 +1,6 @@ from Qt import QtWidgets, QtCore from openpype.tools.settings.settings.widgets import ( - ExpandingWidget, - SpacerWidget + ExpandingWidget ) @@ -56,7 +55,5 @@ class ProxyLabelWidget(QtWidgets.QWidget): __all__ = ( "ExpandingWidget", - "SpacerWidget", "Separator", - "SpacerWidget" ) diff --git a/openpype/tools/settings/local_settings/window.py b/openpype/tools/settings/local_settings/window.py index f22e397323..dc4e4d67f3 100644 --- a/openpype/tools/settings/local_settings/window.py +++ b/openpype/tools/settings/local_settings/window.py @@ -15,7 +15,6 @@ from openpype.api import ( from openpype.modules import ModulesManager from .widgets import ( - SpacerWidget, ExpandingWidget ) from .mongo_widget import OpenPypeMongoWidget @@ -58,8 +57,7 @@ class LocalSettingsWidget(QtWidgets.QWidget): self._create_app_ui() self._create_project_ui() - # Add spacer to main layout - self.main_layout.addWidget(SpacerWidget(self), 1) + self.main_layout.addStretch(1) def _create_pype_mongo_ui(self): pype_mongo_expand_widget = ExpandingWidget("OpenPype Mongo URL", self) @@ -210,7 +208,7 @@ class LocalSettingsWindow(QtWidgets.QWidget): footer_layout = QtWidgets.QHBoxLayout(footer) footer_layout.addWidget(reset_btn, 0) - footer_layout.addWidget(SpacerWidget(footer), 1) + footer_layout.addStretch(1) footer_layout.addWidget(save_btn, 0) main_layout = QtWidgets.QVBoxLayout(self) From 4e4b74340ca72a1f035a6af28b0e66e436052eff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 11:36:19 +0100 Subject: [PATCH 028/100] replaced NiceCheckbox in settings with new one --- .../tools/settings/settings/item_widgets.py | 7 +- .../tools/settings/settings/style/style.css | 5 + openpype/tools/settings/settings/widgets.py | 190 +----------------- 3 files changed, 11 insertions(+), 191 deletions(-) diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index 4d5840d7b7..d808de74a4 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -7,8 +7,8 @@ from .widgets import ( NumberSpinBox, GridLabelWidget, SettingsComboBox, - NiceCheckbox, SettingsPlainTextEdit, + SettingsNiceCheckbox, SettingsLineEdit ) from .multiselection_combobox import MultiSelectionComboBox @@ -21,6 +21,7 @@ from .base import ( BaseWidget, InputWidget ) + from openpype.widgets.sliders import NiceSlider from openpype.tools.settings import CHILD_OFFSET @@ -328,9 +329,7 @@ class BoolWidget(InputWidget): checkbox_height = self.style().pixelMetric( QtWidgets.QStyle.PM_IndicatorHeight ) - self.input_field = NiceCheckbox( - height=checkbox_height, parent=self.content_widget - ) + self.input_field = SettingsNiceCheckbox(parent=self.content_widget) self.content_layout.addWidget(self.input_field, 0) self.content_layout.addStretch(1) diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css index daf7cca822..88ef74101a 100644 --- a/openpype/tools/settings/settings/style/style.css +++ b/openpype/tools/settings/settings/style/style.css @@ -461,3 +461,8 @@ QAbstractItemView::item:selected:!active { border-radius: 5px; background: #21252B;; } + +#NiceCheckbox { + /* Default size hint of NiceCheckbox is defined by font size. */ + font-size: 7pt; +} diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 7ed6827139..7480d4c51b 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -6,6 +6,7 @@ from avalon.mongodb import ( AvalonMongoDB ) +from openpype.widgets.nice_checkbox import NiceCheckbox from openpype.settings.lib import get_system_settings from .constants import ( DEFAULT_PROJECT_LABEL, @@ -421,197 +422,12 @@ class GridLabelWidget(QtWidgets.QWidget): return super(GridLabelWidget, self).mouseReleaseEvent(event) -class NiceCheckboxMoveWidget(QtWidgets.QFrame): - def __init__(self, height, border_width, parent): - super(NiceCheckboxMoveWidget, self).__init__(parent=parent) - - self.checkstate = False - - self.half_size = int(height / 2) - self.full_size = self.half_size * 2 - self.border_width = border_width - self.setFixedHeight(self.full_size) - self.setFixedWidth(self.full_size) - - self.setStyleSheet(( - "background: #444444;border-style: none;" - "border-radius: {};border-width:{}px;" - ).format(self.half_size, self.border_width)) - - def update_position(self): - parent_rect = self.parent().rect() - if self.checkstate is True: - pos_x = ( - parent_rect.x() - + parent_rect.width() - - self.full_size - - self.border_width - ) - else: - pos_x = parent_rect.x() + self.border_width - - pos_y = parent_rect.y() + int( - parent_rect.height() / 2 - self.half_size - ) - self.setGeometry(pos_x, pos_y, self.width(), self.height()) - - def state_offset(self): - diff_x = ( - self.parent().rect().width() - - self.full_size - - (2 * self.border_width) - ) - return QtCore.QPoint(diff_x, 0) - - def change_position(self, checkstate): - self.checkstate = checkstate - - self.update_position() - - def resizeEvent(self, event): - super().resizeEvent(event) - self.update_position() - - -class NiceCheckbox(QtWidgets.QFrame): - stateChanged = QtCore.Signal(int) - checked_bg_color = QtGui.QColor(69, 128, 86) - unchecked_bg_color = QtGui.QColor(170, 80, 80) +class SettingsNiceCheckbox(NiceCheckbox): focused_in = QtCore.Signal() - def set_bg_color(self, color): - self._bg_color = color - self.setStyleSheet(self._stylesheet_template.format( - color.red(), color.green(), color.blue() - )) - - def bg_color(self): - return self._bg_color - - bgcolor = QtCore.Property(QtGui.QColor, bg_color, set_bg_color) - - def __init__(self, checked=True, height=30, *args, **kwargs): - super(NiceCheckbox, self).__init__(*args, **kwargs) - - self._checkstate = checked - if checked: - bg_color = self.checked_bg_color - else: - bg_color = self.unchecked_bg_color - - self.half_height = int(height / 2) - height = self.half_height * 2 - tenth_height = int(height / 10) - - self.setFixedHeight(height) - self.setFixedWidth((height - tenth_height) * 2) - - move_item_size = height - (2 * tenth_height) - - self.move_item = NiceCheckboxMoveWidget( - move_item_size, tenth_height, self - ) - self.move_item.change_position(self._checkstate) - - self._stylesheet_template = ( - "border-radius: {}px;" - "border-width: {}px;" - "background: #333333;" - "border-style: solid;" - "border-color: #555555;" - ).format(self.half_height, tenth_height) - self._stylesheet_template += "background: rgb({},{},{});" - - self.set_bg_color(bg_color) - - def resizeEvent(self, event): - super(NiceCheckbox, self).resizeEvent(event) - self.move_item.update_position() - - def show(self, *args, **kwargs): - super(NiceCheckbox, self).show(*args, **kwargs) - self.move_item.update_position() - - def checkState(self): - if self._checkstate: - return QtCore.Qt.Checked - else: - return QtCore.Qt.Unchecked - - def _on_checkstate_change(self): - self.stateChanged.emit(self.checkState()) - - move_start_value = self.move_item.pos() - offset = self.move_item.state_offset() - if self._checkstate is True: - move_end_value = move_start_value + offset - else: - move_end_value = move_start_value - offset - move_animation = QtCore.QPropertyAnimation( - self.move_item, b"pos", self - ) - move_animation.setDuration(150) - move_animation.setEasingCurve(QtCore.QEasingCurve.OutQuad) - move_animation.setStartValue(move_start_value) - move_animation.setEndValue(move_end_value) - - color_animation = QtCore.QPropertyAnimation( - self, b"bgcolor" - ) - color_animation.setDuration(150) - if self._checkstate is True: - color_animation.setStartValue(self.unchecked_bg_color) - color_animation.setEndValue(self.checked_bg_color) - else: - color_animation.setStartValue(self.checked_bg_color) - color_animation.setEndValue(self.unchecked_bg_color) - - anim_group = QtCore.QParallelAnimationGroup(self) - anim_group.addAnimation(move_animation) - anim_group.addAnimation(color_animation) - - def _finished(): - self.move_item.change_position(self._checkstate) - - anim_group.finished.connect(_finished) - anim_group.start() - - def isChecked(self): - return self._checkstate - - def setChecked(self, checked): - if checked == self._checkstate: - return - self._checkstate = checked - self._on_checkstate_change() - - def setCheckState(self, state=None): - if state is None: - checkstate = not self._checkstate - elif state == QtCore.Qt.Checked: - checkstate = True - elif state == QtCore.Qt.Unchecked: - checkstate = False - else: - return - - if checkstate == self._checkstate: - return - - self._checkstate = checkstate - - self._on_checkstate_change() - def mousePressEvent(self, event): self.focused_in.emit() - super(NiceCheckbox, self).mousePressEvent(event) - - def mouseReleaseEvent(self, event): - if event.button() == QtCore.Qt.LeftButton: - self.setCheckState() - event.accept() - return - return super(NiceCheckbox, self).mouseReleaseEvent(event) + super(SettingsNiceCheckbox, self).mousePressEvent(event) class ProjectModel(QtGui.QStandardItemModel): From 2fe5ae5df6136ee93eedea3dca7f2aba9c4a42e5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 12 Nov 2021 11:40:17 +0100 Subject: [PATCH 029/100] added settings style to openpype style --- openpype/style/style.css | 171 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index 1e457f97f6..307d2d960d 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -949,3 +949,174 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { /* Default size hint of NiceCheckbox is defined by font size. */ font-size: 7pt; } + +/* Settings - NOT USED YET +- we need to define font family for settings UI */ + +#SettingsMainWidget { + background: #141a1f; +} + +#SettingsToolIconBtn { + border: 0px solid #bfccd6; + background-color: transparent; +} + +#SettingsToolBtn { + border: 1px solid #bfccd6; + border-radius: 10px; + background-color: transparent; +} + +#SettingsToolBtn:hover { + border-color: #189aea; + color: #46b1f3; + background-color: transparent; +} +#SettingsToolBtn:disabled { + background-color: #464b54; +} + +#ExpandToggleBtn { + background: transparent; +} + +#SettingsLabel { + background: transparent; + color: #969b9e; +} +#SettingsLabel:hover {color: #b8c1c5;} +#SettingsLabel[state="studio"] {color: #73C990;} +#SettingsLabel[state="studio"]:hover {color: #ffffff;} +#SettingsLabel[state="modified"] {color: #189aea;} +#SettingsLabel[state="modified"]:hover {color: #46b1f3;} +#SettingsLabel[state="overriden-modified"] {color: #189aea;} +#SettingsLabel[state="overriden-modified"]:hover {color: #46b1f3;} +#SettingsLabel[state="overriden"] {color: #ff8c1a;} +#SettingsLabel[state="overriden"]:hover {color: #ffa64d;} +#SettingsLabel[state="invalid"] {color: #ad2e2e;} +#SettingsLabel[state="invalid"]:hover {color: #ad2e2e;} + +/* TODO Replace these with explicit widget types if possible */ +QWidget[input-state="studio"] {border-color: #858a94;} +QWidget[input-state="modified"] {border-color: #189aea;} +QWidget[input-state="overriden-modified"] {border-color: #189aea;} +QWidget[input-state="overriden"] {border-color: #ff8c1a;} +QWidget[input-state="invalid"] {border-color: #ad2e2e;} + +#GroupWidget { + border-bottom: 1px solid #21252B; +} + +#ProjectListWidget QListView { + border: 1px solid #464b54; + background: #21252B; +} + +#ProjectListWidget QListView:disabled { + background: #282C34; +} + +#ProjectListWidget QListView::item:disabled { + color: #4e5254; +} + +#ProjectListWidget QLabel { + background: transparent; + font-weight: bold; +} + +#MultiSelectionComboBox { + font-size: 12px; +} + +#DictKey[state="studio"] {border-color: #464b54;} +#DictKey[state="modified"] {border-color: #189aea;} +#DictKey[state="overriden"] {border-color: #00f;} +#DictKey[state="overriden-modified"] {border-color: #0f0;} +#DictKey[state="invalid"] {border-color: #ad2e2e;} + +#ExpandLabel { + font-weight: bold; +} +#ExpandLabel:hover { + color: #b8c1c5; +} + +#ContentWidget { + background-color: transparent; +} +#ContentWidget[content_state="hightlighted"] { + background-color: rgba(19, 26, 32, 15%); +} + +#SideLineWidget { + background-color: #333942; + border-style: solid; + border-color: #4e5254; + border-left-width: 3px; + border-bottom-width: 0px; + border-right-width: 0px; + border-top-width: 0px; +} + +#SideLineWidget:hover { + border-color: #7d8386; +} + +#SideLineWidget[state="child-studio"] {border-color: #56a06f;} +#SideLineWidget[state="child-studio"]:hover {border-color: #73C990;} + +#SideLineWidget[state="child-modified"] {border-color: #106aa2;} +#SideLineWidget[state="child-modified"]:hover {border-color: #189aea;} + +#SideLineWidget[state="child-invalid"] {border-color: #ad2e2e;} +#SideLineWidget[state="child-invalid"]:hover {border-color: #c93636;} + +#SideLineWidget[state="child-overriden"] {border-color: #e67300;} +#SideLineWidget[state="child-overriden"]:hover {border-color: #ff8c1a;} + +#SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} +#SideLineWidget[state="child-overriden-modified"]:hover {border-color: #189aea;} + +#DictAsWidgetBody { + background: transparent; +} +#DictAsWidgetBody[show_borders="1"] { + border: 1px solid #4e5254; + border-radius: 5px; +} + +#ShadowWidget { + font-size: 36pt; +} + +#BreadcrumbsPathInput { + padding: 2px; + font-size: 9pt; +} + +#BreadcrumbsButton { + padding-right: 12px; + font-size: 9pt; + background: transparent; +} + +#BreadcrumbsButton[empty="1"] { + padding-right: 0px; +} + +#BreadcrumbsButton::menu-button { + border: none; + width: 12px; + background: rgba(127, 127, 127, 60); +} +#BreadcrumbsButton::menu-button:hover { + background: rgba(127, 127, 127, 90); +} + +#BreadcrumbsPanel { + border: 1px solid #4e5254; + border-radius: 5px; + background: #21252B;; +} From 7c3646dd40b3f6259b8c2136aa2a5d88758d0a05 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 16 Nov 2021 14:23:41 +0100 Subject: [PATCH 030/100] moved general names to bottom --- openpype/style/style.css | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index e2198ced31..6ba90921dd 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -669,15 +669,6 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; } -/* Globally used names */ -#Separator { - background: {color:bg-menu-separator}; -} - -#IconButton { - padding: 4px 4px 4px 4px; -} - /* Password dialog*/ #PasswordBtn { border: none; @@ -950,11 +941,6 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; } -#NiceCheckbox { - /* Default size hint of NiceCheckbox is defined by font size. */ - font-size: 7pt; -} - /* Settings - NOT USED YET - we need to define font family for settings UI */ @@ -1125,3 +1111,17 @@ QWidget[input-state="invalid"] {border-color: #ad2e2e;} border-radius: 5px; background: #21252B;; } + +/* Globally used names */ +#Separator { + background: {color:bg-menu-separator}; +} + +#IconButton { + padding: 4px 4px 4px 4px; +} + +#NiceCheckbox { + /* Default size hint of NiceCheckbox is defined by font size. */ + font-size: 7pt; +} From 1aa7e195bf1140da7dec53595433a52f3aa73c3f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 16 Nov 2021 14:23:57 +0100 Subject: [PATCH 031/100] removed ProjectListWidget styles --- openpype/style/style.css | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 6ba90921dd..1ba39e01f7 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -999,19 +999,6 @@ QWidget[input-state="invalid"] {border-color: #ad2e2e;} border-bottom: 1px solid #21252B; } -#ProjectListWidget QListView { - border: 1px solid #464b54; - background: #21252B; -} - -#ProjectListWidget QListView:disabled { - background: #282C34; -} - -#ProjectListWidget QListView::item:disabled { - color: #4e5254; -} - #ProjectListWidget QLabel { background: transparent; font-weight: bold; From 573f6c3aebbcbf6a6f0d7fe799afc405ac130759 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 16 Nov 2021 14:25:31 +0100 Subject: [PATCH 032/100] replace colors with data colors --- openpype/style/data.json | 17 +++++++++++ openpype/style/style.css | 66 +++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index b92ee61764..6dbe8f4d8e 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -71,6 +71,23 @@ "bg-expander-hover": "#2d6c9f", "bg-expander-selected-hover": "#3784c5" } + }, + "settings": { + "invalid-light": "#C93636", + "invalid-dark": "#AD2E2E", + "modified-light": "#46b1f3", + "modified-mid": "#189AEA", + "modified-dark": "#106AA2", + "studio-light": "#73C990", + "studio-dark": "#56a06f", + "studio-label-hover": "#FFFFFF", + "project-light": "#FFA64D", + "project-mid": "#FF8C1A", + "project-dark": "#E67300", + "breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)", + "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", + "content-hightlighted": "rgba(19, 26, 32, 15%)", + "tool-btn-color": "#21252B" } } } diff --git a/openpype/style/style.css b/openpype/style/style.css index 1ba39e01f7..dfd809f0a2 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -961,7 +961,7 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SettingsToolBtn:hover { border-color: #189aea; - color: #46b1f3; + color: {color:settings:modified-light}; background-color: transparent; } #SettingsToolBtn:disabled { @@ -977,23 +977,22 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { color: #969b9e; } #SettingsLabel:hover {color: #b8c1c5;} -#SettingsLabel[state="studio"] {color: #73C990;} -#SettingsLabel[state="studio"]:hover {color: #ffffff;} -#SettingsLabel[state="modified"] {color: #189aea;} -#SettingsLabel[state="modified"]:hover {color: #46b1f3;} -#SettingsLabel[state="overriden-modified"] {color: #189aea;} -#SettingsLabel[state="overriden-modified"]:hover {color: #46b1f3;} -#SettingsLabel[state="overriden"] {color: #ff8c1a;} -#SettingsLabel[state="overriden"]:hover {color: #ffa64d;} -#SettingsLabel[state="invalid"] {color: #ad2e2e;} -#SettingsLabel[state="invalid"]:hover {color: #ad2e2e;} +#SettingsLabel[state="studio"] {color: {color:settings:studio-light};} +#SettingsLabel[state="studio"]:hover {color: {color:settings:studio-label-hover};} +#SettingsLabel[state="modified"] {color: {color:settings:modified-mid};} +#SettingsLabel[state="modified"]:hover {color: {color:settings:modified-light};} +#SettingsLabel[state="overriden-modified"] {color: {color:settings:modified-mid};} +#SettingsLabel[state="overriden-modified"]:hover {color: {color:settings:modified-light};} +#SettingsLabel[state="overriden"] {color: {color:settings:project-mid};} +#SettingsLabel[state="overriden"]:hover {color: {color:settings:project-light};} +#SettingsLabel[state="invalid"] {color:{color:settings:invalid-dark};} +#SettingsLabel[state="invalid"]:hover {color: {color:settings:invalid-dark};} /* TODO Replace these with explicit widget types if possible */ -QWidget[input-state="studio"] {border-color: #858a94;} -QWidget[input-state="modified"] {border-color: #189aea;} -QWidget[input-state="overriden-modified"] {border-color: #189aea;} -QWidget[input-state="overriden"] {border-color: #ff8c1a;} -QWidget[input-state="invalid"] {border-color: #ad2e2e;} +QWidget[input-state="modified"] {border-color: {color:settings:modified-mid};} +QWidget[input-state="overriden-modified"] {border-color: {color:settings:modified-mid};} +QWidget[input-state="overriden"] {border-color: {color:settings:project-mid};} +QWidget[input-state="invalid"] {border-color: {color:settings:invalid-dark};} #GroupWidget { border-bottom: 1px solid #21252B; @@ -1008,11 +1007,8 @@ QWidget[input-state="invalid"] {border-color: #ad2e2e;} font-size: 12px; } -#DictKey[state="studio"] {border-color: #464b54;} -#DictKey[state="modified"] {border-color: #189aea;} -#DictKey[state="overriden"] {border-color: #00f;} -#DictKey[state="overriden-modified"] {border-color: #0f0;} -#DictKey[state="invalid"] {border-color: #ad2e2e;} +#DictKey[state="modified"] {border-color: {color:settings:modified-mid};} +#DictKey[state="invalid"] {border-color: {color:settings:invalid-dark};} #ExpandLabel { font-weight: bold; @@ -1025,7 +1021,7 @@ QWidget[input-state="invalid"] {border-color: #ad2e2e;} background-color: transparent; } #ContentWidget[content_state="hightlighted"] { - background-color: rgba(19, 26, 32, 15%); + background-color: {color:settings:content-hightlighted}; } #SideLineWidget { @@ -1042,20 +1038,20 @@ QWidget[input-state="invalid"] {border-color: #ad2e2e;} border-color: #7d8386; } -#SideLineWidget[state="child-studio"] {border-color: #56a06f;} -#SideLineWidget[state="child-studio"]:hover {border-color: #73C990;} +#SideLineWidget[state="child-studio"] {border-color: {color:settings:studio-dark};} +#SideLineWidget[state="child-studio"]:hover {border-color: {color:settings:studio-light};} -#SideLineWidget[state="child-modified"] {border-color: #106aa2;} -#SideLineWidget[state="child-modified"]:hover {border-color: #189aea;} +#SideLineWidget[state="child-modified"] {border-color: {color:settings:modified-dark};} +#SideLineWidget[state="child-modified"]:hover {border-color: {color:settings:modified-mid};} -#SideLineWidget[state="child-invalid"] {border-color: #ad2e2e;} -#SideLineWidget[state="child-invalid"]:hover {border-color: #c93636;} +#SideLineWidget[state="child-invalid"] {border-color: {color:settings:invalid-dark};} +#SideLineWidget[state="child-invalid"]:hover {border-color: {color:settings:invalid-light};} -#SideLineWidget[state="child-overriden"] {border-color: #e67300;} -#SideLineWidget[state="child-overriden"]:hover {border-color: #ff8c1a;} +#SideLineWidget[state="child-overriden"] {border-color: {color:settings:project-dark};} +#SideLineWidget[state="child-overriden"]:hover {border-color: {color:settings:project-mid};} -#SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} -#SideLineWidget[state="child-overriden-modified"]:hover {border-color: #189aea;} +#SideLineWidget[state="child-overriden-modified"] {border-color: {color:settings:modified-dark};} +#SideLineWidget[state="child-overriden-modified"]:hover {border-color: {color:settings:modified-mid};} #DictAsWidgetBody { background: transparent; @@ -1087,16 +1083,16 @@ QWidget[input-state="invalid"] {border-color: #ad2e2e;} #BreadcrumbsButton::menu-button { border: none; width: 12px; - background: rgba(127, 127, 127, 60); + background: {color:settings:breadcrumbs-btn-bg}; } #BreadcrumbsButton::menu-button:hover { - background: rgba(127, 127, 127, 90); + background: {color:settings:breadcrumbs-btn-bg-hover}; } #BreadcrumbsPanel { border: 1px solid #4e5254; border-radius: 5px; - background: #21252B;; + background: #21252B; } /* Globally used names */ From 609351d264ac31c2a28c8f9b5e8476719b1b251f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 16 Nov 2021 17:39:34 +0100 Subject: [PATCH 033/100] fix percent in rgba --- openpype/style/data.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index 6dbe8f4d8e..2f5984d5ab 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -86,7 +86,7 @@ "project-dark": "#E67300", "breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)", "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", - "content-hightlighted": "rgba(19, 26, 32, 15%)", + "content-hightlighted": "rgba(19, 26, 32, 15)", "tool-btn-color": "#21252B" } } From 283d2575c03d5825e5570a726621be31ee22ed52 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Thu, 18 Nov 2021 09:56:48 +0200 Subject: [PATCH 034/100] publish without selection --- openpype/hosts/nuke/plugins/publish/extract_model.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 8a7ecbe093..7f9e537189 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -33,6 +33,7 @@ class ExtractModel(openpype.api.Extractor): pformat(instance.data))) rm_nodes = list() + model_node = instance[0] self.log.info("Crating additional nodes") subset = instance.data["subset"] staging_dir = self.staging_dir(instance) @@ -49,6 +50,9 @@ class ExtractModel(openpype.api.Extractor): file_path = os.path.join(staging_dir, filename).replace("\\", "/") with anlib.maintained_selection(): + # select model node + anlib.select_nodes([model_node]) + # create write geo node wg_n = nuke.createNode("WriteGeo") wg_n["file"].setValue(file_path) From b3581c8ba57d51f74b8199266fc6ce8743415ebb Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Thu, 18 Nov 2021 10:12:21 +0200 Subject: [PATCH 035/100] bound --- openpype/hosts/nuke/plugins/publish/extract_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/plugins/publish/extract_model.py b/openpype/hosts/nuke/plugins/publish/extract_model.py index 7f9e537189..43214bf3e9 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_model.py +++ b/openpype/hosts/nuke/plugins/publish/extract_model.py @@ -28,7 +28,7 @@ class ExtractModel(openpype.api.Extractor): handle_end = instance.context.data["handleEnd"] first_frame = int(nuke.root()["first_frame"].getValue()) last_frame = int(nuke.root()["last_frame"].getValue()) - + self.log.info("instance.data: `{}`".format( pformat(instance.data))) From 5cbdbd0bfe9c7a70ceb8391cbe19722f71dce1ea Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:28:59 +0100 Subject: [PATCH 036/100] changed focus color of inputs --- openpype/style/data.json | 8 +++++++- openpype/style/style.css | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index 49602d83d4..438e8e11e1 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -83,19 +83,25 @@ "settings": { "invalid-light": "#C93636", "invalid-dark": "#AD2E2E", + "modified-light": "#46b1f3", "modified-mid": "#189AEA", "modified-dark": "#106AA2", + "studio-light": "#73C990", "studio-dark": "#56a06f", "studio-label-hover": "#FFFFFF", + "project-light": "#FFA64D", "project-mid": "#FF8C1A", "project-dark": "#E67300", + "breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)", "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", + "content-hightlighted": "rgba(19, 26, 32, 15)", - "tool-btn-color": "#21252B" + "tool-btn-color": "#21252B", + "focus-border": "#839caf" } } } diff --git a/openpype/style/style.css b/openpype/style/style.css index 33e85c331f..4126f78373 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -968,6 +968,9 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SettingsMainWidget { background: #141a1f; } +#SettingsMainWidget QAbstractSpinBox:focus, #SettingsMainWidget QLineEdit:focus, #SettingsMainWidget QPlainTextEdit:focus, #SettingsMainWidget QTextEdit:focus { + border-color: {color:settings:focus-border}; +} #SettingsToolIconBtn { border: 0px solid #bfccd6; From cb26d111b9466d1ff0d8f558c423bdfc3f5318de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:29:13 +0100 Subject: [PATCH 037/100] reduced input state to widgets in settings window --- openpype/style/style.css | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index 4126f78373..8075ddb1e6 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -1013,10 +1013,18 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SettingsLabel[state="invalid"]:hover {color: {color:settings:invalid-dark};} /* TODO Replace these with explicit widget types if possible */ -QWidget[input-state="modified"] {border-color: {color:settings:modified-mid};} -QWidget[input-state="overriden-modified"] {border-color: {color:settings:modified-mid};} -QWidget[input-state="overriden"] {border-color: {color:settings:project-mid};} -QWidget[input-state="invalid"] {border-color: {color:settings:invalid-dark};} +#SettingsMainWidget QWidget[input-state="modified"] { + border-color: {color:settings:modified-mid}; +} +#SettingsMainWidget QWidget[input-state="overriden-modified"] { + border-color: {color:settings:modified-mid}; +} +#SettingsMainWidget QWidget[input-state="overriden"] { + border-color: {color:settings:project-mid}; +} +#SettingsMainWidget QWidget[input-state="invalid"] { + border-color: {color:settings:invalid-dark}; +} #GroupWidget { border-bottom: 1px solid #21252B; From b89a87fa012cf67b12cb2b3d2123f892e51869c5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:29:26 +0100 Subject: [PATCH 038/100] removed unused variable --- openpype/tools/settings/settings/item_widgets.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index d808de74a4..6fb0596558 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -326,9 +326,6 @@ class DictImmutableKeysWidget(BaseWidget): class BoolWidget(InputWidget): def _add_inputs_to_layout(self): - checkbox_height = self.style().pixelMetric( - QtWidgets.QStyle.PM_IndicatorHeight - ) self.input_field = SettingsNiceCheckbox(parent=self.content_widget) self.content_layout.addWidget(self.input_field, 0) From 227afc9b374d28a70243d3e030c1a1c027098c39 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:29:40 +0100 Subject: [PATCH 039/100] removed unused method --- openpype/widgets/nice_checkbox.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openpype/widgets/nice_checkbox.py b/openpype/widgets/nice_checkbox.py index d550f361ff..17bbc24776 100644 --- a/openpype/widgets/nice_checkbox.py +++ b/openpype/widgets/nice_checkbox.py @@ -73,15 +73,6 @@ class NiceCheckbox(QtWidgets.QFrame): self._draw_icons = draw_icons self.repaint() - def _checkbox_size_hint(self): - checkbox_height = self.style().pixelMetric( - QtWidgets.QStyle.PM_IndicatorHeight - ) - checkbox_height += checkbox_height % 2 - width = (2 * checkbox_height) - (checkbox_height / 5) - new_size = QtCore.QSize(width, checkbox_height) - return new_size - def sizeHint(self): height = self.fontMetrics().height() width = self.get_width_hint_by_height(height) From 29997bb7818ed1bc586572fc2b0a2e89f5454423 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:30:06 +0100 Subject: [PATCH 040/100] start animation only if checkbox is visible --- openpype/widgets/nice_checkbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/widgets/nice_checkbox.py b/openpype/widgets/nice_checkbox.py index 17bbc24776..447f48caa7 100644 --- a/openpype/widgets/nice_checkbox.py +++ b/openpype/widgets/nice_checkbox.py @@ -150,7 +150,7 @@ class NiceCheckbox(QtWidgets.QFrame): if self._animation_timer.isActive(): self._animation_timer.stop() - if self.isEnabled(): + if self.isVisible() and self.isEnabled(): # Start animation self._animation_timer.start(self._animation_timeout) else: From 40eb19231d52a3abac9cbf81348a1c0f1322c684 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:31:27 +0100 Subject: [PATCH 041/100] use safer approach of animating --- openpype/widgets/nice_checkbox.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/widgets/nice_checkbox.py b/openpype/widgets/nice_checkbox.py index 447f48caa7..b032453a7f 100644 --- a/openpype/widgets/nice_checkbox.py +++ b/openpype/widgets/nice_checkbox.py @@ -226,14 +226,16 @@ class NiceCheckbox(QtWidgets.QFrame): def _on_animation_timeout(self): if self._checkstate == QtCore.Qt.Checked: - self._current_step += 1 if self._current_step == self._steps: self._animation_timer.stop() + return + self._current_step += 1 elif self._checkstate == QtCore.Qt.Unchecked: - self._current_step -= 1 if self._current_step == 0: self._animation_timer.stop() + return + self._current_step -= 1 else: if self._current_step < self._middle_step: From a43463d3b9f014f960e1bb43999f9a1a1b00484b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:31:42 +0100 Subject: [PATCH 042/100] boolean has defferend setting of entity too --- openpype/tools/settings/settings/item_widgets.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openpype/tools/settings/settings/item_widgets.py b/openpype/tools/settings/settings/item_widgets.py index 6fb0596558..2e00967a60 100644 --- a/openpype/tools/settings/settings/item_widgets.py +++ b/openpype/tools/settings/settings/item_widgets.py @@ -349,6 +349,9 @@ class BoolWidget(InputWidget): def _on_value_change(self): if self.ignore_input_changes: return + self.start_value_timer() + + def _on_value_change_timer(self): self.entity.set(self.input_field.isChecked()) From 73f729cc78e4326e953fd4ae8d6ae1f68c399c34 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 18 Nov 2021 19:31:53 +0100 Subject: [PATCH 043/100] use openpype style in settings UIs --- openpype/tools/settings/local_settings/window.py | 2 +- openpype/tools/settings/settings/window.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/tools/settings/local_settings/window.py b/openpype/tools/settings/local_settings/window.py index dc4e4d67f3..a00bc232f4 100644 --- a/openpype/tools/settings/local_settings/window.py +++ b/openpype/tools/settings/local_settings/window.py @@ -1,7 +1,7 @@ import logging from Qt import QtWidgets, QtGui -from ..settings import style +from openpype import style from openpype.settings.lib import ( get_local_settings, diff --git a/openpype/tools/settings/settings/window.py b/openpype/tools/settings/settings/window.py index 3ee303cfe9..fd0cd1d7cd 100644 --- a/openpype/tools/settings/settings/window.py +++ b/openpype/tools/settings/settings/window.py @@ -5,7 +5,7 @@ from .categories import ( ProjectWidget ) from .widgets import ShadowWidget, RestartDialog -from . import style +from openpype import style from openpype.lib import is_admin_password_required from openpype.widgets import PasswordDialog From bda21555d5063446e97a79a93b7759ffa9ed8ef6 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 22 Nov 2021 12:59:33 +0200 Subject: [PATCH 044/100] last 3d node in branch --- .../hosts/nuke/plugins/create/create_model.py | 32 +++++++++++++++++++ .../nuke/plugins/publish/collect_model.py | 3 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index c6368ddb0e..849c8bcdde 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -22,7 +22,39 @@ class CreateModel(plugin.PypeCreator): nodes = list() if (self.options or {}).get("useSelection"): nodes = self.nodes + for n in nodes : + n['selected'].setValue(0) + end_nodes = list() + # get the latest nodes in tree for selecion + for n in nodes: + x = n + end = 0 + while end == 0: + try: + x = x.dependent()[0] + except: + end_node = x + end = 1 + end_nodes.append(end_node) + + # set end_nodes + end_nodes = list(set(end_nodes)) + + # check if nodes is 3d nodes + for n in end_nodes : + n['selected'].setValue(1) + sn = nuke.createNode("Scene") + if not sn.input(0) : + end_nodes.remove(n) + nuke.delete(sn) + + # loop over end nodes + for n in end_nodes : + n['selected'].setValue(1) + + self.nodes = nuke.selectedNodes() + nodes = self.nodes if len(nodes) >= 1: # loop selected nodes for n in nodes: diff --git a/openpype/hosts/nuke/plugins/publish/collect_model.py b/openpype/hosts/nuke/plugins/publish/collect_model.py index ade9f90987..5fca240553 100644 --- a/openpype/hosts/nuke/plugins/publish/collect_model.py +++ b/openpype/hosts/nuke/plugins/publish/collect_model.py @@ -19,8 +19,7 @@ class CollectModel(pyblish.api.InstancePlugin): # add family to familiess instance.data["families"].insert(0, instance.data["family"]) # make label nicer - instance.data["label"] = "{0} ({1} nodes)".format( - grpn.name(), len(instance) - 1) + instance.data["label"] = grpn.name() # Get frame range handle_start = instance.context.data["handleStart"] From b2f22accb86ff057d0638b796cdd7ec2ab14d1f7 Mon Sep 17 00:00:00 2001 From: karimmozlia Date: Mon, 22 Nov 2021 13:08:27 +0200 Subject: [PATCH 045/100] bound --- openpype/hosts/nuke/plugins/create/create_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/nuke/plugins/create/create_model.py b/openpype/hosts/nuke/plugins/create/create_model.py index 849c8bcdde..4e30860e05 100644 --- a/openpype/hosts/nuke/plugins/create/create_model.py +++ b/openpype/hosts/nuke/plugins/create/create_model.py @@ -22,7 +22,7 @@ class CreateModel(plugin.PypeCreator): nodes = list() if (self.options or {}).get("useSelection"): nodes = self.nodes - for n in nodes : + for n in nodes: n['selected'].setValue(0) end_nodes = list() @@ -42,15 +42,15 @@ class CreateModel(plugin.PypeCreator): end_nodes = list(set(end_nodes)) # check if nodes is 3d nodes - for n in end_nodes : + for n in end_nodes: n['selected'].setValue(1) sn = nuke.createNode("Scene") - if not sn.input(0) : + if not sn.input(0): end_nodes.remove(n) nuke.delete(sn) # loop over end nodes - for n in end_nodes : + for n in end_nodes: n['selected'].setValue(1) self.nodes = nuke.selectedNodes() From 8f0dee171d483a9982aa49c9dad258e5005c4a65 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:37:16 +0100 Subject: [PATCH 046/100] added images for icons --- .../settings/settings/images/__init__.py | 19 ++++++++++++++++++ .../tools/settings/settings/images/add.png | Bin 0 -> 822 bytes .../tools/settings/settings/images/add.svg | 17 ++++++++++++++++ .../settings/settings/images/confirm.png | Bin 0 -> 931 bytes .../settings/settings/images/confirm.svg | 19 ++++++++++++++++++ .../tools/settings/settings/images/down.png | Bin 0 -> 924 bytes .../tools/settings/settings/images/down.svg | 19 ++++++++++++++++++ .../tools/settings/settings/images/mask.png | Bin 0 -> 744 bytes .../tools/settings/settings/images/mask.svg | 11 ++++++++++ .../tools/settings/settings/images/remove.png | Bin 0 -> 819 bytes .../tools/settings/settings/images/remove.svg | 14 +++++++++++++ .../tools/settings/settings/images/up.png | Bin 0 -> 930 bytes .../tools/settings/settings/images/up.svg | 19 ++++++++++++++++++ 13 files changed, 118 insertions(+) create mode 100644 openpype/tools/settings/settings/images/__init__.py create mode 100644 openpype/tools/settings/settings/images/add.png create mode 100644 openpype/tools/settings/settings/images/add.svg create mode 100644 openpype/tools/settings/settings/images/confirm.png create mode 100644 openpype/tools/settings/settings/images/confirm.svg create mode 100644 openpype/tools/settings/settings/images/down.png create mode 100644 openpype/tools/settings/settings/images/down.svg create mode 100644 openpype/tools/settings/settings/images/mask.png create mode 100644 openpype/tools/settings/settings/images/mask.svg create mode 100644 openpype/tools/settings/settings/images/remove.png create mode 100644 openpype/tools/settings/settings/images/remove.svg create mode 100644 openpype/tools/settings/settings/images/up.png create mode 100644 openpype/tools/settings/settings/images/up.svg diff --git a/openpype/tools/settings/settings/images/__init__.py b/openpype/tools/settings/settings/images/__init__.py new file mode 100644 index 0000000000..3ad65e114a --- /dev/null +++ b/openpype/tools/settings/settings/images/__init__.py @@ -0,0 +1,19 @@ +import os +from Qt import QtGui + + +def get_image_path(image_filename): + return os.path.join( + os.path.dirname(os.path.abspath(__file__)), + image_filename + ) + + +def get_image(image_filename): + image_path = get_image_path(image_filename) + return QtGui.QImage(image_path) + + +def get_pixmap(image_filename): + image_path = get_image_path(image_filename) + return QtGui.QPixmap(image_path) diff --git a/openpype/tools/settings/settings/images/add.png b/openpype/tools/settings/settings/images/add.png new file mode 100644 index 0000000000000000000000000000000000000000..81a68e6d5f6ff7b318bb32aaad01ace2212e4bea GIT binary patch literal 822 zcmV-61Ihe}P)efLXk z^X>bcBv<9SqQu3o1AhTm<*XEulACfSF08N5cUx`AK2M+L^LpOT^ZE2Vp9ieLl#tC_aK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{ zS>Z|H>GiB?@~&{3k_<Tf7UM0DgQpnPQwVh8SQ(<{{j8>6aB%@;!z8Sym-iky&K} zjTI6k$>I`qO{&Kv#zl|GNU>q||8HOQ_@K8~-R^_B7sL4Ih58-H=M3Zf*f8=ZQ1c8| znR5Q>5e$Edo-1oThv3+Pi|eu$*@Me%=zLPcTDTz9h+E@vct3;Y5VYPx(^9c#rF~8x zA-E}Dbp!hc&?n~|%fCV*XVv-qhME8X00~e`R7C&)0Dpgf$wemcv;uMf000AYQchF< z{{Yv@4M6|^010qNS#tmY3ljhU3ljkVnw%H_00A~hL_t(YiM5tX7Q-M2McJeoWC`rY zB{;xUHc>=0c{xp*GU%aR1d41`RRun8YQ8F$1$P?Sh~6COb7U>!hk;z9CY zbs)Bx-94G>Zj%k9z8Pt@NG-MPn@+mkK82`Ns=6&GOISg&Q|11T>YVJPt|!yHtqNqY zRBUkp$zNP<6D!DrG!RD@IzT$13@qkE0XGxoWCvm{oWfTinQsGe^GfA+0{h$x(9dmP zcY6u)40es=9PkE~BZyZZor84)>k*_!AodIQU^xf!Baq-!1>$3nzX5a9{sY|K6+GbE zA91><7as$BaQELX3 + + + + + + + + + + + + + + + + diff --git a/openpype/tools/settings/settings/images/confirm.png b/openpype/tools/settings/settings/images/confirm.png new file mode 100644 index 0000000000000000000000000000000000000000..d40e40f2e90e03d71be7ece9f47a80c027bac276 GIT binary patch literal 931 zcmV;U16=%xP)efLXk z^X>bcBv<9SqQu3o1AhTm<*XEulACfSF08N5cUx`AK2M+L^LpOT^ZE2Vp9ieLl#tC_aK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{ zS>Z|H>GiB?@~&{3k_<Tf7UM0DgQpnPQwVh8SQ(<{{j8>6aB%@;!z8Sym-iky&K} zjTI6k$>I`qO{&Kv#zl|GNU>q||8HOQ_@K8~-R^_B7sL4Ih58-H=M3Zf*f8=ZQ1c8| znR5Q>5e$Edo-1oThv3+Pi|eu$*@Me%=zLPcTDTz9h+E@vct3;Y5VYPx(^9c#rF~8x zA-E}Dbp!hc&?n~|%fCV*XVv-qhME8X00~e`R7C&)0Dpgf$wemcv;uMf000AYQchF< z{{Yv@4M6|^010qNS#tmY3ljhU3ljkVnw%H_00E;(L_t(YiItYwjRPSJKxvYZG9}Ot zCHTWsxqxq2N4x%rm^`onUzCwZ(Gk`u?FRdQM-)_+6LbMj1XxvC0ASz^pgQpYJa`@G zGSkc#HElYZ0-8#-wH6xdg1w|M06o>PuR?Q%6Ix$%`a407w(%Kz?ggL=4=P>INJeKpIXj%rEogI(*C-fGq818 zS{vB9EUlNL*tHXUEa#lh!Pi3%FqC5g4_~aS#w*|?M0*X@%wiXv2?kas6|6MS#OW@z zLaMo16LZid3IR>$uHeXXcq6csQrlEA{$G94LY9}lv{ zdFAacZIEe8O`CAuw$nzRKMm5yMEd;5A1wJ3Cw&y1@&i=76&I5l7YG0V002ovPDHLk FV1m6mq!R!D literal 0 HcmV?d00001 diff --git a/openpype/tools/settings/settings/images/confirm.svg b/openpype/tools/settings/settings/images/confirm.svg new file mode 100644 index 0000000000..ebc5e024e6 --- /dev/null +++ b/openpype/tools/settings/settings/images/confirm.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/openpype/tools/settings/settings/images/down.png b/openpype/tools/settings/settings/images/down.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6b7f74714704f79867c0c62d84824570c6d157 GIT binary patch literal 924 zcmV;N17rM&P)efLXk z^X>bcBv<9SqQu3o1AhTm<*XEulACfSF08N5cUx`AK2M+L^LpOT^ZE2Vp9ieLl#tC_aK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{ zS>Z|H>GiB?@~&{3k_<Tf7UM0DgQpnPQwVh8SQ(<{{j8>6aB%@;!z8Sym-iky&K} zjTI6k$>I`qO{&Kv#zl|GNU>q||8HOQ_@K8~-R^_B7sL4Ih58-H=M3Zf*f8=ZQ1c8| znR5Q>5e$Edo-1oThv3+Pi|eu$*@Me%=zLPcTDTz9h+E@vct3;Y5VYPx(^9c#rF~8x zA-E}Dbp!hc&?n~|%fCV*XVv-qhME8X00~e`R7C&)0Dpgf$wemcv;uMf000AYQchF< z{{Yv@4M6|^010qNS#tmY3ljhU3ljkVnw%H_00EpyL_t(YiItYik;EVjL`l*6^TTP$`coMjvA?OGm z0L?5zzPNPwtPXl?W|*&{o^1QxFS_1;#Za$B`o3TGpsJh;~k1-z*lXjwuhiW(du3Tg&Jz&Itu^b6>x_ELW)Xs7nOZNGqzP06;t0w252 z1z@-R4p1k6dl0<@LT!QgJ~*)X2@}|;#}W4gTEtTZ5H$-lytQUDg#&bmz=5DaI3+M= zn~5M;H`^~Uf;H*a9>I2FA_(@Ji2x8UCIUdFOay>BQ4s(-qdb85P>}$kx(x#O&k&aZ z{P&54gGd3kZ3U46>_cxk+7>rwJM}Y%w7P8!V3z3t?vxvb{N+ckD2Bos``v92pY1Vl zVF1j2l`zpE&eUbhbZHY7=`Pp^E4L0000 + + + + + + + + + + + + + + + + + + diff --git a/openpype/tools/settings/settings/images/mask.png b/openpype/tools/settings/settings/images/mask.png new file mode 100644 index 0000000000000000000000000000000000000000..601a67733e0c0fcd6d6ad9e1c9929b7cd55497c2 GIT binary patch literal 744 zcmVP)efLXk z^X>bcBv<9SqQu3o1AhTm<*XEulACfSF08N5cUx`AK2M+L^LpOT^ZE2Vp9ieLl#tC_aK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{ zS>Z|H>GiB?@~&{3k_<Tf7UM0DgQpnPQwVh8SQ(<{{j8>6aB%@;!z8Sym-iky&K} zjTI6k$>I`qO{&Kv#zl|GNU>q||8HOQ_@K8~-R^_B7sL4Ih58-H=M3Zf*f8=ZQ1c8| znR5Q>5e$Edo-1oThv3+Pi|eu$*@Me%=zLPcTDTz9h+E@vct3;Y5VYPx(^9c#rF~8x zA-E}Dbp!hc&?n~|%fCV*XVv-qhME8X00~e`R7C&)0Dpgf$wemcv;uMf000AYQchF< z{{Yv@4M6|^010qNS#tmY3ljhU3ljkVnw%H_008JoL_t(YiS3p_3dJA{M7^XgJc9S} z2rld?zlyaO$blQc3f&+}5IRT__zt23t^;}AOpIdDOpIdDOlIKa-Q11l zUEL=@2~}fFfD)?4GFqq_YXY?M5^DpfX-nP>p#ER^!;>KD!2Q9mfN$KAgO~c?Q`>mw zaAd4cpY;ichvoX*g(DmeeOwc;SYQ>w^1^io3ldf;EMZ*Ru;}q>0GA24e&B@#uQ+fi alKKE?Ikf`1;C}4@0000 + + + + + + + + + + diff --git a/openpype/tools/settings/settings/images/remove.png b/openpype/tools/settings/settings/images/remove.png new file mode 100644 index 0000000000000000000000000000000000000000..44a4c7e31f27e8c90d9e26e31a80d38b12a1c77c GIT binary patch literal 819 zcmV-31I+x1P)efLXk z^X>bcBv<9SqQu3o1AhTm<*XEulACfSF08N5cUx`AK2M+L^LpOT^ZE2Vp9ieLl#tC_aK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{ zS>Z|H>GiB?@~&{3k_<Tf7UM0DgQpnPQwVh8SQ(<{{j8>6aB%@;!z8Sym-iky&K} zjTI6k$>I`qO{&Kv#zl|GNU>q||8HOQ_@K8~-R^_B7sL4Ih58-H=M3Zf*f8=ZQ1c8| znR5Q>5e$Edo-1oThv3+Pi|eu$*@Me%=zLPcTDTz9h+E@vct3;Y5VYPx(^9c#rF~8x zA-E}Dbp!hc&?n~|%fCV*XVv-qhME8X00~e`R7C&)0Dpgf$wemcv;uMf000AYQchF< z{{Yv@4M6|^010qNS#tmY3ljhU3ljkVnw%H_00A>eL_t(YiM^If7Q-M2McHIJ$P(O- zOK^azZ2Tc&o~P!tWn{d{$0$G%2+4?#OWX|dydnaQDi-(#UL)W`#0?;Ha1P*5qCwE$ zRKT~D-8_luuG0w!-5GAWsA_8N%b4nZISQ^?sf=Yq-r_0<5>@P9RMtc#Wk1PC>neZ; zO<9-AAm|?#+rk3kAPxA@M4h0zz!<5(jerYaYoaV&fM9JW>*oc$wH@=?1(=*FZY_bG zPi{rJ@izN=fyvwC?*iP!mm|Eu6h;c<3Gj1#`AqHs{{XOlgYFYxU+pizzE}S^D=X}MaC$Z+a|$r7eln2=!#he;oo30PQQDT2idmpfP> xVM&EW7?*8W=y7WRn+e!{;D!aaIIt + + + + + + + + + + + + + diff --git a/openpype/tools/settings/settings/images/up.png b/openpype/tools/settings/settings/images/up.png new file mode 100644 index 0000000000000000000000000000000000000000..4c03bcd5c9701957e6a3b20976f53aafbf54c03d GIT binary patch literal 930 zcmV;T16}-yP)efLXk z^X>bcBv<9SqQu3o1AhTm<*XEulACfSF08N5cUx`AK2M+L^LpOT^ZE2Vp9ieLl#tC_aK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{ zS>Z|H>GiB?@~&{3k_<Tf7UM0DgQpnPQwVh8SQ(<{{j8>6aB%@;!z8Sym-iky&K} zjTI6k$>I`qO{&Kv#zl|GNU>q||8HOQ_@K8~-R^_B7sL4Ih58-H=M3Zf*f8=ZQ1c8| znR5Q>5e$Edo-1oThv3+Pi|eu$*@Me%=zLPcTDTz9h+E@vct3;Y5VYPx(^9c#rF~8x zA-E}Dbp!hc&?n~|%fCV*XVv-qhME8X00~e`R7C&)0Dpgf$wemcv;uMf000AYQchF< z{{Yv@4M6|^010qNS#tmY3ljhU3ljkVnw%H_00E*&L_t(YiJg{9wuB%IMA@VcTmt)H z2@GJBP5yy?!R=buNbOYUUp3>dNX$$_-YnV+8{IeJKH+o%IO|Jlh=dBIyC#gqM|p8Cy(Z2sDy! zZX&B{84HLdCn3W?n24wYH_?ayW}=z_%tQkMn2AaTa8uz4h=wU9Adf7E1VkjVcEHd4 zJ2M~^|1%lTL;sfH`ZIE`6|A!tx3WGA!Y+=;Jm48w+ej zuzBHj2OA`8sjvy-whbFSJ{rKo1U!D=0}DRlz(dhFKK)!1JnycGuK)l507*qoM6N<$ Eg7%u8G5`Po literal 0 HcmV?d00001 diff --git a/openpype/tools/settings/settings/images/up.svg b/openpype/tools/settings/settings/images/up.svg new file mode 100644 index 0000000000..5b813f44f8 --- /dev/null +++ b/openpype/tools/settings/settings/images/up.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + From 1e29a7c14a069c203808ad5f64bd0c1014ef1b92 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:37:58 +0100 Subject: [PATCH 047/100] implemented basic ImageButton --- openpype/tools/utils/widgets.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/openpype/tools/utils/widgets.py b/openpype/tools/utils/widgets.py index 493255071d..3b1ae877b9 100644 --- a/openpype/tools/utils/widgets.py +++ b/openpype/tools/utils/widgets.py @@ -38,6 +38,32 @@ class PlaceholderLineEdit(QtWidgets.QLineEdit): self.setPalette(filter_palette) +class ImageButton(QtWidgets.QPushButton): + """PushButton with icon and size of font. + + Using font metrics height as icon size reference. + + TODO: + - handle changes of screen (different resolution) + """ + + def __init__(self, *args, **kwargs): + super(ImageButton, self).__init__(*args, **kwargs) + self.setObjectName("ImageButton") + + def _change_size(self): + font_height = self.fontMetrics().height() + self.setIconSize(QtCore.QSize(font_height, font_height)) + + def showEvent(self, event): + super(ImageButton, self).showEvent(event) + + self._change_size() + + def sizeHint(self): + return self.iconSize() + + class AssetWidget(QtWidgets.QWidget): """A Widget to display a tree of assets with filter From 7aacff9591a6946308dd52a6f30dfb8c9628a953 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:38:29 +0100 Subject: [PATCH 048/100] extracted paint_image_with_color from publisher --- openpype/tools/utils/lib.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index 4626e35a93..738e1a348c 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -25,6 +25,34 @@ def center_window(window): window.move(geo.topLeft()) +def paint_image_with_color(image, color): + """Redraw image with single color using it's alpha. + + It is expected that input image is singlecolor image with alpha. + + Args: + image (QImage): Loaded image with alpha. + color (QColor): Color that will be used to paint image. + """ + width = image.width() + height = image.height() + + alpha_mask = image.createAlphaMask() + alpha_region = QtGui.QRegion(QtGui.QBitmap.fromImage(alpha_mask)) + + pixmap = QtGui.QPixmap(width, height) + pixmap.fill(QtCore.Qt.transparent) + + painter = QtGui.QPainter(pixmap) + painter.setClipRegion(alpha_region) + painter.setPen(QtCore.Qt.NoPen) + painter.setBrush(color) + painter.drawRect(QtCore.QRect(0, 0, width, height)) + painter.end() + + return pixmap + + def format_version(value, hero_version=False): """Formats integer to displayable version name""" label = "v{0:03d}".format(value) From 190b261e70a2fb9d8b71e12cc5dc29fb25c6fa54 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:38:54 +0100 Subject: [PATCH 049/100] added styles for ImageButton --- openpype/style/style.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index 8075ddb1e6..b1ec152f0e 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -1140,3 +1140,13 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { /* Default size hint of NiceCheckbox is defined by font size. */ font-size: 7pt; } + +#ImageButton { + padding: 0; + background: transparent; + font-size: 12pt; +} + +#ImageButton:disabled { + background: {color:bg-buttons-disabled}; +} From 971bb2bb62c471e765e71fd1941913b4b86bedd3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:39:04 +0100 Subject: [PATCH 050/100] define colors of settings buttons --- openpype/style/data.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index 438e8e11e1..5e590bce79 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -100,8 +100,10 @@ "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", "content-hightlighted": "rgba(19, 26, 32, 15)", - "tool-btn-color": "#21252B", - "focus-border": "#839caf" + "focus-border": "#839caf", + "image-btn": "#bfccd6", + "image-btn-hover": "#189aea", + "image-btn-disabled": "#bfccd6" } } } From 5a5285e18a4e4b2ebe522bcd3d489e787ef37055 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:39:46 +0100 Subject: [PATCH 051/100] implemented which has more abilities than a base ImageButton --- openpype/tools/settings/settings/widgets.py | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/openpype/tools/settings/settings/widgets.py b/openpype/tools/settings/settings/widgets.py index 7480d4c51b..7a7213fa66 100644 --- a/openpype/tools/settings/settings/widgets.py +++ b/openpype/tools/settings/settings/widgets.py @@ -6,8 +6,16 @@ from avalon.mongodb import ( AvalonMongoDB ) +from openpype.style import get_objected_colors +from openpype.tools.utils.widgets import ImageButton +from openpype.tools.utils.lib import paint_image_with_color + from openpype.widgets.nice_checkbox import NiceCheckbox from openpype.settings.lib import get_system_settings +from .images import ( + get_pixmap, + get_image +) from .constants import ( DEFAULT_PROJECT_LABEL, PROJECT_NAME_ROLE, @@ -32,6 +40,78 @@ class SettingsPlainTextEdit(QtWidgets.QPlainTextEdit): self.focused_in.emit() +class SettingsToolBtn(ImageButton): + _mask_pixmap = None + _cached_icons = {} + + def __init__(self, btn_type, parent): + super(SettingsToolBtn, self).__init__(parent) + + icon, hover_icon = self._get_icon_type(btn_type) + + self.setIcon(icon) + + self._icon = icon + self._hover_icon = hover_icon + + @classmethod + def _get_icon_type(cls, btn_type): + if btn_type not in cls._cached_icons: + settings_colors = get_objected_colors()["settings"] + normal_color = settings_colors["image-btn"].get_qcolor() + hover_color = settings_colors["image-btn-hover"].get_qcolor() + disabled_color = settings_colors["image-btn-disabled"].get_qcolor() + + image = get_image("{}.png".format(btn_type)) + + pixmap = paint_image_with_color(image, normal_color) + hover_pixmap = paint_image_with_color(image, hover_color) + disabled_pixmap = paint_image_with_color(image, disabled_color) + + icon = QtGui.QIcon(pixmap) + hover_icon = QtGui.QIcon(hover_pixmap) + icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.On + ) + icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.Off + ) + hover_icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.On + ) + hover_icon.addPixmap( + disabled_pixmap, QtGui.QIcon.Disabled, QtGui.QIcon.Off + ) + cls._cached_icons[btn_type] = icon, hover_icon + return cls._cached_icons[btn_type] + + def enterEvent(self, event): + self.setIcon(self._hover_icon) + super(SettingsToolBtn, self).enterEvent(event) + + def leaveEvent(self, event): + self.setIcon(self._icon) + super(SettingsToolBtn, self).leaveEvent(event) + + @classmethod + def _get_mask_pixmap(cls): + if cls._mask_pixmap is None: + mask_pixmap = get_pixmap("mask.png") + cls._mask_pixmap = mask_pixmap + return cls._mask_pixmap + + def _change_size(self): + super(SettingsToolBtn, self)._change_size() + size = self.iconSize() + scaled = self._get_mask_pixmap().scaled( + size.width(), + size.height(), + QtCore.Qt.IgnoreAspectRatio, + QtCore.Qt.SmoothTransformation + ) + self.setMask(scaled.mask()) + + class ShadowWidget(QtWidgets.QWidget): def __init__(self, message, parent): super(ShadowWidget, self).__init__(parent) From 1b05dbbf52c5874e68626f595ab04d0d749519bb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:40:07 +0100 Subject: [PATCH 052/100] added functions creating SettingsToolBtn objects --- openpype/tools/settings/settings/lib.py | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/openpype/tools/settings/settings/lib.py b/openpype/tools/settings/settings/lib.py index 577aaa5671..d12a14259a 100644 --- a/openpype/tools/settings/settings/lib.py +++ b/openpype/tools/settings/settings/lib.py @@ -1,5 +1,7 @@ from Qt import QtCore +from .widgets import SettingsToolBtn + # Offset of value change trigger in ms VALUE_CHANGE_OFFSET_MS = 300 @@ -16,3 +18,33 @@ def create_deffered_value_change_timer(callback): timer.setInterval(VALUE_CHANGE_OFFSET_MS) timer.timeout.connect(callback) return timer + + +def create_add_btn(parent): + add_btn = SettingsToolBtn("add", parent) + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return add_btn + + +def create_remove_btn(parent): + remove_btn = SettingsToolBtn("remove", parent) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return remove_btn + + +def create_up_btn(parent): + remove_btn = SettingsToolBtn("up", parent) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return remove_btn + + +def create_down_btn(parent): + add_btn = SettingsToolBtn("down", parent) + add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return add_btn + + +def create_confirm_btn(parent): + remove_btn = SettingsToolBtn("confirm", parent) + remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + return remove_btn From ca3a29b28bcc7388dc67309d0837ca6508de8925 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:40:44 +0100 Subject: [PATCH 053/100] use create functions to create buttons --- .../settings/settings/dict_mutable_widget.py | 93 ++----------------- .../settings/settings/list_item_widget.py | 52 +++-------- 2 files changed, 20 insertions(+), 125 deletions(-) diff --git a/openpype/tools/settings/settings/dict_mutable_widget.py b/openpype/tools/settings/settings/dict_mutable_widget.py index 07d64263ce..294711b38a 100644 --- a/openpype/tools/settings/settings/dict_mutable_widget.py +++ b/openpype/tools/settings/settings/dict_mutable_widget.py @@ -3,7 +3,12 @@ from uuid import uuid4 from Qt import QtWidgets, QtCore, QtGui from .base import BaseWidget -from .lib import create_deffered_value_change_timer +from .lib import ( + create_deffered_value_change_timer, + create_add_btn, + create_remove_btn, + create_confirm_btn +) from .widgets import ( ExpandingWidget, IconButton @@ -21,92 +26,6 @@ KEY_INPUT_TOOLTIP = ( ) -class PaintHelper: - cached_icons = {} - - @classmethod - def _draw_image(cls, width, height, brush): - image = QtGui.QPixmap(width, height) - image.fill(QtCore.Qt.transparent) - - icon_path_stroker = QtGui.QPainterPathStroker() - icon_path_stroker.setCapStyle(QtCore.Qt.RoundCap) - icon_path_stroker.setJoinStyle(QtCore.Qt.RoundJoin) - icon_path_stroker.setWidth(height / 5) - - painter = QtGui.QPainter(image) - painter.setPen(QtCore.Qt.transparent) - painter.setBrush(brush) - rect = QtCore.QRect(0, 0, image.width(), image.height()) - fifteenth = rect.height() / 15 - # Left point - p1 = QtCore.QPoint( - rect.x() + (5 * fifteenth), - rect.y() + (9 * fifteenth) - ) - # Middle bottom point - p2 = QtCore.QPoint( - rect.center().x(), - rect.y() + (11 * fifteenth) - ) - # Top right point - p3 = QtCore.QPoint( - rect.x() + (10 * fifteenth), - rect.y() + (5 * fifteenth) - ) - - path = QtGui.QPainterPath(p1) - path.lineTo(p2) - path.lineTo(p3) - - stroked_path = icon_path_stroker.createStroke(path) - painter.drawPath(stroked_path) - - painter.end() - - return image - - @classmethod - def get_confirm_icon(cls, width, height): - key = "{}x{}-confirm_image".format(width, height) - icon = cls.cached_icons.get(key) - - if icon is None: - image = cls._draw_image(width, height, QtCore.Qt.white) - icon = QtGui.QIcon(image) - cls.cached_icons[key] = icon - return icon - - -def create_add_btn(parent): - add_btn = QtWidgets.QPushButton("+", parent) - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - add_btn.setObjectName("SettingsToolBtn") - add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - return add_btn - - -def create_remove_btn(parent): - remove_btn = QtWidgets.QPushButton("-", parent) - remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - remove_btn.setObjectName("SettingsToolBtn") - remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - return remove_btn - - -def create_confirm_btn(parent): - confirm_btn = QtWidgets.QPushButton(parent) - - icon = PaintHelper.get_confirm_icon( - BTN_FIXED_SIZE, BTN_FIXED_SIZE - ) - confirm_btn.setIcon(icon) - confirm_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - confirm_btn.setObjectName("SettingsToolBtn") - confirm_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - return confirm_btn - - class ModifiableDictEmptyItem(QtWidgets.QWidget): def __init__(self, entity_widget, store_as_list, parent): super(ModifiableDictEmptyItem, self).__init__(parent) diff --git a/openpype/tools/settings/settings/list_item_widget.py b/openpype/tools/settings/settings/list_item_widget.py index cc539933ff..251c2fe239 100644 --- a/openpype/tools/settings/settings/list_item_widget.py +++ b/openpype/tools/settings/settings/list_item_widget.py @@ -1,13 +1,18 @@ from Qt import QtWidgets, QtCore -from .base import InputWidget -from .widgets import ExpandingWidget from openpype.tools.settings import ( BTN_FIXED_SIZE, CHILD_OFFSET ) -from avalon.vendor import qtawesome +from .base import InputWidget +from .widgets import ExpandingWidget +from .lib import ( + create_add_btn, + create_remove_btn, + create_up_btn, + create_down_btn +) class EmptyListItem(QtWidgets.QWidget): @@ -16,18 +21,11 @@ class EmptyListItem(QtWidgets.QWidget): self.entity_widget = entity_widget - add_btn = QtWidgets.QPushButton("+", self) - remove_btn = QtWidgets.QPushButton("-", self) + add_btn = create_add_btn(self) + remove_btn = create_remove_btn(self) - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) remove_btn.setEnabled(False) - add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - - add_btn.setObjectName("SettingsToolBtn") - remove_btn.setObjectName("SettingsToolBtn") - layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) @@ -52,32 +50,10 @@ class ListItem(QtWidgets.QWidget): self.ignore_input_changes = entity_widget.ignore_input_changes - char_up = qtawesome.charmap("fa.angle-up") - char_down = qtawesome.charmap("fa.angle-down") - - add_btn = QtWidgets.QPushButton("+") - remove_btn = QtWidgets.QPushButton("-") - up_btn = QtWidgets.QPushButton(char_up) - down_btn = QtWidgets.QPushButton(char_down) - - font_up_down = qtawesome.font("fa", 13) - up_btn.setFont(font_up_down) - down_btn.setFont(font_up_down) - - add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - up_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - down_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - - add_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - remove_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - up_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - down_btn.setFixedSize(BTN_FIXED_SIZE, BTN_FIXED_SIZE) - - add_btn.setObjectName("SettingsToolBtn") - remove_btn.setObjectName("SettingsToolBtn") - up_btn.setObjectName("SettingsToolBtn") - down_btn.setObjectName("SettingsToolBtn") + add_btn = create_add_btn(self) + remove_btn = create_remove_btn(self) + up_btn = create_up_btn(self) + down_btn = create_down_btn(self) add_btn.clicked.connect(self._on_add_clicked) remove_btn.clicked.connect(self._on_remove_clicked) From c6450e25e0518a3ce4d3d4287ffe1106bc028a73 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 12:47:27 +0100 Subject: [PATCH 054/100] buttons are smaller --- openpype/style/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/style/style.css b/openpype/style/style.css index b1ec152f0e..5e2d200d17 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -1144,7 +1144,7 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #ImageButton { padding: 0; background: transparent; - font-size: 12pt; + font-size: 11pt; } #ImageButton:disabled { From 26a12167da149ed5b50de9103e48ab000ab08fa7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 17:07:30 +0100 Subject: [PATCH 055/100] removed unused import --- openpype/tools/settings/settings/list_item_widget.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/tools/settings/settings/list_item_widget.py b/openpype/tools/settings/settings/list_item_widget.py index 251c2fe239..cd1fd912ae 100644 --- a/openpype/tools/settings/settings/list_item_widget.py +++ b/openpype/tools/settings/settings/list_item_widget.py @@ -1,7 +1,6 @@ from Qt import QtWidgets, QtCore from openpype.tools.settings import ( - BTN_FIXED_SIZE, CHILD_OFFSET ) From 4a137b4b61f010274743486b17c29cabb167c0ed Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 17:13:18 +0100 Subject: [PATCH 056/100] removed settings style imports --- openpype/tools/settings/__init__.py | 5 ++--- openpype/tools/settings/settings/__init__.py | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/openpype/tools/settings/__init__.py b/openpype/tools/settings/__init__.py index a156228dc1..3e77a8348a 100644 --- a/openpype/tools/settings/__init__.py +++ b/openpype/tools/settings/__init__.py @@ -1,12 +1,13 @@ import sys from Qt import QtWidgets, QtGui + +from openpype import style from .lib import ( BTN_FIXED_SIZE, CHILD_OFFSET ) from .local_settings import LocalSettingsWindow from .settings import ( - style, MainWidget, ProjectListWidget ) @@ -36,8 +37,6 @@ __all__ = ( "BTN_FIXED_SIZE", "CHILD_OFFSET", - "style", - "MainWidget", "ProjectListWidget", "LocalSettingsWindow", diff --git a/openpype/tools/settings/settings/__init__.py b/openpype/tools/settings/settings/__init__.py index 6b4cf94357..9eadd456b7 100644 --- a/openpype/tools/settings/settings/__init__.py +++ b/openpype/tools/settings/settings/__init__.py @@ -1,10 +1,8 @@ -from . import style from .window import MainWidget from .widgets import ProjectListWidget __all__ = ( - "style", "MainWidget", "ProjectListWidget" ) From 48f8959e1d43ff10c54721fd9ab772e1d4534116 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 23 Nov 2021 17:13:26 +0100 Subject: [PATCH 057/100] removed settings style --- .../tools/settings/settings/style/__init__.py | 13 - .../tools/settings/settings/style/style.css | 468 ------------------ 2 files changed, 481 deletions(-) delete mode 100644 openpype/tools/settings/settings/style/__init__.py delete mode 100644 openpype/tools/settings/settings/style/style.css diff --git a/openpype/tools/settings/settings/style/__init__.py b/openpype/tools/settings/settings/style/__init__.py deleted file mode 100644 index f1d9829a04..0000000000 --- a/openpype/tools/settings/settings/style/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import os -from openpype import resources - - -def load_stylesheet(): - style_path = os.path.join(os.path.dirname(__file__), "style.css") - with open(style_path, "r") as style_file: - stylesheet = style_file.read() - return stylesheet - - -def app_icon_path(): - return resources.get_openpype_icon_filepath() diff --git a/openpype/tools/settings/settings/style/style.css b/openpype/tools/settings/settings/style/style.css deleted file mode 100644 index 88ef74101a..0000000000 --- a/openpype/tools/settings/settings/style/style.css +++ /dev/null @@ -1,468 +0,0 @@ -/* :root { - --border-color-: #464b54; -} - */ - - -QWidget { - color: #bfccd6; - background-color: #282C34; - font-size: 12px; - border-radius: 0px; -} - -QMenu { - border: 1px solid #555555; - background-color: #21252B; -} - -QMenu::item { - padding: 5px 10px 5px 10px; - border-left: 5px solid #313131; -} - -QMenu::item:selected { - border-left-color: #61839e; - background-color: #222d37; -} -QCheckBox { - spacing: 0px; -} -QCheckBox::indicator {} -QCheckBox::indicator:focus {} - -QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit, QTextEdit { - border: 1px solid #464b54; - border-radius: 3px; - background-color: #21252B; -} - -QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:disabled, QTextEdit:disabled, QPushButton:disabled { - background-color: #464b54; -} - -QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { - border: 1px solid #839caf; -} - -QComboBox { - border: 1px solid #464b54; - border-radius: 3px; - padding: 2px 2px 4px 4px; - background: #21252B; -} - -QComboBox QAbstractItemView::item { - padding: 3px; -} - -QToolButton { - background: transparent; -} -QLabel { - background: transparent; - color: #969b9e; -} - -#SettingsLabel { - background: transparent; - color: #969b9e; -} -#SettingsLabel:hover {color: #b8c1c5;} - -#SettingsLabel[state="studio"] {color: #73C990;} -#SettingsLabel[state="studio"]:hover {color: #ffffff;} -#SettingsLabel[state="modified"] {color: #189aea;} -#SettingsLabel[state="modified"]:hover {color: #46b1f3;} -#SettingsLabel[state="overriden-modified"] {color: #189aea;} -#SettingsLabel[state="overriden-modified"]:hover {color: #46b1f3;} -#SettingsLabel[state="overriden"] {color: #ff8c1a;} -#SettingsLabel[state="overriden"]:hover {color: #ffa64d;} -#SettingsLabel[state="invalid"] {color: #ad2e2e;} -#SettingsLabel[state="invalid"]:hover {color: #ad2e2e;} - - -QWidget[input-state="studio"] {border-color: #858a94;} -QWidget[input-state="modified"] {border-color: #189aea;} -QWidget[input-state="overriden-modified"] {border-color: #189aea;} -QWidget[input-state="overriden"] {border-color: #ff8c1a;} -QWidget[input-state="invalid"] {border-color: #ad2e2e;} - -QPushButton { - border: 1px solid #aaaaaa; - border-radius: 3px; - padding: 5px; -} -QPushButton:hover { - background-color: #333840; - border: 1px solid #fff; - color: #fff; -} -#SettingsToolBtn { - background: transparent; - border: 1px solid #bfccd6; - border-radius: 10px; -} -#SettingsToolBtn:hover { - border-color: #189aea; - color: #46b1f3; - background-color: transparent; -} -#SettingsToolBtn:disabled { - background-color: #464b54; -} - -#SettingsToolIconBtn { - border: 0px solid #bfccd6; - background-color: transparent; -} - -#ExpandToggleBtn { - background: transparent; -} - -/* SLider */ -QSlider::groove { - border: 1px solid #464b54; - border-radius: 0.3em; -} -QSlider::groove:horizontal { - height: 8px; -} -QSlider::groove:vertical { - width: 8px; -} -QSlider::handle { - width: 10px; - height: 10px; - - border-radius: 5px; -} -QSlider::handle:horizontal { - margin: -2px 0; -} -QSlider::handle:vertical { - margin: 0 -2px; -} - -#GroupWidget { - border-bottom: 1px solid #21252B; -} - -#ProjectListWidget QListView { - border: 1px solid #464b54; - background: #21252B; -} - -#ProjectListWidget QListView:disabled { - background: #282C34; -} - -#ProjectListWidget QListView::item:disabled { - color: #4e5254; -} - -#ProjectListWidget QLabel { - background: transparent; - font-weight: bold; -} - -#MultiSelectionComboBox { - font-size: 12px; -} - -#DictKey[state="studio"] {border-color: #464b54;} -#DictKey[state="modified"] {border-color: #189aea;} -#DictKey[state="overriden"] {border-color: #00f;} -#DictKey[state="overriden-modified"] {border-color: #0f0;} -#DictKey[state="invalid"] {border-color: #ad2e2e;} - -#ExpandLabel { - font-weight: bold; -} -#ExpandLabel:hover { - color: #b8c1c5; -} - -#ContentWidget { - background-color: transparent; -} -#ContentWidget[content_state="hightlighted"] { - background-color: rgba(19, 26, 32, 15%); -} - -#SideLineWidget { - background-color: #333942; - border-style: solid; - border-color: #4e5254; - border-left-width: 3px; - border-bottom-width: 0px; - border-right-width: 0px; - border-top-width: 0px; -} - -#SideLineWidget:hover { - border-color: #7d8386; -} - -#SideLineWidget[state="child-studio"] {border-color: #56a06f;} -#SideLineWidget[state="child-studio"]:hover {border-color: #73C990;} - -#SideLineWidget[state="child-modified"] {border-color: #106aa2;} -#SideLineWidget[state="child-modified"]:hover {border-color: #189aea;} - -#SideLineWidget[state="child-invalid"] {border-color: #ad2e2e;} -#SideLineWidget[state="child-invalid"]:hover {border-color: #c93636;} - -#SideLineWidget[state="child-overriden"] {border-color: #e67300;} -#SideLineWidget[state="child-overriden"]:hover {border-color: #ff8c1a;} - -#SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} -#SideLineWidget[state="child-overriden-modified"]:hover {border-color: #189aea;} - -#SettingsMainWidget { - background: #141a1f; -} - -#DictAsWidgetBody { - background: transparent; -} -#DictAsWidgetBody[show_borders="1"] { - border: 1px solid #4e5254; - border-radius: 5px; -} - -#Separator { - background-color: #21252B; -} - -#ShadowWidget { - font-size: 36pt; -} -QTabWidget::pane { - border-top-style: none; -} - -QTabBar { - background: transparent; -} - -QTabBar::tab { - border-top-left-radius: 4px; - border-top-right-radius: 4px; - padding: 5px; -} - -QTabBar::tab:selected { - background: #282C34; - border-color: #9B9B9B; - border-bottom-color: #C2C7CB; -} - -QTabBar::tab:!selected { - margin-top: 2px; - background: #21252B; -} - -QTabBar::tab:!selected:hover { - background: #333840; -} - -QTabBar::tab:first:selected { - margin-left: 0; -} - -QTabBar::tab:last:selected { - margin-right: 0; -} - -QTabBar::tab:only-one { - margin: 0; -} - -QScrollBar:horizontal { - height: 15px; - margin: 3px 15px 3px 15px; - border: 1px transparent #21252B; - border-radius: 4px; - background-color: #21252B; -} - -QScrollBar::handle:horizontal { - background-color: #4B5362; - min-width: 5px; - border-radius: 4px; -} - -QScrollBar::add-line:horizontal { - margin: 0px 3px 0px 3px; - border-image: url(:/qss_icons/rc/right_arrow_disabled.png); - width: 10px; - height: 10px; - subcontrol-position: right; - subcontrol-origin: margin; -} - -QScrollBar::sub-line:horizontal { - margin: 0px 3px 0px 3px; - border-image: url(:/qss_icons/rc/left_arrow_disabled.png); - height: 10px; - width: 10px; - subcontrol-position: left; - subcontrol-origin: margin; -} - -QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on { - border-image: url(:/qss_icons/rc/right_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: right; - subcontrol-origin: margin; -} - -QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { - border-image: url(:/qss_icons/rc/left_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: left; - subcontrol-origin: margin; -} - -QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { - background: none; -} - -QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { - background: none; -} - -QScrollBar:vertical { - background-color: #21252B; - width: 15px; - margin: 15px 3px 15px 3px; - border: 1px transparent #21252B; - border-radius: 4px; -} - -QScrollBar::handle:vertical { - background-color: #4B5362; - min-height: 5px; - border-radius: 4px; -} - -QScrollBar::sub-line:vertical { - margin: 3px 0px 3px 0px; - border-image: url(:/qss_icons/rc/up_arrow_disabled.png); - height: 10px; - width: 10px; - subcontrol-position: top; - subcontrol-origin: margin; -} - -QScrollBar::add-line:vertical { - margin: 3px 0px 3px 0px; - border-image: url(:/qss_icons/rc/down_arrow_disabled.png); - height: 10px; - width: 10px; - subcontrol-position: bottom; - subcontrol-origin: margin; -} - -QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on { - - border-image: url(:/qss_icons/rc/up_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: top; - subcontrol-origin: margin; -} - - -QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { - border-image: url(:/qss_icons/rc/down_arrow.png); - height: 10px; - width: 10px; - subcontrol-position: bottom; - subcontrol-origin: margin; -} - -QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { - background: none; -} - - -QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background: none; -} - -QTableView -{ - border: 1px solid #444; - gridline-color: #6c6c6c; - background-color: #201F1F; - alternate-background-color:#21252B; -} - -QHeaderView -{ - border: 1px transparent; - border-radius: 2px; - margin: 0px; - padding: 0px; -} - -QHeaderView::section { - background-color: #21252B; - /*color: silver;*/ - padding: 4px; - border: 1px solid #6c6c6c; - border-radius: 0px; - text-align: center; - color: #969b9e; - font-weight: bold; -} - -QAbstractItemView::item:pressed { - background: #78879b; - color: #FFFFFF; -} - -QAbstractItemView::item:selected:active { - background: #3d8ec9; -} -QAbstractItemView::item:selected:!active { - background: #3d8ec9; -} - -#BreadcrumbsPathInput { - padding: 2px; - font-size: 9pt; -} - -#BreadcrumbsButton { - padding-right: 12px; - font-size: 9pt; -} - -#BreadcrumbsButton[empty="1"] { - padding-right: 0px; -} - -#BreadcrumbsButton::menu-button { - width: 12px; - background: rgba(127, 127, 127, 60); -} -#BreadcrumbsButton::menu-button:hover { - background: rgba(127, 127, 127, 90); -} - -#BreadcrumbsPanel { - border: 1px solid #4e5254; - border-radius: 5px; - background: #21252B;; -} - -#NiceCheckbox { - /* Default size hint of NiceCheckbox is defined by font size. */ - font-size: 7pt; -} From b3d581dc474ce1a3e3eb217660eb5acea35ea7cb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Nov 2021 13:43:42 +0100 Subject: [PATCH 058/100] make sure paths are available at any platform --- openpype/lib/delivery.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/openpype/lib/delivery.py b/openpype/lib/delivery.py index c89e2e7ae0..01fcc907ed 100644 --- a/openpype/lib/delivery.py +++ b/openpype/lib/delivery.py @@ -60,12 +60,13 @@ def path_from_representation(representation, anatomy): path = pipeline.format_template_with_optional_keys( context, template ) + path = os.path.normpath(path.replace("/", "\\")) except KeyError: # Template references unavailable data return None - return os.path.normpath(path) + return path def copy_file(src_path, dst_path): @@ -179,9 +180,11 @@ def process_single_file( Returns: (collections.defaultdict , int) """ + # Make sure path is valid for all platforms + src_path = os.path.normpath(src_path.replace("\\", "/")) + if not os.path.exists(src_path): - msg = "{} doesn't exist for {}".format(src_path, - repre["_id"]) + msg = "{} doesn't exist for {}".format(src_path, repre["_id"]) report_items["Source file was not found"].append(msg) return report_items, 0 @@ -192,8 +195,10 @@ def process_single_file( else: delivery_path = anatomy_filled["delivery"][template_name] - # context.representation could be .psd + # Backwards compatibility when extension contained `.` delivery_path = delivery_path.replace("..", ".") + # Make sure path is valid for all platforms + delivery_path = os.path.normpath(delivery_path.replace("\\", "/")) delivery_folder = os.path.dirname(delivery_path) if not os.path.exists(delivery_folder): @@ -230,14 +235,14 @@ def process_sequence( Returns: (collections.defaultdict , int) """ + src_path = os.path.normpath(src_path.replace("\\", "/")) def hash_path_exist(myPath): res = myPath.replace('#', '*') glob_search_results = glob.glob(res) if len(glob_search_results) > 0: return True - else: - return False + return False if not hash_path_exist(src_path): msg = "{} doesn't exist for {}".format(src_path, @@ -307,6 +312,7 @@ def process_sequence( else: delivery_path = anatomy_filled["delivery"][template_name] + delivery_path = os.path.normpath(delivery_path.replace("\\", "/")) delivery_folder = os.path.dirname(delivery_path) dst_head, dst_tail = delivery_path.split(frame_indicator) dst_padding = src_collection.padding From 42fd92173c2b8c7922b63800b3a247ad7518bc64 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Nov 2021 20:39:24 +0100 Subject: [PATCH 059/100] removed unused svgs --- .../tools/settings/settings/images/add.svg | 17 ----------------- .../settings/settings/images/confirm.svg | 19 ------------------- .../tools/settings/settings/images/down.svg | 19 ------------------- .../tools/settings/settings/images/mask.svg | 11 ----------- .../tools/settings/settings/images/remove.svg | 14 -------------- .../tools/settings/settings/images/up.svg | 19 ------------------- 6 files changed, 99 deletions(-) delete mode 100644 openpype/tools/settings/settings/images/add.svg delete mode 100644 openpype/tools/settings/settings/images/confirm.svg delete mode 100644 openpype/tools/settings/settings/images/down.svg delete mode 100644 openpype/tools/settings/settings/images/mask.svg delete mode 100644 openpype/tools/settings/settings/images/remove.svg delete mode 100644 openpype/tools/settings/settings/images/up.svg diff --git a/openpype/tools/settings/settings/images/add.svg b/openpype/tools/settings/settings/images/add.svg deleted file mode 100644 index 9948084cd5..0000000000 --- a/openpype/tools/settings/settings/images/add.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/openpype/tools/settings/settings/images/confirm.svg b/openpype/tools/settings/settings/images/confirm.svg deleted file mode 100644 index ebc5e024e6..0000000000 --- a/openpype/tools/settings/settings/images/confirm.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/openpype/tools/settings/settings/images/down.svg b/openpype/tools/settings/settings/images/down.svg deleted file mode 100644 index 9f3f955a80..0000000000 --- a/openpype/tools/settings/settings/images/down.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/openpype/tools/settings/settings/images/mask.svg b/openpype/tools/settings/settings/images/mask.svg deleted file mode 100644 index 260b2c6fad..0000000000 --- a/openpype/tools/settings/settings/images/mask.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/openpype/tools/settings/settings/images/remove.svg b/openpype/tools/settings/settings/images/remove.svg deleted file mode 100644 index 4a1b075db1..0000000000 --- a/openpype/tools/settings/settings/images/remove.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/openpype/tools/settings/settings/images/up.svg b/openpype/tools/settings/settings/images/up.svg deleted file mode 100644 index 5b813f44f8..0000000000 --- a/openpype/tools/settings/settings/images/up.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - From 2fc409fed3a8d677a6c02b9295e0e995e1b1b5f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Nov 2021 20:39:45 +0100 Subject: [PATCH 060/100] modified icon images --- openpype/tools/settings/settings/images/add.png | Bin 822 -> 778 bytes .../tools/settings/settings/images/confirm.png | Bin 931 -> 853 bytes .../tools/settings/settings/images/down.png | Bin 924 -> 820 bytes .../tools/settings/settings/images/mask.png | Bin 744 -> 720 bytes .../tools/settings/settings/images/remove.png | Bin 819 -> 767 bytes openpype/tools/settings/settings/images/up.png | Bin 930 -> 819 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/openpype/tools/settings/settings/images/add.png b/openpype/tools/settings/settings/images/add.png index 81a68e6d5f6ff7b318bb32aaad01ace2212e4bea..91ef720d32d15cd31f887fe387dcffc5cc9b09cc 100644 GIT binary patch delta 766 zcmVg@CzN3%PZUa5%-uc7e*xMM-E z!@#J&iGRi>Wl{SYQb7I;t%pJBBM{jQBT==1cqsg1U0h$h1~j9@ePNvqe>7=}~Sj7iZldPUC|6f>h!EDWRY zUx-!_8boLm(URX`XxkcZj@*u#7MUS)yNrCMj(28RPgWi-FzlEw&>qq4SpI{O5J606 zegpi$ANK~wzWJ(dzIeDSxJI~OxOxZ$#N|9y=SjrCLX;uo5Pv8PC>bawC^INPEKMj{ wC}${iXaUe1ux&s?fmQ=e2-{PX92MyJ00m0wZbXtbVE_OC07*qoM6N<$g8R8Z1ONa4 delta 791 zcmV+y1L*vU2DS!}7=Ho-0001=_MfW&00Dw&Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&=02!(kl9UmNmc(-h(0u!Pg5nGzR=iBUMrl;N^{_e*W_?fac1SLM2*#Ko@ze*stJ ztQ3)wn{p;Dtgp{^TW!fcPoL-Wdfw0T`Sd)W2du%AlGbZIkbll(wSeE}TnH^X>tC_a zK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{S>Z|H>GiB?@~&{3k_< zTf7UM0DgQpnSWxOF@_jmMCKvfc``9q@Cs6YYSDAAD>Jbcoik>TLJ%`}f zf{W|27TJT#ZRmVb!&O=( zK~zYIwU$d3!ypJn*`yg{3GBxuIKWjlQA9L(IZc`}=%HQ(jq;%kgiMpL2_Hcjcf>$Y znL%t|8G!^79zg0~9YAp6LGoaAAhwy^J(=rnlMST48ELjiEw$~NPP*Pcg{W1kx-BS6 zSV6K=<^GTAob05oC)2#G3S_WUe{699$zNP<6D!DrG!RD@IzT$13@qkE0XGxoWCvm{ zoWfTinQsGe^GfA+0{h$x(9dmPcY6u)40es=9PkE~BZyZZor84)>k*_!AodIQU^xf! zBaq-!1>$3nzX5a9{sY|K6+GbEA91><7as$BaQELX3$0!nkb1LXTSm*i69o12-(V#eq%HEFUks V2!e~iK)V0{002ovPDHLkV1i27Y7qbc diff --git a/openpype/tools/settings/settings/images/confirm.png b/openpype/tools/settings/settings/images/confirm.png index d40e40f2e90e03d71be7ece9f47a80c027bac276..a0fdc66d3e01698711a669366568797f2a6aabe7 100644 GIT binary patch delta 842 zcmV-Q1GW642h|3U7=Hl+0002kR^@vD00Dz(Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&g@CFutXz7ev5E!P!14gX zE{hbIet)E6eoI*hpMrGy5z5U$@{x$fij}CZAU+(i%lRA%R=$XR!A)*C706k?VWdH@ zjf$x6NI|jM>wCp)m=zbpT`?Fo!4V8`Vx-Z)XUfr66BwIgVB8%S#_X6Gi{rt#I(9~I z#5WwHBTa}jIgXLy3xR5A92{*g478W4znrfXgMZ*rp628%A0cU7sH`Azh!2OP`VA$Y z>m(=(mGbP4->*0|kN_&Qt_}&{GbDft37|qdMiEDmg}R1MZ?fySz1fwo&``~C_OXg0FibFJFn~CkFtjkvFzB!az~+G425cy>)xai%+tWc-N6O9d4@Uj_ USpNg^4gdfE07*qoM6N<$f^*Sre*gdg delta 901 zcmV;01A6?`2BQa%7=Ho-0001=_MfW&00Dw&Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&=02!(kl9UmNmc(-h(0u!Pg5nGzR=iBUMrl;N^{_e*W_?fac1SLM2*#Ko@ze*stJ ztQ3)wn{p;Dtgp{^TW!fcPoL-Wdfw0T`Sd)W2du%AlGbZIkbll(wSeE}TnH^X>tC_a zK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{S>Z|H>GiB?@~&{3k_< zTf7UM0DgQpnSWxOF@_jmMCKvfc``9q@Cs6YYSDAAD>Jbcoik>TLJ%`}f zf{W|27TJT#ZRmVb!&hYJbrHazY3phme}H$~kck9F5CJ`!;6DmaIE*l85g-9PP0-XY08ZP> z`a407w(%Kz?ggLSy~&|x-6}iqu8|*d@Sdj&%xJ24=|Kt0uNuTtHvwf zBt&}+)y!fSoe2h3CKaqS(8TF3wL+@7S`%~7B?b1JI0c>qO^JC?JjMQX-iF;aNf4lMxQ?o(#J&l{Ky|H`4cC7 b6rJ(|RJ;`zlNuKY00000NkvXXu0mjf(YT~} diff --git a/openpype/tools/settings/settings/images/down.png b/openpype/tools/settings/settings/images/down.png index 4c6b7f74714704f79867c0c62d84824570c6d157..f78622922f9e42d20e2b794375b248ca82e76cd8 100644 GIT binary patch delta 809 zcmV+^1J?YU2ebx|7=Hl+0002kR^@vD00Dz(Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&g@C?@hL=;d6&ju*hp zh6RBss(%3eC$ZDSh@UY*s0XFXpnMBNW5Y(&HxQ2s|CQ3WDcJbI_XSJ-q$|j?ykUeP z!;JzjYXl?MbopMeDptX)cnJoD%ZNtdEhCHyo+ta^MSMzuAV=NyZdR(*;X+!PZ~kh6`kw3eAOrXce&S z50C1@gTId)1Q1wxNzccF_s$Lr64=00000NkvXXu0mjf(cV_+ delta 894 zcmV-^1A+Xs2Al_w7=Ho-0001=_MfW&00Dw&Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&=02!(kl9UmNmc(-h(0u!Pg5nGzR=iBUMrl;N^{_e*W_?fac1SLM2*#Ko@ze*stJ ztQ3)wn{p;Dtgp{^TW!fcPoL-Wdfw0T`Sd)W2du%AlGbZIkbll(wSeE}TnH^X>tC_a zK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{S>Z|H>GiB?@~&{3k_< zTf7UM0DgQpnSWxOF@_jmMCKvfc``9q@Cs6YYSDAAD>Jbcoik>TLJ%`}f zf{W|27TJT#ZRmVb!&L=LqKpb4! zPS6b88H~$YO`r#O61bot=m;JF%`8K{xODie4ti{6n6ILqZ2R6Xy54`qP_IS$zF;q@ z3c7#Q8>1pNFEm+SyobI7jO1zif2tdFJh;~k1-z*lXjwuhiW(du3Tg&Jz&Itu^b6>x z_ELW)Xs7nOZNGqzP06;t0w2521z@-R4p1k6dl0<@LT!QgJ~*)X2@}|;#}W4gTEtTZ z5H$-lytQUDg#&bmz=5DaI3+M=n~5M;H`^~Uf;H*a9>I2FA_(@Ji2x8UelA5E4t zz0!nCQ#eifyiCx-LQ4@XG+w;i(E>?JDlNjiY|}!|p9b_XL7yM|!NQ+7^ig!SKT&EE Udmy2T=l}o!07*qoM6N<$f{HkwHvj+t diff --git a/openpype/tools/settings/settings/images/mask.png b/openpype/tools/settings/settings/images/mask.png index 601a67733e0c0fcd6d6ad9e1c9929b7cd55497c2..f10f00be2c7849aed4714b920c75028fe933a4df 100644 GIT binary patch delta 708 zcmV;#0z3Wa1<(bM7=Hl+0002kR^@vD00Dz(Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&g@Cw z0J0tKORztC_a zK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{S>Z|H>GiB?@~&{3k_< zTf7UM0DgQpnSWxOF@_jmMCKvfc``9q@Cs6YYSDAAD>Jbcoik>TLJ%`}f zf{W|27TJT#ZRmVb!& zK~zYI?Uq3b#UKnsy`(NYg7@(VF6=44inU3a5fu6G;m@l07BdCS#9TmTd}Uh{-k_Zm zGJx%pAl|@nknK=lAU(h{V2LP56nFw61?~aaGKB#W2Y!Iafg8XI-5^U4I!F@u4x$9E z19{#|jAGGDjAGGDX5i)B+>Pd4e%&WP2~}fFfD)?4GFqq_YXY?M5^DpfX-nP>p#ER^ z!;>KD!2Q9mfN$KAgO~c?Q`>mwaAd4cpY;ichvoX*g(DmeeOwc;SYQ>w^1^io3ldf; uEMZ*Ru;}q>0GA24e&B@#uQ+filKKE?Ikf`1;C}4@0000g@CU6Fdzp-pFI<)Jj*mPu;#ux6d>ye^ zfs;AB5sYd2O3)|tf;M3i)Co&OFbS?gy+MIrkVJwQ8F)3O`ujm^E$9$)!Ek}0U~IlXdqh{T{s%cBf)LUC26(|A*9M<` z^H<&c@#i}S8w^_yp@6uYr|LY37+8ohgdE}zg#jf4#RO#r1&E~yMGNH&g$^wMngg~C lXeiKXpb24n3X-D?9UoWP1bfEv-{k-R002ovPDHLkV1k{PI-dXl delta 788 zcmV+v1MB?%1+xZ_7=Ho-0001=_MfW&00Dw&Lqkw=Qb$4{Nkv08F*!CiEix`K001bF zb&=02!(kl9UmNmc(-h(0u!Pg5nGzR=iBUMrl;N^{_e*W_?fac1SLM2*#Ko@ze*stJ ztQ3)wn{p;Dtgp{^TW!fcPoL-Wdfw0T`Sd)W2du%AlGbZIkbll(wSeE}TnH^X>tC_a zK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{S>Z|H>GiB?@~&{3k_< zTf7UM0DgQpnSWxOF@_jmMCKvfc``9q@Cs6YYSDAAD>Jbcoik>TLJ%`}f zf{W|27TJT#ZRmVb!&)*oc$wH@=?1(=*FZY_bGPi{rJ@izN=fyvwC?*iP!mm|Eu6h;c<3Gj1#`AqHs z{{XOlgYFYxU+pizzE}S^D=X}MaCO2}~PgUJ%6 zSD27t3WrG_mkC%{U@3yd3zs`sAYn;`MHrWDSm<$U0GkQee&B`$w>YpVvhoHkMkTt} S5K0sP0000g@CJpuadcczbY6HM_J0e{H+Wvy-(cy%8x6d`Qy>Rf;B<#W zb+BWHb?7k99ftKn7_DjWDyN{pX`V=MOq>#dHDPR6B}{^uKLvv%Ot5fR3VvezWx%#S zJgN^5{{H6Rg5l~R6cCsDRNW^L0}D}xkVE{TFrZ|hn4rv{0I@WoXrY{;(4hrDbHKI% m4Iu?u4KyKaPl3oZ)bR()5DD(#*KKtC_a zK_l%r!iuiW%uNKTYF`gn%y{QEYgIq@ui2t8T>(pj@Tj6{S>Z|H>GiB?@~&{3k_< zTf7UM0DgQpnSWxOF@_jmMCKvfc``9q@Cs6YYSDAAD>Jbcoik>TLJ%`}f zf{W|27TJT#ZRmVb!&el@N&>Nnu$i8#1) zoS+%FcQ7s=bpt)XvwnV+8{IeJKH+o%IO| zJlh=dBIyC#gqM|p8Cy(Z2sDy!ZX&B{84HLdCn3W?n24wYH_?ayW}=z_f6PP!0+@+P z25?j135bR%CLoV2hXh0u;}A9IsqFCY(=nn;dTcbBy6d$3FEd68$CW6z{3PQe&7QOKH|Vb a(K$Z-ToXL+u8OY!0000 Date: Wed, 24 Nov 2021 21:04:38 +0100 Subject: [PATCH 061/100] added colors for nice checkbox into style --- openpype/style/data.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index 5e590bce79..c17e31afcc 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -59,7 +59,12 @@ "color-selected": "#F0F2F5", "color-hover": "#F0F2F5" }, - + "nice-checkbox": { + "bg-checked": "#56a06f", + "bg-unchecked": "#434b56", + "bg-checker": "#D3D8DE", + "bg-checker-hover": "#F0F2F5" + }, "loader": { "asset-view": { "selected": "rgba(168, 175, 189, 0.6)", From 52cf1a4e2a25569fb6532b68c5c9db56860e1ebe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Nov 2021 21:04:58 +0100 Subject: [PATCH 062/100] skip drawing of shadow under checker --- openpype/widgets/nice_checkbox.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/openpype/widgets/nice_checkbox.py b/openpype/widgets/nice_checkbox.py index b032453a7f..b517e90901 100644 --- a/openpype/widgets/nice_checkbox.py +++ b/openpype/widgets/nice_checkbox.py @@ -353,31 +353,6 @@ class NiceCheckbox(QtWidgets.QFrame): under_mouse = self.isEnabled() and self._under_mouse - shadow_x = checker_rect.x() - shadow_y = checker_rect.y() + margin_size_c - shadow_size = min( - frame_rect.right() - shadow_x, - frame_rect.bottom() - shadow_y, - checker_size + (2 * margin_size_c) - ) - shadow_rect = QtCore.QRect( - checker_rect.x(), - shadow_y, - shadow_size, - shadow_size - ) - - shadow_brush = QtGui.QRadialGradient( - shadow_rect.center(), - shadow_rect.height() / 2 - ) - shadow_brush.setColorAt(0.6, QtCore.Qt.black) - shadow_brush.setColorAt(1, QtCore.Qt.transparent) - - painter.setPen(QtCore.Qt.transparent) - painter.setBrush(shadow_brush) - painter.drawEllipse(shadow_rect) - painter.setBrush(checker_color) painter.drawEllipse(checker_rect) From 0d3f4ba7abbfcc65701aafea0ab38daf0ad8edbc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 24 Nov 2021 21:05:17 +0100 Subject: [PATCH 063/100] use colors from openpype styles to draw nice checkbox --- openpype/widgets/nice_checkbox.py | 72 ++++++++++++++++++------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/openpype/widgets/nice_checkbox.py b/openpype/widgets/nice_checkbox.py index b517e90901..ccd079c0fb 100644 --- a/openpype/widgets/nice_checkbox.py +++ b/openpype/widgets/nice_checkbox.py @@ -1,11 +1,18 @@ from math import floor, sqrt, ceil from Qt import QtWidgets, QtCore, QtGui +from openpype.style import get_objected_colors + class NiceCheckbox(QtWidgets.QFrame): stateChanged = QtCore.Signal(int) clicked = QtCore.Signal() + _checked_bg_color = None + _unchecked_bg_color = None + _checker_color = None + _checker_hover_color = None + def __init__(self, checked=False, draw_icons=False, parent=None): super(NiceCheckbox, self).__init__(parent) @@ -41,12 +48,6 @@ class NiceCheckbox(QtWidgets.QFrame): self._pressed = False self._under_mouse = False - self.checked_bg_color = QtGui.QColor(67, 181, 129) - self.unchecked_bg_color = QtGui.QColor(79, 79, 79) - - self.checker_checked_color = QtGui.QColor(255, 255, 255) - self.checker_unchecked_color = self.checker_checked_color - self.icon_scale_factor = sqrt(2) / 2 icon_path_stroker = QtGui.QPainterPathStroker() @@ -58,6 +59,37 @@ class NiceCheckbox(QtWidgets.QFrame): self._animation_timer.timeout.connect(self._on_animation_timeout) self._base_size = QtCore.QSize(90, 50) + self._load_colors() + + @classmethod + def _load_colors(cls): + if cls._checked_bg_color is not None: + return + + colors_data = get_objected_colors() + colors_info = colors_data["nice-checkbox"] + + cls._checked_bg_color = colors_info["bg-checked"].get_qcolor() + cls._unchecked_bg_color = colors_info["bg-unchecked"].get_qcolor() + + cls._checker_color = colors_info["bg-checker"].get_qcolor() + cls._checker_hover_color = colors_info["bg-checker-hover"].get_qcolor() + + @property + def checked_bg_color(self): + return self._checked_bg_color + + @property + def unchecked_bg_color(self): + return self._unchecked_bg_color + + @property + def checker_color(self): + return self._checker_color + + @property + def checker_hover_color(self): + return self._checker_hover_color def setTristate(self, tristate=True): if self._is_tristate != tristate: @@ -284,11 +316,9 @@ class NiceCheckbox(QtWidgets.QFrame): # Draw inner background if self._current_step == self._steps: bg_color = self.checked_bg_color - checker_color = self.checker_checked_color elif self._current_step == 0: bg_color = self.unchecked_bg_color - checker_color = self.checker_unchecked_color else: offset_ratio = self._current_step / self._steps @@ -298,11 +328,6 @@ class NiceCheckbox(QtWidgets.QFrame): self.unchecked_bg_color, offset_ratio ) - checker_color = self.steped_color( - self.checker_checked_color, - self.checker_unchecked_color, - offset_ratio - ) margins_ratio = self._checker_margins_divider if margins_ratio > 0: @@ -352,27 +377,14 @@ class NiceCheckbox(QtWidgets.QFrame): checker_rect = QtCore.QRect(pos_x, pos_y, checker_size, checker_size) under_mouse = self.isEnabled() and self._under_mouse + if under_mouse: + checker_color = self.checker_hover_color + else: + checker_color = self.checker_color painter.setBrush(checker_color) painter.drawEllipse(checker_rect) - if under_mouse: - adjust = margin_size_c - if adjust < 1 and checker_rect.height() > 4: - adjust = 1 - - smaller_checker_rect = checker_rect.adjusted( - adjust, adjust, -adjust, -adjust - ) - gradient = QtGui.QLinearGradient( - smaller_checker_rect.bottomRight(), - smaller_checker_rect.topLeft() - ) - gradient.setColorAt(0, checker_color) - gradient.setColorAt(1, checker_color.darker(155)) - painter.setBrush(gradient) - painter.drawEllipse(smaller_checker_rect) - if self._draw_icons: painter.setBrush(bg_color) icon_path = self._get_icon_path(painter, checker_rect) From e5efaf842b08a3793a660987a7a744d3888b0020 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 00:39:22 +0100 Subject: [PATCH 064/100] removed imports from avalon vendor and use sys modules --- openpype/hosts/aftereffects/api/__init__.py | 8 ++++---- .../aftereffects/plugins/create/create_render.py | 6 +++--- openpype/hosts/fusion/api/lib.py | 2 +- .../fusion/plugins/inventory/set_tool_color.py | 2 +- openpype/hosts/fusion/scripts/set_rendermode.py | 2 +- .../hosts/fusion/utility_scripts/switch_ui.py | 3 ++- openpype/hosts/hiero/api/lib.py | 4 ++-- openpype/hosts/maya/api/__init__.py | 2 +- openpype/hosts/maya/api/lib.py | 8 ++++---- openpype/hosts/maya/plugins/load/actions.py | 2 +- .../maya/plugins/publish/collect_yeti_rig.py | 2 +- .../maya/plugins/publish/submit_maya_muster.py | 5 +++-- .../publish/validate_assembly_transforms.py | 2 +- .../publish/validate_muster_connection.py | 3 ++- openpype/hosts/photoshop/api/__init__.py | 9 +++++---- .../photoshop/plugins/create/create_image.py | 16 ++++++++-------- .../publish/submit_houdini_remote_publish.py | 2 +- .../publish/submit_houdini_render_deadline.py | 2 +- .../plugins/publish/submit_nuke_deadline.py | 5 +++-- .../plugins/publish/submit_publish_job.py | 3 ++- .../publish/validate_deadline_connection.py | 6 +++--- .../validate_expected_and_rendered_files.py | 4 ++-- .../publish/collect_sequences_from_job.py | 2 +- openpype/plugins/load/copy_file.py | 2 +- openpype/plugins/load/copy_file_path.py | 2 +- openpype/plugins/load/delete_old_versions.py | 2 +- openpype/plugins/load/open_djv.py | 2 +- openpype/plugins/load/open_file.py | 2 +- openpype/tools/assetcreator/model.py | 3 +-- openpype/widgets/message_window.py | 2 +- openpype/widgets/popup.py | 2 +- openpype/widgets/project_settings.py | 5 ++--- 32 files changed, 63 insertions(+), 59 deletions(-) diff --git a/openpype/hosts/aftereffects/api/__init__.py b/openpype/hosts/aftereffects/api/__init__.py index 5f6a64a6d0..b1edb91a5c 100644 --- a/openpype/hosts/aftereffects/api/__init__.py +++ b/openpype/hosts/aftereffects/api/__init__.py @@ -4,7 +4,7 @@ import logging from avalon import io from avalon import api as avalon -from avalon.vendor import Qt +from Qt import QtWidgets from openpype import lib, api import pyblish.api as pyblish import openpype.hosts.aftereffects @@ -41,10 +41,10 @@ def check_inventory(): # Warn about outdated containers. print("Starting new QApplication..") - app = Qt.QtWidgets.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - message_box = Qt.QtWidgets.QMessageBox() - message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning) + message_box = QtWidgets.QMessageBox() + message_box.setIcon(QtWidgets.QMessageBox.Warning) msg = "There are outdated containers in the scene." message_box.setText(msg) message_box.exec_() diff --git a/openpype/hosts/aftereffects/plugins/create/create_render.py b/openpype/hosts/aftereffects/plugins/create/create_render.py index 4234ee0f0c..b796e9eaac 100644 --- a/openpype/hosts/aftereffects/plugins/create/create_render.py +++ b/openpype/hosts/aftereffects/plugins/create/create_render.py @@ -1,5 +1,5 @@ import openpype.api -from avalon.vendor import Qt +from Qt import QtWidgets from avalon import aftereffects import logging @@ -56,7 +56,7 @@ class CreateRender(openpype.api.Creator): stub.rename_item(item.id, stub.PUBLISH_ICON + self.data["subset"]) def _show_msg(self, txt): - msg = Qt.QtWidgets.QMessageBox() - msg.setIcon(Qt.QtWidgets.QMessageBox.Warning) + msg = QtWidgets.QMessageBox() + msg.setIcon(QtWidgets.QMessageBox.Warning) msg.setText(txt) msg.exec_() diff --git a/openpype/hosts/fusion/api/lib.py b/openpype/hosts/fusion/api/lib.py index 77866fde9d..7afcdd82ea 100644 --- a/openpype/hosts/fusion/api/lib.py +++ b/openpype/hosts/fusion/api/lib.py @@ -1,6 +1,6 @@ import sys -from avalon.vendor.Qt import QtGui +from Qt import QtGui import avalon.fusion from avalon import io diff --git a/openpype/hosts/fusion/plugins/inventory/set_tool_color.py b/openpype/hosts/fusion/plugins/inventory/set_tool_color.py index 940a0e9941..9fc7012db7 100644 --- a/openpype/hosts/fusion/plugins/inventory/set_tool_color.py +++ b/openpype/hosts/fusion/plugins/inventory/set_tool_color.py @@ -1,5 +1,5 @@ from avalon import api, style -from avalon.vendor.Qt import QtGui, QtWidgets +from Qt import QtGui, QtWidgets import avalon.fusion diff --git a/openpype/hosts/fusion/scripts/set_rendermode.py b/openpype/hosts/fusion/scripts/set_rendermode.py index cb104445a8..73eec528a2 100644 --- a/openpype/hosts/fusion/scripts/set_rendermode.py +++ b/openpype/hosts/fusion/scripts/set_rendermode.py @@ -1,4 +1,4 @@ -from avalon.vendor.Qt import QtWidgets +from Qt import QtWidgets from avalon.vendor import qtawesome import avalon.fusion as avalon diff --git a/openpype/hosts/fusion/utility_scripts/switch_ui.py b/openpype/hosts/fusion/utility_scripts/switch_ui.py index e0b6b3f882..2be91af32a 100644 --- a/openpype/hosts/fusion/utility_scripts/switch_ui.py +++ b/openpype/hosts/fusion/utility_scripts/switch_ui.py @@ -2,12 +2,13 @@ import os import glob import logging +from Qt import QtWidgets, QtCore + import avalon.io as io import avalon.api as api import avalon.pipeline as pipeline import avalon.fusion import avalon.style as style -from avalon.vendor.Qt import QtWidgets, QtCore from avalon.vendor import qtawesome as qta diff --git a/openpype/hosts/hiero/api/lib.py b/openpype/hosts/hiero/api/lib.py index af58f5b73e..21b65e5c96 100644 --- a/openpype/hosts/hiero/api/lib.py +++ b/openpype/hosts/hiero/api/lib.py @@ -5,13 +5,13 @@ import os import re import sys import ast +import shutil import hiero +from Qt import QtWidgets import avalon.api as avalon import avalon.io -from avalon.vendor.Qt import QtWidgets from openpype.api import (Logger, Anatomy, get_anatomy_settings) from . import tags -import shutil from compiler.ast import flatten try: diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index e330904abf..b25fd44217 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -138,7 +138,7 @@ def on_save(_): def on_open(_): """On scene open let's assume the containers have changed.""" - from avalon.vendor.Qt import QtWidgets + from Qt import QtWidgets from openpype.widgets import popup cmds.evalDeferred( diff --git a/openpype/hosts/maya/api/lib.py b/openpype/hosts/maya/api/lib.py index 4074aa7fa8..52ebcaff64 100644 --- a/openpype/hosts/maya/api/lib.py +++ b/openpype/hosts/maya/api/lib.py @@ -6,19 +6,19 @@ import platform import uuid import math -import bson import json import logging import itertools import contextlib from collections import OrderedDict, defaultdict from math import ceil +from six import string_types +import bson from maya import cmds, mel import maya.api.OpenMaya as om from avalon import api, maya, io, pipeline -from avalon.vendor.six import string_types import avalon.maya.lib import avalon.maya.interactive @@ -1936,7 +1936,7 @@ def validate_fps(): if current_fps != fps: - from avalon.vendor.Qt import QtWidgets + from Qt import QtWidgets from ...widgets import popup # Find maya main window @@ -2694,7 +2694,7 @@ def update_content_on_context_change(): def show_message(title, msg): - from avalon.vendor.Qt import QtWidgets + from Qt import QtWidgets from openpype.widgets import message_window # Find maya main window diff --git a/openpype/hosts/maya/plugins/load/actions.py b/openpype/hosts/maya/plugins/load/actions.py index d4525511f4..1a9adf6142 100644 --- a/openpype/hosts/maya/plugins/load/actions.py +++ b/openpype/hosts/maya/plugins/load/actions.py @@ -133,7 +133,7 @@ class ImportMayaLoader(api.Loader): """ - from avalon.vendor.Qt import QtWidgets + from Qt import QtWidgets accept = QtWidgets.QMessageBox.Ok buttons = accept | QtWidgets.QMessageBox.Cancel diff --git a/openpype/hosts/maya/plugins/publish/collect_yeti_rig.py b/openpype/hosts/maya/plugins/publish/collect_yeti_rig.py index 0d240b1a32..029432223b 100644 --- a/openpype/hosts/maya/plugins/publish/collect_yeti_rig.py +++ b/openpype/hosts/maya/plugins/publish/collect_yeti_rig.py @@ -275,7 +275,7 @@ class CollectYetiRig(pyblish.api.InstancePlugin): list: file sequence. """ - from avalon.vendor import clique + import clique escaped = re.escape(filepath) re_pattern = escaped.replace(pattern, "-?[0-9]+") diff --git a/openpype/hosts/maya/plugins/publish/submit_maya_muster.py b/openpype/hosts/maya/plugins/publish/submit_maya_muster.py index 207cf56cfe..ac3de4114c 100644 --- a/openpype/hosts/maya/plugins/publish/submit_maya_muster.py +++ b/openpype/hosts/maya/plugins/publish/submit_maya_muster.py @@ -1,13 +1,14 @@ import os import json import getpass -import appdirs import platform +import appdirs +import requests + from maya import cmds from avalon import api -from avalon.vendor import requests import pyblish.api from openpype.hosts.maya.api import lib diff --git a/openpype/hosts/maya/plugins/publish/validate_assembly_transforms.py b/openpype/hosts/maya/plugins/publish/validate_assembly_transforms.py index 00600a6f62..dca59b147b 100644 --- a/openpype/hosts/maya/plugins/publish/validate_assembly_transforms.py +++ b/openpype/hosts/maya/plugins/publish/validate_assembly_transforms.py @@ -89,8 +89,8 @@ class ValidateAssemblyModelTransforms(pyblish.api.InstancePlugin): """ + from Qt import QtWidgets from openpype.hosts.maya.api import lib - from avalon.vendor.Qt import QtWidgets # Store namespace in variable, cosmetics thingy messagebox = QtWidgets.QMessageBox diff --git a/openpype/hosts/maya/plugins/publish/validate_muster_connection.py b/openpype/hosts/maya/plugins/publish/validate_muster_connection.py index 1a7ee11230..af32c82f97 100644 --- a/openpype/hosts/maya/plugins/publish/validate_muster_connection.py +++ b/openpype/hosts/maya/plugins/publish/validate_muster_connection.py @@ -1,9 +1,10 @@ import os import json + import appdirs +import requests import pyblish.api -from avalon.vendor import requests from openpype.plugin import contextplugin_should_run import openpype.hosts.maya.api.action diff --git a/openpype/hosts/photoshop/api/__init__.py b/openpype/hosts/photoshop/api/__init__.py index 81942c3b2a..d978d6ecc1 100644 --- a/openpype/hosts/photoshop/api/__init__.py +++ b/openpype/hosts/photoshop/api/__init__.py @@ -2,9 +2,10 @@ import os import sys import logging +from Qt import QtWidgets + from avalon import io from avalon import api as avalon -from avalon.vendor import Qt from openpype import lib from pyblish import api as pyblish import openpype.hosts.photoshop @@ -38,10 +39,10 @@ def check_inventory(): # Warn about outdated containers. print("Starting new QApplication..") - app = Qt.QtWidgets.QApplication(sys.argv) + app = QtWidgets.QApplication(sys.argv) - message_box = Qt.QtWidgets.QMessageBox() - message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning) + message_box = QtWidgets.QMessageBox() + message_box.setIcon(QtWidgets.QMessageBox.Warning) msg = "There are outdated containers in the scene." message_box.setText(msg) message_box.exec_() diff --git a/openpype/hosts/photoshop/plugins/create/create_image.py b/openpype/hosts/photoshop/plugins/create/create_image.py index 967a704ccf..657d41aa93 100644 --- a/openpype/hosts/photoshop/plugins/create/create_image.py +++ b/openpype/hosts/photoshop/plugins/create/create_image.py @@ -1,5 +1,5 @@ +from Qt import QtWidgets import openpype.api -from avalon.vendor import Qt from avalon import photoshop @@ -26,21 +26,21 @@ class CreateImage(openpype.api.Creator): if len(selection) > 1: # Ask user whether to create one image or image per selected # item. - msg_box = Qt.QtWidgets.QMessageBox() - msg_box.setIcon(Qt.QtWidgets.QMessageBox.Warning) + msg_box = QtWidgets.QMessageBox() + msg_box.setIcon(QtWidgets.QMessageBox.Warning) msg_box.setText( "Multiple layers selected." "\nDo you want to make one image per layer?" ) msg_box.setStandardButtons( - Qt.QtWidgets.QMessageBox.Yes | - Qt.QtWidgets.QMessageBox.No | - Qt.QtWidgets.QMessageBox.Cancel + QtWidgets.QMessageBox.Yes | + QtWidgets.QMessageBox.No | + QtWidgets.QMessageBox.Cancel ) ret = msg_box.exec_() - if ret == Qt.QtWidgets.QMessageBox.Yes: + if ret == QtWidgets.QMessageBox.Yes: multiple_instances = True - elif ret == Qt.QtWidgets.QMessageBox.Cancel: + elif ret == QtWidgets.QMessageBox.Cancel: return if multiple_instances: diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_remote_publish.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_remote_publish.py index 9ada437716..c3228bfe52 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_remote_publish.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_remote_publish.py @@ -1,10 +1,10 @@ import os import json +import requests import hou from avalon import api, io -from avalon.vendor import requests import pyblish.api diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_render_deadline.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_render_deadline.py index f471d788b6..fa146c0d30 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_render_deadline.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_houdini_render_deadline.py @@ -2,8 +2,8 @@ import os import json import getpass +import requests from avalon import api -from avalon.vendor import requests import pyblish.api diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_nuke_deadline.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_nuke_deadline.py index 4cba35963c..8d9b0e1e41 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_nuke_deadline.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_nuke_deadline.py @@ -1,10 +1,11 @@ import os +import re import json import getpass +import requests + from avalon import api -from avalon.vendor import requests -import re import pyblish.api import nuke diff --git a/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py b/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py index adf6d2d758..8125a27d43 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/submit_publish_job.py @@ -5,10 +5,11 @@ import os import json import re from copy import copy, deepcopy +import requests +import clique import openpype.api from avalon import api, io -from avalon.vendor import requests, clique import pyblish.api diff --git a/openpype/modules/default_modules/deadline/plugins/publish/validate_deadline_connection.py b/openpype/modules/default_modules/deadline/plugins/publish/validate_deadline_connection.py index ff664d9f83..d5016a4d82 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/validate_deadline_connection.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/validate_deadline_connection.py @@ -1,7 +1,7 @@ -import pyblish.api - -from avalon.vendor import requests import os +import requests + +import pyblish.api class ValidateDeadlineConnection(pyblish.api.InstancePlugin): diff --git a/openpype/modules/default_modules/deadline/plugins/publish/validate_expected_and_rendered_files.py b/openpype/modules/default_modules/deadline/plugins/publish/validate_expected_and_rendered_files.py index addd4a2e80..719c7dfe3e 100644 --- a/openpype/modules/default_modules/deadline/plugins/publish/validate_expected_and_rendered_files.py +++ b/openpype/modules/default_modules/deadline/plugins/publish/validate_expected_and_rendered_files.py @@ -1,8 +1,8 @@ import os import json -import pyblish.api +import requests -from avalon.vendor import requests +import pyblish.api from openpype.lib.abstract_submit_deadline import requests_get from openpype.lib.delivery import collect_frames diff --git a/openpype/modules/default_modules/royal_render/plugins/publish/collect_sequences_from_job.py b/openpype/modules/default_modules/royal_render/plugins/publish/collect_sequences_from_job.py index d2754d1f92..2505d671af 100644 --- a/openpype/modules/default_modules/royal_render/plugins/publish/collect_sequences_from_job.py +++ b/openpype/modules/default_modules/royal_render/plugins/publish/collect_sequences_from_job.py @@ -17,7 +17,7 @@ def collect(root, frame_end=None): """Collect sequence collections in root""" - from avalon.vendor import clique + import clique files = [] for filename in os.listdir(root): diff --git a/openpype/plugins/load/copy_file.py b/openpype/plugins/load/copy_file.py index 1acacf6b27..eaf5853035 100644 --- a/openpype/plugins/load/copy_file.py +++ b/openpype/plugins/load/copy_file.py @@ -18,7 +18,7 @@ class CopyFile(api.Loader): @staticmethod def copy_file_to_clipboard(path): - from avalon.vendor.Qt import QtCore, QtWidgets + from Qt import QtCore, QtWidgets clipboard = QtWidgets.QApplication.clipboard() assert clipboard, "Must have running QApplication instance" diff --git a/openpype/plugins/load/copy_file_path.py b/openpype/plugins/load/copy_file_path.py index f64f3e76d8..2041c79f6d 100644 --- a/openpype/plugins/load/copy_file_path.py +++ b/openpype/plugins/load/copy_file_path.py @@ -19,7 +19,7 @@ class CopyFilePath(api.Loader): @staticmethod def copy_path_to_clipboard(path): - from avalon.vendor.Qt import QtWidgets + from Qt import QtWidgets clipboard = QtWidgets.QApplication.clipboard() assert clipboard, "Must have running QApplication instance" diff --git a/openpype/plugins/load/delete_old_versions.py b/openpype/plugins/load/delete_old_versions.py index 263c534b64..b2f2c88975 100644 --- a/openpype/plugins/load/delete_old_versions.py +++ b/openpype/plugins/load/delete_old_versions.py @@ -5,9 +5,9 @@ import uuid import clique from pymongo import UpdateOne import ftrack_api +from Qt import QtWidgets, QtCore from avalon import api, style -from avalon.vendor.Qt import QtWidgets, QtCore from avalon.vendor import qargparse from avalon.api import AvalonMongoDB import avalon.pipeline diff --git a/openpype/plugins/load/open_djv.py b/openpype/plugins/load/open_djv.py index 5b49bb58d0..4b0e8411c8 100644 --- a/openpype/plugins/load/open_djv.py +++ b/openpype/plugins/load/open_djv.py @@ -32,7 +32,7 @@ class OpenInDJV(api.Loader): def load(self, context, name, namespace, data): directory = os.path.dirname(self.fname) - from avalon.vendor import clique + import clique pattern = clique.PATTERNS["frames"] files = os.listdir(directory) diff --git a/openpype/plugins/load/open_file.py b/openpype/plugins/load/open_file.py index b496311e0c..4133a64eb3 100644 --- a/openpype/plugins/load/open_file.py +++ b/openpype/plugins/load/open_file.py @@ -27,7 +27,7 @@ class Openfile(api.Loader): color = "orange" def load(self, context, name, namespace, data): - from avalon.vendor import clique + import clique directory = os.path.dirname(self.fname) pattern = clique.PATTERNS["frames"] diff --git a/openpype/tools/assetcreator/model.py b/openpype/tools/assetcreator/model.py index 3af1d77127..f84541ca2a 100644 --- a/openpype/tools/assetcreator/model.py +++ b/openpype/tools/assetcreator/model.py @@ -1,8 +1,7 @@ import re import logging -import collections -from avalon.vendor.Qt import QtCore, QtWidgets +from Qt import QtCore, QtWidgets from avalon.vendor import qtawesome from avalon import io from avalon import style diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 969d6ccdd1..94e51f5d4f 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -1,6 +1,6 @@ -from Qt import QtWidgets, QtCore import sys import logging +from Qt import QtWidgets, QtCore log = logging.getLogger(__name__) diff --git a/openpype/widgets/popup.py b/openpype/widgets/popup.py index 7c0fa0f5c5..4026249516 100644 --- a/openpype/widgets/popup.py +++ b/openpype/widgets/popup.py @@ -3,7 +3,7 @@ import logging import contextlib -from avalon.vendor.Qt import QtCore, QtWidgets, QtGui +from Qt import QtCore, QtWidgets, QtGui log = logging.getLogger(__name__) diff --git a/openpype/widgets/project_settings.py b/openpype/widgets/project_settings.py index c69d55fb39..43ff9f2789 100644 --- a/openpype/widgets/project_settings.py +++ b/openpype/widgets/project_settings.py @@ -1,10 +1,9 @@ - - -from avalon.vendor.Qt import QtCore, QtGui, QtWidgets import os import getpass import platform +from Qt import QtCore, QtGui, QtWidgets + from avalon import style import ftrack_api From 2e77590e608f0880ceaac34a3c3b0263beaa9b42 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 00:47:45 +0100 Subject: [PATCH 065/100] removed unused import --- openpype/widgets/popup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/widgets/popup.py b/openpype/widgets/popup.py index 4026249516..3c3f6283c4 100644 --- a/openpype/widgets/popup.py +++ b/openpype/widgets/popup.py @@ -3,7 +3,7 @@ import logging import contextlib -from Qt import QtCore, QtWidgets, QtGui +from Qt import QtCore, QtWidgets log = logging.getLogger(__name__) From cec39c9a67dbbd1c19e08e7a3cd84f7a83134eac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 11:28:24 +0100 Subject: [PATCH 066/100] validate existence of executable instead of executing them --- start.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/start.py b/start.py index 61d8d6a64a..5799132bfe 100644 --- a/start.py +++ b/start.py @@ -100,6 +100,7 @@ import platform import traceback import subprocess import site +import distutils from pathlib import Path # OPENPYPE_ROOT is variable pointing to build (or code) directory @@ -384,23 +385,6 @@ def set_modules_environments(): os.environ.update(env) -def is_tool(name): - try: - import os.errno as errno - except ImportError: - import errno - - try: - devnull = open(os.devnull, "w") - subprocess.Popen( - [name], stdout=devnull, stderr=devnull - ).communicate() - except OSError as exc: - if exc.errno == errno.ENOENT: - return False - return True - - def _startup_validations(): """Validations before OpenPype starts.""" try: @@ -443,7 +427,8 @@ def _validate_thirdparty_binaries(): if low_platform == "windows": ffmpeg_dir = os.path.join(ffmpeg_dir, "bin") ffmpeg_executable = os.path.join(ffmpeg_dir, "ffmpeg") - if not is_tool(ffmpeg_executable): + ffmpeg_result = distutils.spawn.find_executable(ffmpeg_executable) + if ffmpeg_result is None: raise RuntimeError(error_msg.format("FFmpeg")) # Validate existence of OpenImageIO (not on MacOs) @@ -463,7 +448,11 @@ def _validate_thirdparty_binaries(): low_platform, "oiiotool" ) - if oiio_tool_path is not None and not is_tool(oiio_tool_path): + oiio_result = None + if oiio_tool_path is not None: + oiio_result = distutils.spawn.find_executable(oiio_tool_path) + + if oiio_result is None: raise RuntimeError(error_msg.format("OpenImageIO")) From fb003bf9b06987a9da61a30d69a4a7de6f9cef91 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 12:20:43 +0100 Subject: [PATCH 067/100] fix import --- start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.py b/start.py index 5799132bfe..47faaee974 100644 --- a/start.py +++ b/start.py @@ -100,7 +100,7 @@ import platform import traceback import subprocess import site -import distutils +import distutils.spawn from pathlib import Path # OPENPYPE_ROOT is variable pointing to build (or code) directory From 0544147c6fbb2a6428533f2e64c18f365e096624 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 13:13:41 +0100 Subject: [PATCH 068/100] log stderr as info --- openpype/lib/execute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/execute.py b/openpype/lib/execute.py index a1111fba29..ad77b2f899 100644 --- a/openpype/lib/execute.py +++ b/openpype/lib/execute.py @@ -124,7 +124,7 @@ def run_subprocess(*args, **kwargs): if full_output: full_output += "\n" full_output += _stderr - logger.warning(_stderr) + logger.info(_stderr) if proc.returncode != 0: exc_msg = "Executing arguments was not successful: \"{}\"".format(args) From df6a3faef6bac1966fe4bba88cd694c3f91979a5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 25 Nov 2021 15:04:54 +0100 Subject: [PATCH 069/100] Added more logging --- .../custom/plugins/GlobalJobPreLoad.py | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py index 8631b035cf..2e7a00bc48 100644 --- a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py +++ b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py @@ -16,8 +16,9 @@ def inject_openpype_environment(deadlinePlugin): job = deadlinePlugin.GetJob() job = RepositoryUtils.GetJob(job.JobId, True) # invalidates cache - print("inject_openpype_environment start") + print(">>> Injecting OpenPype environments ...") try: + print(">>> Getting OpenPype executable ...") exe_list = job.GetJobExtraInfoKeyValue("openpype_executables") openpype_app = FileUtils.SearchFileList(exe_list) if openpype_app == "": @@ -27,11 +28,13 @@ def inject_openpype_environment(deadlinePlugin): "The path to the render executable can be configured " + "from the Plugin Configuration in the Deadline Monitor.") + print("--- penPype executable: {}".format(openpype_app)) + # tempfile.TemporaryFile cannot be used because of locking export_url = os.path.join(tempfile.gettempdir(), time.strftime('%Y%m%d%H%M%S'), 'env.json') # add HHMMSS + delete later - print("export_url {}".format(export_url)) + print(">>> Temporary path: {}".format(export_url)) args = [ openpype_app, @@ -55,21 +58,31 @@ def inject_openpype_environment(deadlinePlugin): "AVALON_TASK, AVALON_APP_NAME" raise RuntimeError(msg) - print("args:::{}".format(args)) + if not os.environ.get("OPENPYPE_MONGO"): + print(">>> Missing OPENPYPE_MONGO env var, process won't work") - exit_code = subprocess.call(args, cwd=os.path.dirname(openpype_app)) - if exit_code != 0: - raise RuntimeError("Publishing failed, check worker's log") + env = os.environ + env["OPENPYPE_HEADLESS_MODE"] = "1" + print(">>> Executing: {}".format(args)) + std_output = subprocess.check_output(args, + cwd=os.path.dirname(openpype_app), + env=env) + print(">>> Process result {}".format(std_output)) + + print(">>> Loading file ...") with open(export_url) as fp: contents = json.load(fp) for key, value in contents.items(): deadlinePlugin.SetProcessEnvironmentVariable(key, value) + print(">>> Removing temporary file") os.remove(export_url) - print("inject_openpype_environment end") - except Exception: + print(">> Injection end.") + except Exception as e: + if hasattr(e, "output"): + print(">>> Exception {}".format(e.output)) import traceback print(traceback.format_exc()) print("inject_openpype_environment failed") @@ -79,17 +92,17 @@ def inject_openpype_environment(deadlinePlugin): def inject_render_job_id(deadlinePlugin): """Inject dependency ids to publish process as env var for validation.""" - print("inject_render_job_id start") + print(">>> Injecting render job id ...") job = deadlinePlugin.GetJob() job = RepositoryUtils.GetJob(job.JobId, True) # invalidates cache dependency_ids = job.JobDependencyIDs - print("dependency_ids {}".format(dependency_ids)) + print(">>> Dependency IDs: {}".format(dependency_ids)) render_job_ids = ",".join(dependency_ids) deadlinePlugin.SetProcessEnvironmentVariable("RENDER_JOB_IDS", render_job_ids) - print("inject_render_job_id end") + print(">>> Injection end.") def pype_command_line(executable, arguments, workingDirectory): @@ -133,10 +146,13 @@ def pype(deadlinePlugin): deadlinePlugin: Deadline job plugin passed by Deadline """ + print(">>> Getting job ...") job = deadlinePlugin.GetJob() # PYPE should be here, not OPENPYPE - backward compatibility!! pype_metadata = job.GetJobEnvironmentKeyValue("PYPE_METADATA_FILE") pype_python = job.GetJobEnvironmentKeyValue("PYPE_PYTHON_EXE") + print(">>> Having backward compatible env vars {}/{}".format(pype_metadata, + pype_python)) # test if it is pype publish job. if pype_metadata: pype_metadata = RepositoryUtils.CheckPathMapping(pype_metadata) @@ -162,6 +178,8 @@ def pype(deadlinePlugin): def __main__(deadlinePlugin): + print("*** GlobalJobPreload start ...") + print(">>> Getting job ...") job = deadlinePlugin.GetJob() job = RepositoryUtils.GetJob(job.JobId, True) # invalidates cache @@ -170,6 +188,8 @@ def __main__(deadlinePlugin): openpype_publish_job = \ job.GetJobEnvironmentKeyValue('OPENPYPE_PUBLISH_JOB') or '0' + print("--- Job type - render {}".format(openpype_render_job)) + print("--- Job type - publish {}".format(openpype_publish_job)) if openpype_publish_job == '1' and openpype_render_job == '1': raise RuntimeError("Misconfiguration. Job couldn't be both " + "render and publish.") From 22f8c13c7fff94afaa46d7a7500f48810de32996 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 25 Nov 2021 15:05:34 +0100 Subject: [PATCH 070/100] Added possibility for timeout as in other places --- igniter/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/igniter/tools.py b/igniter/tools.py index 04d7451335..3e862f5803 100644 --- a/igniter/tools.py +++ b/igniter/tools.py @@ -59,7 +59,7 @@ def validate_mongo_connection(cnx: str) -> (bool, str): return False, "Not mongodb schema" kwargs = { - "serverSelectionTimeoutMS": 2000 + "serverSelectionTimeoutMS": os.environ.get("AVALON_TIMEOUT", 2000) } # Add certificate path if should be required if should_add_certificate_path_to_mongo_url(cnx): From 883c1336aea5dc8a323ce69267d1cf77ecedfc49 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 25 Nov 2021 16:24:45 +0100 Subject: [PATCH 071/100] Add explicit higher timeout for cloud nodes --- vendor/deadline/custom/plugins/GlobalJobPreLoad.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py index 2e7a00bc48..8d6784c74e 100644 --- a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py +++ b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py @@ -63,6 +63,7 @@ def inject_openpype_environment(deadlinePlugin): env = os.environ env["OPENPYPE_HEADLESS_MODE"] = "1" + env["AVALON_TIMEOUT"] = "5000" print(">>> Executing: {}".format(args)) std_output = subprocess.check_output(args, From 3d4be3b63df314ec3373b0c8055d4cdc7a76aacb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 18:13:13 +0100 Subject: [PATCH 072/100] fix typo of "inputLinks" key --- openpype/lib/avalon_context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 3e0e0c6ea6..85beecab51 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -271,7 +271,7 @@ def get_linked_asset_ids(asset_doc): if not asset_doc: return output - input_links = asset_doc["data"].get("inputsLinks") or [] + input_links = asset_doc["data"].get("inputLinks") or [] if input_links: output = [item["_id"] for item in input_links] return output From 8a8f39d4986ab0e85e3553d7edb5018d9a64b317 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 25 Nov 2021 18:29:03 +0100 Subject: [PATCH 073/100] Fixing typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: OndΕ™ej Samohel <33513211+antirotor@users.noreply.github.com> --- vendor/deadline/custom/plugins/GlobalJobPreLoad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py index 8d6784c74e..4683828445 100644 --- a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py +++ b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py @@ -28,7 +28,7 @@ def inject_openpype_environment(deadlinePlugin): "The path to the render executable can be configured " + "from the Plugin Configuration in the Deadline Monitor.") - print("--- penPype executable: {}".format(openpype_app)) + print("--- OpenPype executable: {}".format(openpype_app)) # tempfile.TemporaryFile cannot be used because of locking export_url = os.path.join(tempfile.gettempdir(), From d76c5720ef585bef3048617bed071f0b6085c5a4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 25 Nov 2021 18:30:31 +0100 Subject: [PATCH 074/100] Fixed label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: OndΕ™ej Samohel <33513211+antirotor@users.noreply.github.com> --- vendor/deadline/custom/plugins/GlobalJobPreLoad.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py index 4683828445..0aa5adaa20 100644 --- a/vendor/deadline/custom/plugins/GlobalJobPreLoad.py +++ b/vendor/deadline/custom/plugins/GlobalJobPreLoad.py @@ -86,7 +86,7 @@ def inject_openpype_environment(deadlinePlugin): print(">>> Exception {}".format(e.output)) import traceback print(traceback.format_exc()) - print("inject_openpype_environment failed") + print("!!! Injection failed.") RepositoryUtils.FailJob(job) raise From f10143371fa5a47b07c3a36a5ff41e58acaa4266 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 19:03:14 +0100 Subject: [PATCH 075/100] keep tab widget same as before --- openpype/style/style.css | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index 5e2d200d17..8118fb5221 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -968,9 +968,52 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SettingsMainWidget { background: #141a1f; } +/* Change focus borders. */ #SettingsMainWidget QAbstractSpinBox:focus, #SettingsMainWidget QLineEdit:focus, #SettingsMainWidget QPlainTextEdit:focus, #SettingsMainWidget QTextEdit:focus { border-color: {color:settings:focus-border}; } +/* Modify tab widget for settings */ +#SettingsMainWidget QTabWidget::pane { + border-top-style: none; +} + +#SettingsMainWidget QTabBar { + background: transparent; +} + +#SettingsMainWidget QTabBar::tab { + border: none; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + padding: 5px; +} + +#SettingsMainWidget QTabBar::tab:selected { + background: {color:bg}; + border-color: #9B9B9B; + border-bottom-color: #C2C7CB; +} + +#SettingsMainWidget QTabBar::tab:!selected { + margin-top: 2px; + background: #21252B; +} + +#SettingsMainWidget QTabBar::tab:!selected:hover { + background: #333840; +} + +#SettingsMainWidget QTabBar::tab:first:selected { + margin-left: 0; +} + +#SettingsMainWidget QTabBar::tab:last:selected { + margin-right: 0; +} + +#SettingsMainWidget QTabBar::tab:only-one { + margin: 0; +} #SettingsToolIconBtn { border: 0px solid #bfccd6; From a00da90b74a3b5ba9bb25fde8f1447c19d609ef9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 19:08:56 +0100 Subject: [PATCH 076/100] fix expand label color --- openpype/style/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/style/style.css b/openpype/style/style.css index 8118fb5221..ea953c83e3 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -1087,6 +1087,7 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #ExpandLabel { font-weight: bold; + color: #969b9e; } #ExpandLabel:hover { color: #b8c1c5; From 8cd841d1d61a4ab8e73d101540243b372267e6be Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 25 Nov 2021 19:17:24 +0100 Subject: [PATCH 077/100] use colors from data --- openpype/style/data.json | 3 +++ openpype/style/style.css | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/openpype/style/data.json b/openpype/style/data.json index c17e31afcc..026eaf4264 100644 --- a/openpype/style/data.json +++ b/openpype/style/data.json @@ -101,6 +101,9 @@ "project-mid": "#FF8C1A", "project-dark": "#E67300", + "label-fg": "#969b9e", + "label-fg-hover": "#b8c1c5", + "breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)", "breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)", diff --git a/openpype/style/style.css b/openpype/style/style.css index ea953c83e3..a60c3592d7 100644 --- a/openpype/style/style.css +++ b/openpype/style/style.css @@ -1041,9 +1041,9 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #SettingsLabel { background: transparent; - color: #969b9e; + color: {color:settings:label-fg}; } -#SettingsLabel:hover {color: #b8c1c5;} +#SettingsLabel:hover {color: {color:settings:label-fg-hover};} #SettingsLabel[state="studio"] {color: {color:settings:studio-light};} #SettingsLabel[state="studio"]:hover {color: {color:settings:studio-label-hover};} #SettingsLabel[state="modified"] {color: {color:settings:modified-mid};} @@ -1087,10 +1087,10 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { #ExpandLabel { font-weight: bold; - color: #969b9e; + color: {color:settings:label-fg}; } #ExpandLabel:hover { - color: #b8c1c5; + color: {color:settings:label-fg-hover}; } #ContentWidget { From d31ba09b6c6e30e3d4d02b3f0d510b9ec383e03d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 11:41:54 +0100 Subject: [PATCH 078/100] fix check of oiio path for darwin --- start.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/start.py b/start.py index 47faaee974..0f7e82071d 100644 --- a/start.py +++ b/start.py @@ -451,9 +451,8 @@ def _validate_thirdparty_binaries(): oiio_result = None if oiio_tool_path is not None: oiio_result = distutils.spawn.find_executable(oiio_tool_path) - - if oiio_result is None: - raise RuntimeError(error_msg.format("OpenImageIO")) + if oiio_result is None: + raise RuntimeError(error_msg.format("OpenImageIO")) def _process_arguments() -> tuple: From c728eec8ab22e3e260bdf2b9cc0fcad9e3b52c18 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 12:55:26 +0100 Subject: [PATCH 079/100] use "id" key where id of input is stored instead of "input" --- openpype/plugins/publish/integrate_inputlinks.py | 2 +- openpype/tools/assetlinks/widgets.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openpype/plugins/publish/integrate_inputlinks.py b/openpype/plugins/publish/integrate_inputlinks.py index e8a8b2296c..3b134345e4 100644 --- a/openpype/plugins/publish/integrate_inputlinks.py +++ b/openpype/plugins/publish/integrate_inputlinks.py @@ -103,7 +103,7 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin): # future. link = OrderedDict() link["type"] = link_type - link["input"] = io.ObjectId(input_id) + link["id"] = io.ObjectId(input_id) link["linkedBy"] = "publish" if "inputLinks" not in version_doc["data"]: diff --git a/openpype/tools/assetlinks/widgets.py b/openpype/tools/assetlinks/widgets.py index 9a136462b0..22e8848a60 100644 --- a/openpype/tools/assetlinks/widgets.py +++ b/openpype/tools/assetlinks/widgets.py @@ -37,8 +37,13 @@ class SimpleLinkView(QtWidgets.QWidget): # inputs # for link in version_doc["data"].get("inputLinks", []): + # Backwards compatibility for "input" key used as "id" + if "id" not in link: + link_id = link["input"] + else: + link_id = link["id"] version = self.dbcon.find_one( - {"_id": link["input"], "type": "version"}, + {"_id": link_id, "type": "version"}, projection={"name": 1, "parent": 1} ) if not version: From 46cb7d7a71bebd51f794c4d3a893dc2b780e3bff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 12:56:20 +0100 Subject: [PATCH 080/100] skip processing if workfile instance is not available --- openpype/plugins/publish/integrate_inputlinks.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/plugins/publish/integrate_inputlinks.py b/openpype/plugins/publish/integrate_inputlinks.py index 3b134345e4..539ad984b1 100644 --- a/openpype/plugins/publish/integrate_inputlinks.py +++ b/openpype/plugins/publish/integrate_inputlinks.py @@ -55,6 +55,7 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin): if workfile is None: self.log.warn("No workfile in this publish session.") + return else: workfile_version_doc = workfile.data["versionEntity"] # link all loaded versions in scene into workfile From a732ce3ee95306a55ab87bc987cb8e4f75e716e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 12:56:37 +0100 Subject: [PATCH 081/100] skip else statement --- .../plugins/publish/integrate_inputlinks.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/openpype/plugins/publish/integrate_inputlinks.py b/openpype/plugins/publish/integrate_inputlinks.py index 539ad984b1..beefd8c05a 100644 --- a/openpype/plugins/publish/integrate_inputlinks.py +++ b/openpype/plugins/publish/integrate_inputlinks.py @@ -56,22 +56,22 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin): if workfile is None: self.log.warn("No workfile in this publish session.") return - else: - workfile_version_doc = workfile.data["versionEntity"] - # link all loaded versions in scene into workfile - for version in context.data.get("loadedVersions", []): - self.add_link( - link_type="reference", - input_id=version["version"], - version_doc=workfile_version_doc, - ) - # link workfile to all publishing versions - for instance in publishing: - self.add_link( - link_type="generative", - input_id=workfile_version_doc["_id"], - version_doc=instance.data["versionEntity"], - ) + + workfile_version_doc = workfile.data["versionEntity"] + # link all loaded versions in scene into workfile + for version in context.data.get("loadedVersions", []): + self.add_link( + link_type="reference", + input_id=version["version"], + version_doc=workfile_version_doc, + ) + # link workfile to all publishing versions + for instance in publishing: + self.add_link( + link_type="generative", + input_id=workfile_version_doc["_id"], + version_doc=instance.data["versionEntity"], + ) # link versions as dependencies to the instance for instance in publishing: From 8a71f5ecacaf93ba2e1c0ec8b0b785d52519b896 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 13:35:14 +0100 Subject: [PATCH 082/100] changed "_id" key to "id" in ftrack sync --- .../ftrack/event_handlers_server/event_sync_links.py | 2 +- openpype/modules/default_modules/ftrack/lib/avalon_sync.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/modules/default_modules/ftrack/event_handlers_server/event_sync_links.py b/openpype/modules/default_modules/ftrack/event_handlers_server/event_sync_links.py index 8c3d858a96..83132acd85 100644 --- a/openpype/modules/default_modules/ftrack/event_handlers_server/event_sync_links.py +++ b/openpype/modules/default_modules/ftrack/event_handlers_server/event_sync_links.py @@ -113,7 +113,7 @@ class SyncLinksToAvalon(BaseEvent): continue links.append({ - "_id": ObjectId(link_mongo_id), + "id": ObjectId(link_mongo_id), "linkedBy": "ftrack", "type": "breakdown" }) diff --git a/openpype/modules/default_modules/ftrack/lib/avalon_sync.py b/openpype/modules/default_modules/ftrack/lib/avalon_sync.py index 9e22f80b1c..3ba874281a 100644 --- a/openpype/modules/default_modules/ftrack/lib/avalon_sync.py +++ b/openpype/modules/default_modules/ftrack/lib/avalon_sync.py @@ -1479,7 +1479,7 @@ class SyncEntitiesFactory: mongo_id = self.ftrack_avalon_mapper.get(ftrack_link_id) if mongo_id is not None: input_links.append({ - "_id": ObjectId(mongo_id), + "id": ObjectId(mongo_id), "linkedBy": "ftrack", "type": "breakdown" }) From 9772282a5c4a6319f470d68896a5ba7e5968a26f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 13:35:34 +0100 Subject: [PATCH 083/100] check for "id" key instead of "_id" in get_linked_asset_ids --- openpype/lib/avalon_context.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openpype/lib/avalon_context.py b/openpype/lib/avalon_context.py index 3e0e0c6ea6..c8e88610a5 100644 --- a/openpype/lib/avalon_context.py +++ b/openpype/lib/avalon_context.py @@ -273,7 +273,15 @@ def get_linked_asset_ids(asset_doc): input_links = asset_doc["data"].get("inputsLinks") or [] if input_links: - output = [item["_id"] for item in input_links] + for item in input_links: + # Backwards compatibility for "_id" key which was replaced with + # "id" + if "_id" in item: + link_id = item["_id"] + else: + link_id = item["id"] + output.append(link_id) + return output From ea269ef8c004e87868d1db5cf00c23364b6d65f3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 13:53:28 +0100 Subject: [PATCH 084/100] added experimental tools action to hiero --- openpype/hosts/hiero/api/menu.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/hiero/api/menu.py b/openpype/hosts/hiero/api/menu.py index 61b515d719..5aaab7a2e5 100644 --- a/openpype/hosts/hiero/api/menu.py +++ b/openpype/hosts/hiero/api/menu.py @@ -105,9 +105,9 @@ def menu_install(): sceneinventory_action.triggered.connect( lambda: host_tools.show_scene_inventory(parent=main_window) ) - menu.addSeparator() if os.getenv("OPENPYPE_DEVELOP"): + menu.addSeparator() reload_action = menu.addAction("Reload pipeline") reload_action.setIcon(QtGui.QIcon("icons:ColorAdd.png")) reload_action.triggered.connect(reload_config) @@ -120,3 +120,10 @@ def menu_install(): apply_colorspace_c_action = menu.addAction("Apply Colorspace Clips") apply_colorspace_c_action.setIcon(QtGui.QIcon("icons:ColorAdd.png")) apply_colorspace_c_action.triggered.connect(apply_colorspace_clips) + + menu.addSeparator() + + exeprimental_action = menu.addAction("Experimental tools...") + exeprimental_action.triggered.connect( + lambda: host_tools.show_experimental_tools_dialog(parent=main_window) + ) From 15d0920bc994a2684b716c644b42dfc539ced144 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Fri, 26 Nov 2021 14:03:54 +0100 Subject: [PATCH 085/100] docs[website]: Add Ellipse Studio (logo) as an OpenPype contributor --- website/src/pages/index.js | 6 +++++- website/static/img/ellipse-studio.png | Bin 0 -> 14742 bytes 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 website/static/img/ellipse-studio.png diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 00cf002aec..29b81e973f 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -64,6 +64,10 @@ const collab = [ title: 'Clothcat Animation', image: '/img/clothcat.png', infoLink: 'https://www.clothcatanimation.com/' + }, { + title: 'Ellipse Studio', + image: '/img/ellipse-studio.png', + infoLink: 'http://www.dargaudmedia.com' } ]; @@ -125,7 +129,7 @@ const studios = [ title: "Moonrock Animation Studio", image: "/img/moonrock_logo.png", infoLink: "https://www.moonrock.eu/", - } + } ]; function Service({imageUrl, title, description}) { diff --git a/website/static/img/ellipse-studio.png b/website/static/img/ellipse-studio.png new file mode 100644 index 0000000000000000000000000000000000000000..c6fd62a6d5bc64742aceb65709fc774c7143f503 GIT binary patch literal 14742 zcmd73WmHw|7d?7F6p#)_v$!{VM2plCvSxp4ux;+AcLWO|} z?+}$+@xdPfRx&aVm1JaS9i1F3tZdB@2-X|df!S>(~$D|xc?iPFdcMK%O_NZ*QK_vwfFTY{g6{WGtzucu<+%D z#N4dsOw+Xhi-bap0mf|W#2B^q4nrTE4bKjQG)8Mwa{B|Zlt;Z^UwX~9eH(9J9oQBB zw{lziCi68f`W?z)oG`aHZmz>aLVtf2G*2v(E5Fam{!7AMX7*r;X5C` zO2_L)5EEHVMR^`6Q2K@%^3>fiUeuSwxx@Gk?*hH0fiG-W%U+WUcfWb!@Z0UdTC6Ja znsaa4=~ANBOKd|cD&JDfc5x*K=c+CO{HYrpWg@AK=!RQ}HuZWl#mL11HsY|>Q!;NY z>f80#QEluUHoeou5s%iak8cPHqIIgoH*M`~U2M%=hz)Q3MRz}ODyqc3^#L9WrlaDc zmk0!&3GyGx2Z;hJcoW@ONmUMg2@CHg8s!8rl?nnui%^o4(srBLoPD8qYjV1E$MZ1M zlvNMA<6&$&EB3q3xx}HS#PS-%fnl0ewuaoH^lag#?^wf0-m`|^mD6BtsA80hAr8$Y z4kDFP3TIS`mt`ZC(};J!OrAffuQm|=H0j?&dWz6Won^luB`oIu zkFSd7{`d%l@y%~hH2>U0+1S|TF9(*Fmy3#u`m-b?czC1-5v@g{)Ob>@zJ*0apLTz- zwfe>tyn9;j93to^eof}=aM}T7^;Q(Mm?@**UmF{nXOB_2QvCUdNlDiSugM5v(&gmj z(7BT@I16`U{NWuOKK=JME-voc(QD7cjTBDaj?T_ck5T5G8fKrCkFOu}U#4wsZJnR~ zd-duS5#{iEryN@Euz{7mW3MMqo}6F3sHmu9siVJ@8q~5fwdU8@PD;PK&(Bw+F(#8BKvfK$mqbi_kDw4Bmiv(t$;Bxkpr=7xU4mfmEY>R@ zaj9HdT9TDnQ99jQ86f3&l9`!#=+Sgzj3ALwRCH!x$E|6uySv*V$z-6v-=k@6W5bpZ z=boccchw zY!oe~E*W0kcN2|>h?v(UgM(}BXO(>siECXk4Dp1Pv1}rI{N)Y%;yZq zW5yHGGEmQ7H+FyV;>D*X`)97Mhfxw2w0wh-8P{kee9|AXk8V!aj*>Z9TC&_q>2PeA z{r7kNvZ&c{p)&$*!~fc!a81;_;n7h!e1yKfmDOs2dKROtzK_qv;vyraKmT~y6D{JU zUu|y#e!smqTEKI`JzFntA;h_)67z6&b8|C!kyBC!BdqMI_GXSa^^qFFY6Hxh=`}FtM0wK_&CY^AD?~OKdZ;5$94BQ-VLNhR4~SE9o-@&6}W$2_5>dvu0K0F zyFON0d1%6O{km~H7Dnu+PoKudbg?Kg@c0nXulp&O1X-CRscqvC z2*U5Zy^I(bvHSbZFPj(-3`PhL6C|+t(o+$Hh8(1mDBd>^{&e*8rcO>nc@YJ0`hMh2 z`CX0-4N2qUYr_JDhllfR_+jC@f-imtTo@^{p=cVvLqkMs$;n-plB@^}3c|(4PX6%4 z&d$yZ$4|7(sHN;ONmJR6c!CuLv3Q@4PYyr(&C$^j#A|A9A;6V=ZCX4^g^)64w0{)^ z6I=}YxD>&aK_%h}5B&SQ8n1XH3Ic^x8UumAC?aA}qm=NO3BPCb(e(Q2o6NQK^+0@{ z+KQ5r-mg3Vj=jXQ)X&im=EK9o_y7GHxb&sMeLK85Q(^Mv#DU*-;-|ClsIRV`b^Et( z-#R)zTDR>2@?!XlTHDyzz3L5par5TQKQHz3zJFJ~c6w*0U|`U)B&WJshno&73eEN+ zR;6}YOkCW4I?{4TZM~qThCk{X!+=Q8jD795g&mJ32-1C-;RAX5b;pW3kW^G=W@gFu z8%)PhZQE}LR>H!=wJ+VBowaN9Ce+l`-v$OM-4-Yxw+TJt=i|!|d8M{HUfx^ocf?s& zS9g4TOda)>h$NcG6ZStFU8q3*GO(lgkl@xWrhsVcDKc{M)YQ~FCM9N>VMz&O8KvZpQ+3&VYckikcxv*wrWPA!# ztf{8Jef!MTmYtDNHp6(j;OyUGH&Jy1hqkshr0lm4Y$S@d`g1&ObX)1CI-VvY{JIy# z&lE86`NccN2(sI^qwfd;c*YiRQwZ1-OUug1_4W1raG=6f(9zM+)ExTy+y9Yrt)IIF zoJLaOEgp^d%jNK@zO1U)qT z?D(bCp}e@bxUeus=0;mrSJ&ET@#v?ooGoY4l71cUAnE)};86wOLmA<*#=aL|%#GUo zrioXZg5Q>Fd%D(PUhSr{4>ii0ybB|nXi**q9_Jy0-`vj_=YhK`|b_zQ@+mPU*;q_OyJa4kltz78#iciLsFpS$u4| zZVGM`V>)F_c`CIJ@H|p0(9(#H zk04PbXgJzu|Id%FzolQk+)L%N3C1p2D{r}gv`3~0g0{h+ z)?R5SR={CS)O|M~yo-&Ox3ZwXviXzazpW>xsCR|jwzEYeAflekHoC{r!n2U?+!CA^ z8DUgsb^SXxJ3g+E6g>}Aak=NF!+lu*1;1z}$s>4s3n3^n49j@+bCQUL0dMyZuC2h~kX=%fHI z4L?;@;*>{!zqAR!H{DzA+b7YYxPAK}aYw5_Ch9Ugx|5idh(Xwe7;*{<%&(@6KIe}y zzC8c7kzas(g{e4Oopj}?pt_d~vPH1dKhAJy9Ue*AM zLEP0-`)Q=OTlSE*`6V|Civos*rlvF}PkCo&=g!WH-w36%v%P^&d?A{s&bu3vy#5eg zj}$c(xDEzRZ{4~jjX~EwGear%J)EANo>7PZV({r?DrBj!$$%UJ(JP&~s->nDdHpvT zAt8N$ev=2^ldxfw3T(LJ?uiL_I0#86jwF@Lkm13>=mgX0>FHt)O$24|J90!J!uLJg8a3Q$xt9#nKn~IY7zrA3Ez$`I38A^# zy1L)TD#F9DDe|BB6v*p9MFWb`q)iR9j~>G>R1hni+3k3b|VY4vW@ z>K^%55CGt@))8os;2X4@0{NOLOy-k4sO>^)%u^CdRTx4Hu{rp|#@wcLWh#`}%mf zsy7DcKkyw$N#j(>oSmKV|L+6vodH^PJw7#k`lP85zr1Y0V^e}d!H@i$E&zFLDf7|I z9UflZTXHW1DV3CzVAmNR`yw$7!;els0gmu9W@BfsYU4kp5%+pXyaY7I%+Qh}spms^ zW=aa(MFl_=9EBlzz=s3ZIuu%jvVRAH^E(u!RfKSGWF-Igba7FUBFg`E0M*LT@gauE z(D;3{_Cl?KkyL3bE4FhwH*wz!+n=>Yjczf-|JzntuKN1=0DMeL%m8T}UETaKVi33? z^2TDm7c&z#fHg;7|KCO*tvA14a+)p__ZdyE)PM@d7YE_oK8m6es0q(F(d zhU6UxKY3nWUL=HoZVBl$l~qu{!^Zw#9tahU2p{MB_wPvk`D}V{eqNp4_~q3$SD1lP zB9aaW3?#VOht!Ho4v@2GX57pyEanrh>AAUM3|o;=ge=-YK|xS=N6j%nV4*Skg@%Q# z^xOnd3E|$pcozzn1~HSUX!=7059lCR&Lyb48uK2KYOe~@j!@t}ri8Y@soUDx_7bi? zy%uw22)t8>Vze3vA!7OS9!kegbdWz%2=5zy-p(#AoAWJ3XZP;hDay%tU2*&Q1s{IV z?yl1*rRTF}?{Zm7OG`DY*G>-BomFT9piUzuDxPu)3hEmetb=hPPJ_Z76UU;SDeCTY z;j8xGLAuDRe$%*VV7^<^wd(yf8A30E)F3i3{Hs8G>>tyc{FJ&ADxJT>nW2eMI5j*u znUb2S{FG6EkFVNxlIH~b!IWiq6AQW9DBt#n%1@sjKYlDoU_7c}BO}uWPbW*%-87dU z9D}o|YMXHFlm}nfpTwh6(o#`l1l+LwiUzf-x2Lbq`|RlBZUop)o}!shLE8*ITaUs` z?FQQM%2ClV2Jp?cUV>=RJXA>`Vcy2#oedI~$@+LG76Wwc-I#l`@9xUGbT!M9d5}o# z`040))Rdxb(e{|#qa!24BqW;3hy~C5K(6_AKlolwJV=jt!d66rJ*Le+9co9v@Z=z= zH>8|T@zDk?fgWb0p)f-ceV8PJ8L+yRhy^BN) z7nYTc{W5@PsE7pR>W_eXqJ8**0dX0qiOP7ezpCZ$_x|^fS8!^sELlllg0ZiXlW^5v zfa=V1-I$QVuh8a53Zn%BjrMi`zI5=HFH+Jb=upd_KqY(O=MFp%?ewm6Fb`a?;x;4) z?pp?7;gf}LQ3M18Xzj83;Rr1KIw$jr7JnVgXuTINxTRV(cbGNcf@sr8oJPp#bh+s; z*GNa3`0>Sp{2E3py@s-1l9$sn}5H+NZ}*XW!f$i9CqLNeck)U@*1yj;~AMBBZx^- z5)yu+M*!hJ;chX)#7E3Aq=PRmd~#7lp4;2!L)L|X6QY1`TqaILPOeOX@buXJ`DJ&h zXXP#yF!u7IB6{}Md`42nWT^O(aHWQ|HEXE5h>f4{shpgg>FZl}b!X~b!n)XXe0_bj zwTW+`wXQnfSdC+2l5_==4Gl#FisA!&$t)CO6rf)Uk(30NRpvd3kZAbn4$rFH_bm8i zLqbBHJ$u%U_T0e%Z-_+;Y#}Lt2{aVg0o~ET!3xiRTjguW1xdJWK;f)Zr<9kM$E6W( zbiDozK!26GRr<@cL8>O|17j%WaLrFnOUhT_W^fEQ1GQs#XsBIaXlO_+OWf}8&YOXi z=@#G1uM43O5lt^wa0}6~>9Ei2cz61F5_O`bKhH51;h2p6RLHrn*z+rZ13 z&;QkU{6to~|F5r~1--q!uV14qDTw==C1+-;eZD$lMIjg;a>bzI@g=X`2&Z?xXkJ}i z9UOdkDPd`0!OYGceum6SM0RDC^JzYadDc+EXkq`hUl=$zI>bxhB8u))%1*v(F5ZE+ILs)qP;q#YK+n)?(kdq-*J*$*KNuJhK4j{B3DKVwHR+*efcNm zn8Q&JyVB7--AAsgHTz{Bhy1rVzYZ*AHk09e)f?2Y)0@oY|D9M#kt9P3?XL$lThp*K&?+Zf*wO5VD!?{(V4u zr_ESZaEUA|mi3Z`1Cvy<2LAp0@&*FVG?2+~JUgW~i@a7hln(ne-^O0oo&E{e@tW;6!lVyO(e_ zM81()(%bUQkKz_@T=voSuWOh?>|kB=#y-k0x3r9-?E~dlm(ybfRm|e=lc(hZ%*;Uq zso2koK7Ha*#?0ShR4W*cX4lr!JDuDG30TNc3a-f|4IKn_UE#e>^+O?TI<$e*lb4>+ zdHpA)d3lT}wJy;!t*xybs@-eHM|a-<@FK3c%KLkJwaZ@vD_L>cZ#u4?#T5h|$D(##_fbw>UU^zHXx!%s)OD?{(=LPy8mw zKQWSF){}S-JW&fuHnPzSGnH2k4u3&s)~$Q5voug`kBr3Q`}!;F&cm_P&qYsoUI%(g2F>!?_BI5^ZcGNKvj zaoH9(yfkS^$I}H&xEsnNEUavK;Sp><%`ni{S6W_Pfc{)dPp{Vd)HMa&eX%RcT_lC6 zQW#u;X!n=s-As&(*toca=-%N`QR^)uW4n5{b(y@@TVG#;wvWL0d$7$Upm7!tMr3_X zjCjU(c0IkU0cZqt@);e(*+n%1RW)k64-1bwPUQ%2gYKKvke9l$x;jgxneIxrBM3&J zAq!*U?1F-~f@o>=48ksGf1cUfN7Cx6w+b{^IXH}4p5c!S=#fsQEUm4%Hr$fy?(ff+ z5ZP$FV=_0}@CuJgSeCL1luJorVN9hRFr!a)(l+!wf5W68#~-0%sh>5z)1tvk1=*RO zmxuqB)_s$0zXl^QUiS`qQI5^dD}M_9e0~}ww&!^olEi_ zB=8QYr3B!EpvY62c78JD&D~X^!&^L;prWj-7`Kcv34Two3>T^j70Su{Du#ccs+wB; zti6PU>_DIL)YKH}MG7PYuVj;@pI1ucG`d*oA#F$?WKU7`B-wFq{k7iBC9(Xx#-fkB`=4pN zs{#5kTj(c;d2!_8;$vdK{FjTYTHV-Ktk&^?7B0|b;-?1oL|GEPHNRTlEab);n@b13 zTHDa~y#z%>R4lqnGQkjUqx^I=sqAJcYI}X?!;R z`R;90Crj=k6T^RJ<3mG)+cQ++Uiz7AA664Hg);iH`)h5it!wP24>R^bt2ept1zDrM z56EutI_BXe>hn3>6zEQ3QEVuE!?uO;x zZO1fQ{1AjX`GqxD%k@-8u=!bLBxfmTKYVCx zya4=CH7PioU%!oIT^Ap_>$=o*TEYWobWB@Mc;-Z{*d(N+FWW|gASF4Db}Gs&poCCS zQzus1ZG`=b0tmO_j5ixAN^udSlnw?DbtupMcCFAyuE5Fdh@MK#p{8|ga$0H{N;#KFX* zQE@+xK1_mML3DaC~pJpXFlg#R?~}$ ziYf|VUHa-BjrRmz^ywD?Pkl%I7=-~l*-7x=aMOU0v0KIl;)^5bMDRw{uLHFD**~RJ z#o)v!LsOlViGA_FgYRFxY8rnxuMB3_gNeqZ!NoCH(=WHs0;hEs1{ z6y)WRXLd2dhKzP$4)_e&V>Kk&FXFOB{6e1EyL4<)^8 zO_h{FE+ZzPi|M|O@!GmAl1hY?>8H^Lk>K4iBfAkjN;z5CuE|DVpZTAfp8jU%8Pq0f_Cc7Efq7MW9TYpbfv%+1M?zd!@EcG_+r zO#bQ9Ihg9W_j2-qs_G`d8^`uNT_!YRo?cd|N)Y_rq-x`%qcO~VGNC`4(lUBuCw;43 zH>W@{Ml;xndmV9caY<65HqSXaImLcJmL{rCc3xhvmJPm9!>3Z6~F|`nkgPki76n^49(2)f?9Y^b-rfN{4&pc zU;|;2MNa~0KwhBcGSxRA=}grC=uqlqO>^^HDzA~+ zu5oZw)Jlj}AIOl{*w{Qf>SEvX`rj3#3@M|~N@>#Z#Tk@RQ&R&fh=VtiM~ZeZ8)tMr z4+Naks5!d*z3H@EA-Qd*9jR)n!ZmfV$AJ4^dAx&aWXM= z=nkv(S!5>&{6i(!ZdBAX;C^^UtbAeOLWj|L$W1xAdNlU z-E<16SlqhaBYQ2t8m5F6U;qj0)ysW&-LuJ&L1N5%_wK!qM?~-vd5YVR ze@IdC@TgC>Q+euCEm+`1T8x$v~u1q8c@c{3o|neI_SqMo$FaxS{fJ_gj~aCB_bk1 z1KV-CDWw}m%Yxr5r-W3ANSK?MA-@VOPN+agUJ~NXefAMJR>Nk;XJk)J_VHu#Nh4M< zG3fnXd;OK!a+4Autw?9G|Q-9>h1%?v@pTqRYEjjS0Vk+ICaRhpr zMRf{FJXp8M$N)LNIQ<*{iciGzutcmN2GaDmL#h#>JReF$5zNBiqum8Q&WsUHxJXDr z(X%y}ii3yO;(e;yUo$#7%FX-379eN{SE(E5^17p706xqI+_%b!)+v8Aes1N z4gx6*XJLDFn5F-^B-3VExLI6!x^1W{)HdtWHt;Z%F)>J7UOoSv4T?H+kvC4_@+=Nc zld>^ciA-Rz_wV0Bxr<@26BZG9KT9fO3G00H=+SQq_z##HP$yln?a!YDt!T_q_i5e{ z26TKVFRyi#E;p<*Z7Sh@mC!#~X}NjWZiUE@@V)rm5$06Wx9Y6iQ1|8xKo1xoQh849 z@89R8?}NYCj~T-IW8>nUa3r1J!cZ0!5m6<0a#ltmyHRxcKO~}$jwxiWx^NMzQx3)x zZ>EfKXy%57ViOX~k3zD2sn1uBVT=(r{esc~mS|;FsKiMwg~QoGCNpk-6NyjT+gzAK zy-Q9pNNWJ7OEhgCwU|dc&a5MlwI+`PYXgI{*{u$rn)z)~xfG5KDZ7dwb$fez{zf7T z3yZZZ1>gE}fEOImgTJMJsU4IP>8G| zqoRT$$A|^c z)56K77EVx8kVsJlS##wTfV+uoR==rQ@Ttz1Wc5RQ+7ws5&}K2Gt_K3Hy*JN)|NcW| zKW=!ChkxhQVJ~7Kp_Xi?kM~x{>aAQ?hnTGX3LqDok(Ndz4U9jA83#rWnC3~Z8GiOd zJl$cujCk@GCS{^4bS@g*p6>DBK!Ap~T%3eaG+KZ!9LuTh_HT>IYDj+hKcz@<>sB?4 z(KzMx{rU6U#-?~NqG}H{ltCeKPzB{0Cj-p-kO-c^V5QB)^x>iFBrXe-h^!=!8>@6+ zn&|KLE<$*=OYQYCa&khiru0d}*jK$2Li^-P!Da{~@rBGs-Fz7r_g5C78eZ=%`l^Z_Fd|Y6}|+3sk5mk`B(N zjwtAK$M8dEd#L{bQsrKytzMZS9Td}0@blv90%728x21&G&lcv~z-Ae7%Mp5=w?*D2IGru1o(Fdf}%N~^tJZRl42I*!J`U>@bpt>WZ3SQ-2ivHRJ5FMnC(edZ=M9-c3B zxN2I&pv}w|yW}ixXCja=jT%l$tZ zR=gsYc^vnn-FxmMD~+(en`sD*W8%~X+^WIPAAg`xc!NI;<fCoj_JlSNeys7Dl*tZNdOG)urnWOKdBz9f&g}79n;(|Na~W#-cGF<7B?3aL!3`Sj zSH{VIy^*^av7m=w3z~h->lq0y&W>L~Xhw^B!Dw>OU#ta7YAh@)@FdtB-`pl63js_s zj^nqRB93k?JvnL z20Ad%LY5_%0Hcy}AnbbI(>s}UTXQ3&Cpd@qD(+=zB;GTCnNagu-XH&Jp$`bIH%?ZC z%ler2>7m_hz0Tz;J7p)H$Io=6TSXRO(+4s{YDb#)p_;b3{;jIIzZE4_->lSd=gY1P z6-AjscD(V6-UlTfa<^~a2D;CpFvWP~HeQJcXuenpyo#O&#ILoR?kpW9KHQpxXRE?S z=l8X(?ajaCRA^I!jevuTd*UVjwk@YDrh5SS!keSkB=6Kq6um28KQr;;2c6Eqcuu_W zsO{8V-3?{TvGJK1Xf`NOR&{rExq)a*w=<}=9z~kVG5k$UO<mSl;ONuNDORaI3;Na(O}dG7}LI(WUI z;o*$9Q&lxJh4FuDZ1@618Ys-+9Q z_`2~#8so?KxaA6?rgB9L^e?aGZJzUriJe1$3r*{4XnfgxR0+*2E8lkJO5MH^;fv`1 zj6g!5wBN|r zFU_}8t7~hcA|tQD3kJ#L6H`kcRmx}WZo$Mq3~oKv1tQu5V`E=loi*8hUmozJFtxCd z2j=|Eaip?ynT>*+-1J>K&Ep!|ltqDdV9|8#fS*b*sNMhrk7j2@lQh0(+#(`(EvHAk zxq*Z!#@&GFGYw)G-vdDFm$9Sf8GoP=4|7AShb}-+!Bw<=M90H3lu5J-wZAeY?AORQ zM>Bg9dHEYMss}e)OgnD=t~hd3ny?!=uXvZ6s|Yi=XA90$WMp)>wiCeQIku}dIjpIkNu z2M4>ml``TcW@dV^35+ei_O|bA|B`{e7Z~2i7)U|7XYlKtMBio>-!Fgu{CJ0L`#?`Q zxz=S}SIn~q+~eE%cR~p_B8=?}l=c6>PeG(qO=0pu>noGVD9*(^@T3E;-y^2|uqVg6 z=0elU&cg3!XQX^yzI;hXM~4(zwlE?+)kn2RN=V2fAYfU)IuE}PffJEZQI+oL>499( z)^7Ct*Ka!8Iv@@DKIi)32k;s=?%oA$WQ33a%Wwfkj)ngkbFK{VLp4AG>h5BQb}1;o z;j>y08y4=70N!WtTb>JFzU1044$dwC!7tZ_(aTjw!4coRP2Y{ZW0DJ_TMK01(O>jH zJ^cOq_l*6&ug&{917wuQS4nB<`R)?dJ1stDNC=pXNTj1Z(ghA+VUa&o3;#o44! uZ_tRk87J1N{U3ePtM=;uPyX{8J)>#N6&`HMOFBg^Nl8vkwoKaC|NjDQ>o8CN literal 0 HcmV?d00001 From 2b042441d9ca6372486d01638d0b5fdbd724d6af Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 14:31:38 +0100 Subject: [PATCH 086/100] added experimental dialog into resolve's menu --- openpype/hosts/resolve/api/menu.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openpype/hosts/resolve/api/menu.py b/openpype/hosts/resolve/api/menu.py index 262ce739dd..0d5930d275 100644 --- a/openpype/hosts/resolve/api/menu.py +++ b/openpype/hosts/resolve/api/menu.py @@ -61,6 +61,9 @@ class OpenPypeMenu(QtWidgets.QWidget): inventory_btn = QtWidgets.QPushButton("Inventory ...", self) subsetm_btn = QtWidgets.QPushButton("Subset Manager ...", self) libload_btn = QtWidgets.QPushButton("Library ...", self) + experimental_btn = QtWidgets.QPushButton( + "Experimental tools ...", self + ) # rename_btn = QtWidgets.QPushButton("Rename", self) # set_colorspace_btn = QtWidgets.QPushButton( # "Set colorspace from presets", self @@ -91,6 +94,8 @@ class OpenPypeMenu(QtWidgets.QWidget): # layout.addWidget(set_colorspace_btn) # layout.addWidget(reset_resolution_btn) + layout.addWidget(Spacer(15, self)) + layout.addWidget(experimental_btn) self.setLayout(layout) @@ -104,6 +109,7 @@ class OpenPypeMenu(QtWidgets.QWidget): # rename_btn.clicked.connect(self.on_rename_clicked) # set_colorspace_btn.clicked.connect(self.on_set_colorspace_clicked) # reset_resolution_btn.clicked.connect(self.on_reset_resolution_clicked) + experimental_btn.clicked.connect(self.on_experimental_clicked) def on_workfile_clicked(self): print("Clicked Workfile") @@ -142,6 +148,9 @@ class OpenPypeMenu(QtWidgets.QWidget): def on_reset_resolution_clicked(self): print("Clicked Reset Resolution") + def on_experimental_clicked(self): + host_tools.show_experimental_tools_dialog() + def launch_pype_menu(): app = QtWidgets.QApplication(sys.argv) From f18f207f03b74a822ab1ab0d79f18e8a940ea7eb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 26 Nov 2021 16:27:53 +0100 Subject: [PATCH 087/100] Fix - provider icons are pulled from a folder --- openpype/tools/utils/lib.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index 4626e35a93..d38cb33029 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -477,6 +477,7 @@ def create_qthread(func, *args, **kwargs): def get_repre_icons(): + """Returns a dict {'provider_name': QIcon}""" try: from openpype_modules import sync_server except Exception: @@ -488,9 +489,17 @@ def get_repre_icons(): "providers", "resources" ) icons = {} - # TODO get from sync module - for provider in ['studio', 'local_drive', 'gdrive']: - pix_url = "{}/{}.png".format(resource_path, provider) + if not os.path.exists(resource_path): + print("No icons for Site Sync found") + return {} + + for file_name in os.listdir(resource_path): + if file_name and not file_name.endswith("png"): + continue + + provider, _ = os.path.splitext(file_name) + + pix_url = "{}{}{}".format(resource_path, os.path.sep, file_name) icons[provider] = QtGui.QIcon(pix_url) return icons From a1c6e1b031ddd01c96e9b2c0621e4b622a8d6808 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Fri, 26 Nov 2021 16:48:03 +0100 Subject: [PATCH 088/100] docs[website]: Homogenize collab and client logo display sizes --- website/src/css/custom.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 4f7f8396f6..0a72dc0f23 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -197,7 +197,7 @@ h5, h6 { font-weight: var(--ifm-font-weight-semibold); } } .showcase .client img { - max-height: 80px; + max-height: 70px; padding: 20px; max-width: 120px; align-self: center; @@ -215,10 +215,10 @@ h5, h6 { font-weight: var(--ifm-font-weight-semibold); } } .showcase .collab img { - max-height: 60px; + max-height: 70px; padding: 20px; align-self: center; - max-width: 200px; + max-width: 160px; } .showcase .pype_logo img{ From 216601a015ceda9def3d64eaefc803ea8280fa4b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 26 Nov 2021 17:52:59 +0100 Subject: [PATCH 089/100] Added basic documentation for new custom provider --- openpype/modules/default_modules/sync_server/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openpype/modules/default_modules/sync_server/README.md b/openpype/modules/default_modules/sync_server/README.md index d7d7f3718b..e283b3bb66 100644 --- a/openpype/modules/default_modules/sync_server/README.md +++ b/openpype/modules/default_modules/sync_server/README.md @@ -56,6 +56,13 @@ representation.files.sites: `db.getCollection('MY_PROJECT').update({type:"representation"}, {$set:{"files.$[].sites.MY_CONFIGURED_REMOTE_SITE" : {}}}, true, true)` +I want to create new custom provider: +----------------------------------- +- take `providers\abstract_provider.py` as a base class +- create provider class in `providers` with a name according to a provider (eg. 'gdrive.py' for gdrive provider etc.) +- upload provider icon in png format, 24x24, into `providers\resources`, its name must follow name of provider (eg. 'gdrive.png' for gdrive provider) +- register new provider into `providers.lib.py`, test how many files could be manipulated at same time, check provider's API for limits + Needed configuration: -------------------- `pype/settings/defaults/project_settings/global.json`.`sync_server`: From 06f23af879d6272123494cb040d57be469a4c786 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 26 Nov 2021 17:54:45 +0100 Subject: [PATCH 090/100] Better path creation --- openpype/tools/utils/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/tools/utils/lib.py b/openpype/tools/utils/lib.py index d38cb33029..8246d606b7 100644 --- a/openpype/tools/utils/lib.py +++ b/openpype/tools/utils/lib.py @@ -499,7 +499,7 @@ def get_repre_icons(): provider, _ = os.path.splitext(file_name) - pix_url = "{}{}{}".format(resource_path, os.path.sep, file_name) + pix_url = os.path.join(resource_path, file_name) icons[provider] = QtGui.QIcon(pix_url) return icons From 6785a054b7abe3d33b25cee9776c66bb3d08bb59 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 18:08:09 +0100 Subject: [PATCH 091/100] add message of raised exception to new exception --- openpype/plugins/publish/extract_review.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openpype/plugins/publish/extract_review.py b/openpype/plugins/publish/extract_review.py index ba6ef17072..3ab6ffd489 100644 --- a/openpype/plugins/publish/extract_review.py +++ b/openpype/plugins/publish/extract_review.py @@ -1010,10 +1010,11 @@ class ExtractReview(pyblish.api.InstancePlugin): streams = ffprobe_streams( full_input_path_single_file, self.log ) - except Exception: + except Exception as exc: raise AssertionError(( - "FFprobe couldn't read information about input file: \"{}\"" - ).format(full_input_path_single_file)) + "FFprobe couldn't read information about input file: \"{}\"." + " Error message: {}" + ).format(full_input_path_single_file, str(exc))) # Try to find first stream with defined 'width' and 'height' # - this is to avoid order of streams where audio can be as first From b306dfd8e947533b64a8cea54d6763981fafdba8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 26 Nov 2021 19:35:22 +0100 Subject: [PATCH 092/100] skip workfile instance linking if workfile instance is not available --- .../plugins/publish/integrate_inputlinks.py | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/openpype/plugins/publish/integrate_inputlinks.py b/openpype/plugins/publish/integrate_inputlinks.py index beefd8c05a..f973dfc963 100644 --- a/openpype/plugins/publish/integrate_inputlinks.py +++ b/openpype/plugins/publish/integrate_inputlinks.py @@ -55,23 +55,22 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin): if workfile is None: self.log.warn("No workfile in this publish session.") - return - - workfile_version_doc = workfile.data["versionEntity"] - # link all loaded versions in scene into workfile - for version in context.data.get("loadedVersions", []): - self.add_link( - link_type="reference", - input_id=version["version"], - version_doc=workfile_version_doc, - ) - # link workfile to all publishing versions - for instance in publishing: - self.add_link( - link_type="generative", - input_id=workfile_version_doc["_id"], - version_doc=instance.data["versionEntity"], - ) + else: + workfile_version_doc = workfile.data["versionEntity"] + # link all loaded versions in scene into workfile + for version in context.data.get("loadedVersions", []): + self.add_link( + link_type="reference", + input_id=version["version"], + version_doc=workfile_version_doc, + ) + # link workfile to all publishing versions + for instance in publishing: + self.add_link( + link_type="generative", + input_id=workfile_version_doc["_id"], + version_doc=instance.data["versionEntity"], + ) # link versions as dependencies to the instance for instance in publishing: @@ -82,7 +81,8 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin): version_doc=instance.data["versionEntity"], ) - publishing.append(workfile) + if workfile is not None: + publishing.append(workfile) self.write_links_to_database(publishing) def add_link(self, link_type, input_id, version_doc): From 13db498e91f5e83494261c6f38c02d896a9bf8d0 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 27 Nov 2021 03:40:43 +0000 Subject: [PATCH 093/100] [Automated] Bump version --- CHANGELOG.md | 47 ++++++++++++++++++++++++++------------------- openpype/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5c928273d..e9405ff759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,26 +1,48 @@ # Changelog -## [3.7.0-nightly.2](https://github.com/pypeclub/OpenPype/tree/HEAD) +## [3.7.0-nightly.3](https://github.com/pypeclub/OpenPype/tree/HEAD) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/3.6.4...HEAD) +### πŸ“– Documentation + +- docs\[website\]: Add Ellipse Studio \(logo\) as an OpenPype contributor [\#2324](https://github.com/pypeclub/OpenPype/pull/2324) + +**πŸ†• New features** + +- Store typed version dependencies for workfiles [\#2192](https://github.com/pypeclub/OpenPype/pull/2192) + **πŸš€ Enhancements** +- Hiero: Add experimental tools action [\#2323](https://github.com/pypeclub/OpenPype/pull/2323) +- Input links: Cleanup and unification of differences [\#2322](https://github.com/pypeclub/OpenPype/pull/2322) +- General: Run process log stderr as info log level [\#2309](https://github.com/pypeclub/OpenPype/pull/2309) +- Tools: Cleanup of unused classes [\#2304](https://github.com/pypeclub/OpenPype/pull/2304) +- Project Manager: Added ability to delete project [\#2298](https://github.com/pypeclub/OpenPype/pull/2298) - Ftrack: Synchronize input links [\#2287](https://github.com/pypeclub/OpenPype/pull/2287) - StandalonePublisher: Remove unused plugin ExtractHarmonyZip [\#2277](https://github.com/pypeclub/OpenPype/pull/2277) - Ftrack: Support multiple reviews [\#2271](https://github.com/pypeclub/OpenPype/pull/2271) - Ftrack: Remove unused clean component plugin [\#2269](https://github.com/pypeclub/OpenPype/pull/2269) -- Royal Render: Support for rr channels in separate dirs [\#2268](https://github.com/pypeclub/OpenPype/pull/2268) - Houdini: Add experimental tools action [\#2267](https://github.com/pypeclub/OpenPype/pull/2267) +- Tools: Assets widget [\#2265](https://github.com/pypeclub/OpenPype/pull/2265) +- Nuke: extract baked review videos presets [\#2248](https://github.com/pypeclub/OpenPype/pull/2248) +- TVPaint: Workers rendering [\#2209](https://github.com/pypeclub/OpenPype/pull/2209) **πŸ› Bug fixes** +- Fix - provider icons are pulled from a folder [\#2326](https://github.com/pypeclub/OpenPype/pull/2326) +- InputLinks: Typo in "inputLinks" key [\#2314](https://github.com/pypeclub/OpenPype/pull/2314) +- Deadline timeout and logging [\#2312](https://github.com/pypeclub/OpenPype/pull/2312) +- nuke: do not multiply representation on class method [\#2311](https://github.com/pypeclub/OpenPype/pull/2311) +- Workfiles tool: Fix task formatting [\#2306](https://github.com/pypeclub/OpenPype/pull/2306) +- Delivery: Fix delivery paths created on windows [\#2302](https://github.com/pypeclub/OpenPype/pull/2302) - Maya: Deadline - fix limit groups [\#2295](https://github.com/pypeclub/OpenPype/pull/2295) - New Publisher: Fix mapping of indexes [\#2285](https://github.com/pypeclub/OpenPype/pull/2285) - Alternate site for site sync doesnt work for sequences [\#2284](https://github.com/pypeclub/OpenPype/pull/2284) - FFmpeg: Execute ffprobe using list of arguments instead of string command [\#2281](https://github.com/pypeclub/OpenPype/pull/2281) - Nuke: Anatomy fill data use task as dictionary [\#2278](https://github.com/pypeclub/OpenPype/pull/2278) - Bug: fix variable name \_asset\_id in workfiles application [\#2274](https://github.com/pypeclub/OpenPype/pull/2274) +- Version handling fixes [\#2272](https://github.com/pypeclub/OpenPype/pull/2272) ## [3.6.4](https://github.com/pypeclub/OpenPype/tree/3.6.4) (2021-11-23) @@ -44,23 +66,22 @@ **πŸš€ Enhancements** -- Tools: Assets widget [\#2265](https://github.com/pypeclub/OpenPype/pull/2265) +- Royal Render: Support for rr channels in separate dirs [\#2268](https://github.com/pypeclub/OpenPype/pull/2268) - SceneInventory: Choose loader in asset switcher [\#2262](https://github.com/pypeclub/OpenPype/pull/2262) - Style: New fonts in OpenPype style [\#2256](https://github.com/pypeclub/OpenPype/pull/2256) - Tools: SceneInventory in OpenPype [\#2255](https://github.com/pypeclub/OpenPype/pull/2255) - Tools: Tasks widget [\#2251](https://github.com/pypeclub/OpenPype/pull/2251) -- Tools: Creator in OpenPype [\#2244](https://github.com/pypeclub/OpenPype/pull/2244) - Added endpoint for configured extensions [\#2221](https://github.com/pypeclub/OpenPype/pull/2221) **πŸ› Bug fixes** -- Version handling fixes [\#2272](https://github.com/pypeclub/OpenPype/pull/2272) - Tools: Parenting of tools in Nuke and Hiero [\#2266](https://github.com/pypeclub/OpenPype/pull/2266) - limiting validator to specific editorial hosts [\#2264](https://github.com/pypeclub/OpenPype/pull/2264) - Tools: Select Context dialog attribute fix [\#2261](https://github.com/pypeclub/OpenPype/pull/2261) - Maya: Render publishing fails on linux [\#2260](https://github.com/pypeclub/OpenPype/pull/2260) - LookAssigner: Fix tool reopen [\#2259](https://github.com/pypeclub/OpenPype/pull/2259) - Standalone: editorial not publishing thumbnails on all subsets [\#2258](https://github.com/pypeclub/OpenPype/pull/2258) +- Loader doesn't allow changing of version before loading [\#2254](https://github.com/pypeclub/OpenPype/pull/2254) - Burnins: Support mxf metadata [\#2247](https://github.com/pypeclub/OpenPype/pull/2247) - Maya: Support for configurable AOV separator characters [\#2197](https://github.com/pypeclub/OpenPype/pull/2197) - Maya: texture colorspace modes in looks [\#2195](https://github.com/pypeclub/OpenPype/pull/2195) @@ -69,10 +90,6 @@ [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.6.1-nightly.1...3.6.1) -**πŸ› Bug fixes** - -- Loader doesn't allow changing of version before loading [\#2254](https://github.com/pypeclub/OpenPype/pull/2254) - ## [3.6.0](https://github.com/pypeclub/OpenPype/tree/3.6.0) (2021-11-15) [Full Changelog](https://github.com/pypeclub/OpenPype/compare/CI/3.6.0-nightly.6...3.6.0) @@ -82,14 +99,9 @@ - Add alternative sites for Site Sync [\#2206](https://github.com/pypeclub/OpenPype/pull/2206) - Add command line way of running site sync server [\#2188](https://github.com/pypeclub/OpenPype/pull/2188) -**πŸ†• New features** - -- Add validate active site button to sync queue on a project [\#2176](https://github.com/pypeclub/OpenPype/pull/2176) -- Maya : Colorspace configuration [\#2170](https://github.com/pypeclub/OpenPype/pull/2170) -- Blender: Added support for audio [\#2168](https://github.com/pypeclub/OpenPype/pull/2168) - **πŸš€ Enhancements** +- Tools: Creator in OpenPype [\#2244](https://github.com/pypeclub/OpenPype/pull/2244) - Tools: Subset manager in OpenPype [\#2243](https://github.com/pypeclub/OpenPype/pull/2243) - General: Skip module directories without init file [\#2239](https://github.com/pypeclub/OpenPype/pull/2239) - General: Static interfaces [\#2238](https://github.com/pypeclub/OpenPype/pull/2238) @@ -109,8 +121,6 @@ - Delivery: Check 'frame' key in template for sequence delivery [\#2196](https://github.com/pypeclub/OpenPype/pull/2196) - Settings: Site sync project settings improvement [\#2193](https://github.com/pypeclub/OpenPype/pull/2193) - Usage of tools code [\#2185](https://github.com/pypeclub/OpenPype/pull/2185) -- Settings: Dictionary based on project roots [\#2184](https://github.com/pypeclub/OpenPype/pull/2184) -- Subset name: Be able to pass asset document to get subset name [\#2179](https://github.com/pypeclub/OpenPype/pull/2179) **πŸ› Bug fixes** @@ -126,9 +136,6 @@ - Tools: Workfiles tool don't use avalon widgets [\#2205](https://github.com/pypeclub/OpenPype/pull/2205) - Ftrack: Fill missing ftrack id on mongo project [\#2203](https://github.com/pypeclub/OpenPype/pull/2203) - Project Manager: Fix copying of tasks [\#2191](https://github.com/pypeclub/OpenPype/pull/2191) -- Blender: Fix trying to pack an image when the shader node has no texture [\#2183](https://github.com/pypeclub/OpenPype/pull/2183) -- Maya: review viewport settings [\#2177](https://github.com/pypeclub/OpenPype/pull/2177) -- Maya: Aspect ratio [\#2174](https://github.com/pypeclub/OpenPype/pull/2174) ## [3.5.0](https://github.com/pypeclub/OpenPype/tree/3.5.0) (2021-10-17) diff --git a/openpype/version.py b/openpype/version.py index 5e23fc2168..2e9592f57d 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.7.0-nightly.2" +__version__ = "3.7.0-nightly.3" diff --git a/pyproject.toml b/pyproject.toml index 8f42fd31a7..ac1d133561 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "OpenPype" -version = "3.7.0-nightly.2" # OpenPype +version = "3.7.0-nightly.3" # OpenPype description = "Open VFX and Animation pipeline with support." authors = ["OpenPype Team "] license = "MIT License" From cd410f4cd68d9fc1e74ea6710afc59ac38142cfd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 29 Nov 2021 10:24:11 +0100 Subject: [PATCH 094/100] fixing multiple templates at a hierarchy parent --- openpype/hosts/hiero/api/plugin.py | 38 +++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index c46ef9abfa..75d1c1b18f 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -6,6 +6,7 @@ from avalon.vendor import qargparse import avalon.api as avalon import openpype.api as openpype from . import lib +from copy import deepcopy log = openpype.Logger().get_logger(__name__) @@ -799,7 +800,8 @@ class PublishClip: # increasing steps by index of rename iteration self.count_steps *= self.rename_index - hierarchy_formating_data = dict() + hierarchy_formating_data = {} + hierarchy_data = deepcopy(self.hierarchy_data) _data = self.track_item_default_data.copy() if self.ui_inputs: # adding tag metadata from ui @@ -824,19 +826,19 @@ class PublishClip: _data.update({"shot": self.shot_num}) # solve # in test to pythonic expression - for _k, _v in self.hierarchy_data.items(): + for _k, _v in hierarchy_data.items(): if "#" not in _v["value"]: continue - self.hierarchy_data[ + hierarchy_data[ _k]["value"] = self._replace_hash_to_expression( _k, _v["value"]) # fill up pythonic expresisons in hierarchy data - for k, _v in self.hierarchy_data.items(): + for k, _v in hierarchy_data.items(): hierarchy_formating_data[k] = _v["value"].format(**_data) else: # if no gui mode then just pass default data - hierarchy_formating_data = self.hierarchy_data + hierarchy_formating_data = hierarchy_data tag_hierarchy_data = self._solve_tag_hierarchy_data( hierarchy_formating_data @@ -886,30 +888,38 @@ class PublishClip: "families": [self.data["family"]] } - def _convert_to_entity(self, key): + def _convert_to_entity(self, type, template): """ Converting input key to key with type. """ # convert to entity type - entity_type = self.types.get(key, None) + entity_type = self.types.get(type, None) assert entity_type, "Missing entity type for `{}`".format( - key + type ) + # first collect formating data to use for formating template + formating_data = {} + for _k, _v in self.hierarchy_data.items(): + value = _v["value"].format( + **self.track_item_default_data) + formating_data[_k] = value + return { "entity_type": entity_type, - "entity_name": self.hierarchy_data[key]["value"].format( - **self.track_item_default_data + "entity_name": template.format( + **formating_data ) } def _create_parents(self): """ Create parents and return it in list. """ - self.parents = list() + self.parents = [] patern = re.compile(self.parents_search_patern) - par_split = [patern.findall(t).pop() + + par_split = [(patern.findall(t).pop(), t) for t in self.hierarchy.split("/")] - for key in par_split: - parent = self._convert_to_entity(key) + for type, template in par_split: + parent = self._convert_to_entity(type, template) self.parents.append(parent) From a8def646fcf5f99f32c02fa838a14e305c0efce6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 29 Nov 2021 11:12:15 +0100 Subject: [PATCH 095/100] do not add preset name to outputName in representation also bring consistency to quotations --- openpype/hosts/nuke/api/plugin.py | 39 +++++++++++-------- .../publish/extract_review_data_mov.py | 10 ++++- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py index e53b97e297..82299dd354 100644 --- a/openpype/hosts/nuke/api/plugin.py +++ b/openpype/hosts/nuke/api/plugin.py @@ -27,7 +27,7 @@ class PypeCreator(PypeCreatorMixin, avalon.nuke.pipeline.Creator): self.data["subset"]): msg = ("The subset name `{0}` is already used on a node in" "this workfile.".format(self.data["subset"])) - self.log.error(msg + '\n\nPlease use other subset name!') + self.log.error(msg + "\n\nPlease use other subset name!") raise NameError("`{0}: {1}".format(__name__, msg)) return @@ -53,7 +53,7 @@ class NukeLoader(api.Loader): container_id = None def reset_container_id(self): - self.container_id = ''.join(random.choice( + self.container_id = "".join(random.choice( string.ascii_uppercase + string.digits) for _ in range(10)) def get_container_id(self, node): @@ -61,7 +61,7 @@ class NukeLoader(api.Loader): return id_knob.value() if id_knob else None def get_members(self, source): - """Return nodes that has same 'containerId' as `source`""" + """Return nodes that has same "containerId" as `source`""" source_id = self.get_container_id(source) return [node for node in nuke.allNodes(recurseGroups=True) if self.get_container_id(node) == source_id @@ -116,11 +116,13 @@ class ExporterReview(object): def __init__(self, klass, - instance + instance, + multiple_presets=True ): self.log = klass.log self.instance = instance + self.multiple_presets = multiple_presets self.path_in = self.instance.data.get("path", None) self.staging_dir = self.instance.data["stagingDir"] self.collection = self.instance.data.get("collection", None) @@ -152,12 +154,10 @@ class ExporterReview(object): def get_representation_data(self, tags=None, range=False): add_tags = tags or [] - repre = { - 'outputName': self.name, - 'name': self.name, - 'ext': self.ext, - 'files': self.file, + "name": self.name, + "ext": self.ext, + "files": self.file, "stagingDir": self.staging_dir, "tags": [self.name.replace("_", "-")] + add_tags } @@ -168,6 +168,9 @@ class ExporterReview(object): "frameEnd": self.last_frame, }) + if self.multiple_presets: + repre["outputName"] = self.name + self.data["representations"].append(repre) def get_view_input_process_node(self): @@ -183,19 +186,19 @@ class ExporterReview(object): anlib.reset_selection() ipn_orig = None for v in nuke.allNodes(filter="Viewer"): - ip = v['input_process'].getValue() - ipn = v['input_process_node'].getValue() + ip = v["input_process"].getValue() + ipn = v["input_process_node"].getValue() if "VIEWER_INPUT" not in ipn and ip: ipn_orig = nuke.toNode(ipn) ipn_orig.setSelected(True) if ipn_orig: # copy selected to clipboard - nuke.nodeCopy('%clipboard%') + nuke.nodeCopy("%clipboard%") # reset selection anlib.reset_selection() # paste node and selection is on it only - nuke.nodePaste('%clipboard%') + nuke.nodePaste("%clipboard%") # assign to variable ipn = nuke.selectedNode() @@ -234,9 +237,11 @@ class ExporterReviewLut(ExporterReview): ext=None, cube_size=None, lut_size=None, - lut_style=None): + lut_style=None, + multiple_presets=True): # initialize parent class - super(ExporterReviewLut, self).__init__(klass, instance) + super(ExporterReviewLut, self).__init__( + klass, instance, multiple_presets) # deal with now lut defined in viewer lut if hasattr(klass, "viewer_lut_raw"): @@ -349,9 +354,11 @@ class ExporterReviewMov(ExporterReview): instance, name=None, ext=None, + multiple_presets=True ): # initialize parent class - super(ExporterReviewMov, self).__init__(klass, instance) + super(ExporterReviewMov, self).__init__( + klass, instance, multiple_presets) # passing presets for nodes to self self.nodes = klass.nodes if hasattr(klass, "nodes") else {} diff --git a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py b/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py index b5890b5c51..261fca6583 100644 --- a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py +++ b/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py @@ -31,7 +31,7 @@ class ExtractReviewDataMov(openpype.api.Extractor): instance.data["representations"] = [] staging_dir = os.path.normpath( - os.path.dirname(instance.data['path'])) + os.path.dirname(instance.data["path"])) instance.data["stagingDir"] = staging_dir @@ -83,9 +83,15 @@ class ExtractReviewDataMov(openpype.api.Extractor): "Baking output `{}` with settings: {}".format( o_name, o_data)) + # check if settings have more then one preset + # so we dont need to add outputName to representation + # in case there is only one preset + multiple_presets = bool(len(self.outputs.keys()) > 1) + # create exporter instance exporter = plugin.ExporterReviewMov( - self, instance, o_name, o_data["extension"]) + self, instance, o_name, o_data["extension"], + multiple_presets) if "render.farm" in families: if "review" in instance.data["families"]: From 19b58d8597835ff67f05bb998b9420fc1a9dcac9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 29 Nov 2021 12:44:32 +0100 Subject: [PATCH 096/100] disable auto stop timer for linux platform --- .../modules/default_modules/timers_manager/timers_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/modules/default_modules/timers_manager/timers_manager.py b/openpype/modules/default_modules/timers_manager/timers_manager.py index 1aeccbb958..0f165ff0ac 100644 --- a/openpype/modules/default_modules/timers_manager/timers_manager.py +++ b/openpype/modules/default_modules/timers_manager/timers_manager.py @@ -95,8 +95,10 @@ class TimersManager(OpenPypeModule, ITrayService): message_time = int(timers_settings["message_time"] * 60) auto_stop = timers_settings["auto_stop"] + platform_name = platform.system().lower() # Turn of auto stop on MacOs because pynput requires root permissions - if platform.system().lower() == "darwin" or full_time <= 0: + # and on linux can cause thread locks on application close + if full_time <= 0 or platform_name in ("darwin", "linux"): auto_stop = False self.auto_stop = auto_stop From 12a6a528ca5a6fe874152cf1e908c41195d00600 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 29 Nov 2021 14:41:12 +0100 Subject: [PATCH 097/100] store site name to reuse it on reset --- openpype/lib/anatomy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/lib/anatomy.py b/openpype/lib/anatomy.py index aaf10479fd..8e69830fbd 100644 --- a/openpype/lib/anatomy.py +++ b/openpype/lib/anatomy.py @@ -91,6 +91,7 @@ class Anatomy: self._data = get_anatomy_settings(project_name, site_name) + self._site_name = site_name self._templates_obj = Templates(self) self._roots_obj = Roots(self) @@ -123,7 +124,7 @@ class Anatomy: def reset(self): """Reset values of cached data in templates and roots objects.""" - self._data = get_anatomy_settings(self.project_name) + self._data = get_anatomy_settings(self.project_name, self._site_name) self.templates_obj.reset() self.roots_obj.reset() From 7a5a0a51687bf833612552a2a392053a4f20a3ad Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 29 Nov 2021 14:41:48 +0100 Subject: [PATCH 098/100] added preparation method which replaces {task} with {task[name]} in templates --- openpype/lib/anatomy.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/openpype/lib/anatomy.py b/openpype/lib/anatomy.py index 8e69830fbd..a18a2a91d6 100644 --- a/openpype/lib/anatomy.py +++ b/openpype/lib/anatomy.py @@ -89,8 +89,9 @@ class Anatomy: self.project_name = project_name - self._data = get_anatomy_settings(project_name, site_name) - + self._data = self._prepare_anatomy_data( + get_anatomy_settings(project_name, site_name) + ) self._site_name = site_name self._templates_obj = Templates(self) self._roots_obj = Roots(self) @@ -122,9 +123,36 @@ class Anatomy: """ return get_default_anatomy_settings(clear_metadata=False) + @staticmethod + def _prepare_anatomy_data(anatomy_data): + """Prepare anatomy data for futher processing. + + Method added to replace `{task}` with `{task[name]}` in templates. + """ + templates_data = anatomy_data.get("templates") + if templates_data: + # Replace `{task}` with `{task[name]}` in templates + value_queue = collections.deque() + value_queue.append(templates_data) + while value_queue: + item = value_queue.popleft() + if not isinstance(item, dict): + continue + + for key in tuple(item.keys()): + value = item[key] + if isinstance(value, dict): + value_queue.append(value) + + elif isinstance(value, StringType): + item[key] = value.replace("{task}", "{task[name]}") + return anatomy_data + def reset(self): """Reset values of cached data in templates and roots objects.""" - self._data = get_anatomy_settings(self.project_name, self._site_name) + self._data = self._prepare_anatomy_data( + get_anatomy_settings(self.project_name, self._site_name) + ) self.templates_obj.reset() self.roots_obj.reset() From 6eecf8e7599b8f421ea484516fd863905740e719 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 29 Nov 2021 15:03:58 +0100 Subject: [PATCH 099/100] change task type before optional keys filling --- openpype/lib/anatomy.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/openpype/lib/anatomy.py b/openpype/lib/anatomy.py index a18a2a91d6..66ecbd66d1 100644 --- a/openpype/lib/anatomy.py +++ b/openpype/lib/anatomy.py @@ -1010,6 +1010,14 @@ class Templates: TemplateResult: Filled or partially filled template containing all data needed or missing for filling template. """ + task_data = data.get("task") + if ( + isinstance(task_data, StringType) + and "{task[name]}" in orig_template + ): + # Change task to dictionary if template expect dictionary + data["task"] = {"name": task_data} + template, missing_optional, invalid_optional = ( self._filter_optional(orig_template, data) ) @@ -1019,13 +1027,6 @@ class Templates: missing_required = [] replace_keys = [] - task_data = data.get("task") - if ( - isinstance(task_data, StringType) - and "{task[name]}" in orig_template - ): - data["task"] = {"name": task_data} - for group in self.key_pattern.findall(template): orig_key = group[1:-1] key = str(orig_key) From eb48fdbf01e5cddc30c75a82086ef0886ef214a4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 29 Nov 2021 15:17:06 +0100 Subject: [PATCH 100/100] removed not needed replacement of task in workfiles tool --- openpype/tools/workfiles/app.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/tools/workfiles/app.py b/openpype/tools/workfiles/app.py index 4f5e179d9b..a4b1717a1c 100644 --- a/openpype/tools/workfiles/app.py +++ b/openpype/tools/workfiles/app.py @@ -100,9 +100,7 @@ class NameWindow(QtWidgets.QDialog): # Store project anatomy self.anatomy = anatomy - self.template = anatomy.templates[template_key]["file"].replace( - "{task}", "{task[name]}" - ) + self.template = anatomy.templates[template_key]["file"] self.template_key = template_key # Btns widget