mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'pypeclub:develop' into enhancement/minimal-ftrack-browser-open-from-tray
This commit is contained in:
commit
5844a17dc6
5 changed files with 232 additions and 35 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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 >")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue