Merge branch 'develop' into feature/OP-3377_Use-query-functions-in-Blender

This commit is contained in:
Jakub Trllo 2022-06-14 11:15:03 +02:00
commit c6d3e52b56
6 changed files with 244 additions and 35 deletions

View file

@ -603,6 +603,18 @@ class CollectLook(pyblish.api.InstancePlugin):
source,
computed_source))
# renderman allows nodes to have filename attribute empty while
# you can have another incoming connection from different node.
pxr_nodes = set()
if cmds.pluginInfo("RenderMan_for_Maya", query=True, loaded=True):
pxr_nodes = set(
cmds.pluginInfo("RenderMan_for_Maya",
query=True,
dependNode=True)
)
if not source and cmds.nodeType(node) in pxr_nodes:
self.log.info("Renderman: source is empty, skipping...")
continue
# We replace backslashes with forward slashes because V-Ray
# can't handle the UDIM files with the backslashes in the
# paths as the computed patterns

View file

@ -539,7 +539,9 @@ def get_created_node_imageio_setting_legacy(nodeclass, creator, subset):
imageio_nodes = get_nuke_imageio_settings()["nodes"]
required_nodes = imageio_nodes["requiredNodes"]
override_nodes = imageio_nodes["overrideNodes"]
# HACK: for backward compatibility this needs to be optional
override_nodes = imageio_nodes.get("overrideNodes", [])
imageio_node = None
for node in required_nodes:

View file

@ -2,7 +2,20 @@ import nuke
from openpype.hosts.nuke.api import plugin
from openpype.hosts.nuke.api.lib import (
create_write_node, create_write_node_legacy)
create_write_node,
create_write_node_legacy,
get_created_node_imageio_setting_legacy
)
# HACK: just to disable still image on projects which
# are not having anatomy imageio preset for CreateWriteStill
# TODO: remove this code as soon as it will be obsolete
imageio_writes = get_created_node_imageio_setting_legacy(
"Write",
"CreateWriteStill",
"stillMain"
)
print(imageio_writes["knobs"])
class CreateWriteStill(plugin.AbstractWriteRender):

View file

@ -1,7 +1,9 @@
import os
import sys
import json
import traceback
import functools
import datetime
from Qt import QtWidgets, QtGui, QtCore
@ -10,7 +12,66 @@ from openpype.tools.settings import CHILD_OFFSET
from .widgets import ExpandingWidget
from .lib import create_deffered_value_change_timer
from .constants import DEFAULT_PROJECT_LABEL
from .constants import (
DEFAULT_PROJECT_LABEL,
SETTINGS_PATH_KEY,
ROOT_KEY,
VALUE_KEY,
SAVE_TIME_KEY,
PROJECT_NAME_KEY,
)
_MENU_SEPARATOR_REQ = object()
class ExtractHelper:
_last_save_dir = os.path.expanduser("~")
@classmethod
def get_last_save_dir(cls):
return cls._last_save_dir
@classmethod
def set_last_save_dir(cls, save_dir):
cls._last_save_dir = save_dir
@classmethod
def ask_for_save_filepath(cls, parent):
dialog = QtWidgets.QFileDialog(
parent,
"Save settings values",
cls.get_last_save_dir(),
"Values (*.json)"
)
# dialog.setOption(dialog.DontUseNativeDialog)
dialog.setAcceptMode(dialog.AcceptSave)
if dialog.exec() != dialog.Accepted:
return
selected_urls = dialog.selectedUrls()
if not selected_urls:
return
filepath = selected_urls[0].toLocalFile()
if not filepath:
return
if not filepath.lower().endswith(".json"):
filepath += ".json"
return filepath
@classmethod
def extract_settings_to_json(cls, filepath, settings_data, project_name):
now = datetime.datetime.now()
settings_data[SAVE_TIME_KEY] = now.strftime("%Y-%m-%d %H:%M:%S")
if project_name != 0:
settings_data[PROJECT_NAME_KEY] = project_name
with open(filepath, "w") as stream:
json.dump(settings_data, stream, indent=4)
new_dir = os.path.dirname(filepath)
cls.set_last_save_dir(new_dir)
class BaseWidget(QtWidgets.QWidget):
@ -190,24 +251,29 @@ class BaseWidget(QtWidgets.QWidget):
actions_mapping[action] = remove_from_project_override
menu.addAction(action)
def _get_mime_data_from_entity(self):
if self.entity.is_dynamic_item or self.entity.is_in_dynamic_item:
entity_path = None
else:
entity_path = "/".join(
[self.entity.root_key, self.entity.path]
)
value = self.entity.value
# Copy for settings tool
return {
VALUE_KEY: value,
ROOT_KEY: self.entity.root_key,
SETTINGS_PATH_KEY: entity_path
}
def _copy_value_actions(self, menu):
def copy_value():
mime_data = QtCore.QMimeData()
if self.entity.is_dynamic_item or self.entity.is_in_dynamic_item:
entity_path = None
else:
entity_path = "/".join(
[self.entity.root_key, self.entity.path]
)
value = self.entity.value
# Copy for settings tool
settings_data = {
"root_key": self.entity.root_key,
"value": value,
"path": entity_path
}
settings_data = self._get_mime_data_from_entity()
settings_encoded_data = QtCore.QByteArray()
settings_stream = QtCore.QDataStream(
settings_encoded_data, QtCore.QIODevice.WriteOnly
@ -218,6 +284,7 @@ class BaseWidget(QtWidgets.QWidget):
)
# Copy as json
value = settings_data[VALUE_KEY]
json_encoded_data = None
if isinstance(value, (dict, list)):
json_encoded_data = QtCore.QByteArray()
@ -241,25 +308,87 @@ class BaseWidget(QtWidgets.QWidget):
action = QtWidgets.QAction("Copy", menu)
return [(action, copy_value)]
def _extract_to_file(self):
filepath = ExtractHelper.ask_for_save_filepath(self)
if not filepath:
return
settings_data = self._get_mime_data_from_entity()
project_name = 0
if hasattr(self.category_widget, "project_name"):
project_name = self.category_widget.project_name
ExtractHelper.extract_settings_to_json(
filepath, settings_data, project_name
)
def _extract_value_to_file_actions(self, menu):
extract_action = QtWidgets.QAction("Extract to file", menu)
return [
_MENU_SEPARATOR_REQ,
(extract_action, self._extract_to_file)
]
def _parse_source_data_for_paste(self, data):
settings_path = None
root_key = None
if isinstance(data, dict):
data.pop(SAVE_TIME_KEY, None)
data.pop(PROJECT_NAME_KEY, None)
settings_path = data.pop(SETTINGS_PATH_KEY, settings_path)
root_key = data.pop(ROOT_KEY, root_key)
data = data.pop(VALUE_KEY, data)
return {
VALUE_KEY: data,
SETTINGS_PATH_KEY: settings_path,
ROOT_KEY: root_key
}
def _get_value_from_clipboard(self):
clipboard = QtWidgets.QApplication.clipboard()
mime_data = clipboard.mimeData()
app_value = mime_data.data("application/copy_settings_value")
if app_value:
settings_stream = QtCore.QDataStream(
app_value, QtCore.QIODevice.ReadOnly
)
mime_data_value_str = settings_stream.readQString()
return json.loads(mime_data_value_str)
if mime_data.hasUrls():
for url in mime_data.urls():
local_file = url.toLocalFile()
try:
with open(local_file, "r") as stream:
value = json.load(stream)
except Exception:
continue
if value:
return self._parse_source_data_for_paste(value)
if mime_data.hasText():
text = mime_data.text()
try:
value = json.loads(text)
except Exception:
try:
value = self.entity.convert_to_valid_type(text)
except Exception:
return None
return self._parse_source_data_for_paste(value)
def _paste_value_actions(self, menu):
output = []
# Allow paste of value only if were copied from this UI
clipboard = QtWidgets.QApplication.clipboard()
mime_data = clipboard.mimeData()
mime_value = mime_data.data("application/copy_settings_value")
mime_data_value = self._get_value_from_clipboard()
# Skip if there is nothing to do
if not mime_value:
if not mime_data_value:
return output
settings_stream = QtCore.QDataStream(
mime_value, QtCore.QIODevice.ReadOnly
)
mime_data_value_str = settings_stream.readQString()
mime_data_value = json.loads(mime_data_value_str)
value = mime_data_value["value"]
path = mime_data_value["path"]
root_key = mime_data_value["root_key"]
value = mime_data_value[VALUE_KEY]
path = mime_data_value[SETTINGS_PATH_KEY]
root_key = mime_data_value[ROOT_KEY]
# Try to find matching entity to be able paste values to same spot
# - entity can't by dynamic or in dynamic item
@ -391,10 +520,19 @@ class BaseWidget(QtWidgets.QWidget):
ui_actions.extend(self._copy_value_actions(menu))
ui_actions.extend(self._paste_value_actions(menu))
if ui_actions:
menu.addSeparator()
for action, callback in ui_actions:
menu.addAction(action)
actions_mapping[action] = callback
ui_actions.insert(0, _MENU_SEPARATOR_REQ)
ui_actions.extend(self._extract_value_to_file_actions(menu))
for item in ui_actions:
if item is _MENU_SEPARATOR_REQ:
if len(menu.actions()) > 0:
menu.addSeparator()
continue
action, callback = item
menu.addAction(action)
actions_mapping[action] = callback
if not actions_mapping:
action = QtWidgets.QAction("< No action >")

View file

@ -45,8 +45,15 @@ from .breadcrumbs_widget import (
SystemSettingsBreadcrumbs,
ProjectSettingsBreadcrumbs
)
from .base import GUIWidget
from .constants import (
SETTINGS_PATH_KEY,
ROOT_KEY,
VALUE_KEY,
)
from .base import (
ExtractHelper,
GUIWidget,
)
from .list_item_widget import ListWidget
from .list_strict_widget import ListStrictWidget
from .dict_mutable_widget import DictMutableKeysWidget
@ -627,11 +634,35 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
self._on_context_version_trigger
)
submenu.addAction(action)
menu.addMenu(submenu)
extract_action = QtWidgets.QAction("Extract to file", menu)
extract_action.triggered.connect(self._on_extract_to_file)
menu.addAction(extract_action)
def _on_context_version_trigger(self, version):
self._on_source_version_change(version)
def _on_extract_to_file(self):
filepath = ExtractHelper.ask_for_save_filepath(self)
if not filepath:
return
settings_data = {
SETTINGS_PATH_KEY: self.entity.root_key,
ROOT_KEY: self.entity.root_key,
VALUE_KEY: self.entity.value
}
project_name = 0
if hasattr(self, "project_name"):
project_name = self.project_name
ExtractHelper.extract_settings_to_json(
filepath, settings_data, project_name
)
def _on_reset_crash(self):
self.save_btn.setEnabled(False)

View file

@ -7,6 +7,12 @@ PROJECT_IS_ACTIVE_ROLE = QtCore.Qt.UserRole + 2
PROJECT_IS_SELECTED_ROLE = QtCore.Qt.UserRole + 3
PROJECT_VERSION_ROLE = QtCore.Qt.UserRole + 4
# Save/Extract keys
SETTINGS_PATH_KEY = "__settings_path__"
ROOT_KEY = "__root_key__"
VALUE_KEY = "__value__"
SAVE_TIME_KEY = "__extracted__"
PROJECT_NAME_KEY = "__project_name__"
__all__ = (
"DEFAULT_PROJECT_LABEL",
@ -15,4 +21,11 @@ __all__ = (
"PROJECT_IS_ACTIVE_ROLE",
"PROJECT_IS_SELECTED_ROLE",
"PROJECT_VERSION_ROLE",
"SETTINGS_PATH_KEY",
"ROOT_KEY",
"SETTINGS_PATH_KEY",
"VALUE_KEY",
"SAVE_TIME_KEY",
"PROJECT_NAME_KEY",
)