mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Merge remote-tracking branch 'upstream/develop' into fusion-new-publisher
This commit is contained in:
commit
fca0ff591b
11 changed files with 159 additions and 53 deletions
15
.github/pull_request_template.md
vendored
15
.github/pull_request_template.md
vendored
|
|
@ -1,16 +1,9 @@
|
|||
## Brief description
|
||||
First sentence is brief description.
|
||||
|
||||
## Description
|
||||
Next paragraf is more elaborate text with more info. This will be displayed for example in collapsed form under the first sentence in a changelog.
|
||||
## Changelog Description
|
||||
Paragraphs contain detailed information on the changes made to the product or service, providing an in-depth description of the updates and enhancements. They can be used to explain the reasoning behind the changes, or to highlight the importance of the new features. Paragraphs can often include links to further information or support documentation.
|
||||
|
||||
## Additional info
|
||||
The rest will be ignored in changelog and should contain any additional
|
||||
technical information.
|
||||
|
||||
## Documentation (add _"type: documentation"_ label)
|
||||
[feature_documentation](future_url_after_it_will_be_merged)
|
||||
Paragraphs of text giving context of additional technical information or code examples.
|
||||
|
||||
## Testing notes:
|
||||
1. start with this step
|
||||
2. follow this step
|
||||
2. follow this step
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ from openpype.pipeline.colorspace import (
|
|||
get_imageio_config
|
||||
)
|
||||
from openpype.pipeline.workfile import BuildWorkfile
|
||||
|
||||
from . import gizmo_menu
|
||||
from .constants import ASSIST
|
||||
|
||||
|
|
@ -2678,6 +2677,18 @@ def process_workfile_builder():
|
|||
open_file(last_workfile_path)
|
||||
|
||||
|
||||
def start_workfile_template_builder():
|
||||
from .workfile_template_builder import (
|
||||
build_workfile_template
|
||||
)
|
||||
|
||||
# to avoid looping of the callback, remove it!
|
||||
log.info("Starting workfile template builder...")
|
||||
build_workfile_template(workfile_creation_enabled=True)
|
||||
|
||||
# remove callback since it would be duplicating the workfile
|
||||
nuke.removeOnCreate(start_workfile_template_builder, nodeClass="Root")
|
||||
|
||||
@deprecated
|
||||
def recreate_instance(origin_node, avalon_data=None):
|
||||
"""Recreate input instance to different data
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from .lib import (
|
|||
add_publish_knob,
|
||||
WorkfileSettings,
|
||||
process_workfile_builder,
|
||||
start_workfile_template_builder,
|
||||
launch_workfiles_app,
|
||||
check_inventory_versions,
|
||||
set_avalon_knob_data,
|
||||
|
|
@ -48,7 +49,6 @@ from .workfile_template_builder import (
|
|||
NukePlaceholderLoadPlugin,
|
||||
NukePlaceholderCreatePlugin,
|
||||
build_workfile_template,
|
||||
update_workfile_template,
|
||||
create_placeholder,
|
||||
update_placeholder,
|
||||
)
|
||||
|
|
@ -156,6 +156,7 @@ def add_nuke_callbacks():
|
|||
nuke.addOnCreate(
|
||||
workfile_settings.set_context_settings, nodeClass="Root")
|
||||
nuke.addOnCreate(workfile_settings.set_favorites, nodeClass="Root")
|
||||
nuke.addOnCreate(start_workfile_template_builder, nodeClass="Root")
|
||||
nuke.addOnCreate(process_workfile_builder, nodeClass="Root")
|
||||
|
||||
# fix ffmpeg settings on script
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import collections
|
||||
|
||||
import nuke
|
||||
|
||||
from openpype.pipeline import registered_host
|
||||
from openpype.pipeline.workfile.workfile_template_builder import (
|
||||
AbstractTemplateBuilder,
|
||||
|
|
@ -14,7 +12,6 @@ from openpype.pipeline.workfile.workfile_template_builder import (
|
|||
from openpype.tools.workfile_template_build import (
|
||||
WorkfileBuildPlaceholderDialog,
|
||||
)
|
||||
|
||||
from .lib import (
|
||||
find_free_space_to_paste_nodes,
|
||||
get_extreme_positions,
|
||||
|
|
@ -45,7 +42,7 @@ class NukeTemplateBuilder(AbstractTemplateBuilder):
|
|||
get_template_preset implementation)
|
||||
|
||||
Returns:
|
||||
bool: Wether the template was succesfully imported or not
|
||||
bool: Wether the template was successfully imported or not
|
||||
"""
|
||||
|
||||
# TODO check if the template is already imported
|
||||
|
|
@ -55,7 +52,6 @@ class NukeTemplateBuilder(AbstractTemplateBuilder):
|
|||
|
||||
return True
|
||||
|
||||
|
||||
class NukePlaceholderPlugin(PlaceholderPlugin):
|
||||
node_color = 4278190335
|
||||
|
||||
|
|
@ -947,9 +943,9 @@ class NukePlaceholderCreatePlugin(
|
|||
siblings_input.setInput(0, copy_output)
|
||||
|
||||
|
||||
def build_workfile_template(*args):
|
||||
def build_workfile_template(*args, **kwargs):
|
||||
builder = NukeTemplateBuilder(registered_host())
|
||||
builder.build_template()
|
||||
builder.build_template(*args, **kwargs)
|
||||
|
||||
|
||||
def update_workfile_template(*args):
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ def has_unsaved_changes():
|
|||
|
||||
def save_file(filepath):
|
||||
path = filepath.replace("\\", "/")
|
||||
nuke.scriptSaveAs(path)
|
||||
nuke.scriptSaveAs(path, overwrite=1)
|
||||
nuke.Root()["name"].setValue(path)
|
||||
nuke.Root()["project_directory"].setValue(os.path.dirname(path))
|
||||
nuke.Root().setModified(False)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ def update_op_assets(
|
|||
op_asset = create_op_asset(item)
|
||||
insert_result = dbcon.insert_one(op_asset)
|
||||
item_doc = get_asset_by_id(
|
||||
project_name, insert_result.inserted_id)
|
||||
project_name, insert_result.inserted_id
|
||||
)
|
||||
|
||||
# Update asset
|
||||
item_data = deepcopy(item_doc["data"])
|
||||
|
|
@ -133,39 +134,47 @@ def update_op_assets(
|
|||
try:
|
||||
fps = float(item_data.get("fps"))
|
||||
except (TypeError, ValueError):
|
||||
fps = float(gazu_project.get(
|
||||
"fps", project_doc["data"].get("fps", 25)))
|
||||
fps = float(
|
||||
gazu_project.get("fps", project_doc["data"].get("fps", 25))
|
||||
)
|
||||
item_data["fps"] = fps
|
||||
# Resolution, fall back to project default
|
||||
match_res = re.match(
|
||||
r"(\d+)x(\d+)",
|
||||
item_data.get("resolution", gazu_project.get("resolution"))
|
||||
item_data.get("resolution", gazu_project.get("resolution")),
|
||||
)
|
||||
if match_res:
|
||||
item_data["resolutionWidth"] = int(match_res.group(1))
|
||||
item_data["resolutionHeight"] = int(match_res.group(2))
|
||||
else:
|
||||
item_data["resolutionWidth"] = project_doc["data"].get(
|
||||
"resolutionWidth")
|
||||
"resolutionWidth"
|
||||
)
|
||||
item_data["resolutionHeight"] = project_doc["data"].get(
|
||||
"resolutionHeight")
|
||||
"resolutionHeight"
|
||||
)
|
||||
# Properties that doesn't fully exist in Kitsu.
|
||||
# Guessing those property names below:
|
||||
# Pixel Aspect Ratio
|
||||
item_data["pixelAspect"] = item_data.get(
|
||||
"pixel_aspect", project_doc["data"].get("pixelAspect"))
|
||||
"pixel_aspect", project_doc["data"].get("pixelAspect")
|
||||
)
|
||||
# Handle Start
|
||||
item_data["handleStart"] = item_data.get(
|
||||
"handle_start", project_doc["data"].get("handleStart"))
|
||||
"handle_start", project_doc["data"].get("handleStart")
|
||||
)
|
||||
# Handle End
|
||||
item_data["handleEnd"] = item_data.get(
|
||||
"handle_end", project_doc["data"].get("handleEnd"))
|
||||
"handle_end", project_doc["data"].get("handleEnd")
|
||||
)
|
||||
# Clip In
|
||||
item_data["clipIn"] = item_data.get(
|
||||
"clip_in", project_doc["data"].get("clipIn"))
|
||||
"clip_in", project_doc["data"].get("clipIn")
|
||||
)
|
||||
# Clip Out
|
||||
item_data["clipOut"] = item_data.get(
|
||||
"clip_out", project_doc["data"].get("clipOut"))
|
||||
"clip_out", project_doc["data"].get("clipOut")
|
||||
)
|
||||
|
||||
# Tasks
|
||||
tasks_list = []
|
||||
|
|
@ -175,11 +184,9 @@ def update_op_assets(
|
|||
elif item_type == "Shot":
|
||||
tasks_list = gazu.task.all_tasks_for_shot(item)
|
||||
item_data["tasks"] = {
|
||||
item_data["tasks"] = {
|
||||
t["task_type_name"]: {
|
||||
"type": t["task_type_name"],
|
||||
"zou": gazu.task.get_task(t["id"]),
|
||||
}
|
||||
t["task_type_name"]: {
|
||||
"type": t["task_type_name"],
|
||||
"zou": gazu.task.get_task(t["id"]),
|
||||
}
|
||||
for t in tasks_list
|
||||
}
|
||||
|
|
@ -218,7 +225,9 @@ def update_op_assets(
|
|||
if parent_zou_id_dict is not None:
|
||||
visual_parent_doc_id = (
|
||||
parent_zou_id_dict.get("_id")
|
||||
if parent_zou_id_dict else None)
|
||||
if parent_zou_id_dict
|
||||
else None
|
||||
)
|
||||
|
||||
if visual_parent_doc_id is None:
|
||||
# Find root folder doc ("Assets" or "Shots")
|
||||
|
|
@ -345,7 +354,8 @@ def write_project_to_op(project: dict, dbcon: AvalonMongoDB) -> UpdateOne:
|
|||
|
||||
|
||||
def sync_all_projects(
|
||||
login: str, password: str, ignore_projects: list = None):
|
||||
login: str, password: str, ignore_projects: list = None
|
||||
):
|
||||
"""Update all OP projects in DB with Zou data.
|
||||
|
||||
Args:
|
||||
|
|
@ -390,7 +400,7 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
|||
if not project:
|
||||
project = gazu.project.get_project_by_name(project["name"])
|
||||
|
||||
log.info("Synchronizing {}...".format(project['name']))
|
||||
log.info("Synchronizing {}...".format(project["name"]))
|
||||
|
||||
# Get all assets from zou
|
||||
all_assets = gazu.asset.all_assets_for_project(project)
|
||||
|
|
@ -473,8 +483,11 @@ def sync_project_from_kitsu(dbcon: AvalonMongoDB, project: dict):
|
|||
[
|
||||
UpdateOne({"_id": id}, update)
|
||||
for id, update in update_op_assets(
|
||||
dbcon, project, project_dict,
|
||||
all_entities, zou_ids_and_asset_docs
|
||||
dbcon,
|
||||
project,
|
||||
project_dict,
|
||||
all_entities,
|
||||
zou_ids_and_asset_docs,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ from openpype.settings import (
|
|||
get_project_settings,
|
||||
get_system_settings,
|
||||
)
|
||||
from openpype.host import IWorkfileHost
|
||||
from openpype.host import HostBase
|
||||
from openpype.lib import (
|
||||
Logger,
|
||||
|
|
@ -440,7 +441,9 @@ class AbstractTemplateBuilder(object):
|
|||
self,
|
||||
template_path=None,
|
||||
level_limit=None,
|
||||
keep_placeholders=None
|
||||
keep_placeholders=None,
|
||||
create_first_version=None,
|
||||
workfile_creation_enabled=False
|
||||
):
|
||||
"""Main callback for building workfile from template path.
|
||||
|
||||
|
|
@ -457,6 +460,11 @@ class AbstractTemplateBuilder(object):
|
|||
keep_placeholders (bool): Add flag to placeholder data for
|
||||
hosts to decide if they want to remove
|
||||
placeholder after it is used.
|
||||
create_first_version (bool): create first version of a workfile
|
||||
workfile_creation_enabled (bool): If True, it might create
|
||||
first version but ignore
|
||||
process if version is created
|
||||
|
||||
"""
|
||||
template_preset = self.get_template_preset()
|
||||
|
||||
|
|
@ -465,6 +473,30 @@ class AbstractTemplateBuilder(object):
|
|||
|
||||
if keep_placeholders is None:
|
||||
keep_placeholders = template_preset["keep_placeholder"]
|
||||
if create_first_version is None:
|
||||
create_first_version = template_preset["create_first_version"]
|
||||
|
||||
# check if first version is created
|
||||
created_version_workfile = self.create_first_workfile_version()
|
||||
|
||||
# if first version is created, import template
|
||||
# and populate placeholders
|
||||
if (
|
||||
create_first_version
|
||||
and workfile_creation_enabled
|
||||
and created_version_workfile
|
||||
):
|
||||
self.import_template(template_path)
|
||||
self.populate_scene_placeholders(
|
||||
level_limit, keep_placeholders)
|
||||
|
||||
# save workfile after template is populated
|
||||
self.save_workfile(created_version_workfile)
|
||||
|
||||
# ignore process if first workfile is enabled
|
||||
# but a version is already created
|
||||
if workfile_creation_enabled:
|
||||
return
|
||||
|
||||
self.import_template(template_path)
|
||||
self.populate_scene_placeholders(
|
||||
|
|
@ -516,6 +548,39 @@ class AbstractTemplateBuilder(object):
|
|||
|
||||
pass
|
||||
|
||||
def create_first_workfile_version(self):
|
||||
"""
|
||||
Create first version of workfile.
|
||||
|
||||
Should load the content of template into scene so
|
||||
'populate_scene_placeholders' can be started.
|
||||
|
||||
Args:
|
||||
template_path (str): Fullpath for current task and
|
||||
host's template file.
|
||||
"""
|
||||
last_workfile_path = os.environ.get("AVALON_LAST_WORKFILE")
|
||||
self.log.info("__ last_workfile_path: {}".format(last_workfile_path))
|
||||
if os.path.exists(last_workfile_path):
|
||||
# ignore in case workfile existence
|
||||
self.log.info("Workfile already exists, skipping creation.")
|
||||
return False
|
||||
|
||||
# Create first version
|
||||
self.log.info("Creating first version of workfile.")
|
||||
self.save_workfile(last_workfile_path)
|
||||
|
||||
# Confirm creation of first version
|
||||
return last_workfile_path
|
||||
|
||||
def save_workfile(self, workfile_path):
|
||||
"""Save workfile in current host."""
|
||||
# Save current scene, continue to open file
|
||||
if isinstance(self.host, IWorkfileHost):
|
||||
self.host.save_workfile(workfile_path)
|
||||
else:
|
||||
self.host.save_file(workfile_path)
|
||||
|
||||
def _prepare_placeholders(self, placeholders):
|
||||
"""Run preparation part for placeholders on plugins.
|
||||
|
||||
|
|
@ -699,6 +764,8 @@ class AbstractTemplateBuilder(object):
|
|||
|
||||
# switch to remove placeholders after they are used
|
||||
keep_placeholder = profile.get("keep_placeholder")
|
||||
create_first_version = profile.get("create_first_version")
|
||||
|
||||
# backward compatibility, since default is True
|
||||
if keep_placeholder is None:
|
||||
keep_placeholder = True
|
||||
|
|
@ -732,7 +799,8 @@ class AbstractTemplateBuilder(object):
|
|||
self.log.info("Found template at: '{}'".format(path))
|
||||
return {
|
||||
"path": path,
|
||||
"keep_placeholder": keep_placeholder
|
||||
"keep_placeholder": keep_placeholder,
|
||||
"create_first_version": create_first_version
|
||||
}
|
||||
|
||||
solved_path = None
|
||||
|
|
@ -761,7 +829,8 @@ class AbstractTemplateBuilder(object):
|
|||
|
||||
return {
|
||||
"path": solved_path,
|
||||
"keep_placeholder": keep_placeholder
|
||||
"keep_placeholder": keep_placeholder,
|
||||
"create_first_version": create_first_version
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -565,7 +565,17 @@
|
|||
]
|
||||
},
|
||||
"templated_workfile_build": {
|
||||
"profiles": []
|
||||
"profiles": [
|
||||
{
|
||||
"task_types": [
|
||||
"Compositing"
|
||||
],
|
||||
"task_names": [],
|
||||
"path": "{project[name]}/templates/comp.nk",
|
||||
"keep_placeholder": true,
|
||||
"create_first_version": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"filters": {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@
|
|||
"label": "Keep placeholders",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "create_first_version",
|
||||
"label": "Create first version",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ class AttributeDefinitionsWidget(QtWidgets.QWidget):
|
|||
|
||||
class _BaseAttrDefWidget(QtWidgets.QWidget):
|
||||
# Type 'object' may not work with older PySide versions
|
||||
value_changed = QtCore.Signal(object, uuid.UUID)
|
||||
value_changed = QtCore.Signal(object, str)
|
||||
|
||||
def __init__(self, attr_def, parent):
|
||||
super(_BaseAttrDefWidget, self).__init__(parent)
|
||||
|
|
|
|||
|
|
@ -98,15 +98,22 @@ class Popup(QtWidgets.QDialog):
|
|||
height = window.height()
|
||||
height = max(height, window.sizeHint().height())
|
||||
|
||||
desktop_geometry = QtWidgets.QDesktopWidget().availableGeometry()
|
||||
screen_geometry = window.geometry()
|
||||
try:
|
||||
screen = window.screen()
|
||||
desktop_geometry = screen.availableGeometry()
|
||||
except AttributeError:
|
||||
# Backwards compatibility for older Qt versions
|
||||
# PySide6 removed QDesktopWidget
|
||||
desktop_geometry = QtWidgets.QDesktopWidget().availableGeometry()
|
||||
|
||||
screen_width = screen_geometry.width()
|
||||
screen_height = screen_geometry.height()
|
||||
window_geometry = window.geometry()
|
||||
|
||||
screen_width = window_geometry.width()
|
||||
screen_height = window_geometry.height()
|
||||
|
||||
# Calculate width and height of system tray
|
||||
systray_width = screen_geometry.width() - desktop_geometry.width()
|
||||
systray_height = screen_geometry.height() - desktop_geometry.height()
|
||||
systray_width = window_geometry.width() - desktop_geometry.width()
|
||||
systray_height = window_geometry.height() - desktop_geometry.height()
|
||||
|
||||
padding = 10
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue