Merge branch 'refs/heads/develop' into bugfix/lighting_btns_font_size
171
pype/nuke/lib.py
|
|
@ -6,6 +6,7 @@ from collections import OrderedDict
|
|||
|
||||
from avalon import api, io, lib
|
||||
import avalon.nuke
|
||||
from avalon.nuke import lib as anlib
|
||||
import pype.api as pype
|
||||
|
||||
import nuke
|
||||
|
|
@ -1195,6 +1196,176 @@ class BuildWorkfile(WorkfileSettings):
|
|||
def position_up(self, multiply=1):
|
||||
self.ypos -= (self.ypos_size * multiply) + self.ypos_gap
|
||||
|
||||
|
||||
class Exporter_review_lut:
|
||||
"""
|
||||
Generator object for review lut from Nuke
|
||||
|
||||
Args:
|
||||
klass (pyblish.plugin): pyblish plugin parent
|
||||
|
||||
|
||||
"""
|
||||
_temp_nodes = []
|
||||
data = dict({
|
||||
"representations": list()
|
||||
})
|
||||
|
||||
def __init__(self,
|
||||
klass,
|
||||
instance,
|
||||
name=None,
|
||||
ext=None,
|
||||
cube_size=None,
|
||||
lut_size=None,
|
||||
lut_style=None):
|
||||
|
||||
self.log = klass.log
|
||||
self.instance = instance
|
||||
|
||||
self.name = name or "baked_lut"
|
||||
self.ext = ext or "cube"
|
||||
self.cube_size = cube_size or 32
|
||||
self.lut_size = lut_size or 1024
|
||||
self.lut_style = lut_style or "linear"
|
||||
|
||||
self.stagingDir = self.instance.data["stagingDir"]
|
||||
self.collection = self.instance.data.get("collection", None)
|
||||
|
||||
# set frame start / end and file name to self
|
||||
self.get_file_info()
|
||||
|
||||
self.log.info("File info was set...")
|
||||
|
||||
self.file = self.fhead + self.name + ".{}".format(self.ext)
|
||||
self.path = os.path.join(self.stagingDir, self.file).replace("\\", "/")
|
||||
|
||||
def generate_lut(self):
|
||||
# ---------- start nodes creation
|
||||
|
||||
# CMSTestPattern
|
||||
cms_node = nuke.createNode("CMSTestPattern")
|
||||
cms_node["cube_size"].setValue(self.cube_size)
|
||||
# connect
|
||||
self._temp_nodes.append(cms_node)
|
||||
self.previous_node = cms_node
|
||||
self.log.debug("CMSTestPattern... `{}`".format(self._temp_nodes))
|
||||
|
||||
# Node View Process
|
||||
ipn = self.get_view_process_node()
|
||||
if ipn is not None:
|
||||
# connect
|
||||
ipn.setInput(0, self.previous_node)
|
||||
self._temp_nodes.append(ipn)
|
||||
self.previous_node = ipn
|
||||
self.log.debug("ViewProcess... `{}`".format(self._temp_nodes))
|
||||
|
||||
# OCIODisplay
|
||||
dag_node = nuke.createNode("OCIODisplay")
|
||||
# connect
|
||||
dag_node.setInput(0, self.previous_node)
|
||||
self._temp_nodes.append(dag_node)
|
||||
self.previous_node = dag_node
|
||||
self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes))
|
||||
|
||||
# GenerateLUT
|
||||
gen_lut_node = nuke.createNode("GenerateLUT")
|
||||
gen_lut_node["file"].setValue(self.path)
|
||||
gen_lut_node["file_type"].setValue(".{}".format(self.ext))
|
||||
gen_lut_node["lut1d"].setValue(self.lut_size)
|
||||
gen_lut_node["style1d"].setValue(self.lut_style)
|
||||
# connect
|
||||
gen_lut_node.setInput(0, self.previous_node)
|
||||
self._temp_nodes.append(gen_lut_node)
|
||||
self.log.debug("GenerateLUT... `{}`".format(self._temp_nodes))
|
||||
|
||||
# ---------- end nodes creation
|
||||
|
||||
# Export lut file
|
||||
nuke.execute(
|
||||
gen_lut_node.name(),
|
||||
int(self.first_frame),
|
||||
int(self.first_frame))
|
||||
|
||||
self.log.info("Exported...")
|
||||
|
||||
# ---------- generate representation data
|
||||
self.get_representation_data()
|
||||
|
||||
self.log.debug("Representation... `{}`".format(self.data))
|
||||
|
||||
# ---------- Clean up
|
||||
for node in self._temp_nodes:
|
||||
nuke.delete(node)
|
||||
self.log.info("Deleted nodes...")
|
||||
|
||||
return self.data
|
||||
|
||||
def get_file_info(self):
|
||||
if self.collection:
|
||||
self.log.debug("Collection: `{}`".format(self.collection))
|
||||
# get path
|
||||
self.fname = os.path.basename(self.collection.format(
|
||||
"{head}{padding}{tail}"))
|
||||
self.fhead = self.collection.format("{head}")
|
||||
|
||||
# get first and last frame
|
||||
self.first_frame = min(self.collection.indexes)
|
||||
self.last_frame = max(self.collection.indexes)
|
||||
else:
|
||||
self.fname = os.path.basename(self.instance.data.get("path", None))
|
||||
self.fhead = os.path.splitext(self.fname)[0] + "."
|
||||
self.first_frame = self.instance.data.get("frameStart", None)
|
||||
self.last_frame = self.instance.data.get("frameEnd", None)
|
||||
|
||||
if "#" in self.fhead:
|
||||
self.fhead = self.fhead.replace("#", "")[:-1]
|
||||
|
||||
def get_representation_data(self):
|
||||
|
||||
repre = {
|
||||
'name': self.name,
|
||||
'ext': self.ext,
|
||||
'files': self.file,
|
||||
"stagingDir": self.stagingDir,
|
||||
"anatomy_template": "publish",
|
||||
"tags": [self.name.replace("_", "-")]
|
||||
}
|
||||
|
||||
self.data["representations"].append(repre)
|
||||
|
||||
def get_view_process_node(self):
|
||||
"""
|
||||
Will get any active view process.
|
||||
|
||||
Arguments:
|
||||
self (class): in object definition
|
||||
|
||||
Returns:
|
||||
nuke.Node: copy node of Input Process node
|
||||
"""
|
||||
anlib.reset_selection()
|
||||
ipn_orig = None
|
||||
for v in [n for n in nuke.allNodes()
|
||||
if "Viewer" in n.Class()]:
|
||||
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%')
|
||||
# reset selection
|
||||
anlib.reset_selection()
|
||||
# paste node and selection is on it only
|
||||
nuke.nodePaste('%clipboard%')
|
||||
# assign to variable
|
||||
ipn = nuke.selectedNode()
|
||||
|
||||
return ipn
|
||||
|
||||
def get_dependent_nodes(nodes):
|
||||
"""Get all dependent nodes connected to the list of nodes.
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
label = "RenderedFrames"
|
||||
|
||||
def process(self, context):
|
||||
pixel_aspect = 1
|
||||
lut_path = None
|
||||
if os.environ.get("PYPE_PUBLISH_PATHS"):
|
||||
paths = os.environ["PYPE_PUBLISH_PATHS"].split(os.pathsep)
|
||||
self.log.info("Collecting paths: {}".format(paths))
|
||||
|
|
@ -144,6 +146,12 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
self.log.info("setting session using metadata")
|
||||
api.Session.update(session)
|
||||
os.environ.update(session)
|
||||
instance = metadata.get("instance")
|
||||
if instance:
|
||||
instance_family = instance.get("family")
|
||||
pixel_aspect = instance.get("pixelAspect", 1)
|
||||
lut_path = instance.get("lutPath", None)
|
||||
|
||||
|
||||
else:
|
||||
# Search in directory
|
||||
|
|
@ -181,6 +189,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
families.append("ftrack")
|
||||
if "review" not in families:
|
||||
families.append("review")
|
||||
if "write" in instance_family:
|
||||
families.append("write")
|
||||
|
||||
for collection in collections:
|
||||
instance = context.create_instance(str(collection))
|
||||
|
|
@ -197,6 +207,11 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
start = data.get("frameStart", indices[0])
|
||||
end = data.get("frameEnd", indices[-1])
|
||||
|
||||
self.log.debug("Collected pixel_aspect:\n"
|
||||
"{}".format(pixel_aspect))
|
||||
self.log.debug("type pixel_aspect:\n"
|
||||
"{}".format(type(pixel_aspect)))
|
||||
|
||||
# root = os.path.normpath(root)
|
||||
# self.log.info("Source: {}}".format(data.get("source", "")))
|
||||
|
||||
|
|
@ -212,8 +227,11 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin):
|
|||
"frameStart": start,
|
||||
"frameEnd": end,
|
||||
"fps": fps,
|
||||
"source": data.get('source', '')
|
||||
"source": data.get('source', ''),
|
||||
"pixelAspect": pixel_aspect,
|
||||
})
|
||||
if lut_path:
|
||||
instance.data.update({"lutPath": lut_path})
|
||||
instance.append(collection)
|
||||
instance.context.data['fps'] = fps
|
||||
|
||||
|
|
|
|||
|
|
@ -85,3 +85,6 @@ class CollectTemplates(pyblish.api.InstancePlugin):
|
|||
instance.data["assumedDestination"] = os.path.dirname(
|
||||
(anatomy.format(template_data))["publish"]["path"]
|
||||
)
|
||||
self.log.info("Assumed Destination has been created...")
|
||||
self.log.debug("__ assumedTemplateData: `{}`".format(instance.data["assumedTemplateData"]))
|
||||
self.log.debug("__ template: `{}`".format(instance.data["template"]))
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import os
|
||||
|
||||
import math
|
||||
import pyblish.api
|
||||
import clique
|
||||
import pype.api
|
||||
from pypeapp import config
|
||||
|
||||
|
||||
class ExtractReview(pyblish.api.InstancePlugin):
|
||||
|
|
@ -22,16 +21,19 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
families = ["review"]
|
||||
hosts = ["nuke", "maya", "shell"]
|
||||
|
||||
outputs = {}
|
||||
ext_filter = []
|
||||
|
||||
def process(self, instance):
|
||||
# adding plugin attributes from presets
|
||||
publish_presets = config.get_presets()["plugins"]["global"]["publish"]
|
||||
plugin_attrs = publish_presets[self.__class__.__name__]
|
||||
output_profiles = plugin_attrs.get("outputs", {})
|
||||
|
||||
output_profiles = self.outputs or {}
|
||||
|
||||
inst_data = instance.data
|
||||
fps = inst_data.get("fps")
|
||||
start_frame = inst_data.get("frameStart")
|
||||
|
||||
resolution_height = instance.data.get("resolutionHeight", 1080)
|
||||
resolution_width = instance.data.get("resolutionWidth", 1920)
|
||||
pixel_aspect = instance.data.get("pixelAspect", 1)
|
||||
self.log.debug("Families In: `{}`".format(instance.data["families"]))
|
||||
|
||||
# get representation and loop them
|
||||
|
|
@ -40,7 +42,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
# filter out mov and img sequences
|
||||
representations_new = representations[:]
|
||||
for repre in representations:
|
||||
if repre['ext'] in plugin_attrs["ext_filter"]:
|
||||
if repre['ext'] in self.ext_filter:
|
||||
tags = repre.get("tags", [])
|
||||
|
||||
self.log.info("Try repre: {}".format(repre))
|
||||
|
|
@ -92,8 +94,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
self.log.info("p_tags: `{}`".format(p_tags))
|
||||
# add families
|
||||
[instance.data["families"].append(t)
|
||||
for t in p_tags
|
||||
if t not in instance.data["families"]]
|
||||
for t in p_tags
|
||||
if t not in instance.data["families"]]
|
||||
|
||||
# add to
|
||||
[new_tags.append(t) for t in p_tags
|
||||
if t not in new_tags]
|
||||
|
|
@ -147,14 +150,16 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
)
|
||||
|
||||
output_args = []
|
||||
output_args.extend(profile.get('codec', []))
|
||||
codec_args = profile.get('codec', [])
|
||||
output_args.extend(codec_args)
|
||||
# preset's output data
|
||||
output_args.extend(profile.get('output', []))
|
||||
|
||||
# letter_box
|
||||
# TODO: add to documentation
|
||||
lb = profile.get('letter_box', None)
|
||||
if lb:
|
||||
lb = profile.get('letter_box', 0)
|
||||
if lb is not 0:
|
||||
if "reformat" not in p_tags:
|
||||
lb /= pixel_aspect
|
||||
output_args.append(
|
||||
"-filter:v drawbox=0:0:iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black,drawbox=0:ih-round((ih-(iw*(1/{0})))/2):iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black".format(lb))
|
||||
|
||||
|
|
@ -163,6 +168,65 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
# output filename
|
||||
output_args.append(full_output_path)
|
||||
|
||||
self.log.debug("__ pixel_aspect: `{}`".format(pixel_aspect))
|
||||
self.log.debug("__ resolution_width: `{}`".format(resolution_width))
|
||||
self.log.debug("__ resolution_height: `{}`".format(resolution_height))
|
||||
# scaling none square pixels and 1920 width
|
||||
if "reformat" in p_tags:
|
||||
width_scale = 1920
|
||||
width_half_pad = 0
|
||||
res_w = int(float(resolution_width) * pixel_aspect)
|
||||
height_half_pad = int((
|
||||
(res_w - 1920) / (
|
||||
res_w * .01) * (
|
||||
1080 * .01)) / 2
|
||||
)
|
||||
height_scale = 1080 - (height_half_pad * 2)
|
||||
if height_scale > 1080:
|
||||
height_half_pad = 0
|
||||
height_scale = 1080
|
||||
width_half_pad = (1920 - (float(resolution_width) * (1080 / float(resolution_height))) ) / 2
|
||||
width_scale = int(1920 - (width_half_pad * 2))
|
||||
|
||||
self.log.debug("__ width_scale: `{}`".format(width_scale))
|
||||
self.log.debug("__ width_half_pad: `{}`".format(width_half_pad))
|
||||
self.log.debug("__ height_scale: `{}`".format(height_scale))
|
||||
self.log.debug("__ height_half_pad: `{}`".format(height_half_pad))
|
||||
|
||||
|
||||
scaling_arg = "scale={0}x{1}:flags=lanczos,pad=1920:1080:{2}:{3}:black,setsar=1".format(
|
||||
width_scale, height_scale, width_half_pad, height_half_pad
|
||||
)
|
||||
|
||||
vf_back = self.add_video_filter_args(
|
||||
output_args, scaling_arg)
|
||||
# add it to output_args
|
||||
output_args.insert(0, vf_back)
|
||||
|
||||
# baking lut file application
|
||||
lut_path = instance.data.get("lutPath")
|
||||
if lut_path and ("bake-lut" in p_tags):
|
||||
# removing Gama info as it is all baked in lut
|
||||
gamma = next((g for g in input_args
|
||||
if "-gamma" in g), None)
|
||||
if gamma:
|
||||
input_args.remove(gamma)
|
||||
|
||||
# create lut argument
|
||||
lut_arg = "lut3d=file='{}'".format(
|
||||
lut_path.replace(
|
||||
"\\", "/").replace(":/", "\\:/")
|
||||
)
|
||||
lut_arg += ",colormatrix=bt601:bt709"
|
||||
|
||||
vf_back = self.add_video_filter_args(
|
||||
output_args, lut_arg)
|
||||
# add it to output_args
|
||||
output_args.insert(0, vf_back)
|
||||
self.log.info("Added Lut to ffmpeg command")
|
||||
self.log.debug("_ output_args: `{}`".format(output_args))
|
||||
|
||||
mov_args = [
|
||||
os.path.join(
|
||||
os.environ.get(
|
||||
|
|
@ -185,7 +249,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
'files': repr_file,
|
||||
"tags": new_tags,
|
||||
"outputName": name,
|
||||
"codec": profile.get('codec', [])
|
||||
"codec": codec_args
|
||||
})
|
||||
if repre_new.get('preview'):
|
||||
repre_new.pop("preview")
|
||||
|
|
@ -209,3 +273,40 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
instance.data["representations"] = representations_new
|
||||
|
||||
self.log.debug("Families Out: `{}`".format(instance.data["families"]))
|
||||
|
||||
def add_video_filter_args(self, args, inserting_arg):
|
||||
"""
|
||||
Fixing video filter argumets to be one long string
|
||||
|
||||
Args:
|
||||
args (list): list of string arguments
|
||||
inserting_arg (str): string argument we want to add
|
||||
(without flag `-vf`)
|
||||
|
||||
Returns:
|
||||
str: long joined argument to be added back to list of arguments
|
||||
|
||||
"""
|
||||
# find all video format settings
|
||||
vf_settings = [p for p in args
|
||||
for v in ["-filter:v", "-vf"]
|
||||
if v in p]
|
||||
self.log.debug("_ vf_settings: `{}`".format(vf_settings))
|
||||
|
||||
# remove them from output args list
|
||||
for p in vf_settings:
|
||||
self.log.debug("_ remove p: `{}`".format(p))
|
||||
args.remove(p)
|
||||
self.log.debug("_ args: `{}`".format(args))
|
||||
|
||||
# strip them from all flags
|
||||
vf_fixed = [p.replace("-vf ", "").replace("-filter:v ", "")
|
||||
for p in vf_settings]
|
||||
|
||||
self.log.debug("_ vf_fixed: `{}`".format(vf_fixed))
|
||||
vf_fixed.insert(0, inserting_arg)
|
||||
self.log.debug("_ vf_fixed: `{}`".format(vf_fixed))
|
||||
# create new video filter setting
|
||||
vf_back = "-vf " + ",".join(vf_fixed)
|
||||
|
||||
return vf_back
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
}
|
||||
|
||||
if sequence_repre and repre.get("frameStart"):
|
||||
representation['context']['frame'] = src_padding_exp % repre.get("frameStart")
|
||||
representation['context']['frame'] = src_padding_exp % int(repre.get("frameStart"))
|
||||
|
||||
self.log.debug("__ representation: {}".format(representation))
|
||||
destination_list.append(dst)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class ValidateFfmpegInstallef(pyblish.api.Validator):
|
|||
return True
|
||||
|
||||
def process(self, instance):
|
||||
self.log.info("ffmpeg path: `{}`".format(
|
||||
os.environ.get("FFMPEG_PATH", "")))
|
||||
if self.is_tool(
|
||||
os.path.join(
|
||||
os.environ.get("FFMPEG_PATH", ""), "ffmpeg")) is False:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
self.log.debug("asset_data: {}".format(asset_data["data"]))
|
||||
instances = []
|
||||
|
||||
root = nuke.root()
|
||||
|
||||
self.log.debug("nuke.allNodes(): {}".format(nuke.allNodes()))
|
||||
for node in nuke.allNodes():
|
||||
|
||||
|
|
@ -34,7 +36,7 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
|
||||
# get data from avalon knob
|
||||
self.log.debug("node[name]: {}".format(node['name'].value()))
|
||||
avalon_knob_data = get_avalon_knob_data(node)
|
||||
avalon_knob_data = get_avalon_knob_data(node, ["avalon:", "ak:"])
|
||||
|
||||
self.log.debug("avalon_knob_data: {}".format(avalon_knob_data))
|
||||
|
||||
|
|
@ -86,6 +88,12 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
family = avalon_knob_data["family"]
|
||||
families = [avalon_knob_data["families"]]
|
||||
|
||||
# Get format
|
||||
format = root['format'].value()
|
||||
resolution_width = format.width()
|
||||
resolution_height = format.height()
|
||||
pixel_aspect = format.pixelAspect()
|
||||
|
||||
if node.Class() not in "Read":
|
||||
if node["render"].value():
|
||||
self.log.info("flagged for render")
|
||||
|
|
@ -111,7 +119,10 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
"avalonKnob": avalon_knob_data,
|
||||
"publish": node.knob('publish').value(),
|
||||
"step": 1,
|
||||
"fps": nuke.root()['fps'].value()
|
||||
"fps": nuke.root()['fps'].value(),
|
||||
"resolutionWidth": resolution_width,
|
||||
"resolutionHeight": resolution_height,
|
||||
"pixelAspect": pixel_aspect,
|
||||
|
||||
})
|
||||
|
||||
|
|
@ -119,5 +130,4 @@ class CollectNukeInstances(pyblish.api.ContextPlugin):
|
|||
instances.append(instance)
|
||||
|
||||
context.data["instances"] = instances
|
||||
|
||||
self.log.debug("context: {}".format(context))
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
|
|||
}
|
||||
|
||||
try:
|
||||
collected_frames = os.listdir(output_dir)
|
||||
collected_frames = [f for f in os.listdir(output_dir)
|
||||
if ext in f]
|
||||
if collected_frames:
|
||||
representation['frameStart'] = "%0{}d".format(
|
||||
len(str(last_frame))) % first_frame
|
||||
|
|
@ -99,7 +100,7 @@ class CollectNukeWrites(pyblish.api.InstancePlugin):
|
|||
"subset": instance.data["subset"],
|
||||
"fps": instance.context.data["fps"]
|
||||
}
|
||||
|
||||
instance.data["family"] = "write"
|
||||
group_node = [x for x in instance if x.Class() == "Group"][0]
|
||||
deadlineChunkSize = 1
|
||||
if "deadlineChunkSize" in group_node.knobs():
|
||||
|
|
|
|||
|
|
@ -1,187 +0,0 @@
|
|||
import os
|
||||
import nuke
|
||||
import pyblish.api
|
||||
import pype
|
||||
|
||||
class ExtractReviewData(pype.api.Extractor):
|
||||
"""Extracts movie and thumbnail with baked in luts
|
||||
|
||||
must be run after extract_render_local.py
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.01
|
||||
label = "Extract Review Data"
|
||||
|
||||
families = ["review"]
|
||||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
# Store selection
|
||||
selection = [i for i in nuke.allNodes() if i["selected"].getValue()]
|
||||
# Deselect all nodes to prevent external connections
|
||||
[i["selected"].setValue(False) for i in nuke.allNodes()]
|
||||
self.log.debug("creating staging dir:")
|
||||
self.staging_dir(instance)
|
||||
|
||||
self.log.debug("instance: {}".format(instance))
|
||||
self.log.debug("instance.data[families]: {}".format(
|
||||
instance.data["families"]))
|
||||
|
||||
if "still" not in instance.data["families"]:
|
||||
self.render_review_representation(instance,
|
||||
representation="mov")
|
||||
self.render_review_representation(instance,
|
||||
representation="jpeg")
|
||||
else:
|
||||
self.render_review_representation(instance, representation="jpeg")
|
||||
|
||||
# Restore selection
|
||||
[i["selected"].setValue(False) for i in nuke.allNodes()]
|
||||
[i["selected"].setValue(True) for i in selection]
|
||||
|
||||
def render_review_representation(self,
|
||||
instance,
|
||||
representation="mov"):
|
||||
|
||||
assert instance.data['representations'][0]['files'], "Instance data files should't be empty!"
|
||||
|
||||
temporary_nodes = []
|
||||
stagingDir = instance.data[
|
||||
'representations'][0]["stagingDir"].replace("\\", "/")
|
||||
self.log.debug("StagingDir `{0}`...".format(stagingDir))
|
||||
|
||||
collection = instance.data.get("collection", None)
|
||||
|
||||
if collection:
|
||||
# get path
|
||||
fname = os.path.basename(collection.format(
|
||||
"{head}{padding}{tail}"))
|
||||
fhead = collection.format("{head}")
|
||||
|
||||
# get first and last frame
|
||||
first_frame = min(collection.indexes)
|
||||
last_frame = max(collection.indexes)
|
||||
else:
|
||||
fname = os.path.basename(instance.data.get("path", None))
|
||||
fhead = os.path.splitext(fname)[0] + "."
|
||||
first_frame = instance.data.get("frameStart", None)
|
||||
last_frame = instance.data.get("frameEnd", None)
|
||||
|
||||
rnode = nuke.createNode("Read")
|
||||
|
||||
rnode["file"].setValue(
|
||||
os.path.join(stagingDir, fname).replace("\\", "/"))
|
||||
|
||||
rnode["first"].setValue(first_frame)
|
||||
rnode["origfirst"].setValue(first_frame)
|
||||
rnode["last"].setValue(last_frame)
|
||||
rnode["origlast"].setValue(last_frame)
|
||||
temporary_nodes.append(rnode)
|
||||
previous_node = rnode
|
||||
|
||||
# get input process and connect it to baking
|
||||
ipn = self.get_view_process_node()
|
||||
if ipn is not None:
|
||||
ipn.setInput(0, previous_node)
|
||||
previous_node = ipn
|
||||
temporary_nodes.append(ipn)
|
||||
|
||||
reformat_node = nuke.createNode("Reformat")
|
||||
|
||||
ref_node = self.nodes.get("Reformat", None)
|
||||
if ref_node:
|
||||
for k, v in ref_node:
|
||||
self.log.debug("k,v: {0}:{1}".format(k,v))
|
||||
if isinstance(v, unicode):
|
||||
v = str(v)
|
||||
reformat_node[k].setValue(v)
|
||||
|
||||
reformat_node.setInput(0, previous_node)
|
||||
previous_node = reformat_node
|
||||
temporary_nodes.append(reformat_node)
|
||||
|
||||
dag_node = nuke.createNode("OCIODisplay")
|
||||
dag_node.setInput(0, previous_node)
|
||||
previous_node = dag_node
|
||||
temporary_nodes.append(dag_node)
|
||||
|
||||
# create write node
|
||||
write_node = nuke.createNode("Write")
|
||||
|
||||
if representation in "mov":
|
||||
file = fhead + "baked.mov"
|
||||
name = "baked"
|
||||
path = os.path.join(stagingDir, file).replace("\\", "/")
|
||||
self.log.debug("Path: {}".format(path))
|
||||
instance.data["baked_colorspace_movie"] = path
|
||||
write_node["file"].setValue(path)
|
||||
write_node["file_type"].setValue("mov")
|
||||
write_node["raw"].setValue(1)
|
||||
write_node.setInput(0, previous_node)
|
||||
temporary_nodes.append(write_node)
|
||||
tags = ["review", "delete"]
|
||||
|
||||
elif representation in "jpeg":
|
||||
file = fhead + "jpeg"
|
||||
name = "thumbnail"
|
||||
path = os.path.join(stagingDir, file).replace("\\", "/")
|
||||
instance.data["thumbnail"] = path
|
||||
write_node["file"].setValue(path)
|
||||
write_node["file_type"].setValue("jpeg")
|
||||
write_node["raw"].setValue(1)
|
||||
write_node.setInput(0, previous_node)
|
||||
temporary_nodes.append(write_node)
|
||||
tags = ["thumbnail"]
|
||||
|
||||
# retime for
|
||||
first_frame = int(last_frame) / 2
|
||||
last_frame = int(last_frame) / 2
|
||||
|
||||
repre = {
|
||||
'name': name,
|
||||
'ext': representation,
|
||||
'files': file,
|
||||
"stagingDir": stagingDir,
|
||||
"frameStart": first_frame,
|
||||
"frameEnd": last_frame,
|
||||
"anatomy_template": "render",
|
||||
"tags": tags
|
||||
}
|
||||
instance.data["representations"].append(repre)
|
||||
|
||||
# Render frames
|
||||
nuke.execute(write_node.name(), int(first_frame), int(last_frame))
|
||||
|
||||
self.log.debug("representations: {}".format(instance.data["representations"]))
|
||||
|
||||
# Clean up
|
||||
for node in temporary_nodes:
|
||||
nuke.delete(node)
|
||||
|
||||
def get_view_process_node(self):
|
||||
|
||||
# Select only the target node
|
||||
if nuke.selectedNodes():
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()]
|
||||
|
||||
ipn_orig = None
|
||||
for v in [n for n in nuke.allNodes()
|
||||
if "Viewer" in n.Class()]:
|
||||
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:
|
||||
nuke.nodeCopy('%clipboard%')
|
||||
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()] # Deselect all
|
||||
|
||||
nuke.nodePaste('%clipboard%')
|
||||
|
||||
ipn = nuke.selectedNode()
|
||||
|
||||
return ipn
|
||||
58
pype/plugins/nuke/publish/extract_review_data_lut.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
from avalon.nuke import lib as anlib
|
||||
from pype.nuke import lib as pnlib
|
||||
import pype
|
||||
reload(pnlib)
|
||||
|
||||
|
||||
class ExtractReviewLutData(pype.api.Extractor):
|
||||
"""Extracts movie and thumbnail with baked in luts
|
||||
|
||||
must be run after extract_render_local.py
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.005
|
||||
label = "Extract Review Data Lut"
|
||||
|
||||
families = ["review"]
|
||||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
families = instance.data["families"]
|
||||
self.log.info("Creating staging dir...")
|
||||
if "representations" in instance.data:
|
||||
staging_dir = instance.data[
|
||||
"representations"][0]["stagingDir"].replace("\\", "/")
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
instance.data["representations"][0]["tags"] = ["review"]
|
||||
else:
|
||||
instance.data["representations"] = []
|
||||
# get output path
|
||||
render_path = instance.data['path']
|
||||
staging_dir = os.path.normpath(os.path.dirname(render_path))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
self.log.info(
|
||||
"StagingDir `{0}`...".format(instance.data["stagingDir"]))
|
||||
|
||||
with anlib.maintained_selection():
|
||||
exporter = pnlib.Exporter_review_lut(
|
||||
self, instance
|
||||
)
|
||||
data = exporter.generate_lut()
|
||||
|
||||
# assign to representations
|
||||
instance.data["lutPath"] = os.path.join(
|
||||
exporter.stagingDir, exporter.file).replace("\\", "/")
|
||||
instance.data["representations"] += data["representations"]
|
||||
|
||||
if "render.farm" in families:
|
||||
instance.data["families"].remove("review")
|
||||
instance.data["families"].remove("ftrack")
|
||||
|
||||
self.log.debug(
|
||||
"_ lutPath: {}".format(instance.data["lutPath"]))
|
||||
self.log.debug(
|
||||
"_ representations: {}".format(instance.data["representations"]))
|
||||
174
pype/plugins/nuke/publish/extract_thumbnail.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
import os
|
||||
import nuke
|
||||
from avalon.nuke import lib as anlib
|
||||
import pyblish.api
|
||||
import pype
|
||||
|
||||
|
||||
class ExtractThumbnail(pype.api.Extractor):
|
||||
"""Extracts movie and thumbnail with baked in luts
|
||||
|
||||
must be run after extract_render_local.py
|
||||
|
||||
"""
|
||||
|
||||
order = pyblish.api.ExtractorOrder + 0.01
|
||||
label = "Extract Thumbnail"
|
||||
|
||||
families = ["review", "render.farm"]
|
||||
hosts = ["nuke"]
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
with anlib.maintained_selection():
|
||||
self.log.debug("instance: {}".format(instance))
|
||||
self.log.debug("instance.data[families]: {}".format(
|
||||
instance.data["families"]))
|
||||
|
||||
self.render_thumbnail(instance)
|
||||
|
||||
def render_thumbnail(self, instance):
|
||||
node = instance[0] # group node
|
||||
self.log.info("Creating staging dir...")
|
||||
if "representations" in instance.data:
|
||||
staging_dir = instance.data[
|
||||
"representations"][0]["stagingDir"].replace("\\", "/")
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
instance.data["representations"][0]["tags"] = ["review"]
|
||||
else:
|
||||
instance.data["representations"] = []
|
||||
# get output path
|
||||
render_path = instance.data['path']
|
||||
staging_dir = os.path.normpath(os.path.dirname(render_path))
|
||||
instance.data["stagingDir"] = staging_dir
|
||||
|
||||
self.log.info(
|
||||
"StagingDir `{0}`...".format(instance.data["stagingDir"]))
|
||||
|
||||
temporary_nodes = []
|
||||
collection = instance.data.get("collection", None)
|
||||
|
||||
if collection:
|
||||
# get path
|
||||
fname = os.path.basename(collection.format(
|
||||
"{head}{padding}{tail}"))
|
||||
fhead = collection.format("{head}")
|
||||
|
||||
# get first and last frame
|
||||
first_frame = min(collection.indexes)
|
||||
last_frame = max(collection.indexes)
|
||||
else:
|
||||
fname = os.path.basename(instance.data.get("path", None))
|
||||
fhead = os.path.splitext(fname)[0] + "."
|
||||
first_frame = instance.data.get("frameStart", None)
|
||||
last_frame = instance.data.get("frameEnd", None)
|
||||
|
||||
if "#" in fhead:
|
||||
fhead = fhead.replace("#", "")[:-1]
|
||||
|
||||
path_render = os.path.join(staging_dir, fname).replace("\\", "/")
|
||||
# check if file exist otherwise connect to write node
|
||||
if os.path.isfile(path_render):
|
||||
rnode = nuke.createNode("Read")
|
||||
|
||||
rnode["file"].setValue(path_render)
|
||||
|
||||
rnode["first"].setValue(first_frame)
|
||||
rnode["origfirst"].setValue(first_frame)
|
||||
rnode["last"].setValue(last_frame)
|
||||
rnode["origlast"].setValue(last_frame)
|
||||
temporary_nodes.append(rnode)
|
||||
previous_node = rnode
|
||||
else:
|
||||
previous_node = node
|
||||
|
||||
# get input process and connect it to baking
|
||||
ipn = self.get_view_process_node()
|
||||
if ipn is not None:
|
||||
ipn.setInput(0, previous_node)
|
||||
previous_node = ipn
|
||||
temporary_nodes.append(ipn)
|
||||
|
||||
reformat_node = nuke.createNode("Reformat")
|
||||
|
||||
ref_node = self.nodes.get("Reformat", None)
|
||||
if ref_node:
|
||||
for k, v in ref_node:
|
||||
self.log.debug("k, v: {0}:{1}".format(k, v))
|
||||
if isinstance(v, unicode):
|
||||
v = str(v)
|
||||
reformat_node[k].setValue(v)
|
||||
|
||||
reformat_node.setInput(0, previous_node)
|
||||
previous_node = reformat_node
|
||||
temporary_nodes.append(reformat_node)
|
||||
|
||||
dag_node = nuke.createNode("OCIODisplay")
|
||||
dag_node.setInput(0, previous_node)
|
||||
previous_node = dag_node
|
||||
temporary_nodes.append(dag_node)
|
||||
|
||||
# create write node
|
||||
write_node = nuke.createNode("Write")
|
||||
file = fhead + "jpeg"
|
||||
name = "thumbnail"
|
||||
path = os.path.join(staging_dir, file).replace("\\", "/")
|
||||
instance.data["thumbnail"] = path
|
||||
write_node["file"].setValue(path)
|
||||
write_node["file_type"].setValue("jpeg")
|
||||
write_node["raw"].setValue(1)
|
||||
write_node.setInput(0, previous_node)
|
||||
temporary_nodes.append(write_node)
|
||||
tags = ["thumbnail"]
|
||||
|
||||
# retime for
|
||||
first_frame = int(last_frame) / 2
|
||||
last_frame = int(last_frame) / 2
|
||||
|
||||
repre = {
|
||||
'name': name,
|
||||
'ext': "jpeg",
|
||||
'files': file,
|
||||
"stagingDir": staging_dir,
|
||||
"frameStart": first_frame,
|
||||
"frameEnd": last_frame,
|
||||
"anatomy_template": "render",
|
||||
"tags": tags
|
||||
}
|
||||
instance.data["representations"].append(repre)
|
||||
|
||||
# Render frames
|
||||
nuke.execute(write_node.name(), int(first_frame), int(last_frame))
|
||||
|
||||
self.log.debug(
|
||||
"representations: {}".format(instance.data["representations"]))
|
||||
|
||||
# Clean up
|
||||
for node in temporary_nodes:
|
||||
nuke.delete(node)
|
||||
|
||||
def get_view_process_node(self):
|
||||
|
||||
# Select only the target node
|
||||
if nuke.selectedNodes():
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()]
|
||||
|
||||
ipn_orig = None
|
||||
for v in [n for n in nuke.allNodes()
|
||||
if "Viewer" in n.Class()]:
|
||||
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:
|
||||
nuke.nodeCopy('%clipboard%')
|
||||
|
||||
[n.setSelected(False) for n in nuke.selectedNodes()] # Deselect all
|
||||
|
||||
nuke.nodePaste('%clipboard%')
|
||||
|
||||
ipn = nuke.selectedNode()
|
||||
|
||||
return ipn
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
import os
|
||||
import json
|
||||
import getpass
|
||||
|
||||
import nuke
|
||||
|
||||
|
||||
from avalon import api
|
||||
from avalon.vendor import requests
|
||||
import re
|
||||
|
|
@ -27,40 +25,36 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
|
|||
|
||||
def process(self, instance):
|
||||
|
||||
node = None
|
||||
for x in instance:
|
||||
if x.Class() == "Write":
|
||||
node = x
|
||||
|
||||
if node is None:
|
||||
return
|
||||
node = instance[0]
|
||||
# for x in instance:
|
||||
# if x.Class() == "Write":
|
||||
# node = x
|
||||
#
|
||||
# if node is None:
|
||||
# return
|
||||
|
||||
DEADLINE_REST_URL = os.environ.get("DEADLINE_REST_URL",
|
||||
"http://localhost:8082")
|
||||
assert DEADLINE_REST_URL, "Requires DEADLINE_REST_URL"
|
||||
|
||||
context = instance.context
|
||||
workspace = os.path.dirname(context.data["currentFile"])
|
||||
filepath = None
|
||||
|
||||
# get path
|
||||
path = nuke.filename(node)
|
||||
output_dir = instance.data['outputDir']
|
||||
# get output path
|
||||
render_path = instance.data['path']
|
||||
render_dir = os.path.normpath(os.path.dirname(render_path))
|
||||
|
||||
filepath = context.data["currentFile"]
|
||||
script_path = context.data["currentFile"]
|
||||
|
||||
self.log.debug(filepath)
|
||||
|
||||
filename = os.path.basename(filepath)
|
||||
script_name = os.path.basename(script_path)
|
||||
comment = context.data.get("comment", "")
|
||||
dirname = os.path.join(workspace, "renders")
|
||||
|
||||
deadline_user = context.data.get("deadlineUser", getpass.getuser())
|
||||
jobname = "%s - %s" % (filename, instance.name)
|
||||
jobname = "%s - %s" % (script_name, instance.name)
|
||||
ver = re.search(r"\d+\.\d+", context.data.get("hostVersion"))
|
||||
|
||||
try:
|
||||
# Ensure render folder exists
|
||||
os.makedirs(dirname)
|
||||
os.makedirs(render_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
|
@ -71,7 +65,7 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
|
|||
payload = {
|
||||
"JobInfo": {
|
||||
# Top-level group name
|
||||
"BatchName": filename,
|
||||
"BatchName": script_name,
|
||||
|
||||
# Job name, as seen in Monitor
|
||||
"Name": jobname,
|
||||
|
|
@ -95,20 +89,20 @@ class NukeSubmitDeadline(pyblish.api.InstancePlugin):
|
|||
},
|
||||
"PluginInfo": {
|
||||
# Input
|
||||
"SceneFile": filepath,
|
||||
"SceneFile": script_path,
|
||||
|
||||
# Output directory and filename
|
||||
"OutputFilePath": dirname.replace("\\", "/"),
|
||||
"OutputFilePath": render_dir.replace("\\", "/"),
|
||||
# "OutputFilePrefix": render_variables["filename_prefix"],
|
||||
|
||||
# Mandatory for Deadline
|
||||
"Version": ver.group(),
|
||||
|
||||
# Resolve relative references
|
||||
"ProjectPath": workspace,
|
||||
|
||||
"ProjectPath": script_path,
|
||||
"AWSAssetFile0": render_path,
|
||||
# Only the specific write node is rendered.
|
||||
"WriteNode": instance[0].name()
|
||||
"WriteNode": node.name()
|
||||
},
|
||||
|
||||
# Mandatory for Deadline, may be empty
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ValidateRenderedFrames(pyblish.api.InstancePlugin):
|
|||
""" Validates file output. """
|
||||
|
||||
order = pyblish.api.ValidatorOrder + 0.1
|
||||
families = ["render.no"]
|
||||
families = ["render"]
|
||||
|
||||
label = "Validate rendered frame"
|
||||
hosts = ["nuke", "nukestudio"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import time
|
||||
import collections
|
||||
from Qt import QtCore, QtGui, QtWidgets
|
||||
from Qt import QtCore
|
||||
from pynput import mouse, keyboard
|
||||
from pypeapp import Logger
|
||||
|
||||
|
|
@ -29,6 +29,13 @@ class IdleManager(QtCore.QThread):
|
|||
def tray_start(self):
|
||||
self.start()
|
||||
|
||||
def tray_exit(self):
|
||||
self.stop()
|
||||
try:
|
||||
self.time_signals = {}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def add_time_signal(self, emit_time, signal):
|
||||
""" If any module want to use IdleManager, need to use add_time_signal
|
||||
:param emit_time: time when signal will be emitted
|
||||
|
|
|
|||
BIN
pype/standalonepublish/resources/menu.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 56 56" style="enable-background:new 0 0 56 56;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M28,0C12.561,0,0,12.561,0,28s12.561,28,28,28s28-12.561,28-28S43.439,0,28,0z M28,54C13.663,54,2,42.336,2,28
|
||||
S13.663,2,28,2s26,11.664,26,26S42.337,54,28,54z"/>
|
||||
<path d="M40,16H16c-0.553,0-1,0.448-1,1s0.447,1,1,1h24c0.553,0,1-0.448,1-1S40.553,16,40,16z"/>
|
||||
<path d="M40,27H16c-0.553,0-1,0.448-1,1s0.447,1,1,1h24c0.553,0,1-0.448,1-1S40.553,27,40,27z"/>
|
||||
<path d="M40,38H16c-0.553,0-1,0.448-1,1s0.447,1,1,1h24c0.553,0,1-0.448,1-1S40.553,38,40,38z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 823 B |
BIN
pype/standalonepublish/resources/menu_disabled.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pype/standalonepublish/resources/menu_hover.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pype/standalonepublish/resources/menu_pressed.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
pype/standalonepublish/resources/menu_pressed_hover.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
pype/standalonepublish/resources/trash.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="482.428px" height="482.429px" viewBox="0 0 482.428 482.429" fill="#ffffff" style="enable-background:new 0 0 482.428 482.429;"
|
||||
xml:space="preserve">
|
||||
<g>
|
||||
<path d="M381.163,57.799h-75.094C302.323,25.316,274.686,0,241.214,0c-33.471,0-61.104,25.315-64.85,57.799h-75.098
|
||||
c-30.39,0-55.111,24.728-55.111,55.117v2.828c0,23.223,14.46,43.1,34.83,51.199v260.369c0,30.39,24.724,55.117,55.112,55.117
|
||||
h210.236c30.389,0,55.111-24.729,55.111-55.117V166.944c20.369-8.1,34.83-27.977,34.83-51.199v-2.828
|
||||
C436.274,82.527,411.551,57.799,381.163,57.799z M241.214,26.139c19.037,0,34.927,13.645,38.443,31.66h-76.879
|
||||
C206.293,39.783,222.184,26.139,241.214,26.139z M375.305,427.312c0,15.978-13,28.979-28.973,28.979H136.096
|
||||
c-15.973,0-28.973-13.002-28.973-28.979V170.861h268.182V427.312z M410.135,115.744c0,15.978-13,28.979-28.973,28.979H101.266
|
||||
c-15.973,0-28.973-13.001-28.973-28.979v-2.828c0-15.978,13-28.979,28.973-28.979h279.897c15.973,0,28.973,13.001,28.973,28.979
|
||||
V115.744z"/>
|
||||
<path d="M171.144,422.863c7.218,0,13.069-5.853,13.069-13.068V262.641c0-7.216-5.852-13.07-13.069-13.07
|
||||
c-7.217,0-13.069,5.854-13.069,13.07v147.154C158.074,417.012,163.926,422.863,171.144,422.863z"/>
|
||||
<path d="M241.214,422.863c7.218,0,13.07-5.853,13.07-13.068V262.641c0-7.216-5.854-13.07-13.07-13.07
|
||||
c-7.217,0-13.069,5.854-13.069,13.07v147.154C228.145,417.012,233.996,422.863,241.214,422.863z"/>
|
||||
<path d="M311.284,422.863c7.217,0,13.068-5.853,13.068-13.068V262.641c0-7.216-5.852-13.07-13.068-13.07
|
||||
c-7.219,0-13.07,5.854-13.07,13.07v147.154C298.213,417.012,304.067,422.863,311.284,422.863z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
pype/standalonepublish/resources/trash_disabled.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
pype/standalonepublish/resources/trash_hover.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
pype/standalonepublish/resources/trash_pressed.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
pype/standalonepublish/resources/trash_pressed_hover.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,15 +1,10 @@
|
|||
import os
|
||||
from . import QtCore, QtGui, QtWidgets
|
||||
from . import SvgButton
|
||||
from . import get_resource
|
||||
from pypeapp import style
|
||||
|
||||
|
||||
class ComponentItem(QtWidgets.QFrame):
|
||||
C_NORMAL = '#777777'
|
||||
C_HOVER = '#ffffff'
|
||||
C_ACTIVE = '#4BB543'
|
||||
C_ACTIVE_HOVER = '#4BF543'
|
||||
|
||||
signal_remove = QtCore.Signal(object)
|
||||
signal_thumbnail = QtCore.Signal(object)
|
||||
|
|
@ -58,10 +53,8 @@ class ComponentItem(QtWidgets.QFrame):
|
|||
self.icon.setText("")
|
||||
self.icon.setScaledContents(True)
|
||||
|
||||
self.btn_action_menu = SvgButton(
|
||||
get_resource('menu.svg'), 22, 22,
|
||||
[self.C_NORMAL, self.C_HOVER],
|
||||
frame_image_info, False
|
||||
self.btn_action_menu = PngButton(
|
||||
name="menu", size=QtCore.QSize(22, 22)
|
||||
)
|
||||
|
||||
self.action_menu = QtWidgets.QMenu()
|
||||
|
|
@ -88,7 +81,9 @@ class ComponentItem(QtWidgets.QFrame):
|
|||
|
||||
self.file_info.setStyleSheet('padding-left:3px;')
|
||||
|
||||
expanding_sizePolicy.setHeightForWidth(self.name.sizePolicy().hasHeightForWidth())
|
||||
expanding_sizePolicy.setHeightForWidth(
|
||||
self.name.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
|
||||
frame_name_repre = QtWidgets.QFrame(frame)
|
||||
|
||||
|
|
@ -104,7 +99,8 @@ class ComponentItem(QtWidgets.QFrame):
|
|||
layout.addWidget(self.ext, alignment=QtCore.Qt.AlignRight)
|
||||
|
||||
frame_name_repre.setSizePolicy(
|
||||
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding
|
||||
QtWidgets.QSizePolicy.MinimumExpanding,
|
||||
QtWidgets.QSizePolicy.MinimumExpanding
|
||||
)
|
||||
|
||||
# Repre + icons
|
||||
|
|
@ -156,12 +152,7 @@ class ComponentItem(QtWidgets.QFrame):
|
|||
|
||||
layout_main.addWidget(frame_middle)
|
||||
|
||||
self.remove = SvgButton(
|
||||
get_resource('trash.svg'), 22, 22,
|
||||
[self.C_NORMAL, self.C_HOVER],
|
||||
frame, False
|
||||
)
|
||||
|
||||
self.remove = PngButton(name="trash", size=QtCore.QSize(22, 22))
|
||||
layout_main.addWidget(self.remove)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
|
|
@ -360,3 +351,172 @@ class LightingButton(QtWidgets.QPushButton):
|
|||
})
|
||||
self.setCheckable(True)
|
||||
|
||||
|
||||
class PngFactory:
|
||||
png_names = {
|
||||
"trash": {
|
||||
"normal": QtGui.QIcon(get_resource("trash.png")),
|
||||
"hover": QtGui.QIcon(get_resource("trash_hover.png")),
|
||||
"pressed": QtGui.QIcon(get_resource("trash_pressed.png")),
|
||||
"pressed_hover": QtGui.QIcon(
|
||||
get_resource("trash_pressed_hover.png")
|
||||
),
|
||||
"disabled": QtGui.QIcon(get_resource("trash_disabled.png"))
|
||||
},
|
||||
|
||||
"menu": {
|
||||
"normal": QtGui.QIcon(get_resource("menu.png")),
|
||||
"hover": QtGui.QIcon(get_resource("menu_hover.png")),
|
||||
"pressed": QtGui.QIcon(get_resource("menu_pressed.png")),
|
||||
"pressed_hover": QtGui.QIcon(
|
||||
get_resource("menu_pressed_hover.png")
|
||||
),
|
||||
"disabled": QtGui.QIcon(get_resource("menu_disabled.png"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PngButton(QtWidgets.QPushButton):
|
||||
png_button_style = """
|
||||
QPushButton {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
QPushButton:hover {}
|
||||
QPushButton:pressed {}
|
||||
QPushButton:disabled {}
|
||||
QPushButton:checked {}
|
||||
QPushButton:checked:hover {}
|
||||
QPushButton:checked:pressed {}
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, name=None, path=None, hover_path=None, pressed_path=None,
|
||||
hover_pressed_path=None, disabled_path=None,
|
||||
size=None, *args, **kwargs
|
||||
):
|
||||
self._hovered = False
|
||||
self._pressed = False
|
||||
super(PngButton, self).__init__(*args, **kwargs)
|
||||
self.setStyleSheet(self.png_button_style)
|
||||
|
||||
png_dict = {}
|
||||
if name:
|
||||
png_dict = PngFactory.png_names.get(name) or {}
|
||||
if not png_dict:
|
||||
print((
|
||||
"WARNING: There is not set icon with name \"{}\""
|
||||
"in PngFactory!"
|
||||
).format(name))
|
||||
|
||||
ico_normal = png_dict.get("normal")
|
||||
ico_hover = png_dict.get("hover")
|
||||
ico_pressed = png_dict.get("pressed")
|
||||
ico_hover_pressed = png_dict.get("pressed_hover")
|
||||
ico_disabled = png_dict.get("disabled")
|
||||
|
||||
if path:
|
||||
ico_normal = QtGui.QIcon(path)
|
||||
if hover_path:
|
||||
ico_hover = QtGui.QIcon(hover_path)
|
||||
|
||||
if pressed_path:
|
||||
ico_pressed = QtGui.QIcon(hover_path)
|
||||
|
||||
if hover_pressed_path:
|
||||
ico_hover_pressed = QtGui.QIcon(hover_pressed_path)
|
||||
|
||||
if disabled_path:
|
||||
ico_disabled = QtGui.QIcon(disabled_path)
|
||||
|
||||
self.setIcon(ico_normal)
|
||||
if size:
|
||||
self.setIconSize(size)
|
||||
self.setMaximumSize(size)
|
||||
|
||||
self.ico_normal = ico_normal
|
||||
self.ico_hover = ico_hover
|
||||
self.ico_pressed = ico_pressed
|
||||
self.ico_hover_pressed = ico_hover_pressed
|
||||
self.ico_disabled = ico_disabled
|
||||
|
||||
def setDisabled(self, in_bool):
|
||||
super(PngButton, self).setDisabled(in_bool)
|
||||
icon = self.ico_normal
|
||||
if in_bool and self.ico_disabled:
|
||||
icon = self.ico_disabled
|
||||
self.setIcon(icon)
|
||||
|
||||
def enterEvent(self, event):
|
||||
self._hovered = True
|
||||
if not self.isEnabled():
|
||||
return
|
||||
icon = self.ico_normal
|
||||
if self.ico_hover:
|
||||
icon = self.ico_hover
|
||||
|
||||
if self._pressed and self.ico_hover_pressed:
|
||||
icon = self.ico_hover_pressed
|
||||
|
||||
if self.icon() != icon:
|
||||
self.setIcon(icon)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
super(PngButton, self).mouseMoveEvent(event)
|
||||
if self._pressed:
|
||||
mouse_pos = event.pos()
|
||||
hovering = self.rect().contains(mouse_pos)
|
||||
if hovering and not self._hovered:
|
||||
self.enterEvent(event)
|
||||
elif not hovering and self._hovered:
|
||||
self.leaveEvent(event)
|
||||
|
||||
def leaveEvent(self, event):
|
||||
self._hovered = False
|
||||
if not self.isEnabled():
|
||||
return
|
||||
icon = self.ico_normal
|
||||
if self._pressed and self.ico_pressed:
|
||||
icon = self.ico_pressed
|
||||
|
||||
if self.icon() != icon:
|
||||
self.setIcon(icon)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
self._pressed = True
|
||||
if not self.isEnabled():
|
||||
return
|
||||
icon = self.ico_hover
|
||||
if self.ico_pressed:
|
||||
icon = self.ico_pressed
|
||||
|
||||
if self.ico_hover_pressed:
|
||||
mouse_pos = event.pos()
|
||||
if self.rect().contains(mouse_pos):
|
||||
icon = self.ico_hover_pressed
|
||||
|
||||
if icon is None:
|
||||
icon = self.ico_normal
|
||||
|
||||
if self.icon() != icon:
|
||||
self.setIcon(icon)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
if not self.isEnabled():
|
||||
return
|
||||
if self._pressed:
|
||||
self._pressed = False
|
||||
mouse_pos = event.pos()
|
||||
if self.rect().contains(mouse_pos):
|
||||
self.clicked.emit()
|
||||
|
||||
icon = self.ico_normal
|
||||
if self._hovered and self.ico_hover:
|
||||
icon = self.ico_hover
|
||||
|
||||
if self.icon() != icon:
|
||||
self.setIcon(icon)
|
||||
|
|
|
|||