js refactoring

This commit is contained in:
Ondrej Samohel 2020-10-17 00:46:19 +02:00
parent 5a1c5bae93
commit 3b22f0c199
No known key found for this signature in database
GPG key ID: 8A29C663C672C2B7
10 changed files with 527 additions and 43 deletions

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
* text=auto
*.js eol=lf
*.c eol=lf

View file

@ -1,15 +1,117 @@
{
"env": {
"browser": true
"browser": true,
"es2021": true
},
"extends": [
"google"
],
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 3
},
"rules": {
"no-var": "off",
"comma-dangle": "off"
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
},
"globals": {
"Action": "readonly",
"Backdrop": "readonly",
"Button": "readonly",
"Cel": "readonly",
"Cel3d": "readonly",
"CheckBox": "readonly",
"ColorRGBA": "readonly",
"ComboBox": "readonly",
"DateEdit": "readonly",
"DateEditEnum": "readonly",
"Dialog": "readonly",
"Dir": "readonly",
"DirSpec": "readonly",
"Drawing": "readonly",
"DrawingToolParams": "readonly",
"DrawingTools": "readonly",
"EnvelopeCreator": "readonly",
"ExportVideoDlg": "readonly",
"File": "readonly",
"FileAccess": "readonly",
"FileDialog": "readonly",
"GroupBox": "readonly",
"ImportDrawingDlg": "readonly",
"Input": "readonly",
"KeyModifiers": "readonly",
"Label": "readonly",
"LayoutExports": "readonly",
"LayoutExportsParams": "readonly",
"LineEdit": "readonly",
"Matrix4x4": "readonly",
"MessageBox": "readonly",
"MessageLog": "readonly",
"Model3d": "readonly",
"MovieImport": "readonly",
"NumberEdit": "readonly",
"PaletteManager": "readonly",
"PaletteObjectManager": "readonly",
"PermanentFile": "readonly",
"Point2d": "readonly",
"Point3d": "readonly",
"Process": "readonly",
"Process2": "readonly",
"Quaternion": "readonly",
"QuicktimeExporter": "readonly",
"RadioButton": "readonly",
"RemoteCmd": "readonly",
"Scene": "readonly",
"Settings": "readonly",
"Slider": "readonly",
"SpinBox": "readonly",
"SubnodeData": "readonly",
"System": "readonly",
"TemporaryFile": "readonly",
"TextEdit": "readonly",
"TimeEdit": "readonly",
"Timeline": "readonly",
"ToolProperties": "readonly",
"UiLoader": "readonly",
"Vector2d": "readonly",
"Vector3d": "readonly",
"WebCCExporter": "readonly",
"Workspaces": "readonly",
"__scriptManager__": "readonly",
"__temporaryFileContext__": "readonly",
"about": "readonly",
"column": "readonly",
"compositionOrder": "readonly",
"copyPaste": "readonly",
"deformation": "readonly",
"drawingExport": "readonly",
"element": "readonly",
"exporter": "readonly",
"fileMapper": "readonly",
"frame": "readonly",
"func": "readonly",
"library": "readonly",
"node": "readonly",
"preferences": "readonly",
"render": "readonly",
"scene": "readonly",
"selection": "readonly",
"sound": "readonly",
"specialFolders": "readonly",
"translator": "readonly",
"view": "readonly",
"waypoint": "readonly",
"xsheet": "readonly"
}
}

View file

@ -63,11 +63,12 @@ PypeHarmony.setSceneSettings = function(settings) {
* Set color of nodes.
* @function
* @param {array} nodes List of nodes.
* @param {array} rgba array of RGBA components of color.
*/
PypeHarmony.setColor = function(nodes) {
PypeHarmony.setColor = function(nodes, rgba) {
for (var i =0; i <= nodes.length - 1; ++i) {
var redColor = new ColorRGBA(255, 0, 0, 255);
node.setColor(nodes[i], redColor);
var color = PypeHarmony.color(rgba);
node.setColor(nodes[i], color);
}
};
@ -147,6 +148,7 @@ PypeHarmony.copyFile = function(src, dst) {
srcFile.copy(dstFile);
};
/**
* create RGBA color from array.
* @function

View file

@ -13,9 +13,6 @@ if (typeof PypeHarmony !== 'undefined') {
/**
* @namespace
* @classdesc Image Sequence loader JS code.
* @property {Object} loaders Namespace for Loaders JS code.
* @property {Object} Creators Namespace for Creators JS code.
* @property {Object} Publish Namespace for Publish plugins JS code.
*/
ImageSequenceLoader = function() {
this.PNGTransparencyMode = 0; // Premultiplied wih Black
@ -57,17 +54,20 @@ ImageSequenceLoader.prototype.getUniqueColumnName = function(columnPrefix) {
* @example
* // Agrguments are in following order:
* var args = [
* root, // Harmony root
* files, // Files in file sequences
* name, // Node name
* startFrame // Sequence starting frame
* files, // Files in file sequences.
* asset, // Asset name.
* subset, // Subset name.
* startFrame, // Sequence starting frame.
* groupId // Unique group ID (uuid4).
* ];
*/
ImageSequenceLoader.prototype.importFiles = function(args) {
var root = args[0];
var files = args[1];
var name = args[2];
var doc = $.scn;
var files = args[0];
var asset = args[1];
var subset = args[2];
var startFrame = args[3];
var groupId = args[4];
var vectorFormat = null;
var extension = null;
var filename = files[0];
@ -76,6 +76,29 @@ ImageSequenceLoader.prototype.importFiles = function(args) {
return null;
}
// Get the current group
nodeViewWidget = $.app.getWidgetByName('Node View');
if (!nodeViewWidget) {
$.alert('You must have a Node View open!', 'No Node View!', 'OK!');
return;
}
nodeViewWidget.setFocus();
var nodeView = view.currentView();
var currentGroup = null;
if (!nodeView) {
currentGroup = doc.root;
} else {
currentGroup = doc.$node(view.group(nodeView));
}
// Get a unique iterative name for the container read node
var num = 0;
var name = '';
do {
name = asset + '_' + (num++) + '_' + subset;
} while (current_group.getNodeByName(name) != null);
extension = filename.substr(pos+1).toLowerCase();
if (extension == 'jpeg') {
extension = 'jpg';
@ -102,7 +125,7 @@ ImageSequenceLoader.prototype.importFiles = function(args) {
var uniqueColumnName = this.getUniqueColumnName(name);
column.add(uniqueColumnName, 'DRAWING');
column.setElementIdOfDrawing(uniqueColumnName, elemId);
var read = node.add(root, name, 'READ', 0, 0, 0);
var read = node.add(currentGroup, name, 'READ', 0, 0, 0);
var transparencyAttr = node.getAttr(
read, frame.current(), 'READ_TRANSPARENCY'
);
@ -156,6 +179,10 @@ ImageSequenceLoader.prototype.importFiles = function(args) {
}
var greenColor = new ColorRGBA(0, 255, 0, 255);
node.setColor(read, greenColor);
// Add uuid to attribute of the container read node
node.createDynamicAttr(read, 'STRING', 'uuid', 'uuid', false);
node.setTextAttr(read, 'uuid', 1.0, groupId);
return read;
};

View file

@ -0,0 +1,175 @@
// ***************************************************************************
// * TemplateLoader *
// ***************************************************************************
// check if PypeHarmony is defined and if not, load it.
if (typeof PypeHarmony !== 'undefined') {
var PYPE_HARMONY_JS = System.getenv('PYPE_HARMONY_JS');
include(PYPE_HARMONY_JS + '/pype_harmony.js');
}
/**
* @namespace
* @classdesc Image Sequence loader JS code.
*/
TemplateLoader = function() {};
/**
* Load template as container.
* @function
* @param {array} args Arguments, see example.
* @return {string} Name of container.
*
* @example
* // arguments are in following order:
* var args = [
* templatePath, // Path to tpl file.
* assetName, // Asset name.
* subsetName, // Subset name.
* groupId // unique ID (uuid4)
* ];
*/
TemplateLoader.prototype.loadContainer = function(args) {
var doc = $.scn;
var templatePath = args[0];
var assetName = args[1];
var subset = args[2];
var groupId = args[3];
// Get the current group
nodeViewWidget = $.app.getWidgetByName('Node View');
if (!nodeViewWidget) {
$.alert('You must have a Node View open!', 'No Node View!', 'OK!');
return;
}
nodeViewWidget.setFocus();
nodeView = view.currentView();
if (!nodeView) {
currentGroup = doc.root;
} else {
currentGroup = doc.$node(view.group(nodeView));
}
// Get a unique iterative name for the container group
var num = 0;
var containerGroupName = '';
do {
containerGroupName = assetName + '_' + (num++) + '_' + subset;
} while (currentGroup.getNodeByName(containerGroupName) != null);
// import the template
var tplNodes = currentGroup.importTemplate(templatePath);
MessageLog.trace(tplNodes);
// Create the container group
var groupNode = currentGroup.addGroup(
containerGroupName, false, false, tplNodes);
// Add uuid to attribute of the container group
node.createDynamicAttr(groupNode, 'STRING', 'uuid', 'uuid', false);
node.setTextAttr(groupNode, 'uuid', 1.0, groupId);
return String(groupNode);
};
/**
* Replace existing node container.
* @function
* @param {string} dstNodePath Harmony path to destination Node.
* @param {string} srcNodePath Harmony path to source Node.
* @param {string} renameSrc ...
* @param {boolean} cloneSrc ...
* @param {array} linkColumns ...
* @return {boolean} Success
* @todo This is work in progress.
*/
TemplateLoader.prototype.replaceNode = function(
dstNodePath, srcNodePath, renameSrc, cloneSrc, linkColumns) {
var doc = $.scn;
var srcNode = doc.$node(srcNodePath);
var dstNode = doc.$node(dstNodePath);
// var dstNodeName = dstNode.name;
var replacementNode = srcNode;
// var dstGroup = dstNode.group;
$.beginUndo();
if (cloneSrc) {
var replacementNode = doc.$node(
Y.nodeTools.copy_paste_node(
srcNodePath, dstNode.name + '_CLONE', dstNode.group.path));
} else {
if (replacement_node.group.path != src_node.group.path) {
replacement_node.moveToGroup(dst_group);
}
}
var inLinks = dstNode.getInLinks();
for (l in inLinks) {
if (Object.prototype.hasOwnProperty.call(inLinks, l)) {
var link = inLinks[l];
inPort = Number(link.inPort);
outPort = Number(link.outPort);
outNode = link.outNode;
success = replacement_node.linkInNode(outNode, inPort, outPort);
if (success) {
log('Successfully connected ' + outNode + ' : ' +
outPort + ' -> ' + replacementNode + ' : ' + inPort);
} else {
log('Failed to connect ' + outNode + ' : ' +
outPort + ' -> ' + replacementNode + ' : ' + inPort);
}
}
}
var outLinks = dstNode.getOutLinks();
for (l in outLinks) {
if (Object.prototype.hasOwnProperty.call(outLinks, l)) {
var link = out_links[l];
inPort = Number(link.inPort);
outPort = Number(link.outPort);
inNode = link.inNode;
// first we must disconnect the port from the node being
// replaced to this links inNode port
inNode.unlinkInPort(inPort);
success = replacement_node.linkOutNode(in_node, out_port, in_port);
if (success) {
log('Successfully connected ' + inNode + ' : ' +
inPort + ' <- ' + replacementNode + ' : ' + outPort);
} else {
if (in_node.type == 'MultiLayerWrite') {
log('Attempting standard api to connect the nodes...');
success = node.link(
replacementNode, outPort, inNode,
inPort, node.numberOfInputPorts(inNode) + 1);
if (success) {
log('Successfully connected ' + inNode + ' : ' +
inPort + ' <- ' + replacementNode + ' : ' + outPort);
}
}
}
if (!success) {
log('Failed to connect ' + inNode + ' : ' +
inPort + ' <- ' + replacementNode + ' : ' + outPort);
return false;
}
}
}
};
TemplateLoader.prototype.askForColumnsUpdate = function() {
// Ask user if they want to also update columns and
// linked attributes here
return ($.confirm(
'Would you like to update in place and reconnect all \n' +
'ins/outs, attributes, and columns?',
'Update & Replace?\n' +
'If you choose No, the version will only be loaded.',
'Yes',
'No'));
};
// add self to Pype Loaders
PypeHarmony.Loaders.TemplateLoader = new TemplateLoader();

View file

@ -0,0 +1,20 @@
{
"name": "pype-harmony",
"version": "1.0.0",
"description": "Pype Harmony Host integration",
"main": "PypeHarmony.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"Pype",
"Avalon",
"Harmony",
"pipeline"
],
"author": "",
"license": "MIT",
"devDependencies": {
"eslint": "^7.11.0"
}
}

View file

@ -2,6 +2,7 @@
"""Loader for image sequences."""
import os
import uuid
from pathlib import Path
import clique
@ -28,36 +29,37 @@ class ImageSequenceLoader(api.Loader):
data (dict, optional): Additional data passed into loader.
"""
fname = Path(self.fname)
self_name = self.__class__.__name__
collections, remainder = clique.assemble(
os.listdir(os.path.dirname(self.fname))
os.listdir(fname.parent.as_posix())
)
files = []
if collections:
for f in list(collections[0]):
files.append(
os.path.join(
os.path.dirname(self.fname), f
).replace("\\", "/")
)
files.append(fname.parent.joinpath(f).as_posix())
else:
files.append(
os.path.join(
os.path.dirname(self.fname), remainder[0]
).replace("\\", "/")
)
files.append(fname.parent.joinpath(remainder[0]).as_posix())
name = context["subset"]["name"]
name += "_{}".format(uuid.uuid4())
asset = context["asset"]["name"]
subset = context["subset"]["name"]
group_id = str(uuid.uuid4())
read_node = harmony.send(
{
"function": f"PypeHarmony.Loaders.{self_name}.importFiles", # noqa: E501
"args": ["Top", files, name, 1]
"args": [
files,
asset,
subset,
1,
group_id
]
}
)["result"]
return harmony.containerise(
name,
f"{asset}_{subset}",
namespace,
read_node,
context,

View file

@ -2,7 +2,6 @@ import os
import shutil
from avalon import api, harmony
from avalon.vendor import Qt
class ImportPaletteLoader(api.Loader):
@ -41,14 +40,14 @@ class ImportPaletteLoader(api.Loader):
harmony.save_scene()
# Dont allow instances with the same name.
message_box = Qt.QtWidgets.QMessageBox()
message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning)
msg = "Updated {}.".format(subset_name)
msg += " You need to reload the scene to see the changes."
message_box.setText(msg)
message_box.exec_()
harmony.send(
{
"function": "PypeHarmony.message",
"args": msg
})
return name
def remove(self, container):

View file

@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
"""Load template."""
import tempfile
import zipfile
import os
import shutil
import uuid
from avalon import api, harmony
import pype.lib
class TemplateLoader(api.Loader):
"""Load Harmony template as container.
.. todo::
This must be implemented properly.
"""
families = ["template", "workfile"]
representations = ["*"]
label = "Load Template"
icon = "gift"
def load(self, context, name=None, namespace=None, data=None):
"""Plugin entry point.
Args:
context (:class:`pyblish.api.Context`): Context.
name (str, optional): Container name.
namespace (str, optional): Container namespace.
data (dict, optional): Additional data passed into loader.
"""
# Load template.
self_name = self.__class__.__name__
temp_dir = tempfile.mkdtemp()
zip_file = api.get_representation_path(context["representation"])
template_path = os.path.join(temp_dir, "temp.tpl")
with zipfile.ZipFile(zip_file, "r") as zip_ref:
zip_ref.extractall(template_path)
group_id = "{}".format(uuid.uuid4())
container_group = harmony.send(
{
"function": f"PypeHarmony.Loaders.{self_name}.loadContainer",
"args": [template_path,
context["asset"]["name"],
context["subset"]["name"],
group_id]
}
)["result"]
# Cleanup the temp directory
shutil.rmtree(temp_dir)
# We must validate the group_node
return harmony.containerise(
name,
namespace,
container_group,
context,
self_name
)
def update(self, container, representation):
"""Update loaded containers.
Args:
container (dict): Container data.
representation (dict): Representation data.
"""
node_name = container["name"]
node = harmony.find_node_by_name(node_name, "GROUP")
self_name = self.__class__.__name__
update_and_replace = False
if pype.lib.is_latest(representation):
self._set_green(node)
else:
self._set_red(node)
update_and_replace = harmony.send(
{
"function": f"PypeHarmony.Loaders.{self_name}."
"askForColumnsUpdate",
"args": []
}
)["result"]
if update_and_replace:
# FIXME: This won't work, need to implement it.
harmony.send(
{
"function": f"PypeHarmony.Loaders.{self_name}."
"replaceNode",
"args": []
}
)
else:
self.load(
container["context"], container["name"],
None, container["data"])
harmony.imprint(
node, {"representation": str(representation["_id"])}
)
def remove(self, container):
"""Remove container.
Args:
container (dict): container definition.
"""
node = harmony.find_node_by_name(container["name"], "GROUP")
harmony.send(
{"function": "PypeHarmony.deleteNode", "args": [node]}
)
def switch(self, container, representation):
"""Switch representation containers."""
self.update(container, representation)
def _set_green(self, node):
"""Set node color to green `rgba(0, 255, 0, 255)`."""
harmony.send(
{
"function": "PypeHarmony.setColor",
"args": [node, [0, 255, 0, 255]]
})
def _set_red(self, node):
"""Set node color to red `rgba(255, 0, 0, 255)`."""
harmony.send(
{
"function": "PypeHarmony.setColor",
"args": [node, [255, 0, 0, 255]]
})

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
"""Collect instances in Harmony."""
import json
import pyblish.api
@ -8,7 +10,7 @@ class CollectInstances(pyblish.api.ContextPlugin):
"""Gather instances by nodes metadata.
This collector takes into account assets that are associated with
a composite node and marked with a unique identifier;
a composite node and marked with a unique identifier.
Identifier:
id (str): "pyblish.avalon.instance"
@ -19,10 +21,19 @@ class CollectInstances(pyblish.api.ContextPlugin):
hosts = ["harmony"]
families_mapping = {
"render": ["imagesequence", "review", "ftrack"],
"harmony.template": []
"harmony.template": [],
"palette": ["palette", "ftrack"]
}
pair_media = True
def process(self, context):
"""Plugin entry point.
Args:
context (:class:`pyblish.api.Context`): Context data.
"""
nodes = harmony.send(
{"function": "node.subNodes", "args": ["Top"]}
)["result"]