From ae7a6555139219c0bb384192965055a0467184de Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 12 Jun 2020 13:03:10 +0300 Subject: [PATCH 001/580] fix(resolve): transition to new structure --- pype/hooks/resolve/prelaunch.py | 6 +- pype/hosts/resolve/lib.py | 2 +- pype/hosts/resolve/pipeline.py | 14 ++-- pype/hosts/resolve/preload_console.py | 2 +- .../resolve/utility_scripts/Pype_menu.py | 2 +- .../utility_scripts/__dev_compound_clip.py | 65 ------------------- .../resolve/utility_scripts/__test_pyblish.py | 57 ---------------- .../utility_scripts/__test_subprocess.py | 35 ---------- 8 files changed, 13 insertions(+), 170 deletions(-) delete mode 100644 pype/hosts/resolve/utility_scripts/__dev_compound_clip.py delete mode 100644 pype/hosts/resolve/utility_scripts/__test_pyblish.py delete mode 100644 pype/hosts/resolve/utility_scripts/__test_subprocess.py diff --git a/pype/hooks/resolve/prelaunch.py b/pype/hooks/resolve/prelaunch.py index bddeccf4a3..a122b87868 100644 --- a/pype/hooks/resolve/prelaunch.py +++ b/pype/hooks/resolve/prelaunch.py @@ -46,13 +46,14 @@ class ResolvePrelaunch(PypeHook): "`RESOLVE_UTILITY_SCRIPTS_DIR` or reinstall DaVinci Resolve. \n" f"RESOLVE_UTILITY_SCRIPTS_DIR: `{us_dir}`" ) + self.log.debug(f"-- us_dir: `{us_dir}`") # correctly format path for pre python script pre_py_sc = os.path.normpath(env.get("PRE_PYTHON_SCRIPT", "")) env["PRE_PYTHON_SCRIPT"] = pre_py_sc - + self.log.debug(f"-- pre_py_sc: `{pre_py_sc}`...") try: - __import__("pype.resolve") + __import__("pype.hosts.resolve") __import__("pyblish") except ImportError as e: @@ -62,6 +63,7 @@ class ResolvePrelaunch(PypeHook): else: # Resolve Setup integration importlib.reload(utils) + self.log.debug(f"-- utils.__file__: `{utils.__file__}`") utils.setup(env) return True diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 2576136df5..2e759ab96c 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -1,6 +1,6 @@ import sys from .utils import get_resolve_module -from pypeapp import Logger +from pype.api import Logger log = Logger().get_logger(__name__, "resolve") diff --git a/pype/hosts/resolve/pipeline.py b/pype/hosts/resolve/pipeline.py index 967aed1436..8dfb94486b 100644 --- a/pype/hosts/resolve/pipeline.py +++ b/pype/hosts/resolve/pipeline.py @@ -6,23 +6,21 @@ import os from avalon.tools import workfiles from avalon import api as avalon from pyblish import api as pyblish -from pypeapp import Logger +import pype +from pype.api import Logger log = Logger().get_logger(__name__, "resolve") # self = sys.modules[__name__] AVALON_CONFIG = os.environ["AVALON_CONFIG"] -PARENT_DIR = os.path.dirname(__file__) -PACKAGE_DIR = os.path.dirname(PARENT_DIR) -PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins") -LOAD_PATH = os.path.join(PLUGINS_DIR, "resolve", "load") -CREATE_PATH = os.path.join(PLUGINS_DIR, "resolve", "create") -INVENTORY_PATH = os.path.join(PLUGINS_DIR, "resolve", "inventory") +LOAD_PATH = os.path.join(pype.PLUGINS_DIR, "resolve", "load") +CREATE_PATH = os.path.join(pype.PLUGINS_DIR, "resolve", "create") +INVENTORY_PATH = os.path.join(pype.PLUGINS_DIR, "resolve", "inventory") PUBLISH_PATH = os.path.join( - PLUGINS_DIR, "resolve", "publish" + pype.PLUGINS_DIR, "resolve", "publish" ).replace("\\", "/") AVALON_CONTAINERS = ":AVALON_CONTAINERS" diff --git a/pype/hosts/resolve/preload_console.py b/pype/hosts/resolve/preload_console.py index ea1bd4f180..58975777b8 100644 --- a/pype/hosts/resolve/preload_console.py +++ b/pype/hosts/resolve/preload_console.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import time from pype.hosts.resolve.utils import get_resolve_module -from pypeapp import Logger +from pype.api import Logger log = Logger().get_logger(__name__, "resolve") diff --git a/pype/hosts/resolve/utility_scripts/Pype_menu.py b/pype/hosts/resolve/utility_scripts/Pype_menu.py index 1f5cd36277..230a7a80f0 100644 --- a/pype/hosts/resolve/utility_scripts/Pype_menu.py +++ b/pype/hosts/resolve/utility_scripts/Pype_menu.py @@ -3,7 +3,7 @@ import sys import avalon.api as avalon import pype -from pypeapp import Logger +from pype.api import Logger log = Logger().get_logger(__name__) diff --git a/pype/hosts/resolve/utility_scripts/__dev_compound_clip.py b/pype/hosts/resolve/utility_scripts/__dev_compound_clip.py deleted file mode 100644 index fe47008c70..0000000000 --- a/pype/hosts/resolve/utility_scripts/__dev_compound_clip.py +++ /dev/null @@ -1,65 +0,0 @@ -#! python3 -# -*- coding: utf-8 -*- - - -# convert clip def -def convert_clip(timeline=None): - """Convert timeline item (clip) into compound clip pype container - - Args: - timeline (MediaPool.Timeline): Object of timeline - - Returns: - bool: `True` if success - - Raises: - Exception: description - - """ - pass - - -# decorator function create_current_timeline_media_bin() -def create_current_timeline_media_bin(timeline=None): - """Convert timeline item (clip) into compound clip pype container - - Args: - timeline (MediaPool.Timeline): Object of timeline - - Returns: - bool: `True` if success - - Raises: - Exception: description - - """ - pass - - -# decorator function get_selected_track_items() -def get_selected_track_items(): - """Convert timeline item (clip) into compound clip pype container - - Args: - timeline (MediaPool.Timeline): Object of timeline - - Returns: - bool: `True` if success - - Raises: - Exception: description - - """ - print("testText") - - -# PypeCompoundClip() class -class PypeCompoundClip(object): - """docstring for .""" - - def __init__(self, arg): - super(self).__init__() - self.arg = arg - - def create_compound_clip(self): - pass diff --git a/pype/hosts/resolve/utility_scripts/__test_pyblish.py b/pype/hosts/resolve/utility_scripts/__test_pyblish.py deleted file mode 100644 index a6fe991025..0000000000 --- a/pype/hosts/resolve/utility_scripts/__test_pyblish.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import sys -import pype -import importlib -import pyblish.api -import pyblish.util -import avalon.api -from avalon.tools import publish -from pypeapp import Logger - -log = Logger().get_logger(__name__) - - -def main(env): - # Registers pype's Global pyblish plugins - pype.install() - - # Register Host (and it's pyblish plugins) - host_name = env["AVALON_APP"] - # TODO not sure if use "pype." or "avalon." for host import - host_import_str = f"pype.{host_name}" - - try: - host_module = importlib.import_module(host_import_str) - except ModuleNotFoundError: - log.error(( - f"Host \"{host_name}\" can't be imported." - f" Import string \"{host_import_str}\" failed." - )) - return False - - avalon.api.install(host_module) - - # Register additional paths - addition_paths_str = env.get("PUBLISH_PATHS") or "" - addition_paths = addition_paths_str.split(os.pathsep) - for path in addition_paths: - path = os.path.normpath(path) - if not os.path.exists(path): - continue - - pyblish.api.register_plugin_path(path) - - # Register project specific plugins - project_name = os.environ["AVALON_PROJECT"] - project_plugins_paths = env.get("PYPE_PROJECT_PLUGINS") or "" - for path in project_plugins_paths.split(os.pathsep): - plugin_path = os.path.join(path, project_name, "plugins") - if os.path.exists(plugin_path): - pyblish.api.register_plugin_path(plugin_path) - - return publish.show() - - -if __name__ == "__main__": - result = main(os.environ) - sys.exit(not bool(result)) diff --git a/pype/hosts/resolve/utility_scripts/__test_subprocess.py b/pype/hosts/resolve/utility_scripts/__test_subprocess.py deleted file mode 100644 index bdc57bbf00..0000000000 --- a/pype/hosts/resolve/utility_scripts/__test_subprocess.py +++ /dev/null @@ -1,35 +0,0 @@ -#! python3 -# -*- coding: utf-8 -*- -import os -from pypeapp import execute, Logger -from pype.hosts.resolve.utils import get_resolve_module - -log = Logger().get_logger("Resolve") - -CURRENT_DIR = os.getenv("RESOLVE_UTILITY_SCRIPTS_DIR", "") -python_dir = os.getenv("PYTHON36_RESOLVE") -python_exe = os.path.normpath( - os.path.join(python_dir, "python.exe") -) - -resolve = get_resolve_module() -PM = resolve.GetProjectManager() -P = PM.GetCurrentProject() - -log.info(P.GetName()) - - -# ______________________________________________________ -# testing subprocessing Scripts -testing_py = os.path.join(CURRENT_DIR, "ResolvePageSwitcher.py") -testing_py = os.path.normpath(testing_py) -log.info(f"Testing path to script: `{testing_py}`") - -returncode = execute( - [python_exe, os.path.normpath(testing_py)], - env=dict(os.environ) -) - -# Check if output file exists -if returncode != 0: - log.error("Executing failed!") From a4d3b40136175ae299ae0306da15c62507e8d998 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 12 Jun 2020 13:03:38 +0300 Subject: [PATCH 002/580] feat(resolve): adding currentFile to collect project --- pype/plugins/resolve/publish/collect_host.py | 17 ----------- .../resolve/publish/collect_project.py | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 17 deletions(-) delete mode 100644 pype/plugins/resolve/publish/collect_host.py create mode 100644 pype/plugins/resolve/publish/collect_project.py diff --git a/pype/plugins/resolve/publish/collect_host.py b/pype/plugins/resolve/publish/collect_host.py deleted file mode 100644 index a5c4b0936c..0000000000 --- a/pype/plugins/resolve/publish/collect_host.py +++ /dev/null @@ -1,17 +0,0 @@ -import pyblish.api -from pype.hosts.resolve.utils import get_resolve_module - - -class CollectProject(pyblish.api.ContextPlugin): - """Collect Project object""" - - order = pyblish.api.CollectorOrder - 0.1 - label = "Collect Project" - hosts = ["resolve"] - - def process(self, context): - resolve = get_resolve_module() - PM = resolve.GetProjectManager() - P = PM.GetCurrentProject() - - self.log.info(P.GetName()) diff --git a/pype/plugins/resolve/publish/collect_project.py b/pype/plugins/resolve/publish/collect_project.py new file mode 100644 index 0000000000..aa57f93619 --- /dev/null +++ b/pype/plugins/resolve/publish/collect_project.py @@ -0,0 +1,29 @@ +import os +import pyblish.api +from pype.hosts.resolve.utils import get_resolve_module + + +class CollectProject(pyblish.api.ContextPlugin): + """Collect Project object""" + + order = pyblish.api.CollectorOrder - 0.1 + label = "Collect Project" + hosts = ["resolve"] + + def process(self, context): + exported_projet_ext = ".drp" + current_dir = os.getenv("AVALON_WORKDIR") + resolve = get_resolve_module() + PM = resolve.GetProjectManager() + P = PM.GetCurrentProject() + name = P.GetName() + + fname = name + exported_projet_ext + current_file = os.path.join(current_dir, fname) + normalised = os.path.normpath(current_file) + + context.data["project"] = P + context.data["currentFile"] = normalised + + self.log.info(name) + self.log.debug(normalised) From 700c62617814d3e9e1c1026bf3423d7cf620eee3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 17 Jun 2020 17:13:17 +0300 Subject: [PATCH 003/580] feat(resolve): adding create shot clip --- pype/plugins/resolve/create/create_shot_clip.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 pype/plugins/resolve/create/create_shot_clip.py diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py new file mode 100644 index 0000000000..97d5663922 --- /dev/null +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -0,0 +1,15 @@ +import avalon.api +from pype.hosts import resolve + + +class CreateShotClip(avalon.api.Creator): + """Publishable clip""" + + label = "Shot" + family = "clip" + icon = "film" + defaults = ["Main"] + + def process(self): + project = resolve.get_current_project() + self.log.info(f"Project name: {project.GetName()}") From 37fff09ecdafb1d4eb3ea8af070d387415c41ec9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 17 Jun 2020 18:27:51 +0300 Subject: [PATCH 004/580] feat(resolve): wip create plugins --- pype/hosts/resolve/__init__.py | 38 ++++++++++---- pype/hosts/resolve/action.py | 6 +-- pype/hosts/resolve/lib.py | 19 +++++-- pype/hosts/resolve/pipeline.py | 51 +++++++++++++++++-- pype/hosts/resolve/plugin.py | 21 +++++++- pype/hosts/resolve/utility_scripts/test.py | 19 +++++++ pype/hosts/resolve/utils.py | 18 +++---- pype/hosts/resolve/workio.py | 5 +- .../resolve/create/create_shot_clip.py | 10 ++-- 9 files changed, 150 insertions(+), 37 deletions(-) create mode 100644 pype/hosts/resolve/utility_scripts/test.py diff --git a/pype/hosts/resolve/__init__.py b/pype/hosts/resolve/__init__.py index 72d6314b5e..b7e6c7dee3 100644 --- a/pype/hosts/resolve/__init__.py +++ b/pype/hosts/resolve/__init__.py @@ -1,17 +1,29 @@ +from .utils import ( + setup, + get_resolve_module +) + from .pipeline import ( install, uninstall, ls, containerise, publish, - launch_workfiles_app + launch_workfiles_app, + maintained_selection ) -from .utils import ( - setup, - get_resolve_module +from .lib import ( + get_project_manager, + get_current_project, + get_current_sequence, + set_project_manager_to_folder_name ) +from .menu import launch_pype_menu + +from .plugin import Creator + from .workio import ( open_file, save_file, @@ -21,12 +33,7 @@ from .workio import ( work_root ) -from .lib import ( - get_project_manager, - set_project_manager_to_folder_name -) - -from .menu import launch_pype_menu +bmd = None __all__ = [ # pipeline @@ -37,6 +44,7 @@ __all__ = [ "reload_pipeline", "publish", "launch_workfiles_app", + "maintained_selection", # utils "setup", @@ -44,16 +52,24 @@ __all__ = [ # lib "get_project_manager", + "get_current_project", + "get_current_sequence", "set_project_manager_to_folder_name", # menu "launch_pype_menu", + # plugin + "Creator", + # workio "open_file", "save_file", "current_file", "has_unsaved_changes", "file_extensions", - "work_root" + "work_root", + + # singleton with black magic resolve module + "bmd" ] diff --git a/pype/hosts/resolve/action.py b/pype/hosts/resolve/action.py index 31830937c1..a9803cef4e 100644 --- a/pype/hosts/resolve/action.py +++ b/pype/hosts/resolve/action.py @@ -21,9 +21,9 @@ class SelectInvalidAction(pyblish.api.Action): def process(self, context, plugin): try: - from pype.hosts.resolve.utils import get_resolve_module - resolve = get_resolve_module() - self.log.debug(resolve) + from . import get_project_manager + pm = get_project_manager() + self.log.debug(pm) except ImportError: raise ImportError("Current host is not Resolve") diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 2e759ab96c..25e177eb1c 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -1,5 +1,4 @@ import sys -from .utils import get_resolve_module from pype.api import Logger log = Logger().get_logger(__name__, "resolve") @@ -9,12 +8,26 @@ self.pm = None def get_project_manager(): + from . import bmd if not self.pm: - resolve = get_resolve_module() - self.pm = resolve.GetProjectManager() + self.pm = bmd.GetProjectManager() return self.pm +def get_current_project(): + # initialize project manager + get_project_manager() + + return self.pm.GetCurrentProject() + + +def get_current_sequence(): + # get current project + project = get_current_project() + + return project.GetCurrentTimeline() + + def set_project_manager_to_folder_name(folder_name): """ Sets context of Project manager to given folder by name. diff --git a/pype/hosts/resolve/pipeline.py b/pype/hosts/resolve/pipeline.py index 8dfb94486b..91d06da274 100644 --- a/pype/hosts/resolve/pipeline.py +++ b/pype/hosts/resolve/pipeline.py @@ -2,7 +2,7 @@ Basic avalon integration """ import os -# import sys +import contextlib from avalon.tools import workfiles from avalon import api as avalon from pyblish import api as pyblish @@ -11,8 +11,6 @@ from pype.api import Logger log = Logger().get_logger(__name__, "resolve") -# self = sys.modules[__name__] - AVALON_CONFIG = os.environ["AVALON_CONFIG"] LOAD_PATH = os.path.join(pype.PLUGINS_DIR, "resolve", "load") @@ -38,11 +36,13 @@ def install(): See the Maya equivalent for inspiration on how to implement this. """ + from . import get_resolve_module # Disable all families except for the ones we explicitly want to see family_states = [ "imagesequence", - "mov" + "mov", + "clip" ] avalon.data["familiesStateDefault"] = False avalon.data["familiesStateToggled"] = family_states @@ -57,6 +57,8 @@ def install(): avalon.register_plugin_path(avalon.Creator, CREATE_PATH) avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH) + get_resolve_module() + def uninstall(): """Uninstall all tha was installed @@ -138,3 +140,44 @@ def publish(parent): """Shorthand to publish from within host""" from avalon.tools import publish return publish.show(parent) + + +@contextlib.contextmanager +def maintained_selection(): + """Maintain selection during context + + Example: + >>> with maintained_selection(): + ... node['selected'].setValue(True) + >>> print(node['selected'].value()) + False + """ + from . import get_current_project + project = get_current_project() + nodes = [] + previous_selection = None + + # deselect all nodes + reset_selection() + + try: + # do the operation + yield + finally: + # unselect all selection in case there is some + reset_selection() + # and select all previously selected nodes + if previous_selection: + try: + for n in nodes: + if n not in previous_selection: + continue + n['selected'].setValue(True) + except ValueError as e: + log.warning(e) + + +def reset_selection(): + """Deselect all selected nodes + """ + pass diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 628d4bdb26..513b9984f4 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -1,6 +1,7 @@ from avalon import api -# from pype.hosts.resolve import lib as drlib +from pype.hosts import resolve from avalon.vendor import qargparse +from pype.api import config def get_reference_node_parents(ref): @@ -73,3 +74,21 @@ class SequenceLoader(api.Loader): """Remove an existing `container` """ pass + + +class Creator(api.Creator): + """Creator class wrapper + """ + marker_color = "Purple" + + def __init__(self, *args, **kwargs): + super(Creator, self).__init__(*args, **kwargs) + self.presets = config.get_presets()['plugins']["resolve"][ + "create"].get(self.__class__.__name__, {}) + + # adding basic current context resolve objects + self.project = resolve.get_current_project() + self.sequence = resolve.get_current_sequence() + + # TODO: make sure no duplicity of subsets are in workfile + return diff --git a/pype/hosts/resolve/utility_scripts/test.py b/pype/hosts/resolve/utility_scripts/test.py new file mode 100644 index 0000000000..4c43507e62 --- /dev/null +++ b/pype/hosts/resolve/utility_scripts/test.py @@ -0,0 +1,19 @@ +#! python3 +import sys +from pype.api import Logger + +log = Logger().get_logger(__name__) + + +def main(): + import pype.hosts.resolve as bmdvr + bm = bmdvr.utils.get_resolve_module() + log.info(f"blackmagicmodule: {bm}") + +import DaVinciResolveScript as bmd +print(f"_>> bmd.scriptapp(Resolve): {bmd.scriptapp('Resolve')}") + + +if __name__ == "__main__": + result = main() + sys.exit(not bool(result)) diff --git a/pype/hosts/resolve/utils.py b/pype/hosts/resolve/utils.py index f5add53a6b..74ce2dc98f 100644 --- a/pype/hosts/resolve/utils.py +++ b/pype/hosts/resolve/utils.py @@ -9,18 +9,16 @@ import os import shutil from pypeapp import Logger - log = Logger().get_logger(__name__, "resolve") -self = sys.modules[__name__] -self.bmd = None - def get_resolve_module(): + from pype.hosts import resolve # dont run if already loaded - if self.bmd: - return self.bmd - + if resolve.bmd: + log.info(("resolve module is assigned to " + f"`pype.hosts.resolve.bmd`: {resolve.bmd}")) + return resolve.bmd try: """ The PYTHONPATH needs to be set correctly for this import @@ -71,8 +69,10 @@ def get_resolve_module(): ) sys.exit() # assign global var and return - self.bmd = bmd.scriptapp("Resolve") - return self.bmd + bmd = bmd.scriptapp("Resolve") + resolve.bmd = bmd + log.info(("Assigning resolve module to " + f"`pype.hosts.resolve.bmd`: {resolve.bmd}")) def _sync_utility_scripts(env=None): diff --git a/pype/hosts/resolve/workio.py b/pype/hosts/resolve/workio.py index e1e30a8734..9d8d320a3c 100644 --- a/pype/hosts/resolve/workio.py +++ b/pype/hosts/resolve/workio.py @@ -2,8 +2,9 @@ import os from pypeapp import Logger -from .lib import ( +from . import ( get_project_manager, + get_current_project, set_project_manager_to_folder_name ) @@ -26,7 +27,7 @@ def save_file(filepath): pm = get_project_manager() file = os.path.basename(filepath) fname, _ = os.path.splitext(file) - project = pm.GetCurrentProject() + project = get_current_project() name = project.GetName() if "Untitled Project" not in name: diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index 97d5663922..43a8ab0cbd 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -1,8 +1,7 @@ -import avalon.api from pype.hosts import resolve -class CreateShotClip(avalon.api.Creator): +class CreateShotClip(resolve.Creator): """Publishable clip""" label = "Shot" @@ -10,6 +9,9 @@ class CreateShotClip(avalon.api.Creator): icon = "film" defaults = ["Main"] + presets = None + def process(self): - project = resolve.get_current_project() - self.log.info(f"Project name: {project.GetName()}") + print(f"Project name: {self.project.GetName()}") + print(f"Sequence name: {self.sequence.GetName()}") + print(self.presets) From 48c163a3319429ba63eb068c928fc77509c4f88c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 22 Jun 2020 19:30:17 +0300 Subject: [PATCH 005/580] feat(resolve): updating resolve integration wip --- pype/hosts/resolve/__init__.py | 12 +- pype/hosts/resolve/lib.py | 205 +++++++++++++++++- pype/hosts/resolve/pipeline.py | 20 +- pype/hosts/resolve/plugin.py | 8 +- pype/hosts/resolve/utility_scripts/test.py | 4 +- pype/hosts/resolve/utils.py | 16 +- .../resolve/create/create_shot_clip.py | 27 ++- 7 files changed, 255 insertions(+), 37 deletions(-) diff --git a/pype/hosts/resolve/__init__.py b/pype/hosts/resolve/__init__.py index b7e6c7dee3..5f651f4b29 100644 --- a/pype/hosts/resolve/__init__.py +++ b/pype/hosts/resolve/__init__.py @@ -17,6 +17,9 @@ from .lib import ( get_project_manager, get_current_project, get_current_sequence, + get_current_track_items, + create_current_sequence_media_bin, + create_compound_clip, set_project_manager_to_folder_name ) @@ -33,7 +36,8 @@ from .workio import ( work_root ) -bmd = None +bmdvr = None +bmdvf = None __all__ = [ # pipeline @@ -54,6 +58,9 @@ __all__ = [ "get_project_manager", "get_current_project", "get_current_sequence", + "get_current_track_items", + "create_current_sequence_media_bin", + "create_compound_clip", "set_project_manager_to_folder_name", # menu @@ -71,5 +78,6 @@ __all__ = [ "work_root", # singleton with black magic resolve module - "bmd" + "bmdvr", + "bmdvf" ] diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 25e177eb1c..9232f8ec68 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -8,9 +8,9 @@ self.pm = None def get_project_manager(): - from . import bmd + from . import bmdvr if not self.pm: - self.pm = bmd.GetProjectManager() + self.pm = bmdvr.GetProjectManager() return self.pm @@ -28,6 +28,207 @@ def get_current_sequence(): return project.GetCurrentTimeline() +def get_current_track_items( + filter=False, + track_type=None, + selecting_color=None): + """ Gets all available current timeline track items + """ + from pprint import pformat + track_type = track_type or "video" + selecting_color = selecting_color or "Chocolate" + project = get_current_project() + sequence = get_current_sequence() + selected_clips = list() + + # get all tracks count filtered by track type + sequence_video_count = sequence.GetTrackCount(track_type) + + # loop all tracks and get items + _clips = dict() + for track_index in range(1, (int(sequence_video_count) + 1)): + track_name = sequence.GetTrackName(track_type, track_index) + track_track_items = sequence.GetItemListInTrack( + track_type, track_index) + _clips[track_index] = track_track_items + + _data = { + "project": project, + "sequence": sequence, + "track": { + "name": track_name, + "index": track_index, + "type": track_type} + } + # get track item object and its color + for clip_index, ti in enumerate(_clips[track_index]): + data = _data.copy() + data["clip"] = { + "item": ti, + "index": clip_index + } + ti_color = ti.GetClipColor() + if filter is True: + if selecting_color in ti_color: + selected_clips.append(data) + ti.ClearClipColor() + else: + selected_clips.append(data) + + return selected_clips + + +def create_current_sequence_media_bin(sequence): + seq_name = sequence.GetName() + media_pool = get_current_project().GetMediaPool() + root_folder = media_pool.GetRootFolder() + sub_folders = root_folder.GetSubFolderList() + testing_names = list() + + print(f"_ sub_folders: {sub_folders}") + for subfolder in sub_folders: + subf_name = subfolder.GetName() + if seq_name in subf_name: + testing_names.append(subfolder) + else: + testing_names.append(False) + + matching = next((f for f in testing_names if f is not False), None) + + if not matching: + new_folder = media_pool.AddSubFolder(root_folder, seq_name) + media_pool.SetCurrentFolder(new_folder) + else: + media_pool.SetCurrentFolder(matching) + + return media_pool.GetCurrentFolder() + + +def create_compound_clip(clip_data, folder, presets): + """ + Convert timeline object into nested timeline object + + Args: + clip_data (dict): timeline item object packed into dict + with project, timeline (sequence) + folder (resolve.MediaPool.Folder): media pool folder object, + presets (dict): pype config plugin presets + + Returns: + resolve.MediaPoolItem: media pool item with compound clip timeline(cct) + """ + from pprint import pformat + + # get basic objects form data + project = clip_data["project"] + sequence = clip_data["sequence"] + clip = clip_data["clip"] + + # get details of objects + clip_item = clip["item"] + track = clip_data["track"] + + # build name + clip_name_split = clip_item.GetName().split(".") + name = "_".join([ + track["name"], + str(track["index"]), + clip_name_split[0], + str(clip["index"])] + ) + + # get metadata + mp_item = clip_item.GetMediaPoolItem() + mp_props = mp_item.GetClipProperty() + metadata = get_metadata_from_clip(clip_item) + mp = project.GetMediaPool() + + # keep original sequence + sq_origin = sequence + + # print(f"_ sequence: {sequence}") + # print(f"_ metadata: {pformat(metadata)}") + + # Set current folder to input media_pool_folder: + mp.SetCurrentFolder(folder) + + # check if clip doesnt exist already: + clips = folder.GetClipList() + cct = next((c for c in clips + if c.GetName() in name), None) + + if cct: + print(f"_ cct exists: {cct}") + return cct + + # Create empty timeline in current folder and give name: + cct = mp.CreateEmptyTimeline(name) + print(f"_ cct: {cct}") + + # Set current timeline to created timeline: + project.SetCurrentTimeline(cct) + + # Add input clip to the current timeline: + # TODO: set offsets if handles + done = mp.AppendToTimeline([{ + "mediaPoolItem": mp_item, + "startFrame": int(mp_props["Start"]), + "endFrame": int(mp_props["End"]) + }]) + print(f"_ done1: {done}") + + # Set current timeline to the working timeline: + project.SetCurrentTimeline(sq_origin) + + # Add collected metadata to the comound clip: + done = mp_item.SetClipProperty("pypeMetadata", metadata) + print(f"_ done2: {done}") + + return cct + + +def validate_tc(x): + # Validate and reformat timecode string + + if len(x) != 11: + print('Invalid timecode. Try again.') + + c = ':' + colonized = x[:2] + c + x[3:5] + c + x[6:8] + c + x[9:] + + if colonized.replace(':', '').isdigit(): + print(f"_ colonized: {colonized}") + return colonized + else: + print('Invalid timecode. Try again.') + + +def get_metadata_from_clip(clip): + """ + Collect all metadata from resolve timeline item + + Args: + clip (resolve.TimelineItem): timeline item object + + Returns: + dict: all collected metadata as key: values + """ + mp_item = clip.GetMediaPoolItem() + + data = { + "clipIn": clip.GetStart(), + "clipOut": clip.GetEnd(), + "clipLeftOffset": clip.GetLeftOffset(), + "clipRightOffset": clip.GetRightOffset(), + "clipMarkers": clip.GetMarkers(), + "clipFlags": clip.GetFlagList(), + "sourceMetadata": mp_item.GetMetadata(), + "sourceId": mp_item.GetMediaId(), + "sourceProperties": mp_item.GetClipProperty() + } + return data + + def set_project_manager_to_folder_name(folder_name): """ Sets context of Project manager to given folder by name. diff --git a/pype/hosts/resolve/pipeline.py b/pype/hosts/resolve/pipeline.py index 91d06da274..92bef2e13b 100644 --- a/pype/hosts/resolve/pipeline.py +++ b/pype/hosts/resolve/pipeline.py @@ -152,29 +152,11 @@ def maintained_selection(): >>> print(node['selected'].value()) False """ - from . import get_current_project - project = get_current_project() - nodes = [] - previous_selection = None - - # deselect all nodes - reset_selection() - try: # do the operation yield finally: - # unselect all selection in case there is some - reset_selection() - # and select all previously selected nodes - if previous_selection: - try: - for n in nodes: - if n not in previous_selection: - continue - n['selected'].setValue(True) - except ValueError as e: - log.warning(e) + pass def reset_selection(): diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 513b9984f4..002d12106d 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -89,6 +89,10 @@ class Creator(api.Creator): # adding basic current context resolve objects self.project = resolve.get_current_project() self.sequence = resolve.get_current_sequence() - - # TODO: make sure no duplicity of subsets are in workfile + + if (self.options or {}).get("useSelection"): + self.selected = resolve.get_current_track_items(filter=True) + else: + self.selected = resolve.get_current_track_items(filter=False) + return diff --git a/pype/hosts/resolve/utility_scripts/test.py b/pype/hosts/resolve/utility_scripts/test.py index 4c43507e62..cf7db3b7e5 100644 --- a/pype/hosts/resolve/utility_scripts/test.py +++ b/pype/hosts/resolve/utility_scripts/test.py @@ -10,8 +10,8 @@ def main(): bm = bmdvr.utils.get_resolve_module() log.info(f"blackmagicmodule: {bm}") -import DaVinciResolveScript as bmd -print(f"_>> bmd.scriptapp(Resolve): {bmd.scriptapp('Resolve')}") +import DaVinciResolveScript as bmdvr +print(f"_>> bmdvr.scriptapp(Resolve): {bmdvr.scriptapp('Resolve')}") if __name__ == "__main__": diff --git a/pype/hosts/resolve/utils.py b/pype/hosts/resolve/utils.py index 74ce2dc98f..dcc92c5b8d 100644 --- a/pype/hosts/resolve/utils.py +++ b/pype/hosts/resolve/utils.py @@ -15,10 +15,10 @@ log = Logger().get_logger(__name__, "resolve") def get_resolve_module(): from pype.hosts import resolve # dont run if already loaded - if resolve.bmd: + if resolve.bmdvr: log.info(("resolve module is assigned to " - f"`pype.hosts.resolve.bmd`: {resolve.bmd}")) - return resolve.bmd + f"`pype.hosts.resolve.bmdvr`: {resolve.bmdvr}")) + return resolve.bmdvr try: """ The PYTHONPATH needs to be set correctly for this import @@ -69,10 +69,14 @@ def get_resolve_module(): ) sys.exit() # assign global var and return - bmd = bmd.scriptapp("Resolve") - resolve.bmd = bmd + bmdvr = bmd.scriptapp("Resolve") + bmdvf = bmd.scriptapp("Fusion") + resolve.bmdvr = bmdvr + resolve.bmdvf = bmdvf log.info(("Assigning resolve module to " - f"`pype.hosts.resolve.bmd`: {resolve.bmd}")) + f"`pype.hosts.resolve.bmdvr`: {resolve.bmdvr}")) + log.info(("Assigning resolve module to " + f"`pype.hosts.resolve.bmdvf`: {resolve.bmdvf}")) def _sync_utility_scripts(env=None): diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index 43a8ab0cbd..c48ca3a5a6 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -1,6 +1,6 @@ +from pprint import pformat from pype.hosts import resolve - class CreateShotClip(resolve.Creator): """Publishable clip""" @@ -12,6 +12,25 @@ class CreateShotClip(resolve.Creator): presets = None def process(self): - print(f"Project name: {self.project.GetName()}") - print(f"Sequence name: {self.sequence.GetName()}") - print(self.presets) + project = self.project + sequence = self.sequence + presets = self.presets + print(f"__ selected_clips: {self.selected}") + + # sequence attrs + sq_frame_start = self.sequence.GetStartFrame() + sq_markers = self.sequence.GetMarkers() + print(f"__ sq_frame_start: {pformat(sq_frame_start)}") + print(f"__ seq_markers: {pformat(sq_markers)}") + + # create media bin for compound clips (trackItems) + mp_folder = resolve.create_current_sequence_media_bin(self.sequence) + print(f"_ mp_folder: {mp_folder.GetName()}") + + for t_data in self.selected: + print(t_data) + # convert track item to timeline media pool item + c_clip = resolve.create_compound_clip( + t_data, mp_folder, presets) + + # replace orig clip with compound_clip From 8e91764c4c06aff57d158e853e3e51d191dcd3dd Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 23 Jun 2020 12:47:06 +0300 Subject: [PATCH 006/580] feat(resolve): create compound clip wip --- pype/hosts/resolve/lib.py | 34 ++++++++++++++++++++++++---------- pype/hosts/resolve/utils.py | 4 ++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 9232f8ec68..5a5980a462 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -1,4 +1,5 @@ import sys +import json from pype.api import Logger log = Logger().get_logger(__name__, "resolve") @@ -140,14 +141,14 @@ def create_compound_clip(clip_data, folder, presets): # get metadata mp_item = clip_item.GetMediaPoolItem() mp_props = mp_item.GetClipProperty() - metadata = get_metadata_from_clip(clip_item) + clip_attributes = get_clip_attributes(clip_item) mp = project.GetMediaPool() # keep original sequence sq_origin = sequence - # print(f"_ sequence: {sequence}") - # print(f"_ metadata: {pformat(metadata)}") + print(f"_ sequence: {sequence}") + print(f"_ metadata: {pformat(clip_attributes)}") # Set current folder to input media_pool_folder: mp.SetCurrentFolder(folder) @@ -163,7 +164,12 @@ def create_compound_clip(clip_data, folder, presets): # Create empty timeline in current folder and give name: cct = mp.CreateEmptyTimeline(name) - print(f"_ cct: {cct}") + + # check if clip doesnt exist already: + clips = folder.GetClipList() + cct = next((c for c in clips + if c.GetName() in name), None) + print(f"_ cct created: {cct}") # Set current timeline to created timeline: project.SetCurrentTimeline(cct) @@ -180,10 +186,19 @@ def create_compound_clip(clip_data, folder, presets): # Set current timeline to the working timeline: project.SetCurrentTimeline(sq_origin) - # Add collected metadata to the comound clip: - done = mp_item.SetClipProperty("pypeMetadata", metadata) + # Add collected metadata and attributes to the comound clip: + clip_attributes["VFX Notes"] = mp_item.GetMetadata( + "VFX Notes")["VFX Notes"] + clip_attributes = json.dumps(clip_attributes) + + for k, v in mp_item.GetMetadata().items(): + done = cct.SetMetadata(k, v) + + done = cct.SetMetadata("VFX Notes", clip_attributes) print(f"_ done2: {done}") + # # add clip item as take to timeline + # AddTake(cct, startFrame, endFrame) return cct @@ -203,15 +218,15 @@ def validate_tc(x): print('Invalid timecode. Try again.') -def get_metadata_from_clip(clip): +def get_clip_attributes(clip): """ - Collect all metadata from resolve timeline item + Collect basic atrributes from resolve timeline item Args: clip (resolve.TimelineItem): timeline item object Returns: - dict: all collected metadata as key: values + dict: all collected attributres as key: values """ mp_item = clip.GetMediaPoolItem() @@ -222,7 +237,6 @@ def get_metadata_from_clip(clip): "clipRightOffset": clip.GetRightOffset(), "clipMarkers": clip.GetMarkers(), "clipFlags": clip.GetFlagList(), - "sourceMetadata": mp_item.GetMetadata(), "sourceId": mp_item.GetMediaId(), "sourceProperties": mp_item.GetClipProperty() } diff --git a/pype/hosts/resolve/utils.py b/pype/hosts/resolve/utils.py index dcc92c5b8d..e11cc64b3b 100644 --- a/pype/hosts/resolve/utils.py +++ b/pype/hosts/resolve/utils.py @@ -70,9 +70,9 @@ def get_resolve_module(): sys.exit() # assign global var and return bmdvr = bmd.scriptapp("Resolve") - bmdvf = bmd.scriptapp("Fusion") + # bmdvf = bmd.scriptapp("Fusion") resolve.bmdvr = bmdvr - resolve.bmdvf = bmdvf + resolve.bmdvf = bmdvr.Fusion() log.info(("Assigning resolve module to " f"`pype.hosts.resolve.bmdvr`: {resolve.bmdvr}")) log.info(("Assigning resolve module to " From 34c27c3fbf7aac183017540f73e15e8335416c2d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 23 Jun 2020 21:02:41 +0300 Subject: [PATCH 007/580] feat(resolve): compound clip create with sequencial rename --- pype/hosts/resolve/lib.py | 228 ++++++++++++++---- .../resolve/create/create_shot_clip.py | 16 +- 2 files changed, 192 insertions(+), 52 deletions(-) diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 5a5980a462..50b70241c0 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -1,11 +1,15 @@ import sys import json +from opentimelineio import opentime + from pype.api import Logger log = Logger().get_logger(__name__, "resolve") self = sys.modules[__name__] self.pm = None +self.rename_index = 0 +self.rename_add = 0 def get_project_manager(): @@ -35,7 +39,6 @@ def get_current_track_items( selecting_color=None): """ Gets all available current timeline track items """ - from pprint import pformat track_type = track_type or "video" selecting_color = selecting_color or "Chocolate" project = get_current_project() @@ -105,7 +108,75 @@ def create_current_sequence_media_bin(sequence): return media_pool.GetCurrentFolder() -def create_compound_clip(clip_data, folder, presets): +def get_name_with_data(clip_data, presets): + """ + Take hierarchy data from presets and build name with parents data + + Args: + clip_data (dict): clip data from `get_current_track_items()` + presets (dict): data from create plugin + + Returns: + list: name, data + + """ + def _replace_hash_to_expression(name, text): + _spl = text.split("#") + _len = (len(_spl) - 1) + _repl = f"{{{name}:0>{_len}}}" + new_text = text.replace(("#" * _len), _repl) + return new_text + + # presets data + clip_name = presets["clipName"] + hierarchy = presets["hierarchy"] + hierarchy_data = presets["hierarchyData"].copy() + count_from = presets["countFrom"] + steps = presets["steps"] + + # reset rename_add + if self.rename_add < count_from: + self.rename_add = count_from + + # shot num calculate + if self.rename_index == 0: + shot_num = self.rename_add + else: + shot_num = self.rename_add + steps + + print(f"shot_num: {shot_num}") + + # clip data + _data = { + "sequence": clip_data["sequence"].GetName(), + "track": clip_data["track"]["name"].replace(" ", "_"), + "shot": shot_num + } + + # solve # in test to pythonic explression + for k, v in hierarchy_data.items(): + if "#" not in v: + continue + hierarchy_data[k] = _replace_hash_to_expression(k, v) + + # fill up pythonic expresisons + for k, v in hierarchy_data.items(): + hierarchy_data[k] = v.format(**_data) + + # fill up clip name and hierarchy keys + hierarchy = hierarchy.format(**hierarchy_data) + clip_name = clip_name.format(**hierarchy_data) + + self.rename_add = shot_num + print(f"shot_num: {shot_num}") + + return (clip_name, { + "hierarchy": hierarchy, + "hierarchyData": hierarchy_data + }) + + +def create_compound_clip(clip_data, folder, rename=False, **kwargs): """ Convert timeline object into nested timeline object @@ -113,12 +184,12 @@ def create_compound_clip(clip_data, folder, presets): clip_data (dict): timeline item object packed into dict with project, timeline (sequence) folder (resolve.MediaPool.Folder): media pool folder object, - presets (dict): pype config plugin presets + rename (bool)[optional]: renaming in sequence or not + kwargs (optional): additional data needed for rename=True (presets) Returns: resolve.MediaPoolItem: media pool item with compound clip timeline(cct) """ - from pprint import pformat # get basic objects form data project = clip_data["project"] @@ -129,27 +200,53 @@ def create_compound_clip(clip_data, folder, presets): clip_item = clip["item"] track = clip_data["track"] - # build name - clip_name_split = clip_item.GetName().split(".") - name = "_".join([ - track["name"], - str(track["index"]), - clip_name_split[0], - str(clip["index"])] - ) + mp = project.GetMediaPool() + + # get clip attributes + clip_attributes = get_clip_attributes(clip_item) + + if rename: + presets = kwargs.get("presets") + if presets: + name, data = get_name_with_data(clip_data, presets) + # add hirarchy data to clip attributes + clip_attributes.update(data) + else: + name = "{:0>3}_{:0>4}".format( + int(track["index"]), int(clip["index"])) + else: + # build name + clip_name_split = clip_item.GetName().split(".") + name = "_".join([ + track["name"], + str(track["index"]), + clip_name_split[0], + str(clip["index"])] + ) # get metadata mp_item = clip_item.GetMediaPoolItem() mp_props = mp_item.GetClipProperty() - clip_attributes = get_clip_attributes(clip_item) - mp = project.GetMediaPool() + + mp_first_frame = int(mp_props["Start"]) + mp_last_frame = int(mp_props["End"]) + + # initialize basic source timing for otio + ci_l_offset = clip_item.GetLeftOffset() + ci_duration = clip_item.GetDuration() + rate = float(mp_props["FPS"]) + + # source rational times + mp_in_rc = opentime.RationalTime((ci_l_offset), rate) + mp_out_rc = opentime.RationalTime((ci_l_offset + ci_duration - 1), rate) + + # get frame in and out for clip swaping + in_frame = opentime.to_frames(mp_in_rc) + out_frame = opentime.to_frames(mp_out_rc) # keep original sequence sq_origin = sequence - print(f"_ sequence: {sequence}") - print(f"_ metadata: {pformat(clip_attributes)}") - # Set current folder to input media_pool_folder: mp.SetCurrentFolder(folder) @@ -160,48 +257,89 @@ def create_compound_clip(clip_data, folder, presets): if cct: print(f"_ cct exists: {cct}") - return cct + else: + # Create empty timeline in current folder and give name: + cct = mp.CreateEmptyTimeline(name) - # Create empty timeline in current folder and give name: - cct = mp.CreateEmptyTimeline(name) + # check if clip doesnt exist already: + clips = folder.GetClipList() + cct = next((c for c in clips + if c.GetName() in name), None) + print(f"_ cct created: {cct}") - # check if clip doesnt exist already: - clips = folder.GetClipList() - cct = next((c for c in clips - if c.GetName() in name), None) - print(f"_ cct created: {cct}") + # Set current timeline to created timeline: + project.SetCurrentTimeline(cct) - # Set current timeline to created timeline: - project.SetCurrentTimeline(cct) + # Add input clip to the current timeline: + mp.AppendToTimeline([{ + "mediaPoolItem": mp_item, + "startFrame": mp_first_frame, + "endFrame": mp_last_frame + }]) - # Add input clip to the current timeline: - # TODO: set offsets if handles - done = mp.AppendToTimeline([{ - "mediaPoolItem": mp_item, - "startFrame": int(mp_props["Start"]), - "endFrame": int(mp_props["End"]) - }]) - print(f"_ done1: {done}") - - # Set current timeline to the working timeline: - project.SetCurrentTimeline(sq_origin) + # Set current timeline to the working timeline: + project.SetCurrentTimeline(sq_origin) # Add collected metadata and attributes to the comound clip: - clip_attributes["VFX Notes"] = mp_item.GetMetadata( - "VFX Notes")["VFX Notes"] + if clip_attributes.get("VFX Notes"): + clip_attributes["VFX Notes"] = mp_item.GetMetadata( + "VFX Notes")["VFX Notes"] clip_attributes = json.dumps(clip_attributes) + # add attributes to metadata for k, v in mp_item.GetMetadata().items(): - done = cct.SetMetadata(k, v) + cct.SetMetadata(k, v) - done = cct.SetMetadata("VFX Notes", clip_attributes) - print(f"_ done2: {done}") + # add metadata to cct + cct.SetMetadata("VFX Notes", clip_attributes) - # # add clip item as take to timeline - # AddTake(cct, startFrame, endFrame) + # reset start timecode of the compound clip + cct.SetClipProperty("Start TC", mp_props["Start TC"]) + + # swap clips on timeline + swap_clips(clip_item, cct, name, in_frame, out_frame) + + cct.SetClipColor("Pink") return cct +def swap_clips(from_clip, to_clip, to_clip_name, to_in_frame, to_out_frame): + """ + Swaping clips on timeline in timelineItem + + It will add take and activate it to the frame range which is inputted + + Args: + from_clip (resolve.mediaPoolItem) + to_clip (resolve.mediaPoolItem) + to_clip_name (str): name of to_clip + to_in_frame (float): cut in frame, usually `GetLeftOffset()` + to_out_frame (float): cut out frame, usually left offset plus duration + + Returns: + bool: True if successfully replaced + + """ + # add clip item as take to timeline + take = from_clip.AddTake( + to_clip, + float(to_in_frame), + float(to_out_frame) + ) + + if not take: + return False + + for take_index in range(1, (int(from_clip.GetTakesCount()) + 1)): + take_item = from_clip.GetTakeByIndex(take_index) + take_mp_item = take_item["mediaPoolItem"] + if to_clip_name in take_mp_item.GetName(): + from_clip.SelectTakeByIndex(take_index) + from_clip.FinalizeTake() + return True + return False + + def validate_tc(x): # Validate and reformat timecode string diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index c48ca3a5a6..c12d5541d4 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -1,5 +1,7 @@ from pprint import pformat from pype.hosts import resolve +from avalon.vendor import Qt + class CreateShotClip(resolve.Creator): """Publishable clip""" @@ -12,9 +14,8 @@ class CreateShotClip(resolve.Creator): presets = None def process(self): - project = self.project - sequence = self.sequence - presets = self.presets + from pype.hosts.resolve import lib + print(f"__ selected_clips: {self.selected}") # sequence attrs @@ -27,10 +28,11 @@ class CreateShotClip(resolve.Creator): mp_folder = resolve.create_current_sequence_media_bin(self.sequence) print(f"_ mp_folder: {mp_folder.GetName()}") - for t_data in self.selected: + lib.rename_add = 0 + for i, t_data in enumerate(self.selected): + lib.rename_index = i print(t_data) # convert track item to timeline media pool item c_clip = resolve.create_compound_clip( - t_data, mp_folder, presets) - - # replace orig clip with compound_clip + t_data, mp_folder, rename=True, **dict( + {"presets": self.presets})) From 4f3565d2cf85d5ff4171f5247176603ce56642b2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 24 Jun 2020 12:55:17 +0300 Subject: [PATCH 008/580] feat(resolve): basic publish collecting of clips --- pype/hosts/resolve/__init__.py | 4 + pype/hosts/resolve/lib.py | 34 +++- pype/plugins/resolve/publish/collect_clips.py | 159 ++++++++++++++++++ 3 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 pype/plugins/resolve/publish/collect_clips.py diff --git a/pype/hosts/resolve/__init__.py b/pype/hosts/resolve/__init__.py index 5f651f4b29..c8f45259ff 100644 --- a/pype/hosts/resolve/__init__.py +++ b/pype/hosts/resolve/__init__.py @@ -20,6 +20,8 @@ from .lib import ( get_current_track_items, create_current_sequence_media_bin, create_compound_clip, + swap_clips, + get_pype_clip_metadata, set_project_manager_to_folder_name ) @@ -61,6 +63,8 @@ __all__ = [ "get_current_track_items", "create_current_sequence_media_bin", "create_compound_clip", + "swap_clips", + "get_pype_clip_metadata", "set_project_manager_to_folder_name", # menu diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 50b70241c0..db3bd989bf 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -1,6 +1,7 @@ import sys import json from opentimelineio import opentime +from pprint import pformat from pype.api import Logger @@ -10,6 +11,7 @@ self = sys.modules[__name__] self.pm = None self.rename_index = 0 self.rename_add = 0 +self.pype_metadata_key = "VFX Notes" def get_project_manager(): @@ -46,11 +48,11 @@ def get_current_track_items( selected_clips = list() # get all tracks count filtered by track type - sequence_video_count = sequence.GetTrackCount(track_type) + selected_track_count = sequence.GetTrackCount(track_type) # loop all tracks and get items _clips = dict() - for track_index in range(1, (int(sequence_video_count) + 1)): + for track_index in range(1, (int(selected_track_count) + 1)): track_name = sequence.GetTrackName(track_type, track_index) track_track_items = sequence.GetItemListInTrack( track_type, track_index) @@ -190,7 +192,6 @@ def create_compound_clip(clip_data, folder, rename=False, **kwargs): Returns: resolve.MediaPoolItem: media pool item with compound clip timeline(cct) """ - # get basic objects form data project = clip_data["project"] sequence = clip_data["sequence"] @@ -204,6 +205,7 @@ def create_compound_clip(clip_data, folder, rename=False, **kwargs): # get clip attributes clip_attributes = get_clip_attributes(clip_item) + print(f"_ clip_attributes: {pformat(clip_attributes)}") if rename: presets = kwargs.get("presets") @@ -281,9 +283,11 @@ def create_compound_clip(clip_data, folder, rename=False, **kwargs): project.SetCurrentTimeline(sq_origin) # Add collected metadata and attributes to the comound clip: - if clip_attributes.get("VFX Notes"): - clip_attributes["VFX Notes"] = mp_item.GetMetadata( - "VFX Notes")["VFX Notes"] + if mp_item.GetMetadata(self.pype_metadata_key): + clip_attributes[self.pype_metadata_key] = mp_item.GetMetadata( + self.pype_metadata_key)[self.pype_metadata_key] + + # stringify clip_attributes = json.dumps(clip_attributes) # add attributes to metadata @@ -291,7 +295,7 @@ def create_compound_clip(clip_data, folder, rename=False, **kwargs): cct.SetMetadata(k, v) # add metadata to cct - cct.SetMetadata("VFX Notes", clip_attributes) + cct.SetMetadata(self.pype_metadata_key, clip_attributes) # reset start timecode of the compound clip cct.SetClipProperty("Start TC", mp_props["Start TC"]) @@ -356,6 +360,22 @@ def validate_tc(x): print('Invalid timecode. Try again.') +def get_pype_clip_metadata(clip): + """ + Get pype metadata created by creator plugin + + Attributes: + clip (resolve.TimelineItem): resolve's object + + Returns: + dict: hierarchy, orig clip attributes + """ + mp_item = clip.GetMediaPoolItem() + metadata = mp_item.GetMetadata() + + return metadata.get(self.pype_metadata_key) + + def get_clip_attributes(clip): """ Collect basic atrributes from resolve timeline item diff --git a/pype/plugins/resolve/publish/collect_clips.py b/pype/plugins/resolve/publish/collect_clips.py new file mode 100644 index 0000000000..0f02f26f2e --- /dev/null +++ b/pype/plugins/resolve/publish/collect_clips.py @@ -0,0 +1,159 @@ +import os +from pyblish import api +from pype.hosts import resolve +import json + +class CollectClips(api.ContextPlugin): + """Collect all Track items selection.""" + + order = api.CollectorOrder + 0.01 + label = "Collect Clips" + hosts = ["resolve"] + + def process(self, context): + # create asset_names conversion table + if not context.data.get("assetsShared"): + self.log.debug("Created `assetsShared` in context") + context.data["assetsShared"] = dict() + + projectdata = context.data["projectEntity"]["data"] + selection = resolve.get_current_track_items( + filter=True, selecting_color="Pink") + + for clip_data in selection: + data = dict() + + # get basic objects form data + project = clip_data["project"] + sequence = clip_data["sequence"] + clip = clip_data["clip"] + + # sequence attrs + sq_frame_start = sequence.GetStartFrame() + self.log.debug(f"sq_frame_start: {sq_frame_start}") + + sq_markers = sequence.GetMarkers() + + # get details of objects + clip_item = clip["item"] + track = clip_data["track"] + + mp = project.GetMediaPool() + + # get clip attributes + clip_metadata = resolve.get_pype_clip_metadata(clip_item) + clip_metadata = json.loads(clip_metadata) + self.log.debug(f"clip_metadata: {clip_metadata}") + + compound_source_prop = clip_metadata["sourceProperties"] + self.log.debug(f"compound_source_prop: {compound_source_prop}") + + asset_name = clip_item.GetName() + mp_item = clip_item.GetMediaPoolItem() + mp_prop = mp_item.GetClipProperty() + source_first = int(compound_source_prop["Start"]) + source_last = int(compound_source_prop["End"]) + source_duration = compound_source_prop["Frames"] + fps = float(mp_prop["FPS"]) + self.log.debug(f"source_first: {source_first}") + self.log.debug(f"source_last: {source_last}") + self.log.debug(f"source_duration: {source_duration}") + self.log.debug(f"fps: {fps}") + + source_path = os.path.normpath( + compound_source_prop["File Path"]) + source_name = compound_source_prop["File Name"] + source_id = clip_metadata["sourceId"] + self.log.debug(f"source_path: {source_path}") + self.log.debug(f"source_name: {source_name}") + self.log.debug(f"source_id: {source_id}") + + clip_left_offset = int(clip_item.GetLeftOffset()) + clip_right_offset = int(clip_item.GetRightOffset()) + self.log.debug(f"clip_left_offset: {clip_left_offset}") + self.log.debug(f"clip_right_offset: {clip_right_offset}") + + # source in/out + source_in = int(source_first + clip_left_offset) + source_out = int(source_first + clip_right_offset) + self.log.debug(f"source_in: {source_in}") + self.log.debug(f"source_out: {source_out}") + + clip_in = int(clip_item.GetStart() - sq_frame_start) + clip_out = int(clip_item.GetEnd() - sq_frame_start) + clip_duration = int(clip_item.GetDuration()) + self.log.debug(f"clip_in: {clip_in}") + self.log.debug(f"clip_out: {clip_out}") + self.log.debug(f"clip_duration: {clip_duration}") + + is_sequence = False + + self.log.debug( + "__ assets_shared: {}".format( + context.data["assetsShared"])) + + # Check for clips with the same range + # this is for testing if any vertically neighbouring + # clips has been already processed + clip_matching_with_range = next( + (k for k, v in context.data["assetsShared"].items() + if (v.get("_clipIn", 0) == clip_in) + and (v.get("_clipOut", 0) == clip_out) + ), False) + + # check if clip name is the same in matched + # vertically neighbouring clip + # if it is then it is correct and resent variable to False + # not to be rised wrong name exception + if asset_name in str(clip_matching_with_range): + clip_matching_with_range = False + + # rise wrong name exception if found one + assert (not clip_matching_with_range), ( + "matching clip: {asset}" + " timeline range ({clip_in}:{clip_out})" + " conflicting with {clip_matching_with_range}" + " >> rename any of clips to be the same as the other <<" + ).format( + **locals()) + + if ("[" in source_name) and ("]" in source_name): + is_sequence = True + + data.update({ + "name": "_".join([ + track["name"], asset_name, source_name]), + "item": clip_item, + "source": mp_item, + # "timecodeStart": str(source.timecodeStart()), + "timelineStart": sq_frame_start, + "sourcePath": source_path, + "sourceFileHead": source_name, + "isSequence": is_sequence, + "track": track["name"], + "trackIndex": track["index"], + "sourceFirst": source_first, + + "sourceIn": source_in, + "sourceOut": source_out, + "mediaDuration": source_duration, + "clipIn": clip_in, + "clipOut": clip_out, + "clipDuration": clip_duration, + "asset": asset_name, + "subset": "plateMain", + "family": "clip", + "families": [], + "handleStart": projectdata.get("handleStart", 0), + "handleEnd": projectdata.get("handleEnd", 0)}) + + instance = context.create_instance(**data) + + self.log.info("Created instance: {}".format(instance)) + self.log.info("Created instance.data: {}".format(instance.data)) + + context.data["assetsShared"][asset_name] = { + "_clipIn": clip_in, + "_clipOut": clip_out + } + self.log.info("context.data[\"assetsShared\"]: {}".format(context.data["assetsShared"])) From 7465d8cb7394ec1c3987b16da782a8b84f66cfd2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 24 Jun 2020 20:17:22 +0300 Subject: [PATCH 009/580] feat(resolve): creator with sequencial rename gui --- pype/hosts/resolve/menu_style.qss | 8 ++ pype/hosts/resolve/plugin.py | 76 ++++++++++++++++++- .../resolve/create/create_shot_clip.py | 53 ++++++++++++- 3 files changed, 133 insertions(+), 4 deletions(-) diff --git a/pype/hosts/resolve/menu_style.qss b/pype/hosts/resolve/menu_style.qss index df4fd7e949..c43886c7c3 100644 --- a/pype/hosts/resolve/menu_style.qss +++ b/pype/hosts/resolve/menu_style.qss @@ -20,6 +20,14 @@ QPushButton:hover { color: #e64b3d; } +QSpinBox { + background-color: #ffffff; +} + +QLineEdit { + background-color: #ffffff; +} + #PypeMenu { border: 1px solid #fef9ef; } diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 002d12106d..2eff278b80 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -1,8 +1,82 @@ +import sys from avalon import api from pype.hosts import resolve from avalon.vendor import qargparse from pype.api import config +from Qt import QtWidgets + + +class Universal_widget(QtWidgets.QDialog): + def __init__(self, widgets, parent=None): + super(Universal_widget, self).__init__(parent) + + # Where inputs and labels are set + content_widget = QtWidgets.QWidget(self) + content_layout = QtWidgets.QFormLayout(content_widget) + + self.items = dict() + for w in widgets: + attr = getattr(QtWidgets, w["type"]) + label = QtWidgets.QLabel(w["label"]) + attr_name = w["label"].replace(" ", "").lower() + setattr( + self, + attr_name, + attr(parent=self)) + item = getattr(self, attr_name) + func = next((k for k in w if k not in ["label", "type"]), None) + if func: + if getattr(item, func): + func_attr = getattr(item, func) + func_attr(w[func]) + + content_layout.addRow(label, item) + self.items.update({ + w["label"]: item + }) + + # Confirmation buttons + btns_widget = QtWidgets.QWidget(self) + btns_layout = QtWidgets.QHBoxLayout(btns_widget) + + cancel_btn = QtWidgets.QPushButton("Cancel") + btns_layout.addWidget(cancel_btn) + + ok_btn = QtWidgets.QPushButton("Ok") + btns_layout.addWidget(ok_btn) + + # Main layout of the dialog + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + main_layout.addWidget(content_widget) + main_layout.addWidget(btns_widget) + + ok_btn.clicked.connect(self._on_ok_clicked) + cancel_btn.clicked.connect(self._on_cancel_clicked) + + stylesheet = resolve.menu.load_stylesheet() + self.setStyleSheet(stylesheet) + + def _on_ok_clicked(self): + self.value() + self.close() + + def _on_cancel_clicked(self): + self.result = None + self.close() + + def value(self): + for k, v in self.items.items(): + if getattr(v, "value", None): + result = getattr(v, "value") + else: + result = getattr(v, "text") + self.items[k] = result() + self.result = self.items + def get_reference_node_parents(ref): """Return all parent reference nodes of reference node @@ -95,4 +169,4 @@ class Creator(api.Creator): else: self.selected = resolve.get_current_track_items(filter=False) - return + self.widget = Universal_widget diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index c12d5541d4..bba9851c0f 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -1,6 +1,13 @@ from pprint import pformat from pype.hosts import resolve -from avalon.vendor import Qt +from pype.hosts.resolve import lib +import re + + +def camel_case_split(text): + matches = re.finditer( + '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', text) + return " ".join([str(m.group(0)).capitalize() for m in matches]) class CreateShotClip(resolve.Creator): @@ -13,11 +20,51 @@ class CreateShotClip(resolve.Creator): presets = None - def process(self): - from pype.hosts.resolve import lib + # widget + layout = [{ + "type": "QLabel", + "label": "Define sequencial rename" + }] + def add_presets_to_layout(self, data): + for k, v in data.items(): + if isinstance(v, dict): + self.layout.append({ + "type": "QLabel", + "label": camel_case_split(k) + }) + self.add_presets_to_layout(v) + elif isinstance(v, str): + self.layout.append({ + "type": "QLineEdit", + "label": camel_case_split(k), + "setText": v + }) + elif isinstance(v, int): + self.layout.append({ + "type": "QSpinBox", + "label": camel_case_split(k), + "setValue": v + }) + + def process(self): print(f"__ selected_clips: {self.selected}") + if len(self.selected) < 1: + return + + self.add_presets_to_layout(self.presets) + + widget = self.widget(self.layout) + widget.exec_() + + print(widget.result) + if widget.result: + print("success") + return + else: + return + # sequence attrs sq_frame_start = self.sequence.GetStartFrame() sq_markers = self.sequence.GetMarkers() From ccadf98c501bc4ee5ae447b846bcc93bb8a6e156 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 25 Jun 2020 09:17:35 +0300 Subject: [PATCH 010/580] feat(resolve): update creator input widget --- pype/hosts/resolve/menu_style.qss | 6 ++++++ pype/hosts/resolve/plugin.py | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pype/hosts/resolve/menu_style.qss b/pype/hosts/resolve/menu_style.qss index c43886c7c3..516c9af72b 100644 --- a/pype/hosts/resolve/menu_style.qss +++ b/pype/hosts/resolve/menu_style.qss @@ -22,10 +22,16 @@ QPushButton:hover { QSpinBox { background-color: #ffffff; + padding: 5; } QLineEdit { background-color: #ffffff; + padding: 5; +} + +QLabel { + color: #ffffff; } #PypeMenu { diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 2eff278b80..c1aa05dc7d 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -4,13 +4,24 @@ from pype.hosts import resolve from avalon.vendor import qargparse from pype.api import config -from Qt import QtWidgets +from Qt import QtWidgets, QtCore class Universal_widget(QtWidgets.QDialog): def __init__(self, widgets, parent=None): super(Universal_widget, self).__init__(parent) + self.setObjectName("PypeCreatorInput") + + self.setWindowFlags( + QtCore.Qt.Window + | QtCore.Qt.CustomizeWindowHint + | QtCore.Qt.WindowTitleHint + | QtCore.Qt.WindowCloseButtonHint + | QtCore.Qt.WindowStaysOnTopHint + ) + self.setWindowTitle("CreatorInput") + # Where inputs and labels are set content_widget = QtWidgets.QWidget(self) content_layout = QtWidgets.QFormLayout(content_widget) @@ -48,7 +59,7 @@ class Universal_widget(QtWidgets.QDialog): # Main layout of the dialog main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setContentsMargins(10, 20, 10, 20) main_layout.setSpacing(0) main_layout.addWidget(content_widget) From 3fb4460b7b412bddff727e438d706c1c567a987f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 26 Jun 2020 14:13:54 +0300 Subject: [PATCH 011/580] feat(resolve): creator plugin with dynamic widget --- pype/hosts/resolve/menu_style.qss | 4 + pype/hosts/resolve/plugin.py | 84 ++++++++++++++----- .../resolve/create/create_shot_clip.py | 39 +-------- 3 files changed, 69 insertions(+), 58 deletions(-) diff --git a/pype/hosts/resolve/menu_style.qss b/pype/hosts/resolve/menu_style.qss index 516c9af72b..f3bfa7a30c 100644 --- a/pype/hosts/resolve/menu_style.qss +++ b/pype/hosts/resolve/menu_style.qss @@ -41,3 +41,7 @@ QLabel { #Spacer { background-color: #282828; } + +#ContentLayout { + background-color: #585858; +} diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index c1aa05dc7d..8c5fd321d1 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -1,4 +1,5 @@ import sys +import re from avalon import api from pype.hosts import resolve from avalon.vendor import qargparse @@ -8,7 +9,11 @@ from Qt import QtWidgets, QtCore class Universal_widget(QtWidgets.QDialog): - def __init__(self, widgets, parent=None): + + # output items + items = dict() + + def __init__(self, name, presets, parent=None): super(Universal_widget, self).__init__(parent) self.setObjectName("PypeCreatorInput") @@ -24,28 +29,14 @@ class Universal_widget(QtWidgets.QDialog): # Where inputs and labels are set content_widget = QtWidgets.QWidget(self) - content_layout = QtWidgets.QFormLayout(content_widget) + self.content_layout = QtWidgets.QFormLayout(content_widget) + self.content_layout.setObjectName("ContentLayout") - self.items = dict() - for w in widgets: - attr = getattr(QtWidgets, w["type"]) - label = QtWidgets.QLabel(w["label"]) - attr_name = w["label"].replace(" ", "").lower() - setattr( - self, - attr_name, - attr(parent=self)) - item = getattr(self, attr_name) - func = next((k for k in w if k not in ["label", "type"]), None) - if func: - if getattr(item, func): - func_attr = getattr(item, func) - func_attr(w[func]) + # first add widget tag line + self.create_row("QLabel", name) - content_layout.addRow(label, item) - self.items.update({ - w["label"]: item - }) + # add preset data into input widget layout + self.add_presets_to_layout(presets) # Confirmation buttons btns_widget = QtWidgets.QWidget(self) @@ -88,6 +79,57 @@ class Universal_widget(QtWidgets.QDialog): self.items[k] = result() self.result = self.items + def camel_case_split(self, text): + matches = re.finditer( + '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', text) + return " ".join([str(m.group(0)).capitalize() for m in matches]) + + def create_row(self, type, text, **kwargs): + # get type attribute from qwidgets + attr = getattr(QtWidgets, type) + + # convert label text to normal capitalized text with spaces + label_text = self.camel_case_split(text) + + # assign the new text to lable widget + label = QtWidgets.QLabel(label_text) + + # create attribute name text strip of spaces + attr_name = text.replace(" ", "") + + # create attribute and assign default values + setattr( + self, + attr_name, + attr(parent=self)) + + # assign the created attribute to variable + item = getattr(self, attr_name) + for func, val in kwargs.items(): + if getattr(item, func): + func_attr = getattr(item, func) + func_attr(val) + + self.content_layout.addRow(label, item) + return item + + def add_presets_to_layout(self, data): + for k, v in data.items(): + if isinstance(v, dict): + # if nested dict then create label + # TODO: create also new layout + self.create_row("QLabel", k) + self.add_presets_to_layout(v) + elif isinstance(v, str): + item = self.create_row("QLineEdit", k, setText=v) + elif isinstance(v, int): + item = self.create_row("QSpinBox", k, setValue=v) + + # add it to items for later requests + self.items.update({ + k: item + }) + def get_reference_node_parents(ref): """Return all parent reference nodes of reference node diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index bba9851c0f..18759a2f98 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -1,13 +1,6 @@ from pprint import pformat from pype.hosts import resolve from pype.hosts.resolve import lib -import re - - -def camel_case_split(text): - matches = re.finditer( - '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', text) - return " ".join([str(m.group(0)).capitalize() for m in matches]) class CreateShotClip(resolve.Creator): @@ -18,44 +11,16 @@ class CreateShotClip(resolve.Creator): icon = "film" defaults = ["Main"] + gui_name = "Define sequencial rename" presets = None - # widget - layout = [{ - "type": "QLabel", - "label": "Define sequencial rename" - }] - - def add_presets_to_layout(self, data): - for k, v in data.items(): - if isinstance(v, dict): - self.layout.append({ - "type": "QLabel", - "label": camel_case_split(k) - }) - self.add_presets_to_layout(v) - elif isinstance(v, str): - self.layout.append({ - "type": "QLineEdit", - "label": camel_case_split(k), - "setText": v - }) - elif isinstance(v, int): - self.layout.append({ - "type": "QSpinBox", - "label": camel_case_split(k), - "setValue": v - }) - def process(self): print(f"__ selected_clips: {self.selected}") if len(self.selected) < 1: return - self.add_presets_to_layout(self.presets) - - widget = self.widget(self.layout) + widget = self.widget(self.gui_name, self.presets) widget.exec_() print(widget.result) From 4391a14da2a2f4063b3692a089b2ae9a1c948040 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 26 Jun 2020 20:28:15 +0300 Subject: [PATCH 012/580] feat(resolve): adding Create widget with style --- pype/hosts/resolve/lib.py | 2 +- pype/hosts/resolve/menu_style.qss | 29 +++-- pype/hosts/resolve/plugin.py | 112 +++++++++++++----- .../resolve/create/create_shot_clip.py | 25 ++-- 4 files changed, 116 insertions(+), 52 deletions(-) diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index db3bd989bf..deb4fa6339 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -77,7 +77,7 @@ def get_current_track_items( if filter is True: if selecting_color in ti_color: selected_clips.append(data) - ti.ClearClipColor() + # ti.ClearClipColor() else: selected_clips.append(data) diff --git a/pype/hosts/resolve/menu_style.qss b/pype/hosts/resolve/menu_style.qss index f3bfa7a30c..ea11c4ca2e 100644 --- a/pype/hosts/resolve/menu_style.qss +++ b/pype/hosts/resolve/menu_style.qss @@ -1,6 +1,7 @@ QWidget { background-color: #282828; border-radius: 3; + font-size: 13px; } QPushButton { @@ -21,27 +22,37 @@ QPushButton:hover { } QSpinBox { - background-color: #ffffff; - padding: 5; + border: 1px solid #090909; + background-color: #201f1f; + color: #ffffff; + padding: 2; + max-width: 8em; + qproperty-alignment: AlignCenter; } QLineEdit { - background-color: #ffffff; - padding: 5; -} - -QLabel { + border: 1px solid #090909; + border-radius: 3px; + background-color: #201f1f; color: #ffffff; + padding: 2; + min-width: 10em; + qproperty-alignment: AlignCenter; } #PypeMenu { border: 1px solid #fef9ef; } -#Spacer { +QVBoxLayout { background-color: #282828; } -#ContentLayout { +#Devider { + border: 1px solid #090909; background-color: #585858; } + +QLabel { + color: #77776b; +} diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 8c5fd321d1..4e7ac80add 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -1,4 +1,3 @@ -import sys import re from avalon import api from pype.hosts import resolve @@ -13,10 +12,10 @@ class Universal_widget(QtWidgets.QDialog): # output items items = dict() - def __init__(self, name, presets, parent=None): + def __init__(self, name, info, presets, parent=None): super(Universal_widget, self).__init__(parent) - self.setObjectName("PypeCreatorInput") + self.setObjectName(name) self.setWindowFlags( QtCore.Qt.Window @@ -25,18 +24,25 @@ class Universal_widget(QtWidgets.QDialog): | QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowStaysOnTopHint ) - self.setWindowTitle("CreatorInput") + self.setWindowTitle(name or "Pype Creator Input") # Where inputs and labels are set - content_widget = QtWidgets.QWidget(self) - self.content_layout = QtWidgets.QFormLayout(content_widget) - self.content_layout.setObjectName("ContentLayout") + self.content_widget = [QtWidgets.QWidget(self)] + top_layout = QtWidgets.QFormLayout(self.content_widget[0]) + top_layout.setObjectName("ContentLayout") + top_layout.addWidget(Spacer(5, self)) # first add widget tag line - self.create_row("QLabel", name) + top_layout.addWidget(QtWidgets.QLabel(info)) + + top_layout.addWidget(Spacer(5, self)) + + # main dynamic layout + self.content_widget.append(QtWidgets.QWidget(self)) + content_layout = QtWidgets.QFormLayout(self.content_widget[-1]) # add preset data into input widget layout - self.add_presets_to_layout(presets) + self.items = self.add_presets_to_layout(content_layout, presets) # Confirmation buttons btns_widget = QtWidgets.QWidget(self) @@ -50,10 +56,13 @@ class Universal_widget(QtWidgets.QDialog): # Main layout of the dialog main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(10, 20, 10, 20) + main_layout.setContentsMargins(10, 10, 10, 10) main_layout.setSpacing(0) - main_layout.addWidget(content_widget) + # adding content widget + for w in self.content_widget: + main_layout.addWidget(w) + main_layout.addWidget(btns_widget) ok_btn.clicked.connect(self._on_ok_clicked) @@ -63,28 +72,34 @@ class Universal_widget(QtWidgets.QDialog): self.setStyleSheet(stylesheet) def _on_ok_clicked(self): - self.value() + self.result = self.value(self.items) self.close() def _on_cancel_clicked(self): self.result = None self.close() - def value(self): - for k, v in self.items.items(): - if getattr(v, "value", None): + def value(self, data): + for k, v in data.items(): + if isinstance(v, dict): + print(f"nested: {k}") + data[k] = self.value(v) + elif getattr(v, "value", None): + print(f"normal int: {k}") result = getattr(v, "value") + data[k] = result() else: + print(f"normal text: {k}") result = getattr(v, "text") - self.items[k] = result() - self.result = self.items + data[k] = result() + return data def camel_case_split(self, text): matches = re.finditer( '.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)', text) return " ".join([str(m.group(0)).capitalize() for m in matches]) - def create_row(self, type, text, **kwargs): + def create_row(self, layout, type, text, **kwargs): # get type attribute from qwidgets attr = getattr(QtWidgets, type) @@ -93,6 +108,7 @@ class Universal_widget(QtWidgets.QDialog): # assign the new text to lable widget label = QtWidgets.QLabel(label_text) + label.setObjectName("LineLabel") # create attribute name text strip of spaces attr_name = text.replace(" ", "") @@ -110,25 +126,57 @@ class Universal_widget(QtWidgets.QDialog): func_attr = getattr(item, func) func_attr(val) - self.content_layout.addRow(label, item) + # add to layout + layout.addRow(label, item) + return item - def add_presets_to_layout(self, data): + def add_presets_to_layout(self, content_layout, data): for k, v in data.items(): if isinstance(v, dict): - # if nested dict then create label - # TODO: create also new layout - self.create_row("QLabel", k) - self.add_presets_to_layout(v) - elif isinstance(v, str): - item = self.create_row("QLineEdit", k, setText=v) - elif isinstance(v, int): - item = self.create_row("QSpinBox", k, setValue=v) + # adding spacer between sections + self.content_widget.append(QtWidgets.QWidget(self)) + devider = QtWidgets.QVBoxLayout(self.content_widget[-1]) + devider.addWidget(Spacer(5, self)) + devider.setObjectName("Devider") - # add it to items for later requests - self.items.update({ - k: item - }) + # adding nested layout with label + self.content_widget.append(QtWidgets.QWidget(self)) + nested_content_layout = QtWidgets.QFormLayout( + self.content_widget[-1]) + nested_content_layout.setObjectName("NestedContentLayout") + + # add nested key as label + self.create_row(nested_content_layout, "QLabel", k) + data[k] = self.add_presets_to_layout(nested_content_layout, v) + elif isinstance(v, str): + print(f"layout.str: {k}") + print(f"content_layout: {content_layout}") + data[k] = self.create_row( + content_layout, "QLineEdit", k, setText=v) + elif isinstance(v, int): + print(f"layout.int: {k}") + print(f"content_layout: {content_layout}") + data[k] = self.create_row( + content_layout, "QSpinBox", k, setValue=v) + return data + + +class Spacer(QtWidgets.QWidget): + def __init__(self, height, *args, **kwargs): + super(self.__class__, self).__init__(*args, **kwargs) + + self.setFixedHeight(height) + + real_spacer = QtWidgets.QWidget(self) + real_spacer.setObjectName("Spacer") + real_spacer.setFixedHeight(height) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(real_spacer) + + self.setLayout(layout) def get_reference_node_parents(ref): diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index 18759a2f98..43207743e2 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -11,7 +11,8 @@ class CreateShotClip(resolve.Creator): icon = "film" defaults = ["Main"] - gui_name = "Define sequencial rename" + gui_name = "Pype sequencial rename with hirerarchy" + gui_info = "Define sequencial rename and fill hierarchy data." presets = None def process(self): @@ -20,14 +21,11 @@ class CreateShotClip(resolve.Creator): if len(self.selected) < 1: return - widget = self.widget(self.gui_name, self.presets) + widget = self.widget(self.gui_name, self.gui_info, self.presets) widget.exec_() - print(widget.result) - if widget.result: - print("success") - return - else: + if not widget.result: + print("Operation aborted") return # sequence attrs @@ -43,8 +41,15 @@ class CreateShotClip(resolve.Creator): lib.rename_add = 0 for i, t_data in enumerate(self.selected): lib.rename_index = i - print(t_data) + + # clear color after it is done + t_data["clip"]["item"].ClearClipColor() + # convert track item to timeline media pool item c_clip = resolve.create_compound_clip( - t_data, mp_folder, rename=True, **dict( - {"presets": self.presets})) + t_data, + mp_folder, + rename=True, + **dict( + {"presets": widget.result}) + ) From 5df2c326142b5434339e3b56d9887cc8816bee2f Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Fri, 3 Jul 2020 17:16:26 +0200 Subject: [PATCH 013/580] WIP POC imlementation of Websocket Json RPC server Includes two testing clients Requires: - adding wsrpc-aiohttp==3.0.1 to pypeapp/requirements.txt - adding code to \pype-config\presets\tray\menu_items.json , { "title": "Websocket Server", "type": "module", "import_path": "pype.modules.websocket_server", "fromlist": ["pype","modules"] } --- pype/modules/websocket_server/__init__.py | 5 + .../websocket_server/external_app_1.py | 46 +++++ .../test_client/wsrpc_client.html | 179 ++++++++++++++++++ .../test_client/wsrpc_client.py | 34 ++++ .../websocket_server/websocket_server.py | 129 +++++++++++++ 5 files changed, 393 insertions(+) create mode 100644 pype/modules/websocket_server/__init__.py create mode 100644 pype/modules/websocket_server/external_app_1.py create mode 100644 pype/modules/websocket_server/test_client/wsrpc_client.html create mode 100644 pype/modules/websocket_server/test_client/wsrpc_client.py create mode 100644 pype/modules/websocket_server/websocket_server.py diff --git a/pype/modules/websocket_server/__init__.py b/pype/modules/websocket_server/__init__.py new file mode 100644 index 0000000000..eb5a0d9f27 --- /dev/null +++ b/pype/modules/websocket_server/__init__.py @@ -0,0 +1,5 @@ +from .websocket_server import WebSocketServer + + +def tray_init(tray_widget, main_widget): + return WebSocketServer() diff --git a/pype/modules/websocket_server/external_app_1.py b/pype/modules/websocket_server/external_app_1.py new file mode 100644 index 0000000000..34a43a4d23 --- /dev/null +++ b/pype/modules/websocket_server/external_app_1.py @@ -0,0 +1,46 @@ +import asyncio + +from pype.api import Logger +from wsrpc_aiohttp import WebSocketRoute + +log = Logger().get_logger("WebsocketServer") + +class ExternalApp1(WebSocketRoute): + """ + One route, mimicking external application (like Harmony, etc). + All functions could be called from client. + 'do_notify' function calls function on the client - mimicking + notification after long running job on the server or similar + """ + + def init(self, **kwargs): + # Python __init__ must be return "self". + # This method might return anything. + log.debug("someone called ExternalApp1 route") + return kwargs + + async def server_function_one(self): + log.info('In function one') + + async def server_function_two(self): + log.info('In function two') + return 'function two' + + async def server_function_three(self): + log.info('In function three') + asyncio.ensure_future(self.do_notify()) + return '{"message":"function tree"}' + + async def server_function_four(self, *args, **kwargs): + log.info('In function four args {} kwargs {}'.format(args, kwargs)) + ret = dict(**kwargs) + ret["message"] = "function four received arguments" + return str(ret) + + # This method calls function on the client side + async def do_notify(self): + import time + time.sleep(5) + log.info('Calling function on server after delay') + awesome = 'Somebody server_function_three method!' + await self.socket.call('notify', result=awesome) diff --git a/pype/modules/websocket_server/test_client/wsrpc_client.html b/pype/modules/websocket_server/test_client/wsrpc_client.html new file mode 100644 index 0000000000..9c3f469aca --- /dev/null +++ b/pype/modules/websocket_server/test_client/wsrpc_client.html @@ -0,0 +1,179 @@ + + + + + Title + + + + + + + + + + + + + +
+
Test of wsrpc javascript client
+ +
+ +
+
+
+
+

No return value

+
+
+
    +
  • Calls server_function_one
  • +
  • Function only logs on server
  • +
  • No return value
  • +
  •  
  • +
  •  
  • +
  •  
  • +
+ +
+
+
+
+

Return value

+
+
+
    +
  • Calls server_function_two
  • +
  • Function logs on server
  • +
  • Returns simple text value
  • +
  •  
  • +
  •  
  • +
  •  
  • +
+ +
+
+
+
+

Notify

+
+
+
    +
  • Calls server_function_three
  • +
  • Function logs on server
  • +
  • Returns json payload
  • +
  • Server then calls function ON the client after delay
  • +
  •  
  • +
+ +
+
+
+
+

Send value

+
+
+
    +
  • Calls server_function_four
  • +
  • Function logs on server
  • +
  • Returns modified sent values
  • +
  •  
  • +
  •  
  • +
  •  
  • +
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/pype/modules/websocket_server/test_client/wsrpc_client.py b/pype/modules/websocket_server/test_client/wsrpc_client.py new file mode 100644 index 0000000000..ef861513ae --- /dev/null +++ b/pype/modules/websocket_server/test_client/wsrpc_client.py @@ -0,0 +1,34 @@ +import asyncio + +from wsrpc_aiohttp import WSRPCClient + +""" + Simple testing Python client for wsrpc_aiohttp + Calls sequentially multiple methods on server +""" + +loop = asyncio.get_event_loop() + + +async def main(): + print("main") + client = WSRPCClient("ws://127.0.0.1:8099/ws/", + loop=asyncio.get_event_loop()) + + client.add_route('notify', notify) + await client.connect() + print("connected") + print(await client.proxy.ExternalApp1.server_function_one()) + print(await client.proxy.ExternalApp1.server_function_two()) + print(await client.proxy.ExternalApp1.server_function_three()) + print(await client.proxy.ExternalApp1.server_function_four(foo="one")) + await client.close() + + +def notify(socket, *args, **kwargs): + print("called from server") + + +if __name__ == "__main__": + # loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py new file mode 100644 index 0000000000..ce5f23180a --- /dev/null +++ b/pype/modules/websocket_server/websocket_server.py @@ -0,0 +1,129 @@ +from pype.api import config, Logger +from Qt import QtCore + +from aiohttp import web, WSCloseCode +import asyncio +import weakref +from wsrpc_aiohttp import STATIC_DIR, WebSocketAsync + +from . import external_app_1 + +log = Logger().get_logger("WebsocketServer") + +class WebSocketServer(): + """ + Basic POC implementation of asychronic websocket RPC server. + Uses class in external_app_1.py to mimic implementation for single + external application. + 'test_client' folder contains two test implementations of client + + WIP + """ + + def __init__(self): + self.qaction = None + self.failed_icon = None + self._is_running = False + default_port = 8099 + + try: + self.presets = config.get_presets()["services"]["websocket_server"] + except Exception: + self.presets = {"default_port": default_port, "exclude_ports": []} + log.debug(( + "There are not set presets for WebsocketServer." + " Using defaults \"{}\"" + ).format(str(self.presets))) + + self.app = web.Application() + self.app["websockets"] = weakref.WeakSet() + + self.app.router.add_route("*", "/ws/", WebSocketAsync) + self.app.router.add_static("/js", STATIC_DIR) + self.app.router.add_static("/", ".") + + # add route with multiple methods for single "external app" + WebSocketAsync.add_route('ExternalApp1', external_app_1.ExternalApp1) + + self.app.on_shutdown.append(self.on_shutdown) + + self.websocket_thread = WebsocketServerThread(self, default_port) + + + def add_routes_for_class(self, cls): + ''' Probably obsolete, use classes inheriting from WebSocketRoute ''' + methods = [method for method in dir(cls) if '__' not in method] + log.info("added routes for {}".format(methods)) + for method in methods: + WebSocketAsync.add_route(method, getattr(cls, method)) + + def tray_start(self): + self.websocket_thread.start() + + # log.info("Starting websocket server") + # loop = asyncio.get_event_loop() + # self.runner = web.AppRunner(self.app) + # loop.run_until_complete(self.runner.setup()) + # self.site = web.TCPSite(self.runner, 'localhost', 8044) + # loop.run_until_complete(self.site.start()) + # log.info('site {}'.format(self.site._server)) + # asyncio.ensure_future() + # #loop.run_forever() + # #web.run_app(self.app, port=8044) + # log.info("Started websocket server") + + @property + def is_running(self): + return self.websocket_thread.is_running + + def stop(self): + self.websocket_thread.is_running = False + + def thread_stopped(self): + self._is_running = False + + async def on_shutdown(self): + """ + Gracefully remove all connected websocket connections + :return: None + """ + log.info('Shutting down websocket server') + for ws in set(self.app['websockets']): + await ws.close(code=WSCloseCode.GOING_AWAY, + message='Server shutdown') + +class WebsocketServerThread(QtCore.QThread): + """ Listener for websocket rpc requests. + + It would be probably better to "attach" this to main thread (as for + example Harmony needs to run something on main thread), but currently + it creates separate thread and separate asyncio event loop + """ + def __init__(self, module, port): + super(WebsocketServerThread, self).__init__() + self.is_running = False + self.port = port + self.module = module + + def run(self): + self.is_running = True + + try: + log.debug( + "Running Websocket server on URL:" + " \"ws://localhost:{}\"".format(self.port) + ) + + log.info("Starting websocket server") + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + web.run_app(self.module.app, port=self.port) # blocking + log.info("Started websocket server") + + except Exception: + log.warning( + "Websocket Server service has failed", exc_info=True + ) + + self.is_running = False + self.module.thread_stopped() From d6485030b5d3f1f19f1c7535fffd00ff2bf5d934 Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Fri, 3 Jul 2020 17:31:53 +0200 Subject: [PATCH 014/580] Hound --- pype/modules/websocket_server/external_app_1.py | 1 + pype/modules/websocket_server/websocket_server.py | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pype/modules/websocket_server/external_app_1.py b/pype/modules/websocket_server/external_app_1.py index 34a43a4d23..9352787175 100644 --- a/pype/modules/websocket_server/external_app_1.py +++ b/pype/modules/websocket_server/external_app_1.py @@ -5,6 +5,7 @@ from wsrpc_aiohttp import WebSocketRoute log = Logger().get_logger("WebsocketServer") + class ExternalApp1(WebSocketRoute): """ One route, mimicking external application (like Harmony, etc). diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index ce5f23180a..29b08a1c6d 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -10,6 +10,7 @@ from . import external_app_1 log = Logger().get_logger("WebsocketServer") + class WebSocketServer(): """ Basic POC implementation of asychronic websocket RPC server. @@ -31,8 +32,8 @@ class WebSocketServer(): except Exception: self.presets = {"default_port": default_port, "exclude_ports": []} log.debug(( - "There are not set presets for WebsocketServer." - " Using defaults \"{}\"" + "There are not set presets for WebsocketServer." + " Using defaults \"{}\"" ).format(str(self.presets))) self.app = web.Application() @@ -49,9 +50,8 @@ class WebSocketServer(): self.websocket_thread = WebsocketServerThread(self, default_port) - def add_routes_for_class(self, cls): - ''' Probably obsolete, use classes inheriting from WebSocketRoute ''' + """ Probably obsolete, use classes inheriting from WebSocketRoute """ methods = [method for method in dir(cls) if '__' not in method] log.info("added routes for {}".format(methods)) for method in methods: @@ -92,6 +92,7 @@ class WebSocketServer(): await ws.close(code=WSCloseCode.GOING_AWAY, message='Server shutdown') + class WebsocketServerThread(QtCore.QThread): """ Listener for websocket rpc requests. From a29c84e9af7180df2a2b12b23bf1d79a91d13315 Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Wed, 8 Jul 2020 16:14:07 +0200 Subject: [PATCH 015/580] Fix - changed usage of QThread to threading.Thread Apparently QThread is making problems on some non-gui linux distros --- pype/modules/websocket_server/websocket_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 29b08a1c6d..de16891ee1 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -1,6 +1,6 @@ from pype.api import config, Logger -from Qt import QtCore +import threading from aiohttp import web, WSCloseCode import asyncio import weakref @@ -93,7 +93,7 @@ class WebSocketServer(): message='Server shutdown') -class WebsocketServerThread(QtCore.QThread): +class WebsocketServerThread(threading.Thread): """ Listener for websocket rpc requests. It would be probably better to "attach" this to main thread (as for From d02e9596a665188249e5f096af21c644f71edd5d Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Thu, 9 Jul 2020 12:30:55 +0200 Subject: [PATCH 016/580] Added separate 'hosts' folder Added auto-routing of classes from selected folders --- .../websocket_server/hosts/__init__.py | 0 .../{ => hosts}/external_app_1.py | 0 .../websocket_server/websocket_server.py | 45 ++++++++++++++----- 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 pype/modules/websocket_server/hosts/__init__.py rename pype/modules/websocket_server/{ => hosts}/external_app_1.py (100%) diff --git a/pype/modules/websocket_server/hosts/__init__.py b/pype/modules/websocket_server/hosts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/modules/websocket_server/external_app_1.py b/pype/modules/websocket_server/hosts/external_app_1.py similarity index 100% rename from pype/modules/websocket_server/external_app_1.py rename to pype/modules/websocket_server/hosts/external_app_1.py diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index de16891ee1..8c8cb7be67 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -6,7 +6,10 @@ import asyncio import weakref from wsrpc_aiohttp import STATIC_DIR, WebSocketAsync -from . import external_app_1 +import os +import sys +import pyclbr +import importlib log = Logger().get_logger("WebsocketServer") @@ -32,8 +35,8 @@ class WebSocketServer(): except Exception: self.presets = {"default_port": default_port, "exclude_ports": []} log.debug(( - "There are not set presets for WebsocketServer." - " Using defaults \"{}\"" + "There are not set presets for WebsocketServer." + " Using defaults \"{}\"" ).format(str(self.presets))) self.app = web.Application() @@ -44,18 +47,40 @@ class WebSocketServer(): self.app.router.add_static("/", ".") # add route with multiple methods for single "external app" - WebSocketAsync.add_route('ExternalApp1', external_app_1.ExternalApp1) + directories_with_routes = ['hosts'] + self.add_routes_for_directories(directories_with_routes) self.app.on_shutdown.append(self.on_shutdown) self.websocket_thread = WebsocketServerThread(self, default_port) - def add_routes_for_class(self, cls): - """ Probably obsolete, use classes inheriting from WebSocketRoute """ - methods = [method for method in dir(cls) if '__' not in method] - log.info("added routes for {}".format(methods)) - for method in methods: - WebSocketAsync.add_route(method, getattr(cls, method)) + def add_routes_for_directories(self, directories_with_routes): + """ Loops through selected directories to find all modules and + in them all classes implementing 'WebSocketRoute' that could be + used as route. + All methods in these classes are registered automatically. + """ + for dir_name in directories_with_routes: + dir_name = os.path.join(os.path.dirname(__file__), dir_name) + for file_name in os.listdir(dir_name): + if '.py' in file_name and '__' not in file_name: + self.add_routes_for_module(file_name, dir_name) + + def add_routes_for_module(self, file_name, dir_name): + """ Auto routes for all classes implementing 'WebSocketRoute' + in 'file_name' in 'dir_name' + """ + module_name = file_name.replace('.py', '') + module_info = pyclbr.readmodule(module_name, [dir_name]) + + for class_name, cls_object in module_info.items(): + sys.path.append(dir_name) + if 'WebSocketRoute' in cls_object.super: + log.debug('Adding route for {}'.format(class_name)) + module = importlib.import_module(module_name) + cls = getattr(module, class_name) + WebSocketAsync.add_route(class_name, cls) + sys.path.pop() def tray_start(self): self.websocket_thread.start() From dc7a1042145b9eb3ee5c20424b8c352a3e13affb Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Fri, 10 Jul 2020 11:15:46 +0200 Subject: [PATCH 017/580] Added proper shutdown --- .../websocket_server/websocket_server.py | 98 ++++++++++++------- 1 file changed, 65 insertions(+), 33 deletions(-) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 8c8cb7be67..87f9bde8e0 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -1,9 +1,8 @@ from pype.api import config, Logger import threading -from aiohttp import web, WSCloseCode +from aiohttp import web import asyncio -import weakref from wsrpc_aiohttp import STATIC_DIR, WebSocketAsync import os @@ -40,7 +39,6 @@ class WebSocketServer(): ).format(str(self.presets))) self.app = web.Application() - self.app["websockets"] = weakref.WeakSet() self.app.router.add_route("*", "/ws/", WebSocketAsync) self.app.router.add_static("/js", STATIC_DIR) @@ -50,8 +48,6 @@ class WebSocketServer(): directories_with_routes = ['hosts'] self.add_routes_for_directories(directories_with_routes) - self.app.on_shutdown.append(self.on_shutdown) - self.websocket_thread = WebsocketServerThread(self, default_port) def add_routes_for_directories(self, directories_with_routes): @@ -85,38 +81,33 @@ class WebSocketServer(): def tray_start(self): self.websocket_thread.start() - # log.info("Starting websocket server") - # loop = asyncio.get_event_loop() - # self.runner = web.AppRunner(self.app) - # loop.run_until_complete(self.runner.setup()) - # self.site = web.TCPSite(self.runner, 'localhost', 8044) - # loop.run_until_complete(self.site.start()) - # log.info('site {}'.format(self.site._server)) - # asyncio.ensure_future() - # #loop.run_forever() - # #web.run_app(self.app, port=8044) - # log.info("Started websocket server") + def tray_exit(self): + self.stop() + + def stop_websocket_server(self): + + self.stop() @property def is_running(self): return self.websocket_thread.is_running def stop(self): - self.websocket_thread.is_running = False + if not self.is_running: + return + try: + log.debug("Stopping websocket server") + self.websocket_thread.is_running = False + self.websocket_thread.stop() + except Exception: + log.warning( + "Error has happened during Killing websocket server", + exc_info=True + ) def thread_stopped(self): self._is_running = False - async def on_shutdown(self): - """ - Gracefully remove all connected websocket connections - :return: None - """ - log.info('Shutting down websocket server') - for ws in set(self.app['websockets']): - await ws.close(code=WSCloseCode.GOING_AWAY, - message='Server shutdown') - class WebsocketServerThread(threading.Thread): """ Listener for websocket rpc requests. @@ -130,26 +121,67 @@ class WebsocketServerThread(threading.Thread): self.is_running = False self.port = port self.module = module + self.loop = None + self.runner = None + self.site = None def run(self): self.is_running = True try: + log.info("Starting websocket server") + self.loop = asyncio.new_event_loop() # create new loop for thread + asyncio.set_event_loop(self.loop) + + self.loop.run_until_complete(self.start_server()) + log.debug( "Running Websocket server on URL:" " \"ws://localhost:{}\"".format(self.port) ) - log.info("Starting websocket server") - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - web.run_app(self.module.app, port=self.port) # blocking - log.info("Started websocket server") - + asyncio.ensure_future(self.check_shutdown(), loop=self.loop) + self.loop.run_forever() except Exception: log.warning( "Websocket Server service has failed", exc_info=True ) + finally: + self.loop.close() # optional self.is_running = False self.module.thread_stopped() + log.info("Websocket server stopped") + + async def start_server(self): + """ Starts runner and TCPsite """ + self.runner = web.AppRunner(self.module.app) + await self.runner.setup() + self.site = web.TCPSite(self.runner, 'localhost', self.port) + await self.site.start() + + def stop(self): + """ Sets is_running flag to false, 'check_shutdown' shuts server down""" + self.is_running = False + + async def check_shutdown(self): + """ Future that is running and checks if server should be running + periodically. + """ + while self.is_running: + await asyncio.sleep(0.5) + + log.debug("Starting shutdown") + await self.site.stop() + log.debug("Site stopped") + await self.runner.cleanup() + log.debug("Runner stopped") + tasks = [task for task in asyncio.all_tasks() if + task is not asyncio.current_task()] + list(map(lambda task: task.cancel(), tasks)) # cancel all the tasks + results = await asyncio.gather(*tasks, return_exceptions=True) + log.debug(f'Finished awaiting cancelled tasks, results: {results}...') + await self.loop.shutdown_asyncgens() + # to really make sure everything else has time to stop + await asyncio.sleep(0.07) + self.loop.stop() From 75ecb02262ef11e43b5ef5164cffc4c14cad08e5 Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Fri, 10 Jul 2020 11:25:22 +0200 Subject: [PATCH 018/580] Hound --- pype/modules/websocket_server/websocket_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 87f9bde8e0..56e71ea895 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -161,7 +161,7 @@ class WebsocketServerThread(threading.Thread): await self.site.start() def stop(self): - """ Sets is_running flag to false, 'check_shutdown' shuts server down""" + """Sets is_running flag to false, 'check_shutdown' shuts server down""" self.is_running = False async def check_shutdown(self): From 76fe88fbccab959ff8c333dcb88e06e950919a5c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 13 Jul 2020 10:19:58 +0200 Subject: [PATCH 019/580] feat(resolve): config moved to plugins and widget rename --- pype/hosts/resolve/plugin.py | 4 +-- .../resolve/create/create_shot_clip.py | 32 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 4e7ac80add..29e544cb47 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -7,7 +7,7 @@ from pype.api import config from Qt import QtWidgets, QtCore -class Universal_widget(QtWidgets.QDialog): +class Creator_widget(QtWidgets.QDialog): # output items items = dict() @@ -270,4 +270,4 @@ class Creator(api.Creator): else: self.selected = resolve.get_current_track_items(filter=False) - self.widget = Universal_widget + self.widget = Creator_widget diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index 43207743e2..e4b3e8fe2a 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -13,17 +13,41 @@ class CreateShotClip(resolve.Creator): gui_name = "Pype sequencial rename with hirerarchy" gui_info = "Define sequencial rename and fill hierarchy data." + gui_inputs = { + "clipName": "{episode}{sequence}{shot}", + "hierarchy": "{folder}/{sequence}/{shot}", + "countFrom": 10, + "steps": 10, + "hierarchyData": { + "folder": "shots", + "shot": "sh####", + "track": "{track}", + "sequence": "sc010", + "episode": "ep01" + } + } presets = None def process(self): - print(f"__ selected_clips: {self.selected}") + # solve gui inputs overwrites from presets + # overwrite gui inputs from presets + for k, v in self.gui_inputs.items(): + if isinstance(v, dict): + # nested dictionary (only one level allowed) + for _k, _v in v.items(): + if self.presets.get(_k): + self.gui_inputs[k][_k] = self.presets[_k] + if self.presets.get(k): + self.gui_inputs[k] = self.presets[k] + # open widget for plugins inputs + widget = self.widget(self.gui_name, self.gui_info, self.gui_inputs) + widget.exec_() + + print(f"__ selected_clips: {self.selected}") if len(self.selected) < 1: return - widget = self.widget(self.gui_name, self.gui_info, self.presets) - widget.exec_() - if not widget.result: print("Operation aborted") return From 309515461aeee31f8d2df4276f7b5942fe240627 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 13 Jul 2020 10:31:11 +0200 Subject: [PATCH 020/580] feat(resolve): hound fixes --- pype/hosts/resolve/plugin.py | 4 ++-- pype/plugins/resolve/publish/collect_clips.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 29e544cb47..67f2820990 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -7,7 +7,7 @@ from pype.api import config from Qt import QtWidgets, QtCore -class Creator_widget(QtWidgets.QDialog): +class CreatorWidget(QtWidgets.QDialog): # output items items = dict() @@ -270,4 +270,4 @@ class Creator(api.Creator): else: self.selected = resolve.get_current_track_items(filter=False) - self.widget = Creator_widget + self.widget = CreatorWidget diff --git a/pype/plugins/resolve/publish/collect_clips.py b/pype/plugins/resolve/publish/collect_clips.py index 0f02f26f2e..f86e5c8384 100644 --- a/pype/plugins/resolve/publish/collect_clips.py +++ b/pype/plugins/resolve/publish/collect_clips.py @@ -3,6 +3,7 @@ from pyblish import api from pype.hosts import resolve import json + class CollectClips(api.ContextPlugin): """Collect all Track items selection.""" @@ -156,4 +157,6 @@ class CollectClips(api.ContextPlugin): "_clipIn": clip_in, "_clipOut": clip_out } - self.log.info("context.data[\"assetsShared\"]: {}".format(context.data["assetsShared"])) + self.log.info( + "context.data[\"assetsShared\"]: {}".format( + context.data["assetsShared"])) From e259a55af9e1efe648842cc3a94bfca6d34c0f62 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 13 Jul 2020 10:42:26 +0200 Subject: [PATCH 021/580] feat(resolve): hound fixes --- pype/hosts/resolve/plugin.py | 6 +++--- pype/hosts/resolve/utility_scripts/test.py | 4 +++- pype/plugins/resolve/create/create_shot_clip.py | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 67f2820990..72eec04896 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -13,7 +13,7 @@ class CreatorWidget(QtWidgets.QDialog): items = dict() def __init__(self, name, info, presets, parent=None): - super(Universal_widget, self).__init__(parent) + super(CreatorWidget, self).__init__(parent) self.setObjectName(name) @@ -86,11 +86,11 @@ class CreatorWidget(QtWidgets.QDialog): data[k] = self.value(v) elif getattr(v, "value", None): print(f"normal int: {k}") - result = getattr(v, "value") + result = v.value() data[k] = result() else: print(f"normal text: {k}") - result = getattr(v, "text") + result = v.text() data[k] = result() return data diff --git a/pype/hosts/resolve/utility_scripts/test.py b/pype/hosts/resolve/utility_scripts/test.py index cf7db3b7e5..69dc4768bd 100644 --- a/pype/hosts/resolve/utility_scripts/test.py +++ b/pype/hosts/resolve/utility_scripts/test.py @@ -1,6 +1,8 @@ #! python3 import sys from pype.api import Logger +import DaVinciResolveScript as bmdvr + log = Logger().get_logger(__name__) @@ -10,7 +12,7 @@ def main(): bm = bmdvr.utils.get_resolve_module() log.info(f"blackmagicmodule: {bm}") -import DaVinciResolveScript as bmdvr + print(f"_>> bmdvr.scriptapp(Resolve): {bmdvr.scriptapp('Resolve')}") diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index e4b3e8fe2a..bd2e013fac 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -70,10 +70,10 @@ class CreateShotClip(resolve.Creator): t_data["clip"]["item"].ClearClipColor() # convert track item to timeline media pool item - c_clip = resolve.create_compound_clip( + resolve.create_compound_clip( t_data, mp_folder, rename=True, **dict( {"presets": widget.result}) - ) + ) From 2909b7453e2117282d7181a84fb850824bf86b5f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 11:03:44 +0200 Subject: [PATCH 022/580] initial commit --- .../kuba_each_case/global/creator.json | 8 + .../kuba_each_case/global/intents.json | 3 + .../project_presets/ftrack/ftrack_config.json | 11 + .../project_presets/global/creator.json | 8 + .../global/slates/example_HD.json | 212 +++ .../config/project_presets/maya/capture.json | 108 ++ .../project_presets/plugins/config.json | 1 + .../plugins/ftrack/publish.json | 6 + .../plugins/global/create.json | 1 + .../plugins/global/filter.json | 1 + .../project_presets/plugins/global/load.json | 1 + .../plugins/global/publish.json | 73 + .../project_presets/plugins/maya/create.json | 1 + .../project_presets/plugins/maya/filter.json | 9 + .../project_presets/plugins/maya/load.json | 18 + .../project_presets/plugins/maya/publish.json | 17 + .../plugins/maya/workfile_build.json | 54 + .../project_presets/plugins/nuke/create.json | 8 + .../project_presets/plugins/nuke/load.json | 1 + .../project_presets/plugins/nuke/publish.json | 48 + .../plugins/nuke/workfile_build.json | 11 + .../plugins/nukestudio/filter.json | 10 + .../plugins/nukestudio/publish.json | 8 + .../plugins/standalonepublisher/publish.json | 17 + .../project_presets/plugins/test/create.json | 8 + .../project_presets/plugins/test/publish.json | 10 + .../premiere/asset_default.json | 5 + .../project_presets/premiere/rules_tasks.json | 21 + .../project_presets/unreal/project_setup.json | 4 + .../studio_presets/ftrack/server_plugins.json | 1 + .../studio_presets/ftrack/user_plugins.json | 5 + .../studio_presets/global/applications.json | 39 + .../global/es/applications.json | 39 + .../config/studio_presets/global/intents.json | 9 + .../studio_presets/global/tray_items.json | 25 + .../muster/templates_mapping.json | 19 + .../applications_gui_schema.json | 153 ++ .../ftrack_projects_gui_schema.json | 30 + .../config_gui_schema/project_gui_schema.json | 13 + .../config_gui_schema/studio_gui_schema.json | 23 + .../config_gui_schema/tools_gui_schema.json | 29 + pype/tools/config_setting/interface.py | 49 + pype/tools/config_setting/style/__init__.py | 12 + pype/tools/config_setting/style/pype_icon.png | Bin 0 -> 3793 bytes pype/tools/config_setting/style/style.css | 90 ++ pype/tools/config_setting/widgets/__init__.py | 6 + pype/tools/config_setting/widgets/base.py | 282 ++++ pype/tools/config_setting/widgets/config.py | 236 +++ pype/tools/config_setting/widgets/inputs.py | 1346 +++++++++++++++++ pype/tools/config_setting/widgets/lib.py | 44 + pype/tools/config_setting/widgets/main.py | 26 + pype/tools/config_setting/widgets/tests.py | 127 ++ 52 files changed, 3286 insertions(+) create mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json create mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json create mode 100644 pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json create mode 100644 pype/tools/config_setting/config/project_presets/global/creator.json create mode 100644 pype/tools/config_setting/config/project_presets/global/slates/example_HD.json create mode 100644 pype/tools/config_setting/config/project_presets/maya/capture.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/config.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/create.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/filter.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/load.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/create.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/filter.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/load.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/create.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/load.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/test/create.json create mode 100644 pype/tools/config_setting/config/project_presets/plugins/test/publish.json create mode 100644 pype/tools/config_setting/config/project_presets/premiere/asset_default.json create mode 100644 pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json create mode 100644 pype/tools/config_setting/config/project_presets/unreal/project_setup.json create mode 100644 pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json create mode 100644 pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json create mode 100644 pype/tools/config_setting/config/studio_presets/global/applications.json create mode 100644 pype/tools/config_setting/config/studio_presets/global/es/applications.json create mode 100644 pype/tools/config_setting/config/studio_presets/global/intents.json create mode 100644 pype/tools/config_setting/config/studio_presets/global/tray_items.json create mode 100644 pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json create mode 100644 pype/tools/config_setting/config_gui_schema/applications_gui_schema.json create mode 100644 pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json create mode 100644 pype/tools/config_setting/config_gui_schema/project_gui_schema.json create mode 100644 pype/tools/config_setting/config_gui_schema/studio_gui_schema.json create mode 100644 pype/tools/config_setting/config_gui_schema/tools_gui_schema.json create mode 100644 pype/tools/config_setting/interface.py create mode 100644 pype/tools/config_setting/style/__init__.py create mode 100644 pype/tools/config_setting/style/pype_icon.png create mode 100644 pype/tools/config_setting/style/style.css create mode 100644 pype/tools/config_setting/widgets/__init__.py create mode 100644 pype/tools/config_setting/widgets/base.py create mode 100644 pype/tools/config_setting/widgets/config.py create mode 100644 pype/tools/config_setting/widgets/inputs.py create mode 100644 pype/tools/config_setting/widgets/lib.py create mode 100644 pype/tools/config_setting/widgets/main.py create mode 100644 pype/tools/config_setting/widgets/tests.py diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json new file mode 100644 index 0000000000..d14e779f01 --- /dev/null +++ b/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json @@ -0,0 +1,8 @@ +{ + "Model": ["model"], + "Render Globals": ["light", "render"], + "Layout": ["layout"], + "Set Dress": ["setdress"], + "Look": ["look"], + "Rig": ["rigging"] +} diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json new file mode 100644 index 0000000000..bf147c7a19 --- /dev/null +++ b/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json @@ -0,0 +1,3 @@ +{ + "default": "test" +} diff --git a/pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json b/pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json new file mode 100644 index 0000000000..c9dbde4596 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json @@ -0,0 +1,11 @@ +{ + "status_update": { + "_ignore_": ["in progress", "ommited", "on hold"], + "Ready": ["not ready"], + "In Progress" : ["_any_"] + }, + "status_version_to_task": { + "in progress": "in progress", + "approved": "approved" + } +} diff --git a/pype/tools/config_setting/config/project_presets/global/creator.json b/pype/tools/config_setting/config/project_presets/global/creator.json new file mode 100644 index 0000000000..d14e779f01 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/global/creator.json @@ -0,0 +1,8 @@ +{ + "Model": ["model"], + "Render Globals": ["light", "render"], + "Layout": ["layout"], + "Set Dress": ["setdress"], + "Look": ["look"], + "Rig": ["rigging"] +} diff --git a/pype/tools/config_setting/config/project_presets/global/slates/example_HD.json b/pype/tools/config_setting/config/project_presets/global/slates/example_HD.json new file mode 100644 index 0000000000..b06391fb63 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/global/slates/example_HD.json @@ -0,0 +1,212 @@ +{ + "width": 1920, + "height": 1080, + "destination_path": "{destination_path}", + "style": { + "*": { + "font-family": "arial", + "font-color": "#ffffff", + "font-bold": false, + "font-italic": false, + "bg-color": "#0077ff", + "alignment-horizontal": "left", + "alignment-vertical": "top" + }, + "layer": { + "padding": 0, + "margin": 0 + }, + "rectangle": { + "padding": 0, + "margin": 0, + "bg-color": "#E9324B", + "fill": true + }, + "main_frame": { + "padding": 0, + "margin": 0, + "bg-color": "#252525" + }, + "table": { + "padding": 0, + "margin": 0, + "bg-color": "transparent" + }, + "table-item": { + "padding": 5, + "padding-bottom": 10, + "margin": 0, + "bg-color": "#212121", + "bg-alter-color": "#272727", + "font-color": "#dcdcdc", + "font-bold": false, + "font-italic": false, + "alignment-horizontal": "left", + "alignment-vertical": "top", + "word-wrap": false, + "ellide": true, + "max-lines": 1 + }, + "table-item-col[0]": { + "font-size": 20, + "font-color": "#898989", + "font-bold": true, + "ellide": false, + "word-wrap": true, + "max-lines": null + }, + "table-item-col[1]": { + "font-size": 40, + "padding-left": 10 + }, + "#colorbar": { + "bg-color": "#9932CC" + } + }, + "items": [{ + "type": "layer", + "direction": 1, + "name": "MainLayer", + "style": { + "#MainLayer": { + "width": 1094, + "height": 1000, + "margin": 25, + "padding": 0 + }, + "#LeftSide": { + "margin-right": 25 + } + }, + "items": [{ + "type": "layer", + "name": "LeftSide", + "items": [{ + "type": "layer", + "direction": 1, + "style": { + "table-item": { + "bg-color": "transparent", + "padding-bottom": 20 + }, + "table-item-col[0]": { + "font-size": 20, + "font-color": "#898989", + "alignment-horizontal": "right" + }, + "table-item-col[1]": { + "alignment-horizontal": "left", + "font-bold": true, + "font-size": 40 + } + }, + "items": [{ + "type": "table", + "values": [ + ["Show:", "{project[name]}"] + ], + "style": { + "table-item-field[0:0]": { + "width": 150 + }, + "table-item-field[0:1]": { + "width": 580 + } + } + }, { + "type": "table", + "values": [ + ["Submitting For:", "{intent}"] + ], + "style": { + "table-item-field[0:0]": { + "width": 160 + }, + "table-item-field[0:1]": { + "width": 218, + "alignment-horizontal": "right" + } + } + }] + }, { + "type": "rectangle", + "style": { + "bg-color": "#bc1015", + "width": 1108, + "height": 5, + "fill": true + } + }, { + "type": "table", + "use_alternate_color": true, + "values": [ + ["Version name:", "{version_name}"], + ["Date:", "{date}"], + ["Shot Types:", "{shot_type}"], + ["Submission Note:", "{submission_note}"] + ], + "style": { + "table-item": { + "padding-bottom": 20 + }, + "table-item-field[0:1]": { + "font-bold": true + }, + "table-item-field[3:0]": { + "word-wrap": true, + "ellide": true, + "max-lines": 4 + }, + "table-item-col[0]": { + "alignment-horizontal": "right", + "width": 150 + }, + "table-item-col[1]": { + "alignment-horizontal": "left", + "width": 958 + } + } + }] + }, { + "type": "layer", + "name": "RightSide", + "items": [{ + "type": "placeholder", + "name": "thumbnail", + "path": "{thumbnail_path}", + "style": { + "width": 730, + "height": 412 + } + }, { + "type": "placeholder", + "name": "colorbar", + "path": "{color_bar_path}", + "return_data": true, + "style": { + "width": 730, + "height": 55 + } + }, { + "type": "table", + "use_alternate_color": true, + "values": [ + ["Vendor:", "{vendor}"], + ["Shot Name:", "{shot_name}"], + ["Frames:", "{frame_start} - {frame_end} ({duration})"] + ], + "style": { + "table-item-col[0]": { + "alignment-horizontal": "left", + "width": 200 + }, + "table-item-col[1]": { + "alignment-horizontal": "right", + "width": 530, + "font-size": 30 + } + } + }] + }] + }] +} diff --git a/pype/tools/config_setting/config/project_presets/maya/capture.json b/pype/tools/config_setting/config/project_presets/maya/capture.json new file mode 100644 index 0000000000..b6c4893034 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/maya/capture.json @@ -0,0 +1,108 @@ +{ + "Codec": { + "compression": "jpg", + "format": "image", + "quality": 95 + }, + "Display Options": { + "background": [ + 0.7137254901960784, + 0.7137254901960784, + 0.7137254901960784 + ], + "backgroundBottom": [ + 0.7137254901960784, + 0.7137254901960784, + 0.7137254901960784 + ], + "backgroundTop": [ + 0.7137254901960784, + 0.7137254901960784, + 0.7137254901960784 + ], + "override_display": true + }, + "Generic": { + "isolate_view": true, + "off_screen": true + }, + "IO": { + "name": "", + "open_finished": false, + "raw_frame_numbers": false, + "recent_playblasts": [], + "save_file": false + }, + "PanZoom": { + "pan_zoom": true + }, + "Renderer": { + "rendererName": "vp2Renderer" + }, + "Resolution": { + "height": 1080, + "mode": "Custom", + "percent": 1.0, + "width": 1920 + }, + "Time Range": { + "end_frame": 25, + "frame": "", + "start_frame": 0, + "time": "Time Slider" + }, + "Viewport Options": { + "cameras": false, + "clipGhosts": false, + "controlVertices": false, + "deformers": false, + "dimensions": false, + "displayLights": 0, + "dynamicConstraints": false, + "dynamics": false, + "fluids": false, + "follicles": false, + "gpuCacheDisplayFilter": false, + "greasePencils": false, + "grid": false, + "hairSystems": false, + "handles": false, + "high_quality": true, + "hud": false, + "hulls": false, + "ikHandles": false, + "imagePlane": false, + "joints": false, + "lights": false, + "locators": false, + "manipulators": false, + "motionTrails": false, + "nCloths": false, + "nParticles": false, + "nRigids": false, + "nurbsCurves": false, + "nurbsSurfaces": false, + "override_viewport_options": true, + "particleInstancers": false, + "pivots": false, + "planes": false, + "pluginShapes": false, + "polymeshes": true, + "shadows": false, + "strokes": false, + "subdivSurfaces": false, + "textures": false, + "twoSidedLighting": true + }, + "Camera Options": { + "displayGateMask": false, + "displayResolution": false, + "displayFilmGate": false, + "displayFieldChart": false, + "displaySafeAction": false, + "displaySafeTitle": false, + "displayFilmPivot": false, + "displayFilmOrigin": false, + "overscan": 1.0 + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/config.json b/pype/tools/config_setting/config/project_presets/plugins/config.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json b/pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json new file mode 100644 index 0000000000..d0469ae4f7 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json @@ -0,0 +1,6 @@ +{ + "IntegrateFtrackNote": { + "note_with_intent_template": "{intent}: {comment}", + "note_labels": [] + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/create.json b/pype/tools/config_setting/config/project_presets/plugins/global/create.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/global/create.json @@ -0,0 +1 @@ +{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/filter.json b/pype/tools/config_setting/config/project_presets/plugins/global/filter.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/global/filter.json @@ -0,0 +1 @@ +{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/load.json b/pype/tools/config_setting/config/project_presets/plugins/global/load.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/global/load.json @@ -0,0 +1 @@ +{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/publish.json b/pype/tools/config_setting/config/project_presets/plugins/global/publish.json new file mode 100644 index 0000000000..6e51e00497 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/global/publish.json @@ -0,0 +1,73 @@ +{ + "IntegrateMasterVersion": { + "enabled": false + }, + "ExtractReview": { + "__documentation__": "http://pype.club/docs/admin_presets_plugins", + "profiles": [ + { + "families": [], + "hosts": [], + "outputs": { + "h264": { + "filter": { + "families": ["render", "review", "ftrack"] + }, + "ext": "mp4", + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "video_filters": [], + "audio_filters": [], + "output": [ + "-pix_fmt yuv420p", + "-crf 18", + "-intra" + ] + }, + "tags": ["burnin", "ftrackreview"] + } + } + } + ] + }, + "ExtractBurnin": { + "options": { + "opacity": 1, + "x_offset": 5, + "y_offset": 5, + "bg_padding": 5, + "bg_opacity": 0.5, + "font_size": 42 + }, + "fields": { + + }, + "profiles": [ + { + "burnins": { + "burnin": { + "TOP_LEFT": "{yy}-{mm}-{dd}", + "TOP_RIGHT": "{anatomy[version]}", + "TOP_CENTERED": "", + "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", + "BOTTOM_CENTERED": "{asset}", + "BOTTOM_LEFT": "{username}" + } + } + } + ] + }, + "IntegrateAssetNew": { + "template_name_profiles": { + "publish": { + "families": [], + "tasks": [] + }, + "render": { + "families": ["review", "render", "prerender"] + } + } + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/create.json b/pype/tools/config_setting/config/project_presets/plugins/maya/create.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/maya/create.json @@ -0,0 +1 @@ +{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/filter.json b/pype/tools/config_setting/config/project_presets/plugins/maya/filter.json new file mode 100644 index 0000000000..83d6f05f31 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/maya/filter.json @@ -0,0 +1,9 @@ +{ + "Preset n1": { + "ValidateNoAnimation": false, + "ValidateShapeDefaultNames": false + }, + "Preset n2": { + "ValidateNoAnimation": false + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/load.json b/pype/tools/config_setting/config/project_presets/plugins/maya/load.json new file mode 100644 index 0000000000..260fbb35ee --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/maya/load.json @@ -0,0 +1,18 @@ +{ + "colors": { + "model": [0.821, 0.518, 0.117], + "rig": [0.144, 0.443, 0.463], + "pointcache": [0.368, 0.821, 0.117], + "animation": [0.368, 0.821, 0.117], + "ass": [1.0, 0.332, 0.312], + "camera": [0.447, 0.312, 1.0], + "fbx": [1.0, 0.931, 0.312], + "mayaAscii": [0.312, 1.0, 0.747], + "setdress": [0.312, 1.0, 0.747], + "layout": [0.312, 1.0, 0.747], + "vdbcache": [0.312, 1.0, 0.428], + "vrayproxy": [0.258, 0.95, 0.541], + "yeticache": [0.2, 0.8, 0.3], + "yetiRig": [0, 0.8, 0.5] + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/publish.json b/pype/tools/config_setting/config/project_presets/plugins/maya/publish.json new file mode 100644 index 0000000000..2e2b3164f3 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/maya/publish.json @@ -0,0 +1,17 @@ +{ + "ValidateModelName": { + "enabled": false, + "material_file": "/path/to/shader_name_definition.txt", + "regex": "(.*)_(\\d)*_(?P.*)_(GEO)" + }, + "ValidateAssemblyName": { + "enabled": false + }, + "ValidateShaderName": { + "enabled": false, + "regex": "(?P.*)_(.*)_SHD" + }, + "ValidateMeshHasOverlappingUVs": { + "enabled": false + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json b/pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json new file mode 100644 index 0000000000..2872b783cb --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json @@ -0,0 +1,54 @@ +[{ + "tasks": ["lighting"], + + "current_context": [{ + "subset_name_filters": [".+[Mm]ain"], + "families": ["model"], + "repre_names": ["abc", "ma"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["animation", "pointcache"], + "repre_names": ["abc"], + "loaders": ["ReferenceLoader"] + },{ + "families": ["rendersetup"], + "repre_names": ["json"], + "loaders": ["RenderSetupLoader"] + }, { + "families": ["camera"], + "repre_names": ["abc"], + "loaders": ["ReferenceLoader"] + }], + + "linked_assets": [{ + "families": ["setdress"], + "repre_names": ["ma"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["ass"], + "repre_names": ["ass"], + "loaders":["assLoader"] + }] +}, { + "tasks": ["animation"], + + "current_context": [{ + "families": ["camera"], + "repre_names": ["abc", "ma"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["audio"], + "repre_names": ["wav"], + "loaders": ["RenderSetupLoader"] + }], + + "linked_assets": [{ + "families": ["setdress"], + "repre_names": ["proxy"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["rig"], + "repre_names": ["ass"], + "loaders": ["rigLoader"] + }] +}] diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/create.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/create.json new file mode 100644 index 0000000000..4deb0b4ad5 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/nuke/create.json @@ -0,0 +1,8 @@ +{ + "CreateWriteRender": { + "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" + }, + "CreateWritePrerender": { + "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/load.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/load.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/nuke/load.json @@ -0,0 +1 @@ +{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json new file mode 100644 index 0000000000..ab0d0e76a5 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json @@ -0,0 +1,48 @@ +{ + "ExtractThumbnail": { + "nodes": { + "Reformat": [ + ["type", "to format"], + ["format", "HD_1080"], + ["filter", "Lanczos6"], + ["black_outside", true], + ["pbb", false] + ] + } + }, + "ValidateNukeWriteKnobs": { + "enabled": false, + "knobs": { + "render": { + "review": true + } + } + }, + "ExtractReviewDataLut": { + "__documentation__": { + "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", + "enabled": "keep in on `false` if you want Nuke baking colorspace workflow applied else FFmpeg will convert imgsequence with baked LUT" + }, + "enabled": false + }, + "ExtractReviewDataMov": { + "__documentation__": { + "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", + "enabled": "keep in on `true` if you want Nuke baking colorspace workflow applied" + }, + "enabled": true, + "viewer_lut_raw": false + }, + "ExtractSlateFrame": { + "__documentation__": { + "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`" + }, + "viewer_lut_raw": false + }, + "NukeSubmitDeadline": { + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_chunk_size": 1 + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json new file mode 100644 index 0000000000..d3613c929e --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json @@ -0,0 +1,11 @@ +[{ + "tasks": ["compositing"], + + "current_context": [{ + "families": ["render", "plate"], + "repre_names": ["exr" ,"dpx"], + "loaders": ["LoadSequence"] + }], + + "linked_assets": [] +}] diff --git a/pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json b/pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json new file mode 100644 index 0000000000..bd6a0dc1bd --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json @@ -0,0 +1,10 @@ +{ + "strict": { + "ValidateVersion": true, + "VersionUpWorkfile": true + }, + "benevolent": { + "ValidateVersion": false, + "VersionUpWorkfile": false + } +} \ No newline at end of file diff --git a/pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json b/pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json new file mode 100644 index 0000000000..8c4ad133f1 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json @@ -0,0 +1,8 @@ +{ + "CollectInstanceVersion": { + "enabled": false + }, + "ExtractReviewCutUpVideo": { + "tags_addition": [] + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json b/pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json new file mode 100644 index 0000000000..ecfff12db9 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json @@ -0,0 +1,17 @@ +{ + "ExtractReviewSP": { + "outputs": { + "h264": { + "input": [ + "-gamma 2.2" + ], + "output": [ + "-pix_fmt yuv420p", + "-crf 18" + ], + "tags": ["preview"], + "ext": "mov" + } + } + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/test/create.json b/pype/tools/config_setting/config/project_presets/plugins/test/create.json new file mode 100644 index 0000000000..fa0b2fc05f --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/test/create.json @@ -0,0 +1,8 @@ +{ + "MyTestCreator": { + "my_test_property": "B", + "active": false, + "new_property": "new", + "family": "new_family" + } +} diff --git a/pype/tools/config_setting/config/project_presets/plugins/test/publish.json b/pype/tools/config_setting/config/project_presets/plugins/test/publish.json new file mode 100644 index 0000000000..3180dd5d8a --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/plugins/test/publish.json @@ -0,0 +1,10 @@ +{ + "MyTestPlugin": { + "label": "loaded from preset", + "optional": true, + "families": ["changed", "by", "preset"] + }, + "MyTestRemovedPlugin": { + "enabled": false + } +} diff --git a/pype/tools/config_setting/config/project_presets/premiere/asset_default.json b/pype/tools/config_setting/config/project_presets/premiere/asset_default.json new file mode 100644 index 0000000000..84d2bde3d8 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/premiere/asset_default.json @@ -0,0 +1,5 @@ +{ + "frameStart": 1001, + "handleStart": 0, + "handleEnd": 0 +} diff --git a/pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json b/pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json new file mode 100644 index 0000000000..333c9cd70b --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json @@ -0,0 +1,21 @@ +{ + "defaultTasks": ["Layout", "Animation"], + "taskToSubsets": { + "Layout": ["reference", "audio"], + "Animation": ["audio"] + }, + "subsetToRepresentations": { + "reference": { + "preset": "h264", + "representation": "mp4" + }, + "thumbnail": { + "preset": "jpeg_thumb", + "representation": "jpg" + }, + "audio": { + "preset": "48khz", + "representation": "wav" + } + } +} diff --git a/pype/tools/config_setting/config/project_presets/unreal/project_setup.json b/pype/tools/config_setting/config/project_presets/unreal/project_setup.json new file mode 100644 index 0000000000..8a4dffc526 --- /dev/null +++ b/pype/tools/config_setting/config/project_presets/unreal/project_setup.json @@ -0,0 +1,4 @@ +{ + "dev_mode": false, + "install_unreal_python_engine": false +} diff --git a/pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json b/pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json @@ -0,0 +1 @@ +{} diff --git a/pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json b/pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json new file mode 100644 index 0000000000..1ba8e9b511 --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json @@ -0,0 +1,5 @@ +{ + "TestAction": { + "ignore_me": true + } +} diff --git a/pype/tools/config_setting/config/studio_presets/global/applications.json b/pype/tools/config_setting/config/studio_presets/global/applications.json new file mode 100644 index 0000000000..35e399444c --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/global/applications.json @@ -0,0 +1,39 @@ +{ + "blender_2.80": true, + "blender_2.81": true, + "blender_2.82": true, + "blender_2.83": true, + "harmony_17": true, + "houdini_16": true, + "houdini_17": true, + "houdini_18": true, + "maya_2016": true, + "maya_2017": true, + "maya_2018": true, + "maya_2019": true, + "maya_2020": true, + "nuke_10.0": true, + "nuke_11.0": true, + "nuke_11.2": true, + "nuke_11.3": true, + "nuke_12.0": true, + "nukex_10.0": true, + "nukex_11.0": true, + "nukex_11.2": true, + "nukex_11.3": true, + "nukex_12.0": true, + "nukestudio_10.0": true, + "nukestudio_11.0": true, + "nukestudio_11.2": true, + "nukestudio_11.3": true, + "nukestudio_12.0": true, + "photoshop_2020": true, + "premiere_2019": true, + "premiere_2020": true, + "python_2": true, + "python_3": true, + "resolve_16": true, + "shell": true, + "storyboardpro_7": true, + "unreal_4.21": true +} diff --git a/pype/tools/config_setting/config/studio_presets/global/es/applications.json b/pype/tools/config_setting/config/studio_presets/global/es/applications.json new file mode 100644 index 0000000000..35e399444c --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/global/es/applications.json @@ -0,0 +1,39 @@ +{ + "blender_2.80": true, + "blender_2.81": true, + "blender_2.82": true, + "blender_2.83": true, + "harmony_17": true, + "houdini_16": true, + "houdini_17": true, + "houdini_18": true, + "maya_2016": true, + "maya_2017": true, + "maya_2018": true, + "maya_2019": true, + "maya_2020": true, + "nuke_10.0": true, + "nuke_11.0": true, + "nuke_11.2": true, + "nuke_11.3": true, + "nuke_12.0": true, + "nukex_10.0": true, + "nukex_11.0": true, + "nukex_11.2": true, + "nukex_11.3": true, + "nukex_12.0": true, + "nukestudio_10.0": true, + "nukestudio_11.0": true, + "nukestudio_11.2": true, + "nukestudio_11.3": true, + "nukestudio_12.0": true, + "photoshop_2020": true, + "premiere_2019": true, + "premiere_2020": true, + "python_2": true, + "python_3": true, + "resolve_16": true, + "shell": true, + "storyboardpro_7": true, + "unreal_4.21": true +} diff --git a/pype/tools/config_setting/config/studio_presets/global/intents.json b/pype/tools/config_setting/config/studio_presets/global/intents.json new file mode 100644 index 0000000000..c853e27b7f --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/global/intents.json @@ -0,0 +1,9 @@ +{ + "default": "wip", + "items": { + "": "", + "wip": "WIP", + "test": "TEST", + "final": "FINAL" + } +} diff --git a/pype/tools/config_setting/config/studio_presets/global/tray_items.json b/pype/tools/config_setting/config/studio_presets/global/tray_items.json new file mode 100644 index 0000000000..a42bf67c38 --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/global/tray_items.json @@ -0,0 +1,25 @@ +{ + "usage": { + "User settings": false, + "Ftrack": false, + "Muster": false, + "Avalon": true, + "Clockify": false, + "Standalone Publish": true, + "Logging": true, + "Idle Manager": true, + "Timers Manager": true, + "Rest Api": true, + "Premiere Communicator": true + }, + "attributes": { + "Rest Api": { + "default_port": 8021, + "exclude_ports": [] + }, + "Timers Manager": { + "full_time": 15, + "message_time": 0.5 + } + } +} diff --git a/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json b/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json new file mode 100644 index 0000000000..4edab9077d --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json @@ -0,0 +1,19 @@ +{ + "3delight": 41, + "arnold": 46, + "arnold_sf": 57, + "gelato": 30, + "harware": 3, + "krakatoa": 51, + "file_layers": 7, + "mentalray": 2, + "mentalray_sf": 6, + "redshift": 55, + "renderman": 29, + "software": 1, + "software_sf": 5, + "turtle": 10, + "vector": 4, + "vray": 37, + "ffmpeg": 48 +} diff --git a/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json b/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json new file mode 100644 index 0000000000..096964b5b8 --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json @@ -0,0 +1,153 @@ +{ + "key": "applications", + "type": "dict-expanding", + "label": "Applications", + "children": [ + { + "type": "dict-form", + "children": [ + { + "key": "blender_2.80", + "type": "boolean", + "label": "Blender 2.80" + }, { + "key": "blender_2.81", + "type": "boolean", + "label": "Blender 2.81" + }, { + "key": "blender_2.82", + "type": "boolean", + "label": "Blender 2.82" + }, { + "key": "blender_2.83", + "type": "boolean", + "label": "Blender 2.83" + }, { + "key": "celaction_local", + "type": "boolean", + "label": "Celaction Local" + }, { + "key": "celaction_remote", + "type": "boolean", + "label": "Celaction Remote" + }, { + "key": "harmony_17", + "type": "boolean", + "label": "Harmony 17" + }, { + "key": "houdini_16", + "type": "boolean", + "label": "Houdini 16" + }, { + "key": "houdini_17", + "type": "boolean", + "label": "Houdini 17" + }, { + "key": "houdini_18", + "type": "boolean", + "label": "Houdini 18" + }, { + "key": "maya_2017", + "type": "boolean", + "label": "Autodest Maya 2017" + }, { + "key": "maya_2018", + "type": "boolean", + "label": "Autodest Maya 2018" + }, { + "key": "maya_2019", + "type": "boolean", + "label": "Autodest Maya 2019" + }, { + "key": "maya_2020", + "type": "boolean", + "label": "Autodest Maya 2020" + }, { + "key": "nuke_10.0", + "type": "boolean", + "label": "Nuke 10.0" + }, { + "key": "nuke_11.2", + "type": "boolean", + "label": "Nuke 11.2" + }, { + "key": "nuke_11.3", + "type": "boolean", + "label": "Nuke 11.3" + }, { + "key": "nuke_12.0", + "type": "boolean", + "label": "Nuke 12.0" + }, { + "key": "nukex_10.0", + "type": "boolean", + "label": "NukeX 10.0" + }, { + "key": "nukex_11.2", + "type": "boolean", + "label": "NukeX 11.2" + }, { + "key": "nukex_11.3", + "type": "boolean", + "label": "NukeX 11.3" + }, { + "key": "nukex_12.0", + "type": "boolean", + "label": "NukeX 12.0" + }, { + "key": "nukestudio_10.0", + "type": "boolean", + "label": "NukeStudio 10.0" + }, { + "key": "nukestudio_11.2", + "type": "boolean", + "label": "NukeStudio 11.2" + }, { + "key": "nukestudio_11.3", + "type": "boolean", + "label": "NukeStudio 11.3" + }, { + "key": "nukestudio_12.0", + "type": "boolean", + "label": "NukeStudio 12.0" + }, { + "key": "houdini_16.5", + "type": "boolean", + "label": "Houdini 16.5" + }, { + "key": "houdini_17", + "type": "boolean", + "label": "Houdini 17" + }, { + "key": "houdini_18", + "type": "boolean", + "label": "Houdini 18" + }, { + "key": "premiere_2019", + "type": "boolean", + "label": "Premiere 2019" + }, { + "key": "premiere_2020", + "type": "boolean", + "label": "Premiere 2020" + }, { + "key": "premiere_2020", + "type": "boolean", + "label": "Premiere 2020" + }, { + "key": "resolve_16", + "type": "boolean", + "label": "BM DaVinci Resolve 16" + }, { + "key": "storyboardpro_7", + "type": "boolean", + "label": "Storyboard Pro 7" + }, { + "key": "unreal_4.24", + "type": "boolean", + "label": "Unreal Editor 4.24" + } + ] + } + ] +} diff --git a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json new file mode 100644 index 0000000000..febf84eb4a --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json @@ -0,0 +1,30 @@ +{ + "key": "ftrack", + "type": "dict-expanding", + "label": "Ftrack", + "children": [ + { + "key": "status_update", + "type": "dict-expanding", + "label": "Status updates", + "children": [ + { + "key": "Ready", + "type": "text-singleline", + "label": "Ready" + } + ] + }, { + "key": "status_version_to_task", + "type": "dict-expanding", + "label": "Version status to Task status", + "children": [ + { + "key": "in progress", + "type": "text-singleline", + "label": "In Progress" + } + ] + } + ] +} diff --git a/pype/tools/config_setting/config_gui_schema/project_gui_schema.json b/pype/tools/config_setting/config_gui_schema/project_gui_schema.json new file mode 100644 index 0000000000..38c07ec33d --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/project_gui_schema.json @@ -0,0 +1,13 @@ +{ + "key": "studio", + "type": "dict-invisible", + "label": "Studio", + "children": [ + { + "type": "schema", + "children": [ + "ftrack_projects_gui_schema" + ] + } + ] +} diff --git a/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json new file mode 100644 index 0000000000..7d902bb8db --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json @@ -0,0 +1,23 @@ +{ + "key": "studio", + "type": "dict-invisible", + "label": "Studio", + "children": [ + { + "type": "schema", + "children": [ + "applications_gui_schema", + "tools_gui_schema" + ] + }, { + "key": "muster", + "type": "dict-invisible", + "children": [{ + "key": "templates_mapping", + "label": "Muster", + "type": "dict-modifiable", + "object_type": "int" + }] + } + ] +} diff --git a/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json b/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json new file mode 100644 index 0000000000..2f46ef0ec5 --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json @@ -0,0 +1,29 @@ +{ + "key": "tools", + "type": "dict-expanding", + "label": "Tools", + "children": [ + { + "type": "dict-form", + "children": [ + { + "key": "mtoa_3.0.1", + "type": "boolean", + "label": "Arnold Maya 3.0.1" + }, { + "key": "mtoa_3.1.1", + "type": "boolean", + "label": "Arnold Maya 3.1.1" + }, { + "key": "mtoa_3.2.0", + "type": "boolean", + "label": "Arnold Maya 3.2.0" + }, { + "key": "yeti_2.1.2", + "type": "boolean", + "label": "Yeti 2.1.2" + } + ] + } + ] +} diff --git a/pype/tools/config_setting/interface.py b/pype/tools/config_setting/interface.py new file mode 100644 index 0000000000..e95f3f5fe3 --- /dev/null +++ b/pype/tools/config_setting/interface.py @@ -0,0 +1,49 @@ +import os +import sys +os.environ["PYPE_CONFIG"] = ( + "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pype-config" +) +os.environ["AVALON_MONGO"] = "mongodb://localhost:2707" +sys_paths = ( + "C:/Users/Public/pype_env2/Lib/site-packages", + "C:/Users/jakub.trllo/Desktop/pype/pype-setup", + "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pype", + "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/avalon-core", + "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pyblish-base", + "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pyblish-lite", + "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pype-config" +) +for path in sys_paths: + sys.path.append(path) + +from widgets import main +import style +from Qt import QtWidgets, QtGui + + +class MyApp(QtWidgets.QApplication): + def __init__(self, *args, **kwargs): + super(MyApp, self).__init__(*args, **kwargs) + stylesheet = style.load_stylesheet() + self.setStyleSheet(stylesheet) + self.setWindowIcon(QtGui.QIcon(style.app_icon_path())) + + +if __name__ == "__main__": + app = MyApp(sys.argv) + + # main_widget = QtWidgets.QWidget() + # main_widget.setWindowIcon(QtGui.QIcon(style.app_icon_path())) + # + # layout = QtWidgets.QVBoxLayout(main_widget) + # + # widget = main.MainWidget(main_widget) + + # layout.addWidget(widget) + # main_widget.setLayout(layout) + # main_widget.show() + + widget = main.MainWidget() + widget.show() + + sys.exit(app.exec_()) diff --git a/pype/tools/config_setting/style/__init__.py b/pype/tools/config_setting/style/__init__.py new file mode 100644 index 0000000000..a8f202d97b --- /dev/null +++ b/pype/tools/config_setting/style/__init__.py @@ -0,0 +1,12 @@ +import os + + +def load_stylesheet(): + style_path = os.path.join(os.path.dirname(__file__), "style.css") + with open(style_path, "r") as style_file: + stylesheet = style_file.read() + return stylesheet + + +def app_icon_path(): + return os.path.join(os.path.dirname(__file__), "pype_icon.png") diff --git a/pype/tools/config_setting/style/pype_icon.png b/pype/tools/config_setting/style/pype_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bfacf6eeedc753db0d77e661843a78b0eb13ce38 GIT binary patch literal 3793 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 b;3u>qRjE!lxug$XMKJrL$8D;P_+R@UX<7IA literal 0 HcmV?d00001 diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css new file mode 100644 index 0000000000..f559a4c3b3 --- /dev/null +++ b/pype/tools/config_setting/style/style.css @@ -0,0 +1,90 @@ +QWidget { + color: #bfccd6; + background-color: #293742; + font-size: 12px; +} + +QCheckBox::indicator { +} +QCheckBox::indicator:focus { + color: #ff0000; +} + +QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit { + border: 1px solid #aaaaaa; + border-radius: 3px; +} + +QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus { + border: 1px solid #ffffff; +} + +QLabel[state="original"] {} + +QLabel[state="modified"] { + color: #137cbd; +} + +QLabel[state="overriden-modified"] { + color: #00b386; +} + +QLabel[state="overriden"] { + color: #ff8c1a; +} + +QWidget[input-state="original"] {} +QWidget[input-state="modified"] { + border-color: #137cbd; +} + +QWidget[input-state="overriden-modified"] { + border-color: #00b386; +} + +QWidget[input-state="overriden"] { + border-color: #ff8c1a; +} + +QPushButton[btn-type="text-list"] { + border: 1px solid #bfccd6; + border-radius: 10px; +} + +QPushButton[btn-type="text-list"]:hover { + border-color: #137cbd; + color: #137cbd; +} + +QPushButton[btn-type="expand-toggle"] { + background: transparent; +} + +#DictKey[state="original"] {} + +#DictKey[state="modified"] { + border-color: #137cbd; +} + +#DictKey[state="overriden"] { + border-color: #00f; +} +#DictKey[state="overriden-modified"] { + border-color: #0f0; +} + +#ExpandLabel { + background: transparent; +} + +#DictExpandWidget, #ModifiableDict, #ExpandingWidget { + border: 1px solid #455c6e; + border-radius: 3px; + background: #1d272f; +} + +#TextListSubWidget { + border: 1px solid #455c6e; + border-radius: 3px; + background: #1d272f; +} diff --git a/pype/tools/config_setting/widgets/__init__.py b/pype/tools/config_setting/widgets/__init__.py new file mode 100644 index 0000000000..b295759a36 --- /dev/null +++ b/pype/tools/config_setting/widgets/__init__.py @@ -0,0 +1,6 @@ +from .lib import CustomNone, NOT_SET + + +from .base import * +from .main import * +from .inputs import * diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py new file mode 100644 index 0000000000..0cc64a66de --- /dev/null +++ b/pype/tools/config_setting/widgets/base.py @@ -0,0 +1,282 @@ +import os +import json +from Qt import QtWidgets, QtCore, QtGui +from . import config +from .lib import NOT_SET +from avalon import io + + +class TypeToKlass: + types = {} + + +class ClickableWidget(QtWidgets.QLabel): + clicked = QtCore.Signal() + + def __init__(self, *args, **kwargs): + super(ClickableWidget, self).__init__(*args, **kwargs) + self.setObjectName("ExpandLabel") + + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.LeftButton: + self.clicked.emit() + super(ClickableWidget, self).mouseReleaseEvent(event) + + +class PypeConfigurationWidget: + is_category = False + is_overriden = False + is_modified = False + + def config_value(self): + raise NotImplementedError( + "Method `config_value` is not implemented for `{}`.".format( + self.__class__.__name__ + ) + ) + + def value_from_values(self, values, keys=None): + if not values: + return NOT_SET + + if keys is None: + keys = self.keys + + value = values + for key in keys: + if not isinstance(value, dict): + raise TypeError( + "Expected dictionary got {}.".format(str(type(value))) + ) + + if key not in value: + return NOT_SET + value = value[key] + return value + + def add_children_gui(self, child_configuration, values): + raise NotImplementedError(( + "Method `add_children_gui` is not implemented for `{}`." + ).format(self.__class__.__name__)) + + +class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): + config_dir = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + "config_gui_schema" + ) + is_overidable = False + + def __init__(self, parent=None): + super(StudioWidget, self).__init__(parent) + + self.input_fields = [] + + scroll_widget = QtWidgets.QScrollArea(self) + content_widget = QtWidgets.QWidget(scroll_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(0) + content_layout.setAlignment(QtCore.Qt.AlignTop) + content_widget.setLayout(content_layout) + + # scroll_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + # scroll_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + scroll_widget.setWidgetResizable(True) + scroll_widget.setWidget(content_widget) + + self.scroll_widget = scroll_widget + self.content_layout = content_layout + self.content_widget = content_widget + + values = {"studio": config.studio_presets()} + schema = config.gui_schema("studio_gui_schema") + self.keys = schema.get("keys", []) + self.add_children_gui(schema, values) + + footer_widget = QtWidgets.QWidget() + footer_layout = QtWidgets.QHBoxLayout(footer_widget) + + btn = QtWidgets.QPushButton("Finish") + spacer_widget = QtWidgets.QWidget() + footer_layout.addWidget(spacer_widget, 1) + footer_layout.addWidget(btn, 0) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + self.setLayout(layout) + + layout.addWidget(scroll_widget, 1) + layout.addWidget(footer_widget, 0) + + btn.clicked.connect(self.___finish) + + def ___finish(self): + output = {} + for item in self.input_fields: + output.update(item.config_value()) + + for key in reversed(self.keys): + _output = {key: output} + output = _output + + print(json.dumps(output, indent=4)) + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + item = klass( + child_configuration, values, self.keys, self + ) + self.input_fields.append(item) + self.content_layout.addWidget(item) + + +class ProjectListWidget(QtWidgets.QWidget): + default = "< Default >" + + def __init__(self, parent=None): + super(ProjectListWidget, self).__init__(parent) + + label = QtWidgets.QLabel("Project") + project_list = QtWidgets.QListView(self) + project_list.setModel(QtGui.QStandardItemModel()) + + layout = QtWidgets.QVBoxLayout(self) + # content_margin = 5 + # layout.setContentsMargins( + # content_margin, + # content_margin, + # content_margin, + # content_margin + # ) + # layout.setSpacing(3) + layout.addWidget(label, 0) + layout.addWidget(project_list, 1) + + self.project_list = project_list + + self.refresh() + + def project_name(self): + current_selection = self.project_list.currentText() + if current_selection == self.default: + return None + return current_selection + + def refresh(self): + selected_project = None + for index in self.project_list.selectedIndexes(): + selected_project = index.data(QtCore.Qt.DisplayRole) + break + + model = self.project_list.model() + model.clear() + items = [self.default] + io.install() + for project_doc in tuple(io.projects()): + print(project_doc["name"]) + items.append(project_doc["name"]) + + for item in items: + model.appendRow(QtGui.QStandardItem(item)) + + if not selected_project: + selected_project = self.default + + found_items = model.findItems(selected_project) + if found_items: + index = model.indexFromItem(found_items[0]) + c = QtCore.QItemSelectionModel.SelectionFlag.SelectCurrent + self.project_list.selectionModel().select( + index, c + ) + # self.project_list.selectionModel().setCurrentIndex( + # index, c + # ) + + + +class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): + config_dir = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + "config_gui_schema" + ) + is_overidable = True + + def __init__(self, parent=None): + super(ProjectWidget, self).__init__(parent) + + self.input_fields = [] + + scroll_widget = QtWidgets.QScrollArea(self) + content_widget = QtWidgets.QWidget(scroll_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(0) + content_layout.setAlignment(QtCore.Qt.AlignTop) + content_widget.setLayout(content_layout) + + scroll_widget.setWidgetResizable(True) + scroll_widget.setWidget(content_widget) + + project_list_widget = ProjectListWidget() + content_layout.addWidget(project_list_widget) + + self.project_list_widget = project_list_widget + self.scroll_widget = scroll_widget + self.content_layout = content_layout + self.content_widget = content_widget + + values = config.project_presets() + schema = config.gui_schema("project_gui_schema") + self.keys = schema.get("keys", []) + self.add_children_gui(schema, values) + + footer_widget = QtWidgets.QWidget() + footer_layout = QtWidgets.QHBoxLayout(footer_widget) + + btn = QtWidgets.QPushButton("Finish") + spacer_widget = QtWidgets.QWidget() + footer_layout.addWidget(spacer_widget, 1) + footer_layout.addWidget(btn, 0) + + presets_widget = QtWidgets.QWidget() + presets_layout = QtWidgets.QVBoxLayout(presets_widget) + presets_layout.setContentsMargins(0, 0, 0, 0) + presets_layout.setSpacing(0) + + presets_layout.addWidget(scroll_widget, 1) + presets_layout.addWidget(footer_widget, 0) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + self.setLayout(layout) + + layout.addWidget(project_list_widget, 0) + layout.addWidget(presets_widget, 1) + + btn.clicked.connect(self.___finish) + + def ___finish(self): + output = {} + for item in self.input_fields: + output.update(item.config_value()) + + for key in reversed(self.keys): + _output = {key: output} + output = _output + + print(json.dumps(output, indent=4)) + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + item = klass( + child_configuration, values, self.keys, self + ) + self.input_fields.append(item) + self.content_layout.addWidget(item) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py new file mode 100644 index 0000000000..335299cb2f --- /dev/null +++ b/pype/tools/config_setting/widgets/config.py @@ -0,0 +1,236 @@ +import os +import json +import logging +import copy + +# DEBUG SETUP +os.environ["AVALON_PROJECT"] = "kuba_each_case" +os.environ["PYPE_PROJECT_CONFIGS"] = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + "config", + "project_overrides" +) +# + +log = logging.getLogger(__name__) + +config_path = os.path.dirname(os.path.dirname(__file__)) +studio_presets_path = os.path.normpath( + os.path.join(config_path, "config", "studio_presets") +) +project_presets_path = os.path.normpath( + os.path.join(config_path, "config", "project_presets") +) +first_run = False + +OVERRIDE_KEY = "__overriden__" +POP_KEY = "__popkey__" + + +def load_json(fpath): + # Load json data + with open(fpath, "r") as opened_file: + lines = opened_file.read().splitlines() + + # prepare json string + standard_json = "" + for line in lines: + # Remove all whitespace on both sides + line = line.strip() + + # Skip blank lines + if len(line) == 0: + continue + + standard_json += line + + # Check if has extra commas + extra_comma = False + if ",]" in standard_json or ",}" in standard_json: + extra_comma = True + standard_json = standard_json.replace(",]", "]") + standard_json = standard_json.replace(",}", "}") + + global first_run + if extra_comma and first_run: + log.error("Extra comma in json file: \"{}\"".format(fpath)) + + # return empty dict if file is empty + if standard_json == "": + if first_run: + log.error("Empty json file: \"{}\"".format(fpath)) + return {} + + # Try to parse string + try: + return json.loads(standard_json) + + except json.decoder.JSONDecodeError: + # Return empty dict if it is first time that decode error happened + if not first_run: + return {} + + # Repreduce the exact same exception but traceback contains better + # information about position of error in the loaded json + try: + with open(fpath, "r") as opened_file: + json.load(opened_file) + + except json.decoder.JSONDecodeError: + log.warning( + "File has invalid json format \"{}\"".format(fpath), + exc_info=True + ) + + return {} + + +def subkey_merge(_dict, value, keys, with_metadata=False): + key = keys.pop(0) + if not keys: + if with_metadata: + _dict[key] = {"type": "file", "value": value} + else: + _dict[key] = value + return _dict + + if key not in _dict: + if with_metadata: + _dict[key] = {"type": "folder", "value": {}} + else: + _dict[key] = {} + + if with_metadata: + sub_dict = _dict[key]["value"] + else: + sub_dict = _dict[key] + + _value = subkey_merge(sub_dict, value, keys, with_metadata) + if with_metadata: + _dict[key]["value"] = _value + else: + _dict[key] = _value + return _dict + + +def load_jsons_from_dir(path, *args, **kwargs): + output = {} + + path = os.path.normpath(path) + if not os.path.exists(path): + # TODO warning + return output + + with_metadata = kwargs.get("with_metadata") + sub_keys = list(kwargs.pop("subkeys", args)) + for sub_key in tuple(sub_keys): + _path = os.path.join(path, sub_key) + if not os.path.exists(_path): + break + + path = _path + sub_keys.pop(0) + + base_len = len(path) + 1 + ext_len = len(".json") + + for base, _directories, filenames in os.walk(path): + for filename in filenames: + basename, ext = os.path.splitext(filename) + if ext == ".json": + full_path = os.path.join(base, filename) + value = load_json(full_path) + + # dict_path = os.path.join(base[base_len:], basename) + # dict_keys = dict_path.split(os.path.sep) + dict_keys = base[base_len:].split(os.path.sep) + [basename] + output = subkey_merge(output, value, dict_keys, with_metadata) + + for sub_key in sub_keys: + output = output[sub_key] + return output + + +def studio_presets(*args, **kwargs): + return load_jsons_from_dir(studio_presets_path, *args, **kwargs) + + +def global_project_presets(**kwargs): + return load_jsons_from_dir(project_presets_path, **kwargs) + + +def studio_presets_with_metadata(*args, **kwargs): + return load_jsons_from_dir(studio_presets_path, *args, **kwargs) + + +def global_project_presets_with_metadata(**kwargs): + return load_jsons_from_dir(project_presets_path, **kwargs) + + +def project_preset_overrides(project_name, **kwargs): + project_configs_path = os.environ.get("PYPE_PROJECT_CONFIGS") + if project_name and project_configs_path: + return load_jsons_from_dir( + os.path.join(project_configs_path, project_name), + **kwargs + ) + return {} + + +def merge_overrides(global_dict, override_dict): + if OVERRIDE_KEY in override_dict: + _override = override_dict.pop(OVERRIDE_KEY) + if _override: + return override_dict + + for key, value in override_dict.items(): + if value == POP_KEY: + global_dict.pop(key) + + elif key == OVERRIDE_KEY: + continue + + elif key not in global_dict: + global_dict[key] = value + + elif isinstance(value, dict) and isinstance(global_dict[key], dict): + global_dict[key] = merge_overrides(global_dict[key], value) + + else: + global_dict[key] = value + return global_dict + + +def apply_overrides(global_presets, project_overrides): + global_presets = copy.deepcopy(global_presets) + if not project_overrides: + return global_presets + return merge_overrides(global_presets, project_overrides) + + +def project_presets(project_name=None, **kwargs): + global_presets = global_project_presets(**kwargs) + + if not project_name: + project_name = os.environ.get("AVALON_PROJECT") + project_overrides = project_preset_overrides(project_name, **kwargs) + + return apply_overrides(global_presets, project_overrides) + + +def gui_schema(schema_name): + filename = schema_name + ".json" + schema_folder = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + "config_gui_schema", + filename + ) + with open(schema_folder, "r") as json_stream: + schema = json.load(json_stream) + return schema + + +p1 = studio_presets(with_metadata=True) +p2 = studio_presets(with_metadata=False) +print(json.dumps(p1, indent=4)) +print(json.dumps(p2, indent=4)) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py new file mode 100644 index 0000000000..1ddc27278d --- /dev/null +++ b/pype/tools/config_setting/widgets/inputs.py @@ -0,0 +1,1346 @@ +from Qt import QtWidgets, QtCore, QtGui +from . import config +from .base import PypeConfigurationWidget, TypeToKlass, ClickableWidget +from .lib import NOT_SET, AS_WIDGET + +import json + + +class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._as_widget = values is AS_WIDGET + self._parent = parent + + super(BooleanWidget, self).__init__(parent) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + self.checkbox = QtWidgets.QCheckBox() + self.checkbox.setAttribute(QtCore.Qt.WA_StyledBackground) + if not self._as_widget and not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + layout.addWidget(label_widget) + + layout.addWidget(self.checkbox) + + if not self._as_widget: + self.label_widget = label_widget + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.checkbox.setChecked(value) + + self.origin_value = self.item_value() + + self.checkbox.stateChanged.connect(self._on_value_change) + + def set_value(self, value, origin_value=False): + self.checkbox.setChecked(value) + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.reset_value() + + @property + def is_overidable(self): + return self._parent.is_overidable + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + self.value_changed.emit() + + def _update_style(self): + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + if not self._as_widget: + property_name = "input-state" + else: + property_name = "state" + + self.label_widget.setProperty(property_name, state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + return self.checkbox.isChecked() + + def config_value(self): + return {self.key: self.item_value()} + + +class ModifiedIntSpinBox(QtWidgets.QSpinBox): + def __init__(self, *args, **kwargs): + super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + def wheelEvent(self, event): + if self.hasFocus(): + super(ModifiedIntSpinBox, self).wheelEvent(event) + else: + event.ignore() + + +class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): + def __init__(self, *args, **kwargs): + super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + def wheelEvent(self, event): + if self.hasFocus(): + super(ModifiedFloatSpinBox, self).wheelEvent(event) + else: + event.ignore() + + +class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + self._as_widget = values is AS_WIDGET + + super(IntegerWidget, self).__init__(parent) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + self.int_input = ModifiedIntSpinBox() + + if not self._as_widget and not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + layout.addWidget(self.int_input) + + if not self._as_widget: + self.label_widget = label_widget + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.int_input.setValue(value) + + self.origin_value = self.item_value() + + self.int_input.valueChanged.connect(self._on_value_change) + + @property + def is_overidable(self): + return self._parent.is_overidable + + def set_value(self, value, origin_value=False): + self.int_input.setValue(value) + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def clear_value(self): + self.set_value(0) + + def reset_value(self): + self.set_value(self.origin_value) + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + self.value_changed.emit() + + def _update_style(self): + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + if self._as_widget: + property_name = "input-state" + widget = self.int_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) + + def item_value(self): + return self.int_input.value() + + def config_value(self): + return {self.key: self.item_value()} + + +class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + self._as_widget = values is AS_WIDGET + + super(FloatWidget, self).__init__(parent) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + self.float_input = ModifiedFloatSpinBox() + + decimals = input_data.get("decimals", 5) + maximum = input_data.get("maximum") + minimum = input_data.get("minimum") + + self.float_input.setDecimals(decimals) + if maximum is not None: + self.float_input.setMaximum(float(maximum)) + if minimum is not None: + self.float_input.setMinimum(float(minimum)) + + if not self._as_widget and not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + layout.addWidget(self.float_input) + + if not self._as_widget: + self.label_widget = label_widget + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.float_input.setValue(value) + + self.origin_value = self.item_value() + + self.float_input.valueChanged.connect(self._on_value_change) + + @property + def is_overidable(self): + return self._parent.is_overidable + + def set_value(self, value, origin_value=False): + self.float_input.setValue(value) + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.set_value(0) + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + self.value_changed.emit() + + def _update_style(self): + if not self._as_widget: + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + return self.float_input.value() + + def config_value(self): + return {self.key: self.item_value()} + + +class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + self._as_widget = values is AS_WIDGET + + super(TextSingleLineWidget, self).__init__(parent) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + self.text_input = QtWidgets.QLineEdit() + + if not self._as_widget and not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + layout.addWidget(self.text_input) + + if not self._as_widget: + self.label_widget = label_widget + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.text_input.setText(value) + + self.origin_value = self.item_value() + + self.text_input.textChanged.connect(self._on_value_change) + + @property + def is_overidable(self): + return self._parent.is_overidable + + def set_value(self, value, origin_value=False): + self.text_input.setText(value) + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.set_value("") + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + self.value_changed.emit() + + def _update_style(self): + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + return self.text_input.text() + + def config_value(self): + return {self.key: self.item_value()} + + +class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + + super(TextMultiLineWidget, self).__init__(parent) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + self.text_input = QtWidgets.QPlainTextEdit() + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + layout.addWidget(self.text_input) + + self.label_widget = label_widget + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.text_input.setPlainText(value) + + self.origin_value = self.item_value() + + self.text_input.textChanged.connect(self._on_value_change) + + @property + def is_overidable(self): + return self._parent.is_overidable + + def set_value(self, value, origin_value=False): + self.text_input.setPlainText(value) + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.set_value("") + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + self.value_changed.emit() + + def _update_style(self): + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + return self.text_input.toPlainText() + + def config_value(self): + return {self.key: self.item_value()} + + +class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): + _btn_size = 20 + value_changed = QtCore.Signal() + + def __init__(self, parent): + super(TextListItem, self).__init__(parent) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(3) + + self.text_input = QtWidgets.QLineEdit() + self.add_btn = QtWidgets.QPushButton("+") + self.remove_btn = QtWidgets.QPushButton("-") + + self.add_btn.setProperty("btn-type", "text-list") + self.remove_btn.setProperty("btn-type", "text-list") + + layout.addWidget(self.text_input, 1) + layout.addWidget(self.add_btn, 0) + layout.addWidget(self.remove_btn, 0) + + self.add_btn.setFixedSize(self._btn_size, self._btn_size) + self.remove_btn.setFixedSize(self._btn_size, self._btn_size) + self.add_btn.clicked.connect(self.on_add_clicked) + self.remove_btn.clicked.connect(self.on_remove_clicked) + + self.text_input.textChanged.connect(self._on_value_change) + + self.is_single = False + + def _on_value_change(self): + self.value_changed.emit() + + def row(self): + return self.parent().input_fields.index(self) + + def on_add_clicked(self): + self.parent().add_row(row=self.row() + 1) + + def on_remove_clicked(self): + if self.is_single: + self.text_input.setText("") + else: + self.parent().remove_row(self) + + def config_value(self): + return self.text_input.text() + + +class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__(self, input_data, values, parent_keys, parent): + super(TextListSubWidget, self).__init__(parent) + self.setObjectName("TextListSubWidget") + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + layout.setSpacing(5) + self.setLayout(layout) + + self.input_fields = [] + self.add_row() + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.set_value(value) + + self.origin_value = self.item_value() + + def set_value(self, value, origin_value=False): + for input_field in self.input_fields: + self.remove_row(input_field) + + for item_text in value: + self.add_row(text=item_text) + + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.set_value([]) + + def _on_value_change(self): + self.value_changed.emit() + + def count(self): + return len(self.input_fields) + + def add_row(self, row=None, text=None): + # Create new item + item_widget = TextListItem(self) + + # Set/unset if new item is single item + current_count = self.count() + if current_count == 0: + item_widget.is_single = True + elif current_count == 1: + for _input_field in self.input_fields: + _input_field.is_single = False + + item_widget.value_changed.connect(self._on_value_change) + + if row is None: + self.layout().addWidget(item_widget) + self.input_fields.append(item_widget) + else: + self.layout().insertWidget(row, item_widget) + self.input_fields.insert(row, item_widget) + + # Set text if entered text is not None + # else (when add button clicked) trigger `_on_value_change` + if text is not None: + item_widget.text_input.setText(text) + else: + self._on_value_change() + self.parent().updateGeometry() + + def remove_row(self, item_widget): + item_widget.value_changed.disconnect() + + self.layout().removeWidget(item_widget) + self.input_fields.remove(item_widget) + item_widget.setParent(None) + item_widget.deleteLater() + + current_count = self.count() + if current_count == 0: + self.add_row() + elif current_count == 1: + for _input_field in self.input_fields: + _input_field.is_single = True + + self._on_value_change() + self.parent().updateGeometry() + + def item_value(self): + output = [] + for item in self.input_fields: + text = item.config_value() + if text: + output.append(text) + + return output + + def config_value(self): + return {self.key: self.item_value()} + + +class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + super(TextListWidget, self).__init__(parent) + self.setObjectName("TextListWidget") + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + + self.label_widget = label_widget + # keys = list(parent_keys) + # keys.append(input_data["key"]) + # self.keys = keys + + self.value_widget = TextListSubWidget( + input_data, values, parent_keys, self + ) + self.value_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + self.value_widget.value_changed.connect(self._on_value_change) + + # self.value_widget.se + self.key = input_data["key"] + layout.addWidget(self.value_widget) + self.setLayout(layout) + + self.origin_value = self.item_value() + + @property + def is_overidable(self): + return self._parent.is_overidable + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + def set_value(self, value, origin_value=False): + self.value_widget.set_value(value) + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.set_value([]) + + def _update_style(self): + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + return self.value_widget.config_value() + + def config_value(self): + return {self.key: self.item_value()} + + +class ExpandingWidget(QtWidgets.QWidget): + def __init__(self, label, parent): + super(ExpandingWidget, self).__init__(parent) + self.setObjectName("ExpandingWidget") + + top_part = ClickableWidget(parent=self) + + button_size = QtCore.QSize(5, 5) + button_toggle = QtWidgets.QToolButton(parent=top_part) + button_toggle.setProperty("btn-type", "expand-toggle") + button_toggle.setIconSize(button_size) + button_toggle.setArrowType(QtCore.Qt.RightArrow) + button_toggle.setCheckable(True) + button_toggle.setChecked(False) + + label_widget = QtWidgets.QLabel(label, parent=top_part) + label_widget.setObjectName("ExpandLabel") + + layout = QtWidgets.QHBoxLayout(top_part) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(button_toggle) + layout.addWidget(label_widget) + top_part.setLayout(layout) + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + self.top_part = top_part + self.button_toggle = button_toggle + self.label_widget = label_widget + + self.top_part.clicked.connect(self._top_part_clicked) + self.button_toggle.clicked.connect(self.toggle_content) + + def set_content_widget(self, content_widget): + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(9, 9, 9, 9) + + content_widget.setVisible(False) + + main_layout.addWidget(self.top_part) + main_layout.addWidget(content_widget) + self.setLayout(main_layout) + + self.content_widget = content_widget + + def _top_part_clicked(self): + self.toggle_content(not self.button_toggle.isChecked()) + + def toggle_content(self, *args): + if len(args) > 0: + checked = args[0] + else: + checked = self.button_toggle.isChecked() + arrow_type = QtCore.Qt.RightArrow + if checked: + arrow_type = QtCore.Qt.DownArrow + self.button_toggle.setChecked(checked) + self.button_toggle.setArrowType(arrow_type) + self.content_widget.setVisible(checked) + self.parent().updateGeometry() + + def resizeEvent(self, event): + super(ExpandingWidget, self).resizeEvent(event) + self.content_widget.updateGeometry() + + +class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + if values is AS_WIDGET: + raise TypeError("Can't use \"{}\" as widget item.".format( + self.__class__.__name__ + )) + self._parent = parent + + super(DictExpandWidget, self).__init__(parent) + self.setObjectName("DictExpandWidget") + top_part = ClickableWidget(parent=self) + + button_size = QtCore.QSize(5, 5) + button_toggle = QtWidgets.QToolButton(parent=top_part) + button_toggle.setProperty("btn-type", "expand-toggle") + button_toggle.setIconSize(button_size) + button_toggle.setArrowType(QtCore.Qt.RightArrow) + button_toggle.setCheckable(True) + button_toggle.setChecked(False) + + label = input_data["label"] + button_toggle_text = QtWidgets.QLabel(label, parent=top_part) + button_toggle_text.setObjectName("ExpandLabel") + + layout = QtWidgets.QHBoxLayout(top_part) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(button_toggle) + layout.addWidget(button_toggle_text) + top_part.setLayout(layout) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(9, 9, 9, 9) + + content_widget = QtWidgets.QWidget(self) + content_widget.setVisible(False) + + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(3, 3, 3, 3) + + main_layout.addWidget(top_part) + main_layout.addWidget(content_widget) + self.setLayout(main_layout) + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + self.top_part = top_part + self.button_toggle = button_toggle + self.button_toggle_text = button_toggle_text + + self.content_widget = content_widget + self.content_layout = content_layout + + self.top_part.clicked.connect(self._top_part_clicked) + self.button_toggle.clicked.connect(self.toggle_content) + + self._is_category = False + self._is_overriden = False + self.input_fields = [] + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + def _top_part_clicked(self): + self.toggle_content(not self.button_toggle.isChecked()) + + def toggle_content(self, *args): + if len(args) > 0: + checked = args[0] + else: + checked = self.button_toggle.isChecked() + arrow_type = QtCore.Qt.RightArrow + if checked: + arrow_type = QtCore.Qt.DownArrow + self.button_toggle.setChecked(checked) + self.button_toggle.setArrowType(arrow_type) + self.content_widget.setVisible(checked) + self.parent().updateGeometry() + + def resizeEvent(self, event): + super(DictExpandWidget, self).resizeEvent(event) + self.content_widget.updateGeometry() + + @property + def is_category(self): + return self._is_category + + @property + def is_overriden(self): + return self._is_overriden + + @property + def is_modified(self): + _is_modified = False + for input_field in self.input_fields: + if input_field.is_modified: + _is_modified = True + break + return _is_modified + + def item_value(self): + output = {} + for input_field in self.input_fields: + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return {self.key: self.item_value()} + + @property + def is_overidable(self): + return self._parent.is_overidable + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + item = klass( + child_configuration, values, self.keys, self + ) + self.content_layout.addWidget(item) + + self.input_fields.append(item) + return item + + +class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + + super(DictInvisible, self).__init__(parent) + self.setObjectName("DictInvisible") + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + self._is_category = False + self._is_overriden = False + self.input_fields = [] + + if "key" not in input_data: + print(json.dumps(input_data, indent=4)) + + self.key = input_data["key"] + self.keys = list(parent_keys) + self.keys.append(self.key) + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + @property + def is_overidable(self): + return self._parent.is_overidable + + @property + def is_category(self): + return self._is_category + + @property + def is_overriden(self): + return self._is_overriden + + @property + def is_modified(self): + _is_modified = False + for input_field in self.input_fields: + if input_field.is_modified: + _is_modified = True + break + return _is_modified + + def item_value(self): + output = {} + for input_field in self.input_fields: + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return {self.key: self.item_value()} + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + if item_type == "schema": + for _schema in child_configuration["children"]: + children = config.gui_schema(_schema) + self.add_children_gui(children, values) + return + + klass = TypeToKlass.types.get(item_type) + item = klass( + child_configuration, values, self.keys, self + ) + self.layout().addWidget(item) + + self.input_fields.append(item) + return item + + +class DictFormWidget(QtWidgets.QWidget): + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + super(DictFormWidget, self).__init__(parent) + + self.input_fields = {} + self.content_layout = QtWidgets.QFormLayout(self) + + self.keys = list(parent_keys) + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + def item_value(self): + output = {} + for input_field in self.input_fields.values(): + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + @property + def is_overidable(self): + return self._parent.is_overidable + + def config_value(self): + return self.item_value() + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + key = child_configuration["key"] + # Pop label to not be set in child + label = child_configuration["label"] + + klass = TypeToKlass.types.get(item_type) + + label_widget = QtWidgets.QLabel(label) + item = klass( + child_configuration, values, self.keys, self, label_widget + ) + self.content_layout.addRow(label_widget, item) + self.input_fields[key] = item + return item + + +class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): + _btn_size = 20 + value_changed = QtCore.Signal() + + def __init__(self, parent): + super(TextListItem, self).__init__(parent) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(3) + + self.text_input = QtWidgets.QLineEdit() + self.add_btn = QtWidgets.QPushButton("+") + self.remove_btn = QtWidgets.QPushButton("-") + + self.add_btn.setProperty("btn-type", "text-list") + self.remove_btn.setProperty("btn-type", "text-list") + + layout.addWidget(self.text_input, 1) + layout.addWidget(self.add_btn, 0) + layout.addWidget(self.remove_btn, 0) + + self.add_btn.setFixedSize(self._btn_size, self._btn_size) + self.remove_btn.setFixedSize(self._btn_size, self._btn_size) + self.add_btn.clicked.connect(self.on_add_clicked) + self.remove_btn.clicked.connect(self.on_remove_clicked) + + self.text_input.textChanged.connect(self._on_value_change) + + self.is_single = False + + def _on_value_change(self): + self.value_changed.emit() + + def row(self): + return self.parent().input_fields.index(self) + + def on_add_clicked(self): + self.parent().add_row(row=self.row() + 1) + + def on_remove_clicked(self): + if self.is_single: + self.text_input.setText("") + else: + self.parent().remove_row(self) + + def config_value(self): + return self.text_input.text() + + +class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): + _btn_size = 20 + value_changed = QtCore.Signal() + + def __init__(self, object_type, parent): + self._parent = parent + + super(ModifiableDictItem, self).__init__(parent) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(3) + + ItemKlass = TypeToKlass.types[object_type] + + self.key_input = QtWidgets.QLineEdit() + self.key_input.setObjectName("DictKey") + + self.value_input = ItemKlass( + {}, + AS_WIDGET, + [], + self, + None + ) + self.add_btn = QtWidgets.QPushButton("+") + self.remove_btn = QtWidgets.QPushButton("-") + + self.add_btn.setProperty("btn-type", "text-list") + self.remove_btn.setProperty("btn-type", "text-list") + + layout.addWidget(self.key_input, 0) + layout.addWidget(self.value_input, 1) + layout.addWidget(self.add_btn, 0) + layout.addWidget(self.remove_btn, 0) + + self.add_btn.setFixedSize(self._btn_size, self._btn_size) + self.remove_btn.setFixedSize(self._btn_size, self._btn_size) + self.add_btn.clicked.connect(self.on_add_clicked) + self.remove_btn.clicked.connect(self.on_remove_clicked) + + self.key_input.textChanged.connect(self._on_value_change) + self.value_input.value_changed.connect(self._on_value_change) + + self.origin_key = self._key() + self.origin_value = self.value_input.item_value() + + self.is_single = False + + def _key(self): + return self.key_input.text() + + def _on_value_change(self): + self._update_style() + self.value_changed.emit() + + @property + def is_overidable(self): + return self._parent.is_overidable + + def _update_style(self): + is_modified = self._key() != self.origin_key + # if self._is_overidable and self.is_overriden: + # if is_modified: + # state = "overriden-modified" + # else: + # state = "overriden" + if is_modified: + state = "modified" + else: + state = "original" + + self.key_input.setProperty("state", state) + self.key_input.style().polish(self.key_input) + + def row(self): + return self.parent().input_fields.index(self) + + def on_add_clicked(self): + self.parent().add_row(row=self.row() + 1) + + def on_remove_clicked(self): + if self.is_single: + self.value_input.clear_value() + self.key_input.setText("") + else: + self.parent().remove_row(self) + + def config_value(self): + key = self.key_input.text() + value = self.value_input.item_value() + if not key: + return {} + return {key: value} + + +class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + + def __init__(self, input_data, values, parent_keys, parent): + self._parent = parent + + super(ModifiableDictSubWidget, self).__init__(parent) + self.setObjectName("ModifiableDictSubWidget") + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + layout.setSpacing(5) + self.setLayout(layout) + + self.input_fields = [] + self.object_type = input_data["object_type"] + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + for item_key, item_value in value.items(): + self.add_row(key=item_key, value=item_value) + + if self.count() == 0: + self.add_row() + + self.origin_value = self.config_value() + + @property + def is_overidable(self): + return self._parent.is_overidable + + def _on_value_change(self): + self.value_changed.emit() + + def count(self): + return len(self.input_fields) + + def add_row(self, row=None, key=None, value=None): + # Create new item + item_widget = ModifiableDictItem(self.object_type, self) + + # Set/unset if new item is single item + current_count = self.count() + if current_count == 0: + item_widget.is_single = True + elif current_count == 1: + for _input_field in self.input_fields: + _input_field.is_single = False + + item_widget.value_changed.connect(self._on_value_change) + + if row is None: + self.layout().addWidget(item_widget) + self.input_fields.append(item_widget) + else: + self.layout().insertWidget(row, item_widget) + self.input_fields.insert(row, item_widget) + + # Set value if entered value is not None + # else (when add button clicked) trigger `_on_value_change` + if value is not None and key is not None: + item_widget.origin_key = key + item_widget.key_input.setText(key) + item_widget.value_input.set_value(value, origin_value=True) + else: + self._on_value_change() + self.parent().updateGeometry() + + def remove_row(self, item_widget): + item_widget.value_changed.disconnect() + + self.layout().removeWidget(item_widget) + self.input_fields.remove(item_widget) + item_widget.setParent(None) + item_widget.deleteLater() + + current_count = self.count() + if current_count == 0: + self.add_row() + elif current_count == 1: + for _input_field in self.input_fields: + _input_field.is_single = True + + self._on_value_change() + self.parent().updateGeometry() + + def config_value(self): + output = {} + for item in self.input_fields: + item_value = item.config_value() + if item_value: + output.update(item_value) + return output + + +class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): + def __init__( + self, input_data, values, parent_keys, parent, + label_widget=None + ): + self._parent = parent + + super(ModifiableDict, self).__init__(input_data["label"], parent) + self.setObjectName("ModifiableDict") + + self.value_widget = ModifiableDictSubWidget( + input_data, values, parent_keys, self + ) + self.value_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + self.value_widget.value_changed.connect(self._on_value_change) + + self.set_content_widget(self.value_widget) + + self.key = input_data["key"] + + self.origin_value = self.item_value() + + def _on_value_change(self, value=None): + self.is_modified = self.item_value() != self.origin_value + self.is_overriden = True + + self._update_style() + + @property + def is_overidable(self): + return self._parent.is_overidable + + def _update_style(self): + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + return self.value_widget.config_value() + + def config_value(self): + return {self.key: self.item_value()} + + +TypeToKlass.types["boolean"] = BooleanWidget +TypeToKlass.types["text-singleline"] = TextSingleLineWidget +TypeToKlass.types["text-multiline"] = TextMultiLineWidget +TypeToKlass.types["int"] = IntegerWidget +TypeToKlass.types["float"] = FloatWidget +TypeToKlass.types["dict-expanding"] = DictExpandWidget +TypeToKlass.types["dict-form"] = DictFormWidget +TypeToKlass.types["dict-invisible"] = DictInvisible +TypeToKlass.types["dict-modifiable"] = ModifiableDict +TypeToKlass.types["list-text"] = TextListWidget diff --git a/pype/tools/config_setting/widgets/lib.py b/pype/tools/config_setting/widgets/lib.py new file mode 100644 index 0000000000..ac0a353d53 --- /dev/null +++ b/pype/tools/config_setting/widgets/lib.py @@ -0,0 +1,44 @@ +import uuid + + +class CustomNone: + """Created object can be used as custom None (not equal to None). + + WARNING: Multiple created objects are not equal either. + Exmple: + >>> a = CustomNone() + >>> a == None + False + >>> b = CustomNone() + >>> a == b + False + >>> a == a + True + """ + + def __init__(self): + """Create uuid as identifier for custom None.""" + self.identifier = str(uuid.uuid4()) + + def __bool__(self): + """Return False (like default None).""" + return False + + def __eq__(self, other): + """Equality is compared by identifier value.""" + if type(other) == type(self): + if other.identifier == self.identifier: + return True + return False + + def __str__(self): + """Return value of identifier when converted to string.""" + return "".format(str(self.identifier)) + + def __repr__(self): + """Representation of custom None.""" + return "".format(str(self.identifier)) + + +NOT_SET = CustomNone() +AS_WIDGET = CustomNone() diff --git a/pype/tools/config_setting/widgets/main.py b/pype/tools/config_setting/widgets/main.py new file mode 100644 index 0000000000..af23e68f77 --- /dev/null +++ b/pype/tools/config_setting/widgets/main.py @@ -0,0 +1,26 @@ +from Qt import QtWidgets +from .base import StudioWidget, ProjectWidget + + +class MainWidget(QtWidgets.QWidget): + widget_width = 1000 + widget_height = 600 + + def __init__(self, parent=None): + super(MainWidget, self).__init__(parent) + + self.resize(self.widget_width, self.widget_height) + + header_tab_widget = QtWidgets.QTabWidget(parent=self) + + studio_widget = StudioWidget() + project_widget = ProjectWidget() + header_tab_widget.addTab(studio_widget, "Studio") + header_tab_widget.addTab(project_widget, "Project") + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + layout.addWidget(header_tab_widget) + + self.setLayout(layout) diff --git a/pype/tools/config_setting/widgets/tests.py b/pype/tools/config_setting/widgets/tests.py new file mode 100644 index 0000000000..53b67de3a1 --- /dev/null +++ b/pype/tools/config_setting/widgets/tests.py @@ -0,0 +1,127 @@ +from Qt import QtWidgets, QtCore + + +class SelectableMenu(QtWidgets.QMenu): + + selection_changed = QtCore.Signal() + + def mouseReleaseEvent(self, event): + action = self.activeAction() + if action and action.isEnabled(): + action.trigger() + self.selection_changed.emit() + else: + super(SelectableMenu, self).mouseReleaseEvent(event) + + def event(self, event): + result = super(SelectableMenu, self).event(event) + if event.type() == QtCore.QEvent.Show: + parent = self.parent() + + move_point = parent.mapToGlobal(QtCore.QPoint(0, parent.height())) + check_point = ( + move_point + + QtCore.QPoint(self.width(), self.height()) + ) + visibility_check = ( + QtWidgets.QApplication.desktop().rect().contains(check_point) + ) + if not visibility_check: + move_point -= QtCore.QPoint(0, parent.height() + self.height()) + self.move(move_point) + + self.updateGeometry() + self.repaint() + + return result + + +class AddibleComboBox(QtWidgets.QComboBox): + """Searchable ComboBox with empty placeholder value as first value""" + + def __init__(self, placeholder="", parent=None): + super(AddibleComboBox, self).__init__(parent) + + self.setEditable(True) + # self.setInsertPolicy(self.NoInsert) + + self.lineEdit().setPlaceholderText(placeholder) + # self.lineEdit().returnPressed.connect(self.on_return_pressed) + + # Apply completer settings + completer = self.completer() + completer.setCompletionMode(completer.PopupCompletion) + completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) + + # def on_return_pressed(self): + # text = self.lineEdit().text().strip() + # if not text: + # return + # + # index = self.findText(text) + # if index < 0: + # self.addItems([text]) + # index = self.findText(text) + + + + def populate(self, items): + self.clear() + # self.addItems([""]) # ensure first item is placeholder + self.addItems(items) + + def get_valid_value(self): + """Return the current text if it's a valid value else None + + Note: The empty placeholder value is valid and returns as "" + + """ + + text = self.currentText() + lookup = set(self.itemText(i) for i in range(self.count())) + if text not in lookup: + return None + + return text or None + + +class MultiselectEnum(QtWidgets.QWidget): + + selection_changed = QtCore.Signal() + + def __init__(self, title, parent=None): + super(MultiselectEnum, self).__init__(parent) + toolbutton = QtWidgets.QToolButton(self) + toolbutton.setText(title) + + toolmenu = SelectableMenu(toolbutton) + + toolbutton.setMenu(toolmenu) + toolbutton.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup) + + layout = QtWidgets.QHBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(toolbutton) + + self.setLayout(layout) + + toolmenu.selection_changed.connect(self.selection_changed) + + self.toolbutton = toolbutton + self.toolmenu = toolmenu + self.main_layout = layout + + def populate(self, items): + self.toolmenu.clear() + self.addItems(items) + + def addItems(self, items): + for item in items: + action = self.toolmenu.addAction(item) + action.setCheckable(True) + action.setChecked(True) + self.toolmenu.addAction(action) + + def items(self): + for action in self.toolmenu.actions(): + yield action From 899b654acec03e32eaac8e48df169f24a4232d24 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 11:48:27 +0200 Subject: [PATCH 023/580] added attribute is_group to be able recognize if key will be overriden on one subvalue change --- pype/tools/config_setting/widgets/inputs.py | 24 +++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 1ddc27278d..02dd86c946 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1,10 +1,9 @@ +import json from Qt import QtWidgets, QtCore, QtGui from . import config from .base import PypeConfigurationWidget, TypeToKlass, ClickableWidget from .lib import NOT_SET, AS_WIDGET -import json - class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal() @@ -15,6 +14,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._as_widget = values is AS_WIDGET self._parent = parent + self.is_group = False + super(BooleanWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -129,6 +130,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + self.is_group = False + super(IntegerWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -220,6 +223,8 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + self.is_group = False + super(FloatWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -315,6 +320,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + self.is_group = False + super(TextSingleLineWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -398,6 +405,8 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_group = False + super(TextMultiLineWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -635,6 +644,9 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self, input_data, values, parent_keys, parent, label_widget=None ): self._parent = parent + + self.is_group = False + super(TextListWidget, self).__init__(parent) self.setObjectName("TextListWidget") @@ -785,6 +797,8 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): )) self._parent = parent + self.is_group = input_data.get("is_group", False) + super(DictExpandWidget, self).__init__(parent) self.setObjectName("DictExpandWidget") top_part = ClickableWidget(parent=self) @@ -916,6 +930,8 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_group = input_data.get("is_group", False) + super(DictInvisible, self).__init__(parent) self.setObjectName("DictInvisible") @@ -993,6 +1009,8 @@ class DictFormWidget(QtWidgets.QWidget): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + self.is_group = input_data.get("is_group", False) + super(DictFormWidget, self).__init__(parent) self.input_fields = {} @@ -1288,6 +1306,8 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_group = input_data.get("is_group", False) + super(ModifiableDict, self).__init__(input_data["label"], parent) self.setObjectName("ModifiableDict") From 908cccca120d9b372fb6f946148ed9496d1a6740 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 11:57:16 +0200 Subject: [PATCH 024/580] moved widgets out of the box to widgets.py --- pype/tools/config_setting/widgets/base.py | 14 --- pype/tools/config_setting/widgets/inputs.py | 99 ++--------------- pype/tools/config_setting/widgets/widgets.py | 105 +++++++++++++++++++ 3 files changed, 112 insertions(+), 106 deletions(-) create mode 100644 pype/tools/config_setting/widgets/widgets.py diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 0cc64a66de..3a495c6ae1 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -10,19 +10,6 @@ class TypeToKlass: types = {} -class ClickableWidget(QtWidgets.QLabel): - clicked = QtCore.Signal() - - def __init__(self, *args, **kwargs): - super(ClickableWidget, self).__init__(*args, **kwargs) - self.setObjectName("ExpandLabel") - - def mouseReleaseEvent(self, event): - if event.button() == QtCore.Qt.LeftButton: - self.clicked.emit() - super(ClickableWidget, self).mouseReleaseEvent(event) - - class PypeConfigurationWidget: is_category = False is_overriden = False @@ -197,7 +184,6 @@ class ProjectListWidget(QtWidgets.QWidget): # ) - class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): config_dir = os.path.join( os.path.dirname(os.path.dirname(__file__)), diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 02dd86c946..7ef154ac9e 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1,7 +1,13 @@ import json from Qt import QtWidgets, QtCore, QtGui from . import config -from .base import PypeConfigurationWidget, TypeToKlass, ClickableWidget +from .base import PypeConfigurationWidget, TypeToKlass +from .widgets import ( + ClickableWidget, + ExpandingWidget, + ModifiedIntSpinBox, + ModifiedFloatSpinBox +) from .lib import NOT_SET, AS_WIDGET @@ -97,30 +103,6 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: self.item_value()} -class ModifiedIntSpinBox(QtWidgets.QSpinBox): - def __init__(self, *args, **kwargs): - super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) - self.setFocusPolicy(QtCore.Qt.StrongFocus) - - def wheelEvent(self, event): - if self.hasFocus(): - super(ModifiedIntSpinBox, self).wheelEvent(event) - else: - event.ignore() - - -class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): - def __init__(self, *args, **kwargs): - super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) - self.setFocusPolicy(QtCore.Qt.StrongFocus) - - def wheelEvent(self, event): - if self.hasFocus(): - super(ModifiedFloatSpinBox, self).wheelEvent(event) - else: - event.ignore() - - class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal() @@ -720,73 +702,6 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: self.item_value()} -class ExpandingWidget(QtWidgets.QWidget): - def __init__(self, label, parent): - super(ExpandingWidget, self).__init__(parent) - self.setObjectName("ExpandingWidget") - - top_part = ClickableWidget(parent=self) - - button_size = QtCore.QSize(5, 5) - button_toggle = QtWidgets.QToolButton(parent=top_part) - button_toggle.setProperty("btn-type", "expand-toggle") - button_toggle.setIconSize(button_size) - button_toggle.setArrowType(QtCore.Qt.RightArrow) - button_toggle.setCheckable(True) - button_toggle.setChecked(False) - - label_widget = QtWidgets.QLabel(label, parent=top_part) - label_widget.setObjectName("ExpandLabel") - - layout = QtWidgets.QHBoxLayout(top_part) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(button_toggle) - layout.addWidget(label_widget) - top_part.setLayout(layout) - - self.setAttribute(QtCore.Qt.WA_StyledBackground) - - self.top_part = top_part - self.button_toggle = button_toggle - self.label_widget = label_widget - - self.top_part.clicked.connect(self._top_part_clicked) - self.button_toggle.clicked.connect(self.toggle_content) - - def set_content_widget(self, content_widget): - main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(9, 9, 9, 9) - - content_widget.setVisible(False) - - main_layout.addWidget(self.top_part) - main_layout.addWidget(content_widget) - self.setLayout(main_layout) - - self.content_widget = content_widget - - def _top_part_clicked(self): - self.toggle_content(not self.button_toggle.isChecked()) - - def toggle_content(self, *args): - if len(args) > 0: - checked = args[0] - else: - checked = self.button_toggle.isChecked() - arrow_type = QtCore.Qt.RightArrow - if checked: - arrow_type = QtCore.Qt.DownArrow - self.button_toggle.setChecked(checked) - self.button_toggle.setArrowType(arrow_type) - self.content_widget.setVisible(checked) - self.parent().updateGeometry() - - def resizeEvent(self, event): - super(ExpandingWidget, self).resizeEvent(event) - self.content_widget.updateGeometry() - - class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def __init__( self, input_data, values, parent_keys, parent, label_widget=None diff --git a/pype/tools/config_setting/widgets/widgets.py b/pype/tools/config_setting/widgets/widgets.py new file mode 100644 index 0000000000..34fdfde1a5 --- /dev/null +++ b/pype/tools/config_setting/widgets/widgets.py @@ -0,0 +1,105 @@ +from Qt import QtWidgets, QtCore + + +class ModifiedIntSpinBox(QtWidgets.QSpinBox): + def __init__(self, *args, **kwargs): + super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + def wheelEvent(self, event): + if self.hasFocus(): + super(ModifiedIntSpinBox, self).wheelEvent(event) + else: + event.ignore() + + +class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): + def __init__(self, *args, **kwargs): + super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + def wheelEvent(self, event): + if self.hasFocus(): + super(ModifiedFloatSpinBox, self).wheelEvent(event) + else: + event.ignore() + + +class ClickableWidget(QtWidgets.QLabel): + clicked = QtCore.Signal() + + def __init__(self, *args, **kwargs): + super(ClickableWidget, self).__init__(*args, **kwargs) + self.setObjectName("ExpandLabel") + + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.LeftButton: + self.clicked.emit() + super(ClickableWidget, self).mouseReleaseEvent(event) + + +class ExpandingWidget(QtWidgets.QWidget): + def __init__(self, label, parent): + super(ExpandingWidget, self).__init__(parent) + self.setObjectName("ExpandingWidget") + + top_part = ClickableWidget(parent=self) + + button_size = QtCore.QSize(5, 5) + button_toggle = QtWidgets.QToolButton(parent=top_part) + button_toggle.setProperty("btn-type", "expand-toggle") + button_toggle.setIconSize(button_size) + button_toggle.setArrowType(QtCore.Qt.RightArrow) + button_toggle.setCheckable(True) + button_toggle.setChecked(False) + + label_widget = QtWidgets.QLabel(label, parent=top_part) + label_widget.setObjectName("ExpandLabel") + + layout = QtWidgets.QHBoxLayout(top_part) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(button_toggle) + layout.addWidget(label_widget) + top_part.setLayout(layout) + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + self.top_part = top_part + self.button_toggle = button_toggle + self.label_widget = label_widget + + self.top_part.clicked.connect(self._top_part_clicked) + self.button_toggle.clicked.connect(self.toggle_content) + + def set_content_widget(self, content_widget): + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(9, 9, 9, 9) + + content_widget.setVisible(False) + + main_layout.addWidget(self.top_part) + main_layout.addWidget(content_widget) + self.setLayout(main_layout) + + self.content_widget = content_widget + + def _top_part_clicked(self): + self.toggle_content(not self.button_toggle.isChecked()) + + def toggle_content(self, *args): + if len(args) > 0: + checked = args[0] + else: + checked = self.button_toggle.isChecked() + arrow_type = QtCore.Qt.RightArrow + if checked: + arrow_type = QtCore.Qt.DownArrow + self.button_toggle.setChecked(checked) + self.button_toggle.setArrowType(arrow_type) + self.content_widget.setVisible(checked) + self.parent().updateGeometry() + + def resizeEvent(self, event): + super(ExpandingWidget, self).resizeEvent(event) + self.content_widget.updateGeometry() From 63c13c655e2b41694055ef8940ba7824b95fd352 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 11:59:11 +0200 Subject: [PATCH 025/580] removed category attribute (as was replaced with group attribute) --- pype/tools/config_setting/widgets/base.py | 2 +- pype/tools/config_setting/widgets/inputs.py | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 3a495c6ae1..0fb4cd94cb 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -11,7 +11,7 @@ class TypeToKlass: class PypeConfigurationWidget: - is_category = False + is_group = False is_overriden = False is_modified = False diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 7ef154ac9e..64deb4d909 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -762,7 +762,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) - self._is_category = False self._is_overriden = False self.input_fields = [] @@ -794,10 +793,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): super(DictExpandWidget, self).resizeEvent(event) self.content_widget.updateGeometry() - @property - def is_category(self): - return self._is_category - @property def is_overriden(self): return self._is_overriden @@ -856,7 +851,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self._is_category = False self._is_overriden = False self.input_fields = [] @@ -874,10 +868,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): def is_overidable(self): return self._parent.is_overidable - @property - def is_category(self): - return self._is_category - @property def is_overriden(self): return self._is_overriden From f184f71a0fbbe19b798ed7fa83e4dd77f208dd91 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 17:12:45 +0200 Subject: [PATCH 026/580] handle project view selection --- pype/tools/config_setting/widgets/base.py | 92 ++++++++++++++++------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 0fb4cd94cb..bd19873b5f 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -120,37 +120,80 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.content_layout.addWidget(item) +class ProjectListView(QtWidgets.QListView): + left_mouse_released_at = QtCore.Signal(QtCore.QModelIndex) + + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.LeftButton: + index = self.indexAt(event.pos()) + self.left_mouse_released_at.emit(index) + super(ProjectListView, self).mouseReleaseEvent(event) + + class ProjectListWidget(QtWidgets.QWidget): default = "< Default >" - def __init__(self, parent=None): + def __init__(self, parent): + self._parent = parent + + self.current_project = None + super(ProjectListWidget, self).__init__(parent) - label = QtWidgets.QLabel("Project") - project_list = QtWidgets.QListView(self) + label_widget = QtWidgets.QLabel("Projects") + project_list = ProjectListView(self) project_list.setModel(QtGui.QStandardItemModel()) + # Do not allow editing + project_list.setEditTriggers( + QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers + ) + # Do not automatically handle selection + project_list.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) + layout = QtWidgets.QVBoxLayout(self) - # content_margin = 5 - # layout.setContentsMargins( - # content_margin, - # content_margin, - # content_margin, - # content_margin - # ) - # layout.setSpacing(3) - layout.addWidget(label, 0) + layout.setSpacing(3) + layout.addWidget(label_widget, 0) layout.addWidget(project_list, 1) + project_list.left_mouse_released_at.connect(self.on_item_clicked) + self.project_list = project_list self.refresh() + def on_item_clicked(self, new_index): + new_project_name = new_index.data(QtCore.Qt.DisplayRole) + if new_project_name is None: + return + + if self.current_project == new_project_name: + return + + if self.validate_context_change(): + self.select_project(new_project_name) + self.current_project = new_project_name + + def validate_context_change(self): + # TODO add check if project can be changed (is modified) + return True + def project_name(self): - current_selection = self.project_list.currentText() - if current_selection == self.default: + if self.current_project == self.default: return None - return current_selection + return self.current_project + + def select_project(self, project_name): + model = self.project_list.model() + found_items = model.findItems(project_name) + if not found_items: + found_items = model.findItems(self.default) + + index = model.indexFromItem(found_items[0]) + self.project_list.selectionModel().clear() + self.project_list.selectionModel().setCurrentIndex( + index, QtCore.QItemSelectionModel.SelectionFlag.SelectCurrent + ) def refresh(self): selected_project = None @@ -163,25 +206,16 @@ class ProjectListWidget(QtWidgets.QWidget): items = [self.default] io.install() for project_doc in tuple(io.projects()): - print(project_doc["name"]) items.append(project_doc["name"]) for item in items: model.appendRow(QtGui.QStandardItem(item)) - if not selected_project: - selected_project = self.default + self.select_project(selected_project) - found_items = model.findItems(selected_project) - if found_items: - index = model.indexFromItem(found_items[0]) - c = QtCore.QItemSelectionModel.SelectionFlag.SelectCurrent - self.project_list.selectionModel().select( - index, c - ) - # self.project_list.selectionModel().setCurrentIndex( - # index, c - # ) + self.current_project = self.project_list.currentIndex().data( + QtCore.Qt.DisplayRole + ) class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): @@ -207,7 +241,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): scroll_widget.setWidgetResizable(True) scroll_widget.setWidget(content_widget) - project_list_widget = ProjectListWidget() + project_list_widget = ProjectListWidget(self) content_layout.addWidget(project_list_widget) self.project_list_widget = project_list_widget From 355d60c3b4b8224a680af956d693fd3be47c977d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 18:03:10 +0200 Subject: [PATCH 027/580] make sure inputs has is_modified and is_overriden not with metaclass --- pype/tools/config_setting/widgets/base.py | 4 ---- pype/tools/config_setting/widgets/inputs.py | 22 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index bd19873b5f..ebe15a370c 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -11,10 +11,6 @@ class TypeToKlass: class PypeConfigurationWidget: - is_group = False - is_overriden = False - is_modified = False - def config_value(self): raise NotImplementedError( "Method `config_value` is not implemented for `{}`.".format( diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 64deb4d909..1ba062ec82 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -20,7 +20,9 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._as_widget = values is AS_WIDGET self._parent = parent + self.is_modified = False self.is_group = False + self.is_overriden = False super(BooleanWidget, self).__init__(parent) @@ -112,7 +114,9 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + self.is_modified = False self.is_group = False + self.is_overriden = False super(IntegerWidget, self).__init__(parent) @@ -205,7 +209,9 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + self.is_modified = False self.is_group = False + self.is_overriden = False super(FloatWidget, self).__init__(parent) @@ -302,7 +308,9 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + self.is_modified = False self.is_group = False + self.is_overriden = False super(TextSingleLineWidget, self).__init__(parent) @@ -387,7 +395,9 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_modified = False self.is_group = False + self.is_overriden = False super(TextMultiLineWidget, self).__init__(parent) @@ -627,7 +637,9 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_modified = False self.is_group = False + self.is_overriden = False super(TextListWidget, self).__init__(parent) self.setObjectName("TextListWidget") @@ -712,6 +724,8 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): )) self._parent = parent + self.is_modified = False + self.is_overriden = False self.is_group = input_data.get("is_group", False) super(DictExpandWidget, self).__init__(parent) @@ -840,6 +854,8 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_modified = False + self.is_overriden = False self.is_group = input_data.get("is_group", False) super(DictInvisible, self).__init__(parent) @@ -914,7 +930,9 @@ class DictFormWidget(QtWidgets.QWidget): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): - self.is_group = input_data.get("is_group", False) + self.is_modified = False + self.is_overriden = False + self.is_group = False super(DictFormWidget, self).__init__(parent) @@ -1211,6 +1229,8 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): ): self._parent = parent + self.is_modified = False + self.is_overriden = False self.is_group = input_data.get("is_group", False) super(ModifiableDict, self).__init__(input_data["label"], parent) From 6b42c7bdc17763b84244fe1f4c7c06bc09e92b77 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 15:22:23 +0200 Subject: [PATCH 028/580] child modified attribute added --- pype/tools/config_setting/style/style.css | 5 ++ pype/tools/config_setting/widgets/inputs.py | 87 +++++++++++++++------ 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css index f559a4c3b3..db46cc4c24 100644 --- a/pype/tools/config_setting/style/style.css +++ b/pype/tools/config_setting/style/style.css @@ -34,6 +34,7 @@ QLabel[state="overriden"] { } QWidget[input-state="original"] {} + QWidget[input-state="modified"] { border-color: #137cbd; } @@ -83,6 +84,10 @@ QPushButton[btn-type="expand-toggle"] { background: #1d272f; } +#ModifiableDict[state="child-modified"] { + border-color: #137cbd; +} + #TextListSubWidget { border: 1px solid #455c6e; border-radius: 3px; diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 1ba062ec82..9b24227a1d 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1,5 +1,5 @@ import json -from Qt import QtWidgets, QtCore, QtGui +from Qt import QtWidgets, QtCore from . import config from .base import PypeConfigurationWidget, TypeToKlass from .widgets import ( @@ -67,6 +67,10 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.reset_value() + @property + def child_modified(self): + return self.is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -148,6 +152,10 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.int_input.valueChanged.connect(self._on_value_change) + @property + def child_modified(self): + return self.is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -253,6 +261,10 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.float_input.valueChanged.connect(self._on_value_change) + @property + def child_modified(self): + return self.is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -342,6 +354,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.text_input.textChanged.connect(self._on_value_change) + @property + def child_modified(self): + return self.is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -427,6 +443,10 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.text_input.textChanged.connect(self._on_value_change) + @property + def child_modified(self): + return self.is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -671,6 +691,10 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.origin_value = self.item_value() + @property + def child_modified(self): + return self.is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -808,17 +832,11 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.content_widget.updateGeometry() @property - def is_overriden(self): - return self._is_overriden - - @property - def is_modified(self): - _is_modified = False + def child_modified(self): for input_field in self.input_fields: - if input_field.is_modified: - _is_modified = True - break - return _is_modified + if input_field.child_modified: + return True + return False def item_value(self): output = {} @@ -885,17 +903,11 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overidable @property - def is_overriden(self): - return self._is_overriden - - @property - def is_modified(self): - _is_modified = False + def child_modified(self): for input_field in self.input_fields: - if input_field.is_modified: - _is_modified = True - break - return _is_modified + if input_field.child_modified: + return True + return False def item_value(self): output = {} @@ -930,6 +942,8 @@ class DictFormWidget(QtWidgets.QWidget): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + self._parent = parent + self.is_modified = False self.is_overriden = False self.is_group = False @@ -952,6 +966,13 @@ class DictFormWidget(QtWidgets.QWidget): output.update(input_field.config_value()) return output + @property + def child_modified(self): + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False + @property def is_overidable(self): return self._parent.is_overidable @@ -1086,14 +1107,23 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def is_overidable(self): return self._parent.is_overidable + def is_key_modified(self): + return self._key() != self.origin_key + + def is_value_modified(self): + return self.value_input.is_modified + + @property + def is_modified(self): + return self.is_value_modified() or self.is_key_modified() + def _update_style(self): - is_modified = self._key() != self.origin_key # if self._is_overidable and self.is_overriden: # if is_modified: # state = "overriden-modified" # else: # state = "overriden" - if is_modified: + if self.is_key_modified(): state = "modified" else: state = "original" @@ -1230,6 +1260,7 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self._parent = parent self.is_modified = False + self.child_modified = False self.is_overriden = False self.is_group = input_data.get("is_group", False) @@ -1249,7 +1280,7 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.origin_value = self.item_value() def _on_value_change(self, value=None): - self.is_modified = self.item_value() != self.origin_value + self.child_modified = self.item_value() != self.origin_value self.is_overriden = True self._update_style() @@ -1259,6 +1290,14 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): return self._parent.is_overidable def _update_style(self): + if self.child_modified: + widget_state = "child-modified" + else: + widget_state = "" + + self.setProperty("state", widget_state) + self.style().polish(self) + if self.is_overidable and self.is_overriden: if self.is_modified: state = "overriden-modified" From 7058dc7d10312fb8c11dc4e45a0225634100dad0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 16:49:20 +0200 Subject: [PATCH 029/580] style fixes --- pype/tools/config_setting/style/style.css | 2 +- pype/tools/config_setting/widgets/base.py | 4 +- pype/tools/config_setting/widgets/inputs.py | 98 +++++++++++++++++---- 3 files changed, 83 insertions(+), 21 deletions(-) diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css index db46cc4c24..db2d746a23 100644 --- a/pype/tools/config_setting/style/style.css +++ b/pype/tools/config_setting/style/style.css @@ -84,7 +84,7 @@ QPushButton[btn-type="expand-toggle"] { background: #1d272f; } -#ModifiableDict[state="child-modified"] { +#DictExpandWidget[state="child-modified"], #ModifiableDict[state="child-modified"] { border-color: #137cbd; } diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index ebe15a370c..d2ccdddfc1 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -58,7 +58,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): scroll_widget = QtWidgets.QScrollArea(self) content_widget = QtWidgets.QWidget(scroll_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setContentsMargins(3, 3, 3, 3) content_layout.setSpacing(0) content_layout.setAlignment(QtCore.Qt.AlignTop) content_widget.setLayout(content_layout) @@ -229,7 +229,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): scroll_widget = QtWidgets.QScrollArea(self) content_widget = QtWidgets.QWidget(scroll_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setContentsMargins(3, 3, 3, 3) content_layout.setSpacing(0) content_layout.setAlignment(QtCore.Qt.AlignTop) content_widget.setLayout(content_layout) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 9b24227a1d..c2a6eff0cc 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -19,7 +19,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._as_widget = values is AS_WIDGET self._parent = parent - + print(10*"*", parent) + print(values) self.is_modified = False self.is_group = False self.is_overriden = False @@ -94,7 +95,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: state = "original" - if not self._as_widget: + if self._as_widget: property_name = "input-state" else: property_name = "state" @@ -290,19 +291,25 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit() def _update_style(self): - if not self._as_widget: - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" - elif self.is_modified: - state = "modified" + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" else: - state = "original" + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + if self._as_widget: + property_name = "input-state" + widget = self.float_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) def item_value(self): return self.float_input.value() @@ -393,8 +400,15 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: state = "original" - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + if self._as_widget: + property_name = "input-state" + widget = self.text_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) def item_value(self): return self.text_input.text() @@ -482,8 +496,15 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: state = "original" - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + if self._as_widget: + property_name = "input-state" + widget = self.text_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) def item_value(self): return self.text_input.toPlainText() @@ -652,6 +673,8 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): @@ -705,6 +728,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._update_style() + self.value_changed.emit() + def set_value(self, value, origin_value=False): self.value_widget.set_value(value) if origin_value: @@ -739,6 +764,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal() + def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): @@ -831,6 +858,33 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): super(DictExpandWidget, self).resizeEvent(event) self.content_widget.updateGeometry() + def _on_value_change(self, value=None): + self.is_overriden = True + + self._update_style() + + def _update_style(self): + if self.child_modified: + widget_state = "child-modified" + else: + widget_state = "" + + self.setProperty("state", widget_state) + self.style().polish(self) + + if self.is_overidable and self.is_overriden: + if self.is_modified: + state = "overriden-modified" + else: + state = "overriden" + elif self.is_modified: + state = "modified" + else: + state = "original" + + self.button_toggle_text.setProperty("state", state) + self.button_toggle_text.style().polish(self.button_toggle_text) + @property def child_modified(self): for input_field in self.input_fields: @@ -860,6 +914,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): item = klass( child_configuration, values, self.keys, self ) + item.value_changed.connect(self._on_value_change) self.content_layout.addWidget(item) self.input_fields.append(item) @@ -939,6 +994,8 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): class DictFormWidget(QtWidgets.QWidget): + value_changed = QtCore.Signal() + def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): @@ -958,6 +1015,9 @@ class DictFormWidget(QtWidgets.QWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def _on_value_change(self): + self.value_changed.emit() + def item_value(self): output = {} for input_field in self.input_fields.values(): @@ -968,7 +1028,7 @@ class DictFormWidget(QtWidgets.QWidget): @property def child_modified(self): - for input_field in self.input_fields: + for input_field in self.input_fields.values(): if input_field.child_modified: return True return False @@ -989,9 +1049,11 @@ class DictFormWidget(QtWidgets.QWidget): klass = TypeToKlass.types.get(item_type) label_widget = QtWidgets.QLabel(label) + item = klass( child_configuration, values, self.keys, self, label_widget ) + item.value_changed.connect(self._on_value_change) self.content_layout.addRow(label_widget, item) self.input_fields[key] = item return item From e083e9585912bf920475244a0096e6e8eb1a3c57 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 17:53:20 +0200 Subject: [PATCH 030/580] made it a little bit globally usable --- pype/tools/config_setting/interface.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/interface.py b/pype/tools/config_setting/interface.py index e95f3f5fe3..e227443c95 100644 --- a/pype/tools/config_setting/interface.py +++ b/pype/tools/config_setting/interface.py @@ -1,17 +1,26 @@ import os import sys -os.environ["PYPE_CONFIG"] = ( - "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pype-config" + + +def folder_up(path, times=1): + if times <= 0: + return path + return folder_up(os.path.dirname(path), times - 1) + + +PYPE_SETUP_PATH = folder_up(__file__, 6) + +os.environ["PYPE_CONFIG"] = os.path.join( + PYPE_SETUP_PATH, "repos", "pype-config" ) os.environ["AVALON_MONGO"] = "mongodb://localhost:2707" sys_paths = ( "C:/Users/Public/pype_env2/Lib/site-packages", - "C:/Users/jakub.trllo/Desktop/pype/pype-setup", - "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pype", - "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/avalon-core", - "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pyblish-base", - "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pyblish-lite", - "C:/Users/jakub.trllo/Desktop/pype/pype-setup/repos/pype-config" + PYPE_SETUP_PATH, + os.path.join(PYPE_SETUP_PATH, "repos", "pype"), + os.path.join(PYPE_SETUP_PATH, "repos", "avalon-core"), + os.path.join(PYPE_SETUP_PATH, "repos", "pyblish-base"), + os.path.join(PYPE_SETUP_PATH, "repos", "pype-config"), ) for path in sys_paths: sys.path.append(path) From 8d92a455e6b2083df3f8476a838f7908b00d9f77 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 18:07:45 +0200 Subject: [PATCH 031/580] minor tweaks in temp config files --- .../global/es/applications.json | 39 ------------------- .../config_gui_schema/studio_gui_schema.json | 15 ++++--- 2 files changed, 10 insertions(+), 44 deletions(-) delete mode 100644 pype/tools/config_setting/config/studio_presets/global/es/applications.json diff --git a/pype/tools/config_setting/config/studio_presets/global/es/applications.json b/pype/tools/config_setting/config/studio_presets/global/es/applications.json deleted file mode 100644 index 35e399444c..0000000000 --- a/pype/tools/config_setting/config/studio_presets/global/es/applications.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "blender_2.80": true, - "blender_2.81": true, - "blender_2.82": true, - "blender_2.83": true, - "harmony_17": true, - "houdini_16": true, - "houdini_17": true, - "houdini_18": true, - "maya_2016": true, - "maya_2017": true, - "maya_2018": true, - "maya_2019": true, - "maya_2020": true, - "nuke_10.0": true, - "nuke_11.0": true, - "nuke_11.2": true, - "nuke_11.3": true, - "nuke_12.0": true, - "nukex_10.0": true, - "nukex_11.0": true, - "nukex_11.2": true, - "nukex_11.3": true, - "nukex_12.0": true, - "nukestudio_10.0": true, - "nukestudio_11.0": true, - "nukestudio_11.2": true, - "nukestudio_11.3": true, - "nukestudio_12.0": true, - "photoshop_2020": true, - "premiere_2019": true, - "premiere_2020": true, - "python_2": true, - "python_3": true, - "resolve_16": true, - "shell": true, - "storyboardpro_7": true, - "unreal_4.21": true -} diff --git a/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json index 7d902bb8db..1a49735b8a 100644 --- a/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json @@ -4,11 +4,16 @@ "label": "Studio", "children": [ { - "type": "schema", - "children": [ - "applications_gui_schema", - "tools_gui_schema" - ] + "key": "global", + "type": "dict-invisible", + "label": "Global", + "children": [{ + "type": "schema", + "children": [ + "applications_gui_schema", + "tools_gui_schema" + ] + }] }, { "key": "muster", "type": "dict-invisible", From cbb77c05b10affef9a66a2bfb2284635adbaa71f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 18:07:57 +0200 Subject: [PATCH 032/580] preparation for studio save --- pype/tools/config_setting/widgets/base.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index d2ccdddfc1..337beb040e 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -80,10 +80,10 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) - btn = QtWidgets.QPushButton("Finish") + save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() footer_layout.addWidget(spacer_widget, 1) - footer_layout.addWidget(btn, 0) + footer_layout.addWidget(save_btn, 0) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -93,9 +93,9 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): layout.addWidget(scroll_widget, 1) layout.addWidget(footer_widget, 0) - btn.clicked.connect(self.___finish) + save_btn.clicked.connect(self._save) - def ___finish(self): + def _save(self): output = {} for item in self.input_fields: output.update(item.config_value()) @@ -104,6 +104,9 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): _output = {key: output} output = _output + config_with_metadata = config.studio_presets_with_metadata() + + print(json.dumps(config_with_metadata, indent=4)) print(json.dumps(output, indent=4)) def add_children_gui(self, child_configuration, values): From 5ba9eb2eed39d05647d360621353d9a3a4ba3cb1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 18:08:35 +0200 Subject: [PATCH 033/580] paths are correct and metadata presets are with metadata --- pype/tools/config_setting/interface.py | 6 ++---- pype/tools/config_setting/widgets/config.py | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/interface.py b/pype/tools/config_setting/interface.py index e227443c95..a8c05f5af3 100644 --- a/pype/tools/config_setting/interface.py +++ b/pype/tools/config_setting/interface.py @@ -8,8 +8,7 @@ def folder_up(path, times=1): return folder_up(os.path.dirname(path), times - 1) -PYPE_SETUP_PATH = folder_up(__file__, 6) - +PYPE_SETUP_PATH = folder_up(os.path.realpath(__file__), 6) os.environ["PYPE_CONFIG"] = os.path.join( PYPE_SETUP_PATH, "repos", "pype-config" ) @@ -19,8 +18,7 @@ sys_paths = ( PYPE_SETUP_PATH, os.path.join(PYPE_SETUP_PATH, "repos", "pype"), os.path.join(PYPE_SETUP_PATH, "repos", "avalon-core"), - os.path.join(PYPE_SETUP_PATH, "repos", "pyblish-base"), - os.path.join(PYPE_SETUP_PATH, "repos", "pype-config"), + os.path.join(PYPE_SETUP_PATH, "repos", "pyblish-base") ) for path in sys_paths: sys.path.append(path) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 335299cb2f..58b1e03a25 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -160,10 +160,12 @@ def global_project_presets(**kwargs): def studio_presets_with_metadata(*args, **kwargs): + kwargs["with_metadata"] = True return load_jsons_from_dir(studio_presets_path, *args, **kwargs) def global_project_presets_with_metadata(**kwargs): + kwargs["with_metadata"] = True return load_jsons_from_dir(project_presets_path, **kwargs) From 5ba7a45235ca82486fe3db36774d4892aa3fedd4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 24 Jul 2020 18:35:44 +0200 Subject: [PATCH 034/580] more close to saving studio presets --- pype/tools/config_setting/widgets/base.py | 42 ++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 337beb040e..a5f912d7cb 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -4,6 +4,7 @@ from Qt import QtWidgets, QtCore, QtGui from . import config from .lib import NOT_SET from avalon import io +from queue import Queue class TypeToKlass: @@ -96,18 +97,49 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): save_btn.clicked.connect(self._save) def _save(self): - output = {} + all_values = {} for item in self.input_fields: - output.update(item.config_value()) + all_values.update(item.config_value()) for key in reversed(self.keys): - _output = {key: output} - output = _output + _all_values = {key: all_values} + all_values = _all_values + # Skip first key + all_values = all_values["studio"] + + # Load studio data with metadata config_with_metadata = config.studio_presets_with_metadata() print(json.dumps(config_with_metadata, indent=4)) - print(json.dumps(output, indent=4)) + print(json.dumps(all_values, indent=4)) + + per_file_values = {} + process_queue = Queue() + for _key, _values in all_values.items(): + process_queue.put(( + config.studio_presets_path, _key, config_with_metadata, _values + )) + + while not process_queue.empty(): + path, key, metadata, values = process_queue.get() + new_path = os.path.join(path, key) + # TODO this should not be + if key in metadata: + key_metadata = metadata[key] + + if key_metadata["type"] == "file": + new_path += ".json" + per_file_values[new_path] = values + continue + + for new_key, new_values in values.items(): + process_queue.put( + (new_path, new_key, key_metadata["value"], new_values) + ) + + for path in per_file_values: + print(path) def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] From 22adf6f9e3ffb3dfe2891f0bc23198a112babbe6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 10:51:17 +0200 Subject: [PATCH 035/580] fix dictinary value changed --- pype/tools/config_setting/widgets/inputs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index c2a6eff0cc..01a22bd702 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -861,6 +861,8 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_overriden = True + self.value_changed.emit() + self._update_style() def _update_style(self): From 4d52556f2b4cbbbe7b4c9c28944d4c88d877bab3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 11:14:56 +0200 Subject: [PATCH 036/580] fix values keys --- pype/tools/config_setting/widgets/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index a5f912d7cb..b4ad206076 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -130,7 +130,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): if key_metadata["type"] == "file": new_path += ".json" - per_file_values[new_path] = values + per_file_values[new_path] = {key: values} continue for new_key, new_values in values.items(): From ce9f4315086b039ca0eb7b3b2ae44a09df2d32b7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 12:04:48 +0200 Subject: [PATCH 037/580] saving studio files --- pype/tools/config_setting/widgets/base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index b4ad206076..b68ec4126a 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -130,7 +130,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): if key_metadata["type"] == "file": new_path += ".json" - per_file_values[new_path] = {key: values} + per_file_values[new_path] = values continue for new_key, new_values in values.items(): @@ -138,8 +138,9 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): (new_path, new_key, key_metadata["value"], new_values) ) - for path in per_file_values: - print(path) + for file_path, file_values in per_file_values.items(): + with open(file_path, "w") as file_stream: + json.dump(file_values, file_stream, indent=4) def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] From 8ebbf14097557f22dd87f59a040bc1f353cd221d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 17:36:04 +0200 Subject: [PATCH 038/580] added child overriden attribute --- pype/tools/config_setting/style/style.css | 8 +++ pype/tools/config_setting/widgets/inputs.py | 70 +++++++++++++++++++-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css index db2d746a23..1371056c1a 100644 --- a/pype/tools/config_setting/style/style.css +++ b/pype/tools/config_setting/style/style.css @@ -88,6 +88,14 @@ QPushButton[btn-type="expand-toggle"] { border-color: #137cbd; } +#DictExpandWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"] { + border-color: #ff8c1a; +} + +#DictExpandWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"] { + border-color: #00b386; +} + #TextListSubWidget { border: 1px solid #455c6e; border-radius: 3px; diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 01a22bd702..9bed1207a8 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -19,8 +19,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._as_widget = values is AS_WIDGET self._parent = parent - print(10*"*", parent) - print(values) + self.is_modified = False self.is_group = False self.is_overriden = False @@ -72,6 +71,10 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_modified(self): return self.is_modified + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -157,6 +160,10 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_modified(self): return self.is_modified + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -266,6 +273,10 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_modified(self): return self.is_modified + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -365,6 +376,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_modified(self): return self.is_modified + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -461,6 +476,10 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_modified(self): return self.is_modified + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -718,6 +737,10 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_modified(self): return self.is_modified + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -866,8 +889,15 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._update_style() def _update_style(self): - if self.child_modified: + child_modified = self.child_modified + child_overriden = self.child_overriden + + if child_modified and child_overriden: + widget_state = "child-overriden-modified" + elif child_modified: widget_state = "child-modified" + elif child_overriden: + widget_state = "child-overriden" else: widget_state = "" @@ -894,6 +924,13 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): return True return False + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + def item_value(self): output = {} for input_field in self.input_fields: @@ -966,6 +1003,13 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): return True return False + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + def item_value(self): output = {} for input_field in self.input_fields: @@ -1035,6 +1079,13 @@ class DictFormWidget(QtWidgets.QWidget): return True return False + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + @property def is_overidable(self): return self._parent.is_overidable @@ -1349,13 +1400,24 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self._update_style() + @property + def child_overriden(self): + return self.is_overriden + @property def is_overidable(self): return self._parent.is_overidable def _update_style(self): - if self.child_modified: + child_modified = self.child_modified + child_overriden = self.child_overriden + + if child_modified and child_overriden: + widget_state = "child-overriden-modified" + elif child_modified: widget_state = "child-modified" + elif child_overriden: + widget_state = "child-overriden" else: widget_state = "" From 669631d71edc96c8adeb5ff32954389a4f5edfb7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 18:55:36 +0200 Subject: [PATCH 039/580] removed duplicated class --- pype/tools/config_setting/widgets/inputs.py | 50 --------------------- 1 file changed, 50 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 9bed1207a8..01c69c1c0b 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1112,56 +1112,6 @@ class DictFormWidget(QtWidgets.QWidget): return item -class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): - _btn_size = 20 - value_changed = QtCore.Signal() - - def __init__(self, parent): - super(TextListItem, self).__init__(parent) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(3) - - self.text_input = QtWidgets.QLineEdit() - self.add_btn = QtWidgets.QPushButton("+") - self.remove_btn = QtWidgets.QPushButton("-") - - self.add_btn.setProperty("btn-type", "text-list") - self.remove_btn.setProperty("btn-type", "text-list") - - layout.addWidget(self.text_input, 1) - layout.addWidget(self.add_btn, 0) - layout.addWidget(self.remove_btn, 0) - - self.add_btn.setFixedSize(self._btn_size, self._btn_size) - self.remove_btn.setFixedSize(self._btn_size, self._btn_size) - self.add_btn.clicked.connect(self.on_add_clicked) - self.remove_btn.clicked.connect(self.on_remove_clicked) - - self.text_input.textChanged.connect(self._on_value_change) - - self.is_single = False - - def _on_value_change(self): - self.value_changed.emit() - - def row(self): - return self.parent().input_fields.index(self) - - def on_add_clicked(self): - self.parent().add_row(row=self.row() + 1) - - def on_remove_clicked(self): - if self.is_single: - self.text_input.setText("") - else: - self.parent().remove_row(self) - - def config_value(self): - return self.text_input.text() - - class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 value_changed = QtCore.Signal() From a8fb14a1bca842e45c81eb2d60b16f1a68f1505b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 18:55:53 +0200 Subject: [PATCH 040/580] added is_group feature --- pype/tools/config_setting/widgets/inputs.py | 160 ++++++++++++++++++-- 1 file changed, 145 insertions(+), 15 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 01c69c1c0b..485eda6d35 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -11,6 +11,14 @@ from .widgets import ( from .lib import NOT_SET, AS_WIDGET +class SchemeGroupHierarchyBug(Exception): + def __init__(self, msg=None): + if not msg: + # TODO better message + msg = "SCHEME BUG: Attribute `is_group` is mixed in the hierarchy" + super(SchemeGroupHierarchyBug, self).__init(msg) + + class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal() @@ -20,8 +28,19 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._as_widget = values is AS_WIDGET self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(BooleanWidget, self).__init__(parent) @@ -122,8 +141,19 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(IntegerWidget, self).__init__(parent) @@ -225,8 +255,19 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(FloatWidget, self).__init__(parent) @@ -338,8 +379,19 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(TextSingleLineWidget, self).__init__(parent) @@ -440,8 +492,19 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(TextMultiLineWidget, self).__init__(parent) @@ -699,8 +762,16 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + self.is_modified = False - self.is_group = False + self.is_group = is_group self.is_overriden = False super(TextListWidget, self).__init__(parent) @@ -747,7 +818,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_group and self.is_overidable: + self.is_overriden = True self._update_style() @@ -798,9 +870,19 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): )) self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False - self.is_overriden = False - self.is_group = input_data.get("is_group", False) + self._is_overriden = False + self.is_group = is_group super(DictExpandWidget, self).__init__(parent) self.setObjectName("DictExpandWidget") @@ -850,7 +932,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) - self._is_overriden = False self.input_fields = [] self.key = input_data["key"] @@ -881,8 +962,15 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): super(DictExpandWidget, self).resizeEvent(event) self.content_widget.updateGeometry() + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + + def _on_value_change(self, value=None): - self.is_overriden = True + if self.is_group: + self._is_overriden = True self.value_changed.emit() @@ -966,9 +1054,19 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False self.is_overriden = False - self.is_group = input_data.get("is_group", False) + self.is_group = is_group super(DictInvisible, self).__init__(parent) self.setObjectName("DictInvisible") @@ -979,7 +1077,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self._is_overriden = False self.input_fields = [] if "key" not in input_data: @@ -1047,6 +1144,12 @@ class DictFormWidget(QtWidgets.QWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False self.is_overriden = False self.is_group = False @@ -1168,6 +1271,14 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): self._update_style() self.value_changed.emit() + @property + def is_group(self): + return self._parent.is_group + + @property + def any_parent_is_group(self): + return self._parent.any_parent_is_group + @property def is_overidable(self): return self._parent.is_overidable @@ -1253,6 +1364,14 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_overidable(self): return self._parent.is_overidable + @property + def is_group(self): + return self._parent.is_group + + @property + def any_parent_is_group(self): + return self._parent.any_parent_is_group + def _on_value_change(self): self.value_changed.emit() @@ -1324,10 +1443,20 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False self.child_modified = False self.is_overriden = False - self.is_group = input_data.get("is_group", False) + self.is_group = is_group super(ModifiableDict, self).__init__(input_data["label"], parent) self.setObjectName("ModifiableDict") @@ -1346,7 +1475,8 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.child_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_group: + self.is_overriden = True self._update_style() From e7e3526c72b5ca06f716bb195e2dfc99b3be0ee0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 18:56:04 +0200 Subject: [PATCH 041/580] added is_group feature --- pype/tools/config_setting/widgets/base.py | 6 +- pype/tools/config_setting/widgets/inputs.py | 160 ++++++++++++++++++-- 2 files changed, 150 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index b68ec4126a..222cf2ba41 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -50,6 +50,8 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): "config_gui_schema" ) is_overidable = False + is_group = False + any_parent_is_group = False def __init__(self, parent=None): super(StudioWidget, self).__init__(parent) @@ -124,7 +126,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): while not process_queue.empty(): path, key, metadata, values = process_queue.get() new_path = os.path.join(path, key) - # TODO this should not be + # TODO this should not be if key in metadata: key_metadata = metadata[key] @@ -256,6 +258,8 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): "config_gui_schema" ) is_overidable = True + is_group = False + any_parent_is_group = False def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 01c69c1c0b..485eda6d35 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -11,6 +11,14 @@ from .widgets import ( from .lib import NOT_SET, AS_WIDGET +class SchemeGroupHierarchyBug(Exception): + def __init__(self, msg=None): + if not msg: + # TODO better message + msg = "SCHEME BUG: Attribute `is_group` is mixed in the hierarchy" + super(SchemeGroupHierarchyBug, self).__init(msg) + + class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal() @@ -20,8 +28,19 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._as_widget = values is AS_WIDGET self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(BooleanWidget, self).__init__(parent) @@ -122,8 +141,19 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(IntegerWidget, self).__init__(parent) @@ -225,8 +255,19 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(FloatWidget, self).__init__(parent) @@ -338,8 +379,19 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(TextSingleLineWidget, self).__init__(parent) @@ -440,8 +492,19 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group self.is_modified = False - self.is_group = False self.is_overriden = False super(TextMultiLineWidget, self).__init__(parent) @@ -699,8 +762,16 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + self.is_modified = False - self.is_group = False + self.is_group = is_group self.is_overriden = False super(TextListWidget, self).__init__(parent) @@ -747,7 +818,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_group and self.is_overidable: + self.is_overriden = True self._update_style() @@ -798,9 +870,19 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): )) self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False - self.is_overriden = False - self.is_group = input_data.get("is_group", False) + self._is_overriden = False + self.is_group = is_group super(DictExpandWidget, self).__init__(parent) self.setObjectName("DictExpandWidget") @@ -850,7 +932,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) - self._is_overriden = False self.input_fields = [] self.key = input_data["key"] @@ -881,8 +962,15 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): super(DictExpandWidget, self).resizeEvent(event) self.content_widget.updateGeometry() + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + + def _on_value_change(self, value=None): - self.is_overriden = True + if self.is_group: + self._is_overriden = True self.value_changed.emit() @@ -966,9 +1054,19 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False self.is_overriden = False - self.is_group = input_data.get("is_group", False) + self.is_group = is_group super(DictInvisible, self).__init__(parent) self.setObjectName("DictInvisible") @@ -979,7 +1077,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self._is_overriden = False self.input_fields = [] if "key" not in input_data: @@ -1047,6 +1144,12 @@ class DictFormWidget(QtWidgets.QWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False self.is_overriden = False self.is_group = False @@ -1168,6 +1271,14 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): self._update_style() self.value_changed.emit() + @property + def is_group(self): + return self._parent.is_group + + @property + def any_parent_is_group(self): + return self._parent.any_parent_is_group + @property def is_overidable(self): return self._parent.is_overidable @@ -1253,6 +1364,14 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_overidable(self): return self._parent.is_overidable + @property + def is_group(self): + return self._parent.is_group + + @property + def any_parent_is_group(self): + return self._parent.any_parent_is_group + def _on_value_change(self): self.value_changed.emit() @@ -1324,10 +1443,20 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): ): self._parent = parent + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + self.is_modified = False self.child_modified = False self.is_overriden = False - self.is_group = input_data.get("is_group", False) + self.is_group = is_group super(ModifiableDict, self).__init__(input_data["label"], parent) self.setObjectName("ModifiableDict") @@ -1346,7 +1475,8 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.child_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_group: + self.is_overriden = True self._update_style() From 9ef5bad10ea76dfe8beccd0925403715658c779b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 27 Jul 2020 18:57:49 +0200 Subject: [PATCH 042/580] added first testing groups --- .../config_gui_schema/ftrack_projects_gui_schema.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json index febf84eb4a..2e930acca5 100644 --- a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json @@ -7,6 +7,7 @@ "key": "status_update", "type": "dict-expanding", "label": "Status updates", + "is_group": true, "children": [ { "key": "Ready", @@ -18,6 +19,7 @@ "key": "status_version_to_task", "type": "dict-expanding", "label": "Version status to Task status", + "is_group": true, "children": [ { "key": "in progress", From 9ec21131f3e258aea80cb762fc03a56eab0e627b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 28 Jul 2020 10:44:15 +0200 Subject: [PATCH 043/580] just fast commit --- pype/tools/config_setting/widgets/inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 485eda6d35..c094dcd9db 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -966,7 +966,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_overriden(self): if self._is_overriden: return self._is_overriden - + return self._parent.is_overriden def _on_value_change(self, value=None): if self.is_group: From d234181f93d17de70706b2cd26b1c5fe0ec4a8e8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 28 Jul 2020 17:08:56 +0200 Subject: [PATCH 044/580] added second item for testing --- .../config_gui_schema/ftrack_projects_gui_schema.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json index 2e930acca5..4a35fc9b61 100644 --- a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json @@ -13,6 +13,10 @@ "key": "Ready", "type": "text-singleline", "label": "Ready" + }, { + "key": "Ready2", + "type": "text-singleline", + "label": "Ready2" } ] }, { From 57a040fadbfbba1e672c3abb7ab044ac0be908aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 28 Jul 2020 17:28:14 +0200 Subject: [PATCH 045/580] better overridable control --- pype/tools/config_setting/widgets/base.py | 4 +- pype/tools/config_setting/widgets/inputs.py | 195 +++++++++++++------- 2 files changed, 128 insertions(+), 71 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 222cf2ba41..ddeae365d8 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -50,6 +50,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): "config_gui_schema" ) is_overidable = False + is_overriden = False is_group = False any_parent_is_group = False @@ -257,13 +258,14 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): os.path.dirname(os.path.dirname(__file__)), "config_gui_schema" ) - is_overidable = True + is_overriden = False is_group = False any_parent_is_group = False def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) + self.is_overidable = True self.input_fields = [] scroll_widget = QtWidgets.QScrollArea(self) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index c094dcd9db..2b1b5b3af6 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -41,7 +41,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False - self.is_overriden = False + self._is_overriden = False super(BooleanWidget, self).__init__(parent) @@ -92,26 +92,33 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_overidable: + self._is_overriden = True self._update_style() self.value_changed.emit() def _update_style(self): - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" + is_overriden = self.is_overriden + if is_overriden and self.is_modified: + state = "overriden-modified" + elif is_overriden: + state = "overriden" elif self.is_modified: state = "modified" else: @@ -154,7 +161,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False - self.is_overriden = False + self._is_overriden = False super(IntegerWidget, self).__init__(parent) @@ -192,12 +199,18 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def set_value(self, value, origin_value=False): self.int_input.setValue(value) if origin_value: @@ -212,18 +225,19 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_overidable: + self._is_overriden = True self._update_style() self.value_changed.emit() def _update_style(self): - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" + is_overriden = self.is_overriden + if is_overriden and self.is_modified: + state = "overriden-modified" + elif is_overriden: + state = "overriden" elif self.is_modified: state = "modified" else: @@ -268,7 +282,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False - self.is_overriden = False + self._is_overriden = False super(FloatWidget, self).__init__(parent) @@ -316,12 +330,18 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def set_value(self, value, origin_value=False): self.float_input.setValue(value) if origin_value: @@ -336,18 +356,19 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_overidable: + self._is_overriden = True self._update_style() self.value_changed.emit() def _update_style(self): - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" + is_overriden = self.is_overriden + if is_overriden and self.is_modified: + state = "overriden-modified" + elif is_overriden: + state = "overriden" elif self.is_modified: state = "modified" else: @@ -392,7 +413,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False - self.is_overriden = False + self._is_overriden = False super(TextSingleLineWidget, self).__init__(parent) @@ -430,12 +451,18 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def set_value(self, value, origin_value=False): self.text_input.setText(value) if origin_value: @@ -450,18 +477,19 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_overidable: + self._is_overriden = True self._update_style() self.value_changed.emit() def _update_style(self): - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" + is_overriden = self.is_overriden + if is_overriden and self.is_modified: + state = "overriden-modified" + elif is_overriden: + state = "overriden" elif self.is_modified: state = "modified" else: @@ -505,7 +533,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False - self.is_overriden = False + self._is_overriden = False super(TextMultiLineWidget, self).__init__(parent) @@ -541,12 +569,18 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def set_value(self, value, origin_value=False): self.text_input.setPlainText(value) if origin_value: @@ -561,18 +595,19 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - self.is_overriden = True + if self.is_overidable: + self._is_overriden = True self._update_style() self.value_changed.emit() def _update_style(self): - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" + is_overriden = self.is_overriden + if is_overriden and self.is_modified: + state = "overriden-modified" + elif is_overriden: + state = "overriden" elif self.is_modified: state = "modified" else: @@ -770,9 +805,12 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): if is_group and any_parent_is_group: raise SchemeGroupHierarchyBug() + if not any_parent_is_group and not is_group: + is_group = True + self.is_modified = False self.is_group = is_group - self.is_overriden = False + self._is_overriden = False super(TextListWidget, self).__init__(parent) self.setObjectName("TextListWidget") @@ -810,16 +848,22 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def _on_value_change(self, value=None): self.is_modified = self.item_value() != self.origin_value - if self.is_group and self.is_overidable: - self.is_overriden = True + if self.is_overidable: + self._is_overriden = True self._update_style() @@ -838,11 +882,11 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value([]) def _update_style(self): - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" + is_overriden = self.is_overriden + if is_overriden and self.is_modified: + state = "overriden-modified" + elif is_overriden: + state = "overriden" elif self.is_modified: state = "modified" else: @@ -969,7 +1013,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def _on_value_change(self, value=None): - if self.is_group: + if self.is_group and self.is_overidable: self._is_overriden = True self.value_changed.emit() @@ -992,13 +1036,10 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.setProperty("state", widget_state) self.style().polish(self) - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" - elif self.is_modified: - state = "modified" + if child_modified and self.is_overriden: + state = "overriden-modified" + elif self.is_overriden: + state = "overriden" else: state = "original" @@ -1065,7 +1106,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): self.any_parent_is_group = any_parent_is_group self.is_modified = False - self.is_overriden = False self.is_group = is_group super(DictInvisible, self).__init__(parent) @@ -1089,6 +1129,10 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + @property + def is_overriden(self): + return self._parent.is_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -1184,7 +1228,7 @@ class DictFormWidget(QtWidgets.QWidget): @property def child_overriden(self): - for input_field in self.input_fields: + for input_field in self.input_fields.values(): if input_field.child_overriden: return True return False @@ -1283,6 +1327,10 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + return self._parent.is_overriden + def is_key_modified(self): return self._key() != self.origin_key @@ -1364,6 +1412,10 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + return self._parent.is_overriden + @property def is_group(self): return self._parent.is_group @@ -1455,7 +1507,7 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.is_modified = False self.child_modified = False - self.is_overriden = False + self._is_overriden = False self.is_group = is_group super(ModifiableDict, self).__init__(input_data["label"], parent) @@ -1475,19 +1527,25 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def _on_value_change(self, value=None): self.child_modified = self.item_value() != self.origin_value - if self.is_group: - self.is_overriden = True + if self.is_group and self.is_overidable: + self._is_overriden = True self._update_style() @property def child_overriden(self): - return self.is_overriden + return self._is_overriden @property def is_overidable(self): return self._parent.is_overidable + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + def _update_style(self): child_modified = self.child_modified child_overriden = self.child_overriden @@ -1504,13 +1562,10 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.setProperty("state", widget_state) self.style().polish(self) - if self.is_overidable and self.is_overriden: - if self.is_modified: - state = "overriden-modified" - else: - state = "overriden" - elif self.is_modified: - state = "modified" + if child_modified and self.is_overriden: + state = "overriden-modified" + elif self.is_overriden: + state = "overriden" else: state = "original" From f7323144e0073b2201aadaf02627390b28354db2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 28 Jul 2020 18:54:22 +0200 Subject: [PATCH 046/580] working overriden workflow --- pype/tools/config_setting/style/style.css | 6 - pype/tools/config_setting/widgets/base.py | 10 + pype/tools/config_setting/widgets/inputs.py | 313 ++++++++++---------- 3 files changed, 171 insertions(+), 158 deletions(-) diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css index 1371056c1a..aabffc3f84 100644 --- a/pype/tools/config_setting/style/style.css +++ b/pype/tools/config_setting/style/style.css @@ -19,8 +19,6 @@ QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus { border: 1px solid #ffffff; } -QLabel[state="original"] {} - QLabel[state="modified"] { color: #137cbd; } @@ -33,8 +31,6 @@ QLabel[state="overriden"] { color: #ff8c1a; } -QWidget[input-state="original"] {} - QWidget[input-state="modified"] { border-color: #137cbd; } @@ -61,8 +57,6 @@ QPushButton[btn-type="expand-toggle"] { background: transparent; } -#DictKey[state="original"] {} - #DictKey[state="modified"] { border-color: #137cbd; } diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index ddeae365d8..e01f14aa70 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -12,6 +12,8 @@ class TypeToKlass: class PypeConfigurationWidget: + default_state = "" + def config_value(self): raise NotImplementedError( "Method `config_value` is not implemented for `{}`.".format( @@ -38,6 +40,14 @@ class PypeConfigurationWidget: value = value[key] return value + def style_state(self, is_overriden, is_modified): + items = [] + if is_overriden: + items.append("overriden") + if is_modified: + items.append("modified") + return "-".join(items) or self.default_state + def add_children_gui(self, child_configuration, values): raise NotImplementedError(( "Method `add_children_gui` is not implemented for `{}`." diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 2b1b5b3af6..e5b929b7ca 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -20,7 +20,7 @@ class SchemeGroupHierarchyBug(Exception): class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -43,6 +43,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_modified = False self._is_overriden = False + self._state = None + super(BooleanWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -104,25 +106,23 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() - self.value_changed.emit() + self.value_changed.emit(self) - def _update_style(self): - is_overriden = self.is_overriden - if is_overriden and self.is_modified: - state = "overriden-modified" - elif is_overriden: - state = "overriden" - elif self.is_modified: - state = "modified" - else: - state = "original" + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return if self._as_widget: property_name = "input-state" @@ -131,6 +131,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.label_widget.setProperty(property_name, state) self.label_widget.style().polish(self.label_widget) + self._state = state def item_value(self): return self.checkbox.isChecked() @@ -140,7 +141,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -163,6 +164,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_modified = False self._is_overriden = False + self._state = None + super(IntegerWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -223,25 +226,23 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset_value(self): self.set_value(self.origin_value) - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() - self.value_changed.emit() + self.value_changed.emit(self) - def _update_style(self): - is_overriden = self.is_overriden - if is_overriden and self.is_modified: - state = "overriden-modified" - elif is_overriden: - state = "overriden" - elif self.is_modified: - state = "modified" - else: - state = "original" + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return if self._as_widget: property_name = "input-state" @@ -261,7 +262,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -284,6 +285,8 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_modified = False self._is_overriden = False + self._state = None + super(FloatWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -354,25 +357,23 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value(0) - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() - self.value_changed.emit() + self.value_changed.emit(self) - def _update_style(self): - is_overriden = self.is_overriden - if is_overriden and self.is_modified: - state = "overriden-modified" - elif is_overriden: - state = "overriden" - elif self.is_modified: - state = "modified" - else: - state = "original" + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return if self._as_widget: property_name = "input-state" @@ -392,7 +393,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -415,6 +416,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_modified = False self._is_overriden = False + self._state = None + super(TextSingleLineWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -475,25 +478,23 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value("") - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() - self.value_changed.emit() + self.value_changed.emit(self) - def _update_style(self): - is_overriden = self.is_overriden - if is_overriden and self.is_modified: - state = "overriden-modified" - elif is_overriden: - state = "overriden" - elif self.is_modified: - state = "modified" - else: - state = "original" + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return if self._as_widget: property_name = "input-state" @@ -513,7 +514,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -535,6 +536,8 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_modified = False self._is_overriden = False + self._state = None + super(TextMultiLineWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -593,25 +596,23 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value("") - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() - self.value_changed.emit() + self.value_changed.emit(self) - def _update_style(self): - is_overriden = self.is_overriden - if is_overriden and self.is_modified: - state = "overriden-modified" - elif is_overriden: - state = "overriden" - elif self.is_modified: - state = "modified" - else: - state = "original" + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return if self._as_widget: property_name = "input-state" @@ -632,7 +633,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__(self, parent): super(TextListItem, self).__init__(parent) @@ -661,8 +662,8 @@ class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): self.is_single = False - def _on_value_change(self): - self.value_changed.emit() + def _on_value_change(self, item=None): + self.value_changed.emit(self) def row(self): return self.parent().input_fields.index(self) @@ -681,7 +682,7 @@ class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): super(TextListSubWidget, self).__init__(parent) @@ -723,8 +724,8 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value([]) - def _on_value_change(self): - self.value_changed.emit() + def _on_value_change(self, item=None): + self.value_changed.emit(self) def count(self): return len(self.input_fields) @@ -790,7 +791,7 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -812,6 +813,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self._is_overriden = False + self._state = None + super(TextListWidget, self).__init__(parent) self.setObjectName("TextListWidget") @@ -860,14 +863,14 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() - self.value_changed.emit() + self.value_changed.emit(self) def set_value(self, value, origin_value=False): self.value_widget.set_value(value) @@ -881,16 +884,14 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value([]) - def _update_style(self): - is_overriden = self.is_overriden - if is_overriden and self.is_modified: - state = "overriden-modified" - elif is_overriden: - state = "overriden" - elif self.is_modified: - state = "modified" - else: - state = "original" + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return self.label_widget.setProperty("state", state) self.label_widget.style().polish(self.label_widget) @@ -903,7 +904,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -928,6 +929,9 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._is_overriden = False self.is_group = is_group + self._state = None + self._child_state = None + super(DictExpandWidget, self).__init__(parent) self.setObjectName("DictExpandWidget") top_part = ClickableWidget(parent=self) @@ -1012,40 +1016,50 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def _on_value_change(self, value=None): - if self.is_group and self.is_overidable: - self._is_overriden = True + def _on_value_change(self, item=None): + if self.is_group: + if self.is_overidable: + self._is_overriden = True + # TODO update items + if item is not None: + is_overriden = self.is_overriden + for _item in self.input_fields: + if _item is not item: + _item.update_style(is_overriden) - self.value_changed.emit() + self.value_changed.emit(self) - self._update_style() + self.update_style() - def _update_style(self): + def update_style(self, is_overriden=None): child_modified = self.child_modified - child_overriden = self.child_overriden + if is_overriden is None: + child_overriden = self.child_overriden + child_state = self.style_state(child_overriden, child_modified) + if child_state: + child_state = "child-{}".format(child_state) - if child_modified and child_overriden: - widget_state = "child-overriden-modified" - elif child_modified: - widget_state = "child-modified" - elif child_overriden: - widget_state = "child-overriden" + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state + + if is_overriden is None: + is_overriden = self.is_overriden + + if child_modified and not is_overriden: + state = self.default_state else: - widget_state = "" + state = self.style_state(is_overriden, child_modified) - self.setProperty("state", widget_state) - self.style().polish(self) - - if child_modified and self.is_overriden: - state = "overriden-modified" - elif self.is_overriden: - state = "overriden" - else: - state = "original" + if self._state == state: + return self.button_toggle_text.setProperty("state", state) self.button_toggle_text.style().polish(self.button_toggle_text) + self._state = state + @property def child_modified(self): for input_field in self.input_fields: @@ -1181,7 +1195,7 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): class DictFormWidget(QtWidgets.QWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -1208,8 +1222,8 @@ class DictFormWidget(QtWidgets.QWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) - def _on_value_change(self): - self.value_changed.emit() + def _on_value_change(self, item=None): + self.value_changed.emit(self) def item_value(self): output = {} @@ -1261,7 +1275,7 @@ class DictFormWidget(QtWidgets.QWidget): class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__(self, object_type, parent): self._parent = parent @@ -1311,9 +1325,9 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def _key(self): return self.key_input.text() - def _on_value_change(self): - self._update_style() - self.value_changed.emit() + def _on_value_change(self, item=None): + self.update_style() + self.value_changed.emit(self) @property def is_group(self): @@ -1341,16 +1355,11 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def is_modified(self): return self.is_value_modified() or self.is_key_modified() - def _update_style(self): - # if self._is_overidable and self.is_overriden: - # if is_modified: - # state = "overriden-modified" - # else: - # state = "overriden" + def update_style(self, is_overriden=None): if self.is_key_modified(): state = "modified" else: - state = "original" + state = "" self.key_input.setProperty("state", state) self.key_input.style().polish(self.key_input) @@ -1377,7 +1386,7 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): self._parent = parent @@ -1424,8 +1433,8 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def any_parent_is_group(self): return self._parent.any_parent_is_group - def _on_value_change(self): - self.value_changed.emit() + def _on_value_change(self, item=None): + self.value_changed.emit(self) def count(self): return len(self.input_fields) @@ -1503,6 +1512,9 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): if is_group and any_parent_is_group: raise SchemeGroupHierarchyBug() + if not any_parent_is_group and not is_group: + is_group = True + self.any_parent_is_group = any_parent_is_group self.is_modified = False @@ -1525,12 +1537,12 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.origin_value = self.item_value() - def _on_value_change(self, value=None): + def _on_value_change(self, item=None): self.child_modified = self.item_value() != self.origin_value if self.is_group and self.is_overidable: self._is_overriden = True - self._update_style() + self.update_style() @property def child_overriden(self): @@ -1546,32 +1558,29 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def _update_style(self): + def update_style(self, is_overriden=None): child_modified = self.child_modified - child_overriden = self.child_overriden + if is_overriden is None: + child_overriden = self.child_overriden + child_state = self.style_state(child_overriden, child_modified) + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state - if child_modified and child_overriden: - widget_state = "child-overriden-modified" - elif child_modified: - widget_state = "child-modified" - elif child_overriden: - widget_state = "child-overriden" + if is_overriden is None: + is_overriden = self.is_overriden + + if child_modified and not is_overriden: + state = self.default_state else: - widget_state = "" - - self.setProperty("state", widget_state) - self.style().polish(self) - - if child_modified and self.is_overriden: - state = "overriden-modified" - elif self.is_overriden: - state = "overriden" - else: - state = "original" + state = self.style_state(self.is_overriden, child_modified) self.label_widget.setProperty("state", state) self.label_widget.style().polish(self.label_widget) + self._state = state + def item_value(self): return self.value_widget.config_value() From ec7bbcf19e4fe59437f8daee3ba3c591e25ab6d0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 29 Jul 2020 15:55:22 +0200 Subject: [PATCH 047/580] small bugfixes and added rawjson widget --- .../config_gui_schema/plugins_gui_schema.json | 24 +++ .../config_gui_schema/project_gui_schema.json | 3 +- pype/tools/config_setting/widgets/base.py | 57 ++++--- pype/tools/config_setting/widgets/inputs.py | 139 +++++++++++++++++- 4 files changed, 198 insertions(+), 25 deletions(-) create mode 100644 pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json b/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json new file mode 100644 index 0000000000..79c1f85b85 --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json @@ -0,0 +1,24 @@ +{ + "key": "plugins", + "type": "dict-expanding", + "label": "Plugins", + "children": [ + { + "key": "maya", + "type": "dict-expanding", + "label": "Maya", + "is_group": true, + "children": [ + { + "key": "test1", + "type": "raw-json", + "label": "Test1" + }, { + "key": "test2", + "type": "raw-json", + "label": "Test2" + } + ] + } + ] +} diff --git a/pype/tools/config_setting/config_gui_schema/project_gui_schema.json b/pype/tools/config_setting/config_gui_schema/project_gui_schema.json index 38c07ec33d..d2a6221f99 100644 --- a/pype/tools/config_setting/config_gui_schema/project_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/project_gui_schema.json @@ -6,7 +6,8 @@ { "type": "schema", "children": [ - "ftrack_projects_gui_schema" + "ftrack_projects_gui_schema", + "plugins_gui_schema" ] } ] diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index e01f14aa70..52184b4c8a 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -177,6 +177,7 @@ class ProjectListView(QtWidgets.QListView): class ProjectListWidget(QtWidgets.QWidget): default = "< Default >" + project_changed = QtCore.Signal() def __init__(self, parent): self._parent = parent @@ -218,6 +219,10 @@ class ProjectListWidget(QtWidgets.QWidget): if self.validate_context_change(): self.select_project(new_project_name) self.current_project = new_project_name + self.project_changed.emit() + return + + self.select_project(self.current_project) def validate_context_change(self): # TODO add check if project can be changed (is modified) @@ -275,7 +280,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) - self.is_overidable = True + self.is_overidable = False self.input_fields = [] scroll_widget = QtWidgets.QScrollArea(self) @@ -292,23 +297,13 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): project_list_widget = ProjectListWidget(self) content_layout.addWidget(project_list_widget) - self.project_list_widget = project_list_widget - self.scroll_widget = scroll_widget - self.content_layout = content_layout - self.content_widget = content_widget - - values = config.project_presets() - schema = config.gui_schema("project_gui_schema") - self.keys = schema.get("keys", []) - self.add_children_gui(schema, values) - footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) - btn = QtWidgets.QPushButton("Finish") + save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() footer_layout.addWidget(spacer_widget, 1) - footer_layout.addWidget(btn, 0) + footer_layout.addWidget(save_btn, 0) presets_widget = QtWidgets.QWidget() presets_layout = QtWidgets.QVBoxLayout(presets_widget) @@ -326,18 +321,18 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): layout.addWidget(project_list_widget, 0) layout.addWidget(presets_widget, 1) - btn.clicked.connect(self.___finish) + save_btn.clicked.connect(self._save) + project_list_widget.project_changed.connect(self._on_project_change) - def ___finish(self): - output = {} - for item in self.input_fields: - output.update(item.config_value()) + self.project_list_widget = project_list_widget + self.scroll_widget = scroll_widget + self.content_layout = content_layout + self.content_widget = content_widget - for key in reversed(self.keys): - _output = {key: output} - output = _output - - print(json.dumps(output, indent=4)) + values = config.global_project_presets() + schema = config.gui_schema("project_gui_schema") + self.keys = schema.get("keys", []) + self.add_children_gui(schema, values) def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] @@ -348,3 +343,19 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): ) self.input_fields.append(item) self.content_layout.addWidget(item) + + def _on_project_change(self): + self.is_overidable = ( + self.project_list_widget.project_name() is not None + ) + + def _save(self): + output = {} + for item in self.input_fields: + output.update(item.config_value()) + + for key in reversed(self.keys): + _output = {key: output} + output = _output + + print(json.dumps(output, indent=4)) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index e5b929b7ca..58898aeccb 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1,5 +1,5 @@ import json -from Qt import QtWidgets, QtCore +from Qt import QtWidgets, QtCore, QtGui from . import config from .base import PypeConfigurationWidget, TypeToKlass from .widgets import ( @@ -520,6 +520,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self, input_data, values, parent_keys, parent, label_widget=None ): self._parent = parent + self._as_widget = values is AS_WIDGET any_parent_is_group = parent.is_group if not any_parent_is_group: @@ -631,6 +632,141 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: self.item_value()} +class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + self._as_widget = values is AS_WIDGET + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + if not any_parent_is_group and not is_group: + is_group = True + + self.is_group = is_group + self.is_modified = False + self._is_overriden = False + + self._state = None + + super(RawJsonWidget, self).__init__(parent) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + self.text_input = QtWidgets.QPlainTextEdit() + self.text_input.setTabStopDistance( + QtGui.QFontMetricsF( + self.text_input.font() + ).horizontalAdvance(" ") * 4 + ) + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + layout.addWidget(self.text_input) + + self.label_widget = label_widget + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + value = self.value_from_values(values) + if value is not NOT_SET: + self.text_input.setPlainText(value) + + self.origin_value = self.item_value() + + self.text_input.textChanged.connect(self._on_value_change) + + @property + def child_modified(self): + return self.is_modified + + @property + def child_overriden(self): + return self._is_overriden + + @property + def is_overidable(self): + return self._parent.is_overidable + + @property + def is_overriden(self): + if self._is_overriden: + return self._is_overriden + return self._parent.is_overriden + + def validate_value(self, value): + try: + json.dumps(value) + return True + except Exception: + return False + + def set_value(self, value, origin_value=False): + is_valid = self.validate_value(value) + if is_valid: + value = json.dumps(value, indent=4) + self.text_input.setPlainText(value) + + if origin_value: + self.origin_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.origin_value) + + def clear_value(self): + self.set_value("{{}}") + + def _on_value_change(self, item=None): + self.is_modified = self.item_value() != self.origin_value + if self.is_overidable: + self._is_overriden = True + + self.update_style() + + self.value_changed.emit(self) + + def update_style(self, is_overriden=None): + if is_overriden is None: + is_overriden = self.is_overriden + is_modified = self.is_modified + + state = self.style_state(is_overriden, is_modified) + if self._state == state: + return + + if self._as_widget: + property_name = "input-state" + widget = self.text_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) + + def item_value(self): + return self.text_input.toPlainText() + + def config_value(self): + return {self.key: self.item_value()} + + class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1591,6 +1727,7 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["text-singleline"] = TextSingleLineWidget TypeToKlass.types["text-multiline"] = TextMultiLineWidget +TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["int"] = IntegerWidget TypeToKlass.types["float"] = FloatWidget TypeToKlass.types["dict-expanding"] = DictExpandWidget From 0ab6161193abfc2066edc230d143bb4064a055e6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 29 Jul 2020 16:07:45 +0200 Subject: [PATCH 048/580] minor changes in raw json --- pype/tools/config_setting/style/style.css | 4 ++++ pype/tools/config_setting/widgets/inputs.py | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css index aabffc3f84..adf8344f89 100644 --- a/pype/tools/config_setting/style/style.css +++ b/pype/tools/config_setting/style/style.css @@ -57,6 +57,10 @@ QPushButton[btn-type="expand-toggle"] { background: transparent; } +#RawJson[state="invalid"] { + border-color: #ff5511; +} + #DictKey[state="modified"] { border-color: #137cbd; } diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 58898aeccb..50bd3d58f4 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -658,6 +658,8 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._state = None + self.is_valid = None + super(RawJsonWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) @@ -665,6 +667,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): layout.setSpacing(0) self.text_input = QtWidgets.QPlainTextEdit() + self.text_input.setObjectName("RawJson") self.text_input.setTabStopDistance( QtGui.QFontMetricsF( self.text_input.font() @@ -710,6 +713,8 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def validate_value(self, value): + if not value: + return True try: json.dumps(value) return True @@ -720,6 +725,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_valid = self.validate_value(value) if is_valid: value = json.dumps(value, indent=4) + self.text_input.setPlainText(value) if origin_value: @@ -730,13 +736,23 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.origin_value) def clear_value(self): - self.set_value("{{}}") + self.set_value("") def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + value = self.item_value() + self.is_modified = value != self.origin_value if self.is_overidable: self._is_overriden = True + is_valid = self.validate_value(value) + if is_valid != self.is_valid: + self.is_valid = is_valid + if is_valid: + state = "" + else: + state = "invalid" + self.text_input.setProperty("state", state) + self.text_input.style().polish(self.text_input) self.update_style() self.value_changed.emit(self) From 7f156a957e9eabce4d214a573cdb55bf0303796e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 10:47:09 +0200 Subject: [PATCH 049/580] input have is_modified property methods and was_overriden attribute --- pype/tools/config_setting/widgets/inputs.py | 65 ++++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 50bd3d58f4..5fadf2ee60 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -40,7 +40,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_group = True self.is_group = is_group - self.is_modified = False + self._is_modified = False + self.was_overriden = False self._is_overriden = False self._state = None @@ -96,6 +97,10 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -107,7 +112,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True @@ -161,7 +166,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_group = True self.is_group = is_group - self.is_modified = False + self._is_modified = False + self.was_overriden = False self._is_overriden = False self._state = None @@ -204,6 +210,10 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -227,7 +237,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.origin_value) def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True @@ -282,7 +292,8 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_group = True self.is_group = is_group - self.is_modified = False + self._is_modified = False + self.was_overriden = False self._is_overriden = False self._state = None @@ -335,6 +346,10 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -358,7 +373,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(0) def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True @@ -413,7 +428,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_group = True self.is_group = is_group - self.is_modified = False + self._is_modified = False + self.was_overriden = False self._is_overriden = False self._state = None @@ -456,6 +472,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -479,7 +499,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value("") def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True @@ -535,6 +555,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False + self.was_overriden = False self._is_overriden = False self._state = None @@ -575,6 +596,10 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -598,7 +623,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value("") def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True @@ -653,7 +678,8 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_group = True self.is_group = is_group - self.is_modified = False + self._is_modified = False + self.was_overriden = False self._is_overriden = False self._state = None @@ -702,6 +728,10 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -740,7 +770,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_value_change(self, item=None): value = self.item_value() - self.is_modified = value != self.origin_value + self._is_modified = value != self.origin_value if self.is_overidable: self._is_overriden = True @@ -961,7 +991,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): if not any_parent_is_group and not is_group: is_group = True - self.is_modified = False + self._is_modified = False self.is_group = is_group self._is_overriden = False @@ -1005,6 +1035,10 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def child_overriden(self): return self._is_overriden + @property + def is_modified(self): + return self._is_modified + @property def is_overidable(self): return self._parent.is_overidable @@ -1016,7 +1050,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def _on_value_change(self, item=None): - self.is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.origin_value if self.is_overidable: self._is_overriden = True @@ -1713,6 +1747,8 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def update_style(self, is_overriden=None): child_modified = self.child_modified if is_overriden is None: + is_overriden = self.is_overriden + child_overriden = self.child_overriden child_state = self.style_state(child_overriden, child_modified) if child_state != self._child_state: @@ -1720,9 +1756,6 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.style().polish(self) self._child_state = child_state - if is_overriden is None: - is_overriden = self.is_overriden - if child_modified and not is_overriden: state = self.default_state else: From fde11ec034de0d9f414119c878dcb007f7603b9c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 11:15:05 +0200 Subject: [PATCH 050/580] is_modified also looks if overridatio nhas changed --- pype/tools/config_setting/widgets/inputs.py | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 5fadf2ee60..052520d8d5 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -41,7 +41,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self._is_modified = False - self.was_overriden = False + self._was_overriden = False self._is_overriden = False self._state = None @@ -99,7 +99,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -167,7 +167,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self._is_modified = False - self.was_overriden = False + self._was_overriden = False self._is_overriden = False self._state = None @@ -212,7 +212,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -293,7 +293,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self._is_modified = False - self.was_overriden = False + self._was_overriden = False self._is_overriden = False self._state = None @@ -348,7 +348,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -429,7 +429,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self._is_modified = False - self.was_overriden = False + self._was_overriden = False self._is_overriden = False self._state = None @@ -474,7 +474,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -555,7 +555,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self.is_modified = False - self.was_overriden = False + self._was_overriden = False self._is_overriden = False self._state = None @@ -598,7 +598,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -679,7 +679,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_group = is_group self._is_modified = False - self.was_overriden = False + self._was_overriden = False self._is_overriden = False self._state = None @@ -730,7 +730,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -993,6 +993,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._is_modified = False self.is_group = is_group + self._was_overriden = False self._is_overriden = False self._state = None @@ -1037,7 +1038,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): From 2a4a81bde19fe47a01d03c79af9878a6d170c86d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 14:45:27 +0200 Subject: [PATCH 051/580] raw json input has special input widget --- pype/tools/config_setting/style/style.css | 2 +- pype/tools/config_setting/widgets/inputs.py | 90 ++++++++++++++------- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/style/style.css index adf8344f89..a0c5db86a1 100644 --- a/pype/tools/config_setting/style/style.css +++ b/pype/tools/config_setting/style/style.css @@ -57,7 +57,7 @@ QPushButton[btn-type="expand-toggle"] { background: transparent; } -#RawJson[state="invalid"] { +#RawJsonInput[state="invalid"] { border-color: #ff5511; } diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 052520d8d5..bd7d4b501f 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -657,6 +657,63 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: self.item_value()} +class RawJsonInput(QtWidgets.QPlainTextEdit): + tab_length = 4 + + def __init__(self, *args, **kwargs): + super(RawJsonInput, self).__init__(*args, **kwargs) + self.setObjectName("RawJsonInput") + self.setTabStopDistance( + QtGui.QFontMetricsF( + self.font() + ).horizontalAdvance(" ") * self.tab_length + ) + + self.is_valid = None + + def set_value(self, value): + self.setPlainText(value) + + def setPlainText(self, *args, **kwargs): + super(RawJsonInput, self).setPlainText(*args, **kwargs) + self.validate() + + def focusOutEvent(self, event): + super(RawJsonInput, self).focusOutEvent(event) + self.validate() + + def validate_value(self, value): + if isinstance(value, str) and not value: + return True + + try: + json.loads(value) + return True + except Exception: + return False + + def update_style(self, is_valid=None): + if is_valid is None: + return self.validate() + + if is_valid != self.is_valid: + self.is_valid = is_valid + if is_valid: + state = "" + else: + state = "invalid" + self.setProperty("state", state) + self.style().polish(self) + + def value(self): + return self.toPlainText() + + def validate(self): + value = self.value() + is_valid = self.validate_value(value) + self.update_style(is_valid) + + class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal(object) @@ -684,21 +741,14 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._state = None - self.is_valid = None - super(RawJsonWidget, self).__init__(parent) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) - self.text_input = QtWidgets.QPlainTextEdit() - self.text_input.setObjectName("RawJson") - self.text_input.setTabStopDistance( - QtGui.QFontMetricsF( - self.text_input.font() - ).horizontalAdvance(" ") * 4 - ) + self.text_input = RawJsonInput() + if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) @@ -742,20 +792,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def validate_value(self, value): - if not value: - return True - try: - json.dumps(value) - return True - except Exception: - return False - def set_value(self, value, origin_value=False): - is_valid = self.validate_value(value) - if is_valid: - value = json.dumps(value, indent=4) - self.text_input.setPlainText(value) if origin_value: @@ -774,15 +811,6 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): if self.is_overidable: self._is_overriden = True - is_valid = self.validate_value(value) - if is_valid != self.is_valid: - self.is_valid = is_valid - if is_valid: - state = "" - else: - state = "invalid" - self.text_input.setProperty("state", state) - self.text_input.style().polish(self.text_input) self.update_style() self.value_changed.emit(self) From fb2681f98618b41a54e6dabc78364acf7b6a391c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 15:53:55 +0200 Subject: [PATCH 052/580] renamed origin_value to default_value --- pype/tools/config_setting/widgets/inputs.py | 106 ++++++++++---------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index bd7d4b501f..e3e60612cc 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -73,22 +73,24 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.checkbox.setChecked(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() self.checkbox.stateChanged.connect(self._on_value_change) - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.checkbox.setChecked(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.reset_value() + def apply_overrides(self, overrides): + @property def child_modified(self): return self.is_modified @@ -112,7 +114,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -198,7 +200,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.int_input.setValue(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() self.int_input.valueChanged.connect(self._on_value_change) @@ -224,20 +226,20 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.int_input.setValue(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def clear_value(self): self.set_value(0) def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -334,7 +336,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.float_input.setValue(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() self.float_input.valueChanged.connect(self._on_value_change) @@ -360,20 +362,20 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.float_input.setValue(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.set_value(0) def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -460,7 +462,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.text_input.setText(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() self.text_input.textChanged.connect(self._on_value_change) @@ -486,20 +488,20 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.text_input.setText(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.set_value("") def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -584,7 +586,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.text_input.setPlainText(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() self.text_input.textChanged.connect(self._on_value_change) @@ -610,20 +612,20 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.text_input.setPlainText(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.set_value("") def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -766,7 +768,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.text_input.setPlainText(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() self.text_input.textChanged.connect(self._on_value_change) @@ -792,22 +794,22 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.text_input.setPlainText(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.set_value("") def _on_value_change(self, item=None): value = self.item_value() - self._is_modified = value != self.origin_value + self._is_modified = value != self.default_value if self.is_overidable: self._is_overriden = True @@ -915,21 +917,21 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: self.set_value(value) - self.origin_value = self.item_value() + self.default_value = self.item_value() - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): for input_field in self.input_fields: self.remove_row(input_field) for item_text in value: self.add_row(text=item_text) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.set_value([]) @@ -1054,7 +1056,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): layout.addWidget(self.value_widget) self.setLayout(layout) - self.origin_value = self.item_value() + self.default_value = self.item_value() @property def child_modified(self): @@ -1079,7 +1081,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.origin_value + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -1087,14 +1089,14 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def set_value(self, value, origin_value=False): + def set_value(self, value, default_value=False): self.value_widget.set_value(value) - if origin_value: - self.origin_value = self.item_value() + if default_value: + self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.origin_value) + self.set_value(self.default_value) def clear_value(self): self.set_value([]) @@ -1533,7 +1535,7 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): self.value_input.value_changed.connect(self._on_value_change) self.origin_key = self._key() - self.origin_value = self.value_input.item_value() + self.default_value = self.value_input.item_value() self.is_single = False @@ -1630,7 +1632,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): if self.count() == 0: self.add_row() - self.origin_value = self.config_value() + self.default_value = self.config_value() @property def is_overidable(self): @@ -1680,7 +1682,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not None and key is not None: item_widget.origin_key = key item_widget.key_input.setText(key) - item_widget.value_input.set_value(value, origin_value=True) + item_widget.value_input.set_value(value, default_value=True) else: self._on_value_change() self.parent().updateGeometry() @@ -1750,10 +1752,10 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.key = input_data["key"] - self.origin_value = self.item_value() + self.default_value = self.item_value() def _on_value_change(self, item=None): - self.child_modified = self.item_value() != self.origin_value + self.child_modified = self.item_value() != self.default_value if self.is_group and self.is_overidable: self._is_overriden = True From a59aa34a8ab27b202c377c2134db3a9b17bbfda0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 16:04:39 +0200 Subject: [PATCH 053/580] just added override_value attribute --- pype/tools/config_setting/widgets/inputs.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index e3e60612cc..5f0411b72b 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -74,6 +74,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.checkbox.setChecked(value) self.default_value = self.item_value() + self.override_value = None self.checkbox.stateChanged.connect(self._on_value_change) @@ -201,6 +202,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.int_input.setValue(value) self.default_value = self.item_value() + self.override_value = None self.int_input.valueChanged.connect(self._on_value_change) @@ -337,6 +339,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.float_input.setValue(value) self.default_value = self.item_value() + self.override_value = None self.float_input.valueChanged.connect(self._on_value_change) @@ -463,6 +466,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.text_input.setText(value) self.default_value = self.item_value() + self.override_value = None self.text_input.textChanged.connect(self._on_value_change) @@ -587,6 +591,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.text_input.setPlainText(value) self.default_value = self.item_value() + self.override_value = None self.text_input.textChanged.connect(self._on_value_change) @@ -769,6 +774,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.text_input.setPlainText(value) self.default_value = self.item_value() + self.override_value = None self.text_input.textChanged.connect(self._on_value_change) @@ -918,6 +924,7 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(value) self.default_value = self.item_value() + self.override_value = None def set_value(self, value, default_value=False): for input_field in self.input_fields: @@ -1057,6 +1064,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.setLayout(layout) self.default_value = self.item_value() + self.override_value = None @property def child_modified(self): @@ -1534,9 +1542,12 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): self.key_input.textChanged.connect(self._on_value_change) self.value_input.value_changed.connect(self._on_value_change) - self.origin_key = self._key() + self.default_key = self._key() self.default_value = self.value_input.item_value() + self.override_key = None + self.override_value = None + self.is_single = False def _key(self): @@ -1563,7 +1574,7 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def is_key_modified(self): - return self._key() != self.origin_key + return self._key() != self.default_key def is_value_modified(self): return self.value_input.is_modified @@ -1633,6 +1644,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.add_row() self.default_value = self.config_value() + self.override_value = None @property def is_overidable(self): @@ -1680,7 +1692,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` if value is not None and key is not None: - item_widget.origin_key = key + item_widget.default_key = key item_widget.key_input.setText(key) item_widget.value_input.set_value(value, default_value=True) else: @@ -1753,6 +1765,7 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.key = input_data["key"] self.default_value = self.item_value() + self.override_value = None def _on_value_change(self, item=None): self.child_modified = self.item_value() != self.default_value From 407fbbe77babb1fddf7fec433152d7c2b3cf8831 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 16:57:09 +0200 Subject: [PATCH 054/580] call aplpy_overrides on project change --- pype/tools/config_setting/widgets/base.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 52184b4c8a..a90eefd400 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -345,9 +345,17 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.content_layout.addWidget(item) def _on_project_change(self): - self.is_overidable = ( - self.project_list_widget.project_name() is not None - ) + project_name = self.project_list_widget.project_name() + + if project_name is None: + overrides = None + self.is_overidable = False + else: + overrides = config.project_preset_overrides(project_name) + self.is_overidable = True + + for item in self.input_fields: + item.apply_overrides(overrides) def _save(self): output = {} From 2e7980104f1cee00828455148e48250a8fc7c04b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 16:57:54 +0200 Subject: [PATCH 055/580] addde apply_overrides to inputs --- pype/tools/config_setting/widgets/inputs.py | 76 +++++++++++++++++---- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 5f0411b72b..ea6a9e3483 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -78,19 +78,30 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.checkbox.stateChanged.connect(self._on_value_change) - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.checkbox.setChecked(value) if default_value: self.default_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + if self.is_overidable: + self.set_value(self.override_value) + else: + self.set_value(self.default_value) def clear_value(self): self.reset_value() - def apply_overrides(self, overrides): + def apply_overrides(self, override_value): + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.checkbox.setChecked(value) @property def child_modified(self): @@ -115,9 +126,17 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.default_value + _value = self.item_value() + is_modified = None if self.is_overidable: self._is_overriden = True + if self.override_value is not None: + is_modified = _value != self.override_value + + if is_modified is None: + is_modified = _value != self.default_value + + self._is_modified = is_modified self.update_style() @@ -228,7 +247,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.int_input.setValue(value) if default_value: self.default_value = self.item_value() @@ -240,6 +259,16 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset_value(self): self.set_value(self.default_value) + def apply_overrides(self, override_value): + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.int_input.setValue(value) + def _on_value_change(self, item=None): self._is_modified = self.item_value() != self.default_value if self.is_overidable: @@ -365,7 +394,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.float_input.setValue(value) if default_value: self.default_value = self.item_value() @@ -374,6 +403,16 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset_value(self): self.set_value(self.default_value) + def apply_overrides(self, override_value): + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.float_input.setChecked(value) + def clear_value(self): self.set_value(0) @@ -492,7 +531,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.text_input.setText(value) if default_value: self.default_value = self.item_value() @@ -501,6 +540,9 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset_value(self): self.set_value(self.default_value) + def apply_overrides(self, override_value): + self.set_value(override_value, override_value=True) + def clear_value(self): self.set_value("") @@ -617,7 +659,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: self.default_value = self.item_value() @@ -626,6 +668,9 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset_value(self): self.set_value(self.default_value) + def apply_overrides(self, override_value): + self.set_value(override_value, override_value=True) + def clear_value(self): self.set_value("") @@ -678,7 +723,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.is_valid = None - def set_value(self, value): + def set_value(self, value, *, default_value=False): self.setPlainText(value) def setPlainText(self, *args, **kwargs): @@ -800,9 +845,8 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) - if default_value: self.default_value = self.item_value() self._on_value_change() @@ -813,6 +857,9 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value("") + def apply_overrides(self, override_value): + self.set_value(override_value, override_value=True) + def _on_value_change(self, item=None): value = self.item_value() self._is_modified = value != self.default_value @@ -926,7 +973,7 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.default_value = self.item_value() self.override_value = None - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): for input_field in self.input_fields: self.remove_row(input_field) @@ -1097,7 +1144,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def set_value(self, value, default_value=False): + def set_value(self, value, *, default_value=False): self.value_widget.set_value(value) if default_value: self.default_value = self.item_value() @@ -1109,6 +1156,9 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def clear_value(self): self.set_value([]) + def apply_overrides(self, override_value): + self.set_value(override_value, override_value=True) + def update_style(self, is_overriden=None): if is_overriden is None: is_overriden = self.is_overriden From 04f650b9b59637adc74e3b6e9a67eff2f142a5e8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 18:12:01 +0200 Subject: [PATCH 056/580] project overrides are appliable for boolean --- pype/tools/config_setting/widgets/inputs.py | 98 ++++++++++++++++++--- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index ea6a9e3483..53bb2d729d 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -95,13 +95,16 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self.override_value = override_value + self._is_modified = False if override_value is None: self._is_overriden = False + self._was_overriden = False value = self.default_value else: self._is_overriden = True + self._was_overriden = True value = override_value - self.checkbox.setChecked(value) + self.set_value(value) @property def child_modified(self): @@ -113,7 +116,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self._was_overriden != self._is_overriden) @property def is_overidable(self): @@ -267,7 +270,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: self._is_overriden = True value = override_value - self.int_input.setValue(value) + self.set_value(value) def _on_value_change(self, item=None): self._is_modified = self.item_value() != self.default_value @@ -411,7 +414,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: self._is_overriden = True value = override_value - self.float_input.setChecked(value) + self.set_value(value) def clear_value(self): self.set_value(0) @@ -541,7 +544,14 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.default_value) def apply_overrides(self, override_value): - self.set_value(override_value, override_value=True) + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.set_value(value) def clear_value(self): self.set_value("") @@ -669,7 +679,14 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.default_value) def apply_overrides(self, override_value): - self.set_value(override_value, override_value=True) + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.set_value(value) def clear_value(self): self.set_value("") @@ -858,7 +875,14 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value("") def apply_overrides(self, override_value): - self.set_value(override_value, override_value=True) + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.set_value(value) def _on_value_change(self, item=None): value = self.item_value() @@ -1157,7 +1181,14 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value([]) def apply_overrides(self, override_value): - self.set_value(override_value, override_value=True) + self.override_value = override_value + if override_value is None: + self._is_overriden = False + value = self.default_value + else: + self._is_overriden = True + value = override_value + self.set_value(value) def update_style(self, is_overriden=None): if is_overriden is None: @@ -1291,6 +1322,14 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden + def apply_overrides(self, override_value): + for item in self.input_fields: + if override_value is None: + child_value = None + else: + child_value = override_value.get(item.key) + item.apply_overrides(child_value) + def _on_value_change(self, item=None): if self.is_group: if self.is_overidable: @@ -1379,6 +1418,8 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal(object) + def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): @@ -1418,6 +1459,9 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def update_style(self, *args, **kwargs): + return + @property def is_overriden(self): return self._parent.is_overriden @@ -1465,9 +1509,32 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): ) self.layout().addWidget(item) + item.value_changed.connect(self._on_value_change) + self.input_fields.append(item) return item + def _on_value_change(self, item=None): + if self.is_group: + if self.is_overidable: + self._is_overriden = True + # TODO update items + if item is not None: + is_overriden = self.is_overriden + for _item in self.input_fields: + if _item is not item: + _item.update_style(is_overriden) + + self.value_changed.emit(self) + + def apply_overrides(self, override_value): + for item in self.input_fields: + if override_value is None: + child_value = None + else: + child_value = override_value.get(item.key) + item.apply_overrides(child_value) + class DictFormWidget(QtWidgets.QWidget): value_changed = QtCore.Signal(object) @@ -1777,6 +1844,10 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): + # Should be used only for dictionary with one datatype as value + # TODO this is actually input field (do not care if is group or not) + value_changed = QtCore.Signal(object) + def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -1819,8 +1890,12 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def _on_value_change(self, item=None): self.child_modified = self.item_value() != self.default_value - if self.is_group and self.is_overidable: - self._is_overriden = True + + if self.is_group: + if self.is_overidable: + self._is_overriden = True + + self.value_changed.emit(self) self.update_style() @@ -1838,6 +1913,9 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden + def apply_overrides(self, override_value): + print(self, override_value) + def update_style(self, is_overriden=None): child_modified = self.child_modified if is_overriden is None: From 369e1cc08a2b8c8d637b1b17839a7e3fa7f91883 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 18:12:17 +0200 Subject: [PATCH 057/580] added testing data --- .../kuba_each_case/plugins/maya/publish.json | 8 ++++ .../config/studio_presets/global/tools.json | 6 +++ .../config_gui_schema/plugins_gui_schema.json | 37 +++++++++++++++---- 3 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json create mode 100644 pype/tools/config_setting/config/studio_presets/global/tools.json diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json new file mode 100644 index 0000000000..46fc343b6c --- /dev/null +++ b/pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json @@ -0,0 +1,8 @@ +{ + "ValidateModelName": { + "enabled": true + }, + "ValidateAssemblyName": { + "enabled": false + } +} diff --git a/pype/tools/config_setting/config/studio_presets/global/tools.json b/pype/tools/config_setting/config/studio_presets/global/tools.json new file mode 100644 index 0000000000..53aab7b2ca --- /dev/null +++ b/pype/tools/config_setting/config/studio_presets/global/tools.json @@ -0,0 +1,6 @@ +{ + "mtoa_3.0.1": false, + "mtoa_3.1.1": false, + "mtoa_3.2.0": false, + "yeti_2.1.2": false +} \ No newline at end of file diff --git a/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json b/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json index 79c1f85b85..6c83fee172 100644 --- a/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json @@ -7,16 +7,37 @@ "key": "maya", "type": "dict-expanding", "label": "Maya", - "is_group": true, "children": [ { - "key": "test1", - "type": "raw-json", - "label": "Test1" - }, { - "key": "test2", - "type": "raw-json", - "label": "Test2" + "key": "publish", + "type": "dict-expanding", + "label": "Publish plugins", + "is_group": true, + "children": [ + { + "key": "ValidateModelName", + "type": "dict-invisible", + "label": "Validate Model Name", + "children": [ + { + "key": "enabled", + "type": "boolean", + "label": "Enabled" + } + ] + }, { + "key": "ValidateAssemblyName", + "type": "dict-invisible", + "label": "Validate Assembly Name", + "children": [ + { + "key": "enabled", + "type": "boolean", + "label": "Enabled" + } + ] + } + ] } ] } From d6a998d953cc68e0b9f8fce6588728bf7fc464d6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 6 Aug 2020 19:01:13 +0200 Subject: [PATCH 058/580] project change won't affect state attributes --- pype/tools/config_setting/widgets/inputs.py | 68 +++++++++++++++------ 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 53bb2d729d..a192a370b0 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -76,16 +76,29 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.default_value = self.item_value() self.override_value = None + self._ignore_value_change = False + self.checkbox.stateChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value( + self, value, *, + ignore_attr_changes=True, + default_value=False + ): + # Ignore value change because if `self.isChecked()` has same + # value as `value` the `_on_value_change` is not triggered + self._ignore_value_change = True + self.checkbox.setChecked(value) + if default_value: + ignore_attr_changes = True self.default_value = self.item_value() - self._on_value_change() + + self._on_value_change(ignore_attr_changes=ignore_attr_changes) def reset_value(self): - if self.is_overidable: + if self.is_overidable and self.override_value is not None: self.set_value(self.override_value) else: self.set_value(self.default_value) @@ -95,7 +108,6 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self.override_value = override_value - self._is_modified = False if override_value is None: self._is_overriden = False self._was_overriden = False @@ -104,7 +116,12 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._is_overriden = True self._was_overriden = True value = override_value - self.set_value(value) + + self._is_modified = False + + self.set_value(value, ignore_attr_changes=True) + + print("apply_overrides", self.keys, override_value) @property def child_modified(self): @@ -128,18 +145,23 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def _on_value_change(self, item=None): - _value = self.item_value() - is_modified = None - if self.is_overidable: - self._is_overriden = True - if self.override_value is not None: - is_modified = _value != self.override_value + def _on_value_change(self, item=None, ignore_attr_changes=False): + if self._ignore_value_change: + self._ignore_value_change = False + return - if is_modified is None: - is_modified = _value != self.default_value + if not ignore_attr_changes: + _value = self.item_value() + is_modified = None + if self.is_overidable: + self._is_overriden = True + if self.override_value is not None: + is_modified = _value != self.override_value - self._is_modified = is_modified + if is_modified is None: + is_modified = _value != self.default_value + + self._is_modified = is_modified self.update_style() @@ -1293,6 +1315,8 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): keys.append(self.key) self.keys = keys + self._ignore_value_change = False + for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) @@ -1323,6 +1347,9 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._parent.is_overriden def apply_overrides(self, override_value): + self._ignore_value_change = True + + self._is_overriden = False for item in self.input_fields: if override_value is None: child_value = None @@ -1330,8 +1357,15 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): child_value = override_value.get(item.key) item.apply_overrides(child_value) - def _on_value_change(self, item=None): - if self.is_group: + self._ignore_value_change = False + + self._on_value_change(ignore_attr_changes=True) + + def _on_value_change(self, item=None, ignore_attr_changes=False): + if self._ignore_value_change: + return + + if not ignore_attr_changes and self.is_group: if self.is_overidable: self._is_overriden = True # TODO update items From ca948504997739e334e661b680ad5bbc72d04d01 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 11:59:11 +0200 Subject: [PATCH 059/580] added testing schema --- .../config_gui_schema/project_gui_schema.json | 1 + .../test_project_schema.json | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 pype/tools/config_setting/config_gui_schema/test_project_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/project_gui_schema.json b/pype/tools/config_setting/config_gui_schema/project_gui_schema.json index d2a6221f99..366400e5ff 100644 --- a/pype/tools/config_setting/config_gui_schema/project_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/project_gui_schema.json @@ -6,6 +6,7 @@ { "type": "schema", "children": [ + "test_project_schema", "ftrack_projects_gui_schema", "plugins_gui_schema" ] diff --git a/pype/tools/config_setting/config_gui_schema/test_project_schema.json b/pype/tools/config_setting/config_gui_schema/test_project_schema.json new file mode 100644 index 0000000000..e789b422a3 --- /dev/null +++ b/pype/tools/config_setting/config_gui_schema/test_project_schema.json @@ -0,0 +1,33 @@ +{ + "key": "test_inputs", + "type": "dict-expanding", + "label": "Test inputs", + "is_group": true, + "children": [ + { + "key": "boolean", + "type": "boolean", + "label": "Boolean" + }, { + "key": "test_singleline", + "type": "text-singleline", + "label": "Text singleline" + }, { + "key": "test_multiline", + "type": "text-multiline", + "label": "Text multiline" + }, { + "key": "raw_json", + "type": "raw-json", + "label": "Raw json" + }, { + "key": "int", + "type": "int", + "label": "Int" + }, { + "key": "float", + "type": "float", + "label": "Float" + } + ] +} From 3d24d4db53fbff285ffa67658f27486bf7d37497 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 11:59:29 +0200 Subject: [PATCH 060/580] added ignore to integer --- pype/tools/config_setting/widgets/inputs.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index a192a370b0..7e91d11a21 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -121,8 +121,6 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(value, ignore_attr_changes=True) - print("apply_overrides", self.keys, override_value) - @property def child_modified(self): return self.is_modified @@ -248,6 +246,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.default_value = self.item_value() self.override_value = None + self._ignore_value_change = False + self.int_input.valueChanged.connect(self._on_value_change) @property @@ -294,10 +294,15 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): value = override_value self.set_value(value) - def _on_value_change(self, item=None): - self._is_modified = self.item_value() != self.default_value - if self.is_overidable: - self._is_overriden = True + def _on_value_change(self, item=None, ignore_attr_changes=False): + if self._ignore_value_change: + self._ignore_value_change = False + return + + if not ignore_attr_changes: + self._is_modified = self.item_value() != self.default_value + if self.is_overidable: + self._is_overriden = True self.update_style() @@ -634,7 +639,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_group = True self.is_group = is_group - self.is_modified = False + self._is_modified = False self._was_overriden = False self._is_overriden = False From 1c5b923888cbb2ca2246e2f7150fd0e816be7186 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 17:18:36 +0200 Subject: [PATCH 061/580] overrides are apllies in right way --- pype/tools/config_setting/widgets/base.py | 5 + pype/tools/config_setting/widgets/inputs.py | 220 ++++++++++++++------ 2 files changed, 156 insertions(+), 69 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index a90eefd400..9413b07733 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -63,6 +63,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_overriden = False is_group = False any_parent_is_group = False + ignore_value_changes = False def __init__(self, parent=None): super(StudioWidget, self).__init__(parent) @@ -281,6 +282,8 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): super(ProjectWidget, self).__init__(parent) self.is_overidable = False + self.ignore_value_changes = False + self.input_fields = [] scroll_widget = QtWidgets.QScrollArea(self) @@ -354,8 +357,10 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): overrides = config.project_preset_overrides(project_name) self.is_overidable = True + self.ignore_value_changes = True for item in self.input_fields: item.apply_overrides(overrides) + self.ignore_value_changes = False def _save(self): output = {} diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 7e91d11a21..a0226d7b73 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -76,26 +76,17 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.default_value = self.item_value() self.override_value = None - self._ignore_value_change = False - self.checkbox.stateChanged.connect(self._on_value_change) - def set_value( - self, value, *, - ignore_attr_changes=True, - default_value=False - ): + def set_value(self, value, *, default_value=False): # Ignore value change because if `self.isChecked()` has same # value as `value` the `_on_value_change` is not triggered - self._ignore_value_change = True - self.checkbox.setChecked(value) if default_value: - ignore_attr_changes = True self.default_value = self.item_value() - self._on_value_change(ignore_attr_changes=ignore_attr_changes) + self._on_value_change() def reset_value(self): if self.is_overidable and self.override_value is not None: @@ -119,7 +110,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._is_modified = False - self.set_value(value, ignore_attr_changes=True) + self.set_value(value) + self.update_style() @property def child_modified(self): @@ -143,23 +135,25 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden - def _on_value_change(self, item=None, ignore_attr_changes=False): - if self._ignore_value_change: - self._ignore_value_change = False + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + + def _on_value_change(self, item=None): + if self.ignore_value_changes: return - if not ignore_attr_changes: - _value = self.item_value() - is_modified = None - if self.is_overidable: - self._is_overriden = True - if self.override_value is not None: - is_modified = _value != self.override_value + _value = self.item_value() + is_modified = None + if self.is_overidable: + self._is_overriden = True + if self.override_value is not None: + is_modified = _value != self.override_value - if is_modified is None: - is_modified = _value != self.default_value + if is_modified is None: + is_modified = _value != self.default_value - self._is_modified = is_modified + self._is_modified = is_modified self.update_style() @@ -246,8 +240,6 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.default_value = self.item_value() self.override_value = None - self._ignore_value_change = False - self.int_input.valueChanged.connect(self._on_value_change) @property @@ -272,6 +264,10 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): return self._is_overriden return self._parent.is_overriden + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + def set_value(self, value, *, default_value=False): self.int_input.setValue(value) if default_value: @@ -288,21 +284,25 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.override_value = override_value if override_value is None: self._is_overriden = False + self._was_overriden = False value = self.default_value else: self._is_overriden = True + self._was_overriden = True value = override_value - self.set_value(value) - def _on_value_change(self, item=None, ignore_attr_changes=False): - if self._ignore_value_change: - self._ignore_value_change = False + self._is_modified = False + + self.set_value(value) + self.update_style() + + def _on_value_change(self, item=None): + if self.ignore_value_changes: return - if not ignore_attr_changes: - self._is_modified = self.item_value() != self.default_value - if self.is_overidable: - self._is_overriden = True + self._is_modified = self.item_value() != self.default_value + if self.is_overidable: + self._is_overriden = True self.update_style() @@ -420,9 +420,11 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def set_value(self, value, *, default_value=False): self.float_input.setValue(value) @@ -441,12 +443,17 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: self._is_overriden = True value = override_value + self.set_value(value) + self.update_style() def clear_value(self): self.set_value(0) def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -557,9 +564,11 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def set_value(self, value, *, default_value=False): self.text_input.setText(value) @@ -571,19 +580,27 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.default_value) def apply_overrides(self, override_value): + self._is_modified = False self.override_value = override_value if override_value is None: self._is_overriden = False + self._was_overriden = False value = self.default_value else: self._is_overriden = True + self._was_overriden = True value = override_value + self.set_value(value) + self.update_style() def clear_value(self): self.set_value("") def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -692,9 +709,11 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) @@ -713,12 +732,17 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: self._is_overriden = True value = override_value + self.set_value(value) + self.update_style() def clear_value(self): self.set_value("") def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -885,9 +909,11 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) @@ -909,11 +935,15 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: self._is_overriden = True value = override_value + self.set_value(value) + self.update_style() def _on_value_change(self, item=None): - value = self.item_value() - self._is_modified = value != self.default_value + if self.ignore_value_changes: + return + + self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -1182,11 +1212,15 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def _on_value_change(self, item=None): + if self.ignore_value_changes: + return self._is_modified = self.item_value() != self.default_value if self.is_overidable: self._is_overriden = True @@ -1215,7 +1249,9 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): else: self._is_overriden = True value = override_value + self.set_value(value) + self.update_style() def update_style(self, is_overriden=None): if is_overriden is None: @@ -1320,8 +1356,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): keys.append(self.key) self.keys = keys - self._ignore_value_change = False - for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) @@ -1347,30 +1381,39 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def apply_overrides(self, override_value): - self._ignore_value_change = True - + # Make sure this is set to False self._is_overriden = False + for item in self.input_fields: if override_value is None: child_value = None else: child_value = override_value.get(item.key) + item.apply_overrides(child_value) - self._ignore_value_change = False + self._is_overriden = ( + self.is_group + and self.is_overidable + and ( + override_value is not None + or self.child_overriden + ) + ) + self.update_style() - self._on_value_change(ignore_attr_changes=True) - - def _on_value_change(self, item=None, ignore_attr_changes=False): - if self._ignore_value_change: + def _on_value_change(self, item=None): + if self.ignore_value_changes: return - if not ignore_attr_changes and self.is_group: + if self.is_group: if self.is_overidable: self._is_overriden = True # TODO update items @@ -1457,6 +1500,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): + # TODO is not overridable by itself value_changed = QtCore.Signal(object) def __init__( @@ -1474,6 +1518,7 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): self.any_parent_is_group = any_parent_is_group + self._is_overriden = False self.is_modified = False self.is_group = is_group @@ -1503,7 +1548,7 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden @property def is_overidable(self): @@ -1523,6 +1568,10 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): return True return False + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + def item_value(self): output = {} for input_field in self.input_fields: @@ -1554,6 +1603,9 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): return item def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + if self.is_group: if self.is_overidable: self._is_overriden = True @@ -1567,6 +1619,7 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) def apply_overrides(self, override_value): + self._is_overriden = False for item in self.input_fields: if override_value is None: child_value = None @@ -1574,6 +1627,16 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): child_value = override_value.get(item.key) item.apply_overrides(child_value) + self._is_overriden = ( + self.is_group + and self.is_overidable + and ( + override_value is not None + or self.child_overriden + ) + ) + self.update_style() + class DictFormWidget(QtWidgets.QWidget): value_changed = QtCore.Signal(object) @@ -1604,6 +1667,8 @@ class DictFormWidget(QtWidgets.QWidget): self.add_children_gui(child_data, values) def _on_value_change(self, item=None): + if self.ignore_value_changes: + return self.value_changed.emit(self) def item_value(self): @@ -1632,6 +1697,10 @@ class DictFormWidget(QtWidgets.QWidget): def is_overidable(self): return self._parent.is_overidable + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + def config_value(self): return self.item_value() @@ -1729,6 +1798,10 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def is_overriden(self): return self._parent.is_overriden + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + def is_key_modified(self): return self._key() != self.default_key @@ -1814,6 +1887,10 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_group(self): return self._parent.is_group + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + @property def any_parent_is_group(self): return self._parent.any_parent_is_group @@ -1928,6 +2005,9 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.override_value = None def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + self.child_modified = self.item_value() != self.default_value if self.is_group: @@ -1948,9 +2028,11 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes def apply_overrides(self, override_value): print(self, override_value) From b6f948826dd1c471e7299d959c456b04e9771646 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 17:31:11 +0200 Subject: [PATCH 062/580] fix is modified appliance --- pype/tools/config_setting/widgets/inputs.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index a0226d7b73..8464eb8459 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -98,6 +98,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.reset_value() def apply_overrides(self, override_value): + self._is_modified = False self.override_value = override_value if override_value is None: self._is_overriden = False @@ -108,8 +109,6 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._was_overriden = True value = override_value - self._is_modified = False - self.set_value(value) self.update_style() @@ -260,9 +259,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden @property def ignore_value_changes(self): @@ -281,6 +278,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.default_value) def apply_overrides(self, override_value): + self._is_modified = False + self.override_value = override_value if override_value is None: self._is_overriden = False @@ -291,8 +290,6 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._was_overriden = True value = override_value - self._is_modified = False - self.set_value(value) self.update_style() @@ -436,6 +433,8 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.default_value) def apply_overrides(self, override_value): + self._is_modified = False + self.override_value = override_value if override_value is None: self._is_overriden = False @@ -581,6 +580,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False + self.override_value = override_value if override_value is None: self._is_overriden = False @@ -725,6 +725,8 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(self.default_value) def apply_overrides(self, override_value): + self._is_modified = False + self.override_value = override_value if override_value is None: self._is_overriden = False @@ -928,6 +930,8 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value("") def apply_overrides(self, override_value): + self._is_modified = False + self.override_value = override_value if override_value is None: self._is_overriden = False @@ -1242,6 +1246,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value([]) def apply_overrides(self, override_value): + self._is_modified = False + self.override_value = override_value if override_value is None: self._is_overriden = False From 02051472d6813abc335cae002088e8b615ebd36b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 18:12:22 +0200 Subject: [PATCH 063/580] attribute cleanup on apply overrides --- pype/tools/config_setting/widgets/inputs.py | 100 +++++++------------- 1 file changed, 34 insertions(+), 66 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 8464eb8459..e0a18afe1d 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -99,6 +99,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -122,7 +123,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self._is_overriden) + return self._is_modified or (self._was_overriden != self.is_overriden) @property def is_overidable(self): @@ -130,9 +131,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): @property def is_overriden(self): - if self._is_overriden: - return self._is_overriden - return self._parent.is_overriden + return self._is_overriden or self._parent.is_overriden @property def ignore_value_changes(self): @@ -158,12 +157,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -279,7 +274,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False - + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -305,12 +300,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -434,7 +425,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False - + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -461,12 +452,8 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -580,7 +567,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False - + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -609,12 +596,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -726,7 +709,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False - + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -753,12 +736,8 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -931,7 +910,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False - + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -955,12 +934,8 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.value_changed.emit(self) - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -1247,7 +1222,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): self._is_modified = False - + self._state = None self.override_value = override_value if override_value is None: self._is_overriden = False @@ -1259,12 +1234,8 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.set_value(value) self.update_style() - def update_style(self, is_overriden=None): - if is_overriden is None: - is_overriden = self.is_overriden - is_modified = self.is_modified - - state = self.style_state(is_overriden, is_modified) + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -1396,7 +1367,8 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False - + self._state = None + self._child_state = None for item in self.input_fields: if override_value is None: child_value = None @@ -1427,7 +1399,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): is_overriden = self.is_overriden for _item in self.input_fields: if _item is not item: - _item.update_style(is_overriden) + _item.update_style() self.value_changed.emit(self) @@ -1435,20 +1407,16 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def update_style(self, is_overriden=None): child_modified = self.child_modified - if is_overriden is None: - child_overriden = self.child_overriden - child_state = self.style_state(child_overriden, child_modified) - if child_state: - child_state = "child-{}".format(child_state) + child_state = self.style_state(self.child_overriden, child_modified) + if child_state: + child_state = "child-{}".format(child_state) - if child_state != self._child_state: - self.setProperty("state", child_state) - self.style().polish(self) - self._child_state = child_state - - if is_overriden is None: - is_overriden = self.is_overriden + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state + is_overriden = self.is_overriden if child_modified and not is_overriden: state = self.default_state else: From aee77e630c36f5f1ccd064948b8acda0c9c109f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 18:50:42 +0200 Subject: [PATCH 064/580] modifiabledict is working better now --- pype/tools/config_setting/widgets/inputs.py | 74 ++++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index e0a18afe1d..839fe1e8a2 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1786,7 +1786,7 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def is_modified(self): return self.is_value_modified() or self.is_key_modified() - def update_style(self, is_overriden=None): + def update_style(self): if self.is_key_modified(): state = "modified" else: @@ -1957,10 +1957,11 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): self.any_parent_is_group = any_parent_is_group - self.is_modified = False - self.child_modified = False - self._is_overriden = False self.is_group = is_group + self._is_modified = False + self._is_overriden = False + self._was_overriden = False + self._state = None super(ModifiableDict, self).__init__(input_data["label"], parent) self.setObjectName("ModifiableDict") @@ -1982,16 +1983,26 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): if self.ignore_value_changes: return - self.child_modified = self.item_value() != self.default_value + if self.is_overidable: + self._is_overriden = True - if self.is_group: - if self.is_overidable: - self._is_overriden = True + if self.is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.default_value self.value_changed.emit(self) self.update_style() + @property + def child_modified(self): + return self.is_modified + + @property + def is_modified(self): + return self._is_modified + @property def child_overriden(self): return self._is_overriden @@ -2004,29 +2015,42 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def is_overriden(self): return self._is_overriden or self._parent.is_overriden + @property + def is_modified(self): + return self._is_modified + @property def ignore_value_changes(self): return self._parent.ignore_value_changes def apply_overrides(self, override_value): - print(self, override_value) - - def update_style(self, is_overriden=None): - child_modified = self.child_modified - if is_overriden is None: - is_overriden = self.is_overriden - - child_overriden = self.child_overriden - child_state = self.style_state(child_overriden, child_modified) - if child_state != self._child_state: - self.setProperty("state", child_state) - self.style().polish(self) - self._child_state = child_state - - if child_modified and not is_overriden: - state = self.default_state + self._state = None + self._is_modified = False + self.override_value = override_value + if override_value is None: + self._is_overriden = False + self._was_overriden = False + value = self.default_value else: - state = self.style_state(self.is_overriden, child_modified) + self._is_overriden = True + self._was_overriden = True + value = override_value + + self.set_value(value) + self.update_style() + + def update_style(self): + state = self.style_state(self.is_overriden, self.is_modified) + if self._state == state: + return + + if state: + child_state = "child-{}".format(state) + else: + child_state = "" + + self.setProperty("state", child_state) + self.style().polish(self) self.label_widget.setProperty("state", state) self.label_widget.style().polish(self.label_widget) From de331447bec8b76a836b5e46a17de2ee02340f5b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 7 Aug 2020 19:21:35 +0200 Subject: [PATCH 065/580] added Websocket server to module imports --- pype/tools/tray/modules_imports.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/tray/modules_imports.json b/pype/tools/tray/modules_imports.json index e9526dcddb..6a278840ea 100644 --- a/pype/tools/tray/modules_imports.json +++ b/pype/tools/tray/modules_imports.json @@ -54,5 +54,10 @@ "type": "module", "import_path": "pype.modules.adobe_communicator", "fromlist": ["pype", "modules"] + }, { + "title": "Websocket Server", + "type": "module", + "import_path": "pype.modules.websocket_server", + "fromlist": ["pype", "modules"] } ] From 0badfc0a5ace0cebc8252122f1e14b4a521a15c2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 11:22:07 +0200 Subject: [PATCH 066/580] adde unsaved changes dialog with 3 possible results --- pype/tools/config_setting/widgets/widgets.py | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pype/tools/config_setting/widgets/widgets.py b/pype/tools/config_setting/widgets/widgets.py index 34fdfde1a5..1d30a67e28 100644 --- a/pype/tools/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/widgets/widgets.py @@ -103,3 +103,40 @@ class ExpandingWidget(QtWidgets.QWidget): def resizeEvent(self, event): super(ExpandingWidget, self).resizeEvent(event) self.content_widget.updateGeometry() + + +class UnsavedChangesDialog(QtWidgets.QDialog): + message = "My message" + + def __init__(self, parent=None): + super().__init__(parent) + message_label = QtWidgets.QLabel(self.message) + + btns_widget = QtWidgets.QWidget(self) + btns_layout = QtWidgets.QHBoxLayout(btns_widget) + + btn_ok = QtWidgets.QPushButton("OK") + btn_ok.clicked.connect(self.on_ok_pressed) + btn_discard = QtWidgets.QPushButton("Discard changes") + btn_discard.clicked.connect(self.on_discard_pressed) + btn_cancel = QtWidgets.QPushButton("Cancel") + btn_cancel.clicked.connect(self.on_cancel_pressed) + + btns_layout.addWidget(btn_ok) + btns_layout.addWidget(btn_discard) + btns_layout.addWidget(btn_cancel) + + layout = QtWidgets.QVBoxLayout(self) + layout.addWidget(message_label) + layout.addWidget(btns_widget) + + self.state = None + + def on_cancel_pressed(self): + self.done(0) + + def on_ok_pressed(self): + self.done(1) + + def on_discard_pressed(self): + self.done(2) From 242c55716174fdc9482733098144aae14681db34 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 11:24:30 +0200 Subject: [PATCH 067/580] modified dialog --- pype/tools/config_setting/widgets/widgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/widgets/widgets.py b/pype/tools/config_setting/widgets/widgets.py index 1d30a67e28..3d5528e17a 100644 --- a/pype/tools/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/widgets/widgets.py @@ -106,7 +106,7 @@ class ExpandingWidget(QtWidgets.QWidget): class UnsavedChangesDialog(QtWidgets.QDialog): - message = "My message" + message = "You have unsaved changes. What do you want to do with them?" def __init__(self, parent=None): super().__init__(parent) @@ -115,9 +115,9 @@ class UnsavedChangesDialog(QtWidgets.QDialog): btns_widget = QtWidgets.QWidget(self) btns_layout = QtWidgets.QHBoxLayout(btns_widget) - btn_ok = QtWidgets.QPushButton("OK") + btn_ok = QtWidgets.QPushButton("Save") btn_ok.clicked.connect(self.on_ok_pressed) - btn_discard = QtWidgets.QPushButton("Discard changes") + btn_discard = QtWidgets.QPushButton("Discard") btn_discard.clicked.connect(self.on_discard_pressed) btn_cancel = QtWidgets.QPushButton("Cancel") btn_cancel.clicked.connect(self.on_cancel_pressed) From 1eb5b1ed2b3cb4aff3cf6d6eb89382fabbafa76e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 11:24:47 +0200 Subject: [PATCH 068/580] on project change is corrrect validation with dialog --- pype/tools/config_setting/widgets/base.py | 28 ++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 9413b07733..76fbad06c6 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -2,6 +2,7 @@ import os import json from Qt import QtWidgets, QtCore, QtGui from . import config +from .widgets import UnsavedChangesDialog from .lib import NOT_SET from avalon import io from queue import Queue @@ -217,16 +218,37 @@ class ProjectListWidget(QtWidgets.QWidget): if self.current_project == new_project_name: return + save_changes = False + change_project = False if self.validate_context_change(): + change_project = True + + else: + dialog = UnsavedChangesDialog(self) + result = dialog.exec_() + if result == 1: + save_changes = True + change_project = True + + elif result == 2: + change_project = True + + if save_changes: + self._parent._save() + + if change_project: self.select_project(new_project_name) self.current_project = new_project_name self.project_changed.emit() - return - - self.select_project(self.current_project) + else: + self.select_project(self.current_project) def validate_context_change(self): # TODO add check if project can be changed (is modified) + for item in self._parent.input_fields: + is_modified = item.child_modified + if is_modified: + return False return True def project_name(self): From 2b07663fee86e91ebf6d21ad4635eea0077f04ec Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 11:41:56 +0200 Subject: [PATCH 069/580] added "is_file" key to schemas --- .../config_gui_schema/applications_gui_schema.json | 1 + .../config_gui_schema/ftrack_projects_gui_schema.json | 2 ++ .../config_setting/config_gui_schema/plugins_gui_schema.json | 1 + .../config_setting/config_gui_schema/test_project_schema.json | 1 + .../config_setting/config_gui_schema/tools_gui_schema.json | 1 + 5 files changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json b/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json index 096964b5b8..5c20e630fa 100644 --- a/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json @@ -2,6 +2,7 @@ "key": "applications", "type": "dict-expanding", "label": "Applications", + "is_file": true, "children": [ { "type": "dict-form", diff --git a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json index 4a35fc9b61..ac696d18d0 100644 --- a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json @@ -8,6 +8,7 @@ "type": "dict-expanding", "label": "Status updates", "is_group": true, + "is_file": true, "children": [ { "key": "Ready", @@ -24,6 +25,7 @@ "type": "dict-expanding", "label": "Version status to Task status", "is_group": true, + "is_file": true, "children": [ { "key": "in progress", diff --git a/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json b/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json index 6c83fee172..1eaecbb8e5 100644 --- a/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json @@ -13,6 +13,7 @@ "type": "dict-expanding", "label": "Publish plugins", "is_group": true, + "is_file": true, "children": [ { "key": "ValidateModelName", diff --git a/pype/tools/config_setting/config_gui_schema/test_project_schema.json b/pype/tools/config_setting/config_gui_schema/test_project_schema.json index e789b422a3..43c9a647f4 100644 --- a/pype/tools/config_setting/config_gui_schema/test_project_schema.json +++ b/pype/tools/config_setting/config_gui_schema/test_project_schema.json @@ -3,6 +3,7 @@ "type": "dict-expanding", "label": "Test inputs", "is_group": true, + "is_file": true, "children": [ { "key": "boolean", diff --git a/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json b/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json index 2f46ef0ec5..3507d14a36 100644 --- a/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json @@ -2,6 +2,7 @@ "key": "tools", "type": "dict-expanding", "label": "Tools", + "is_file": true, "children": [ { "type": "dict-form", From 745e1cff968b70cf52dfd131c1def152b9136112 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 12:09:29 +0200 Subject: [PATCH 070/580] moved gui creation to reset method --- pype/tools/config_setting/widgets/base.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 76fbad06c6..f36e21483e 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -88,11 +88,6 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.content_layout = content_layout self.content_widget = content_widget - values = {"studio": config.studio_presets()} - schema = config.gui_schema("studio_gui_schema") - self.keys = schema.get("keys", []) - self.add_children_gui(schema, values) - footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) @@ -111,6 +106,20 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): save_btn.clicked.connect(self._save) + self.reset() + + def reset(self): + if self.content_layout.count() != 0: + for widget in self.input_fields: + self.content_layout.removeWidget(widget) + widget.deleteLater() + self.input_fields.clear() + + values = {"studio": config.studio_presets()} + schema = config.gui_schema("studio_gui_schema") + self.keys = schema.get("keys", []) + self.add_children_gui(schema, values) + def _save(self): all_values = {} for item in self.input_fields: @@ -354,6 +363,9 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.content_layout = content_layout self.content_widget = content_widget + self.reset() + + def reset(self): values = config.global_project_presets() schema = config.gui_schema("project_gui_schema") self.keys = schema.get("keys", []) From 20c6ef6a6c5648e70780d16345ad7abf276da18a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 12:37:47 +0200 Subject: [PATCH 071/580] separate gui schemas byt studio and project --- .../{ => projects_schema}/ftrack_projects_gui_schema.json | 0 .../{ => projects_schema}/plugins_gui_schema.json | 0 .../{ => projects_schema}/project_gui_schema.json | 0 .../{ => projects_schema}/test_project_schema.json | 0 .../{ => studio_schema}/applications_gui_schema.json | 0 .../config_gui_schema/{ => studio_schema}/studio_gui_schema.json | 0 .../config_gui_schema/{ => studio_schema}/tools_gui_schema.json | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename pype/tools/config_setting/config_gui_schema/{ => projects_schema}/ftrack_projects_gui_schema.json (100%) rename pype/tools/config_setting/config_gui_schema/{ => projects_schema}/plugins_gui_schema.json (100%) rename pype/tools/config_setting/config_gui_schema/{ => projects_schema}/project_gui_schema.json (100%) rename pype/tools/config_setting/config_gui_schema/{ => projects_schema}/test_project_schema.json (100%) rename pype/tools/config_setting/config_gui_schema/{ => studio_schema}/applications_gui_schema.json (100%) rename pype/tools/config_setting/config_gui_schema/{ => studio_schema}/studio_gui_schema.json (100%) rename pype/tools/config_setting/config_gui_schema/{ => studio_schema}/tools_gui_schema.json (100%) diff --git a/pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/ftrack_projects_gui_schema.json rename to pype/tools/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json b/pype/tools/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/plugins_gui_schema.json rename to pype/tools/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/project_gui_schema.json b/pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/project_gui_schema.json rename to pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/test_project_schema.json b/pype/tools/config_setting/config_gui_schema/projects_schema/test_project_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/test_project_schema.json rename to pype/tools/config_setting/config_gui_schema/projects_schema/test_project_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/applications_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/applications_gui_schema.json rename to pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/studio_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/studio_gui_schema.json rename to pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/tools_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/tools_gui_schema.json rename to pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json From 17c1587631a9052c3a350b88b990d42a6e4312a7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 12:38:25 +0200 Subject: [PATCH 072/580] gui_schema function also resolves inner schemas so inputs don't have to acrea about them --- pype/tools/config_setting/widgets/config.py | 56 +++++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 58b1e03a25..5aaa0e20ee 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -220,19 +220,53 @@ def project_presets(project_name=None, **kwargs): return apply_overrides(global_presets, project_overrides) -def gui_schema(schema_name): - filename = schema_name + ".json" - schema_folder = os.path.join( +def replace_inner_schemas(schema_data, schema_collection): + if schema_data["type"] == "schema": + raise ValueError("First item in schema data can't be schema.") + + children = schema_data.get("children") + if not children: + return schema_data + + new_children = [] + for child in children: + if child["type"] != "schema": + new_child = replace_inner_schemas(child, schema_collection) + new_children.append(new_child) + continue + + for schema_name in child["children"]: + new_child = replace_inner_schemas( + schema_collection[schema_name], + schema_collection + ) + new_children.append(new_child) + + schema_data["children"] = new_children + return schema_data + + +def gui_schema(subfolder, main_schema_name): + subfolder, main_schema_name + dirpath = os.path.join( os.path.dirname(os.path.dirname(__file__)), "config_gui_schema", - filename + subfolder ) - with open(schema_folder, "r") as json_stream: - schema = json.load(json_stream) - return schema + loaded_schemas = {} + for filename in os.listdir(dirpath): + basename, ext = os.path.splitext(filename) + if ext != ".json": + continue -p1 = studio_presets(with_metadata=True) -p2 = studio_presets(with_metadata=False) -print(json.dumps(p1, indent=4)) -print(json.dumps(p2, indent=4)) + filepath = os.path.join(dirpath, filename) + with open(filepath, "r") as json_stream: + schema_data = json.load(json_stream) + loaded_schemas[basename] = schema_data + + main_schema = replace_inner_schemas( + loaded_schemas[main_schema_name], + loaded_schemas + ) + return main_schema From c5730f915aa014f826e159fed9cb80dd8d8ecc32 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 12:38:42 +0200 Subject: [PATCH 073/580] project and studio widgets use new gui_schema function --- pype/tools/config_setting/widgets/base.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index f36e21483e..134735974c 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -56,10 +56,6 @@ class PypeConfigurationWidget: class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): - config_dir = os.path.join( - os.path.dirname(os.path.dirname(__file__)), - "config_gui_schema" - ) is_overidable = False is_overriden = False is_group = False @@ -116,7 +112,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.input_fields.clear() values = {"studio": config.studio_presets()} - schema = config.gui_schema("studio_gui_schema") + schema = config.gui_schema("studio_schema", "studio_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) @@ -301,10 +297,6 @@ class ProjectListWidget(QtWidgets.QWidget): class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): - config_dir = os.path.join( - os.path.dirname(os.path.dirname(__file__)), - "config_gui_schema" - ) is_overriden = False is_group = False any_parent_is_group = False @@ -367,7 +359,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset(self): values = config.global_project_presets() - schema = config.gui_schema("project_gui_schema") + schema = config.gui_schema("projects_schema", "project_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) From ea433367ce44f9fdf4f03245ca1347aa37852482 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 12:42:59 +0200 Subject: [PATCH 074/580] minor changes --- .../config_gui_schema/studio_schema/applications_gui_schema.json | 1 + .../config_gui_schema/studio_schema/studio_gui_schema.json | 1 + .../config_gui_schema/studio_schema/tools_gui_schema.json | 1 + 3 files changed, 3 insertions(+) diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json index 5c20e630fa..12fbb3cc26 100644 --- a/pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json @@ -3,6 +3,7 @@ "type": "dict-expanding", "label": "Applications", "is_file": true, + "is_group": true, "children": [ { "type": "dict-form", diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json index 1a49735b8a..ba017760f3 100644 --- a/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json @@ -17,6 +17,7 @@ }, { "key": "muster", "type": "dict-invisible", + "is_group": true, "children": [{ "key": "templates_mapping", "label": "Muster", diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json index 3507d14a36..4c905a3826 100644 --- a/pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json @@ -2,6 +2,7 @@ "key": "tools", "type": "dict-expanding", "label": "Tools", + "is_group": true, "is_file": true, "children": [ { From 7f39070df4f468ff6568d4b6f16aa86c807f1431 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 13:12:34 +0200 Subject: [PATCH 075/580] enhance expanding dict states --- pype/tools/config_setting/widgets/inputs.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 839fe1e8a2..2c231e087a 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1271,7 +1271,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.any_parent_is_group = any_parent_is_group - self.is_modified = False + self._is_modified = False self._is_overriden = False self.is_group = is_group @@ -1394,9 +1394,9 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): if self.is_group: if self.is_overidable: self._is_overriden = True + # TODO update items if item is not None: - is_overriden = self.is_overriden for _item in self.input_fields: if _item is not item: _item.update_style() @@ -1416,12 +1416,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.style().polish(self) self._child_state = child_state - is_overriden = self.is_overriden - if child_modified and not is_overriden: - state = self.default_state - else: - state = self.style_state(is_overriden, child_modified) - + state = self.style_state(self.is_overriden, self.is_modified) if self._state == state: return @@ -1430,6 +1425,12 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._state = state + @property + def is_modified(self): + if self.is_group: + return self.child_modified + return False + @property def child_modified(self): for input_field in self.input_fields: From de62bc42d2680fdc5151cc5857dc3214d9a612b3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 15:15:15 +0200 Subject: [PATCH 076/580] added schema validations --- .../studio_schema/studio_gui_schema.json | 1 + pype/tools/config_setting/widgets/config.py | 52 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json b/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json index ba017760f3..088c407804 100644 --- a/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json @@ -21,6 +21,7 @@ "children": [{ "key": "templates_mapping", "label": "Muster", + "is_file": true, "type": "dict-modifiable", "object_type": "int" }] diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 5aaa0e20ee..3604316131 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -132,8 +132,6 @@ def load_jsons_from_dir(path, *args, **kwargs): sub_keys.pop(0) base_len = len(path) + 1 - ext_len = len(".json") - for base, _directories, filenames in os.walk(path): for filename in filenames: basename, ext = os.path.splitext(filename) @@ -246,6 +244,55 @@ def replace_inner_schemas(schema_data, schema_collection): return schema_data +class ShemaMissingFileInfo(Exception): + def __init__(self, invalid): + full_path_keys = [] + for item in invalid: + full_path_keys.append("\"{}\"".format("/".join(item))) + + msg = ( + "Schema has missing definition of output file (\"is_file\" key)" + " for keys. [{}]" + ).format(", ".join(full_path_keys)) + super(ShemaMissingFileInfo, self).__init__(msg) + + +def validate_all_has_ending_file(schema_data, is_top=True): + if schema_data.get("is_file"): + return None + + children = schema_data.get("children") + if not children: + return [[schema_data["key"]]] + + invalid = [] + keyless = "key" not in schema_data + for child in children: + result = validate_all_has_ending_file(child, False) + if result is None: + continue + + if keyless: + invalid.extend(result) + else: + for item in result: + new_invalid = [schema_data["key"]] + new_invalid.extend(item) + invalid.append(new_invalid) + + if not invalid: + return None + + if not is_top: + return invalid + + raise ShemaMissingFileInfo(invalid) + + +def validate_schema(schema_data): + validate_all_has_ending_file(schema_data) + + def gui_schema(subfolder, main_schema_name): subfolder, main_schema_name dirpath = os.path.join( @@ -269,4 +316,5 @@ def gui_schema(subfolder, main_schema_name): loaded_schemas[main_schema_name], loaded_schemas ) + validate_schema(main_schema) return main_schema From e2fdb92a97296c10fb796113c6bcff4f7de93afa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 15:52:05 +0200 Subject: [PATCH 077/580] changed way of storing data --- pype/tools/config_setting/widgets/base.py | 59 ++++++++++++----------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 134735974c..830902f6bb 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -115,6 +115,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): schema = config.gui_schema("studio_schema", "studio_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) + self.schema = schema def _save(self): all_values = {} @@ -129,38 +130,38 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): all_values = all_values["studio"] # Load studio data with metadata - config_with_metadata = config.studio_presets_with_metadata() + current_presets = config.studio_presets() - print(json.dumps(config_with_metadata, indent=4)) + print(json.dumps(current_presets, indent=4)) print(json.dumps(all_values, indent=4)) - per_file_values = {} - process_queue = Queue() - for _key, _values in all_values.items(): - process_queue.put(( - config.studio_presets_path, _key, config_with_metadata, _values - )) - - while not process_queue.empty(): - path, key, metadata, values = process_queue.get() - new_path = os.path.join(path, key) - # TODO this should not be - if key in metadata: - key_metadata = metadata[key] - - if key_metadata["type"] == "file": - new_path += ".json" - per_file_values[new_path] = values - continue - - for new_key, new_values in values.items(): - process_queue.put( - (new_path, new_key, key_metadata["value"], new_values) - ) - - for file_path, file_values in per_file_values.items(): - with open(file_path, "w") as file_stream: - json.dump(file_values, file_stream, indent=4) + # per_file_values = {} + # process_queue = Queue() + # for _key, _values in all_values.items(): + # process_queue.put(( + # config.studio_presets_path, _key, config_with_metadata, _values + # )) + # + # while not process_queue.empty(): + # path, key, metadata, values = process_queue.get() + # new_path = os.path.join(path, key) + # # TODO this should not be + # if key in metadata: + # key_metadata = metadata[key] + # + # if key_metadata["type"] == "file": + # new_path += ".json" + # per_file_values[new_path] = values + # continue + # + # for new_key, new_values in values.items(): + # process_queue.put( + # (new_path, new_key, key_metadata["value"], new_values) + # ) + # + # for file_path, file_values in per_file_values.items(): + # with open(file_path, "w") as file_stream: + # json.dump(file_values, file_stream, indent=4) def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] From cf971151b2fc7270a2e851bddb2f01fdc900b82d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 18:00:51 +0200 Subject: [PATCH 078/580] studio can again safe changes --- pype/tools/config_setting/widgets/base.py | 55 ++++++++++----------- pype/tools/config_setting/widgets/config.py | 24 +++++++++ pype/tools/config_setting/widgets/inputs.py | 2 +- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 830902f6bb..3ca3b910b0 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -1,5 +1,6 @@ import os import json +import copy from Qt import QtWidgets, QtCore, QtGui from . import config from .widgets import UnsavedChangesDialog @@ -132,36 +133,32 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): # Load studio data with metadata current_presets = config.studio_presets() - print(json.dumps(current_presets, indent=4)) - print(json.dumps(all_values, indent=4)) + output = {} + keys_to_file = config.file_keys_from_schema(self.schema) + for key_sequence in keys_to_file: + key_sequence = key_sequence[1:] + subpath = "/".join(key_sequence) + ".json" + origin_values = current_presets + for key in key_sequence: + if key not in origin_values: + origin_values = {} + break + origin_values = origin_values[key] - # per_file_values = {} - # process_queue = Queue() - # for _key, _values in all_values.items(): - # process_queue.put(( - # config.studio_presets_path, _key, config_with_metadata, _values - # )) - # - # while not process_queue.empty(): - # path, key, metadata, values = process_queue.get() - # new_path = os.path.join(path, key) - # # TODO this should not be - # if key in metadata: - # key_metadata = metadata[key] - # - # if key_metadata["type"] == "file": - # new_path += ".json" - # per_file_values[new_path] = values - # continue - # - # for new_key, new_values in values.items(): - # process_queue.put( - # (new_path, new_key, key_metadata["value"], new_values) - # ) - # - # for file_path, file_values in per_file_values.items(): - # with open(file_path, "w") as file_stream: - # json.dump(file_values, file_stream, indent=4) + new_values = all_values + for key in key_sequence: + new_values = new_values[key] + origin_values.update(new_values) + + output_path = os.path.join( + config.studio_presets_path, subpath + ) + dirpath = os.path.dirname(output_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + with open(output_path, "w") as file_stream: + json.dump(origin_values, file_stream, indent=4) def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 3604316131..8319c3d51d 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -257,6 +257,27 @@ class ShemaMissingFileInfo(Exception): super(ShemaMissingFileInfo, self).__init__(msg) +def file_keys_from_schema(schema_data): + output = [] + keys = [] + key = schema_data.get("key") + if key: + keys.append(key) + + for child in schema_data["children"]: + if child.get("is_file"): + _keys = copy.deepcopy(keys) + _keys.append(child["key"]) + output.append(_keys) + continue + + for result in file_keys_from_schema(child): + _keys = copy.deepcopy(keys) + _keys.extend(result) + output.append(_keys) + return output + + def validate_all_has_ending_file(schema_data, is_top=True): if schema_data.get("is_file"): return None @@ -290,6 +311,9 @@ def validate_all_has_ending_file(schema_data, is_top=True): def validate_schema(schema_data): + # TODO validator for key uniquenes + # TODO validator that is_group key is not before is_file child + # TODO validator that is_group or is_file is not on child without key validate_all_has_ending_file(schema_data) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 2c231e087a..c4ec7a4347 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -16,7 +16,7 @@ class SchemeGroupHierarchyBug(Exception): if not msg: # TODO better message msg = "SCHEME BUG: Attribute `is_group` is mixed in the hierarchy" - super(SchemeGroupHierarchyBug, self).__init(msg) + super(SchemeGroupHierarchyBug, self).__init__(msg) class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): From 8b7d565208bf5ea76db9330c7a43b6e6f5669930 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 18:13:10 +0200 Subject: [PATCH 079/580] smaller changes --- .../config/studio_presets/global/applications.json | 8 ++++++-- .../config/studio_presets/muster/templates_mapping.json | 2 +- pype/tools/config_setting/widgets/base.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config/studio_presets/global/applications.json b/pype/tools/config_setting/config/studio_presets/global/applications.json index 35e399444c..21693e5fee 100644 --- a/pype/tools/config_setting/config/studio_presets/global/applications.json +++ b/pype/tools/config_setting/config/studio_presets/global/applications.json @@ -35,5 +35,9 @@ "resolve_16": true, "shell": true, "storyboardpro_7": true, - "unreal_4.21": true -} + "unreal_4.21": true, + "celaction_local": true, + "celaction_remote": true, + "houdini_16.5": false, + "unreal_4.24": true +} \ No newline at end of file diff --git a/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json b/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json index 4edab9077d..0c09113515 100644 --- a/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json +++ b/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json @@ -16,4 +16,4 @@ "vector": 4, "vray": 37, "ffmpeg": 48 -} +} \ No newline at end of file diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 3ca3b910b0..14ff56aa2a 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -133,9 +133,9 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): # Load studio data with metadata current_presets = config.studio_presets() - output = {} keys_to_file = config.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: + # Skip first key key_sequence = key_sequence[1:] subpath = "/".join(key_sequence) + ".json" origin_values = current_presets From 7e65e5c830a63cf05aff5438cbcd1f18bfd57ec2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 19 Aug 2020 12:06:59 +0200 Subject: [PATCH 080/580] basic overrides values getting implemented --- pype/tools/config_setting/widgets/base.py | 61 +++++++++++- pype/tools/config_setting/widgets/inputs.py | 101 +++++++++++++++++--- 2 files changed, 150 insertions(+), 12 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 14ff56aa2a..c131966f6c 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -304,6 +304,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.is_overidable = False self.ignore_value_changes = False + self.project_name = None self.input_fields = [] @@ -373,7 +374,6 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): def _on_project_change(self): project_name = self.project_list_widget.project_name() - if project_name is None: overrides = None self.is_overidable = False @@ -381,12 +381,28 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): overrides = config.project_preset_overrides(project_name) self.is_overidable = True + self.project_name = project_name self.ignore_value_changes = True for item in self.input_fields: item.apply_overrides(overrides) self.ignore_value_changes = False def _save(self): + if self.project_name is None: + self._save_defaults() + else: + self._save_overrides() + + def _save_overrides(self): + output = {} + for item in self.input_fields: + value = item.overrides() + if value is not NOT_SET: + output.update(value) + + print(json.dumps(output, indent=4)) + + def _save_defaults(self): output = {} for item in self.input_fields: output.update(item.config_value()) @@ -396,3 +412,46 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): output = _output print(json.dumps(output, indent=4)) + return + + # TODO check implementation copied from studio + all_values = {} + for item in self.input_fields: + all_values.update(item.config_value()) + + for key in reversed(self.keys): + _all_values = {key: all_values} + all_values = _all_values + + # Skip first key + all_values = all_values["studio"] + + # Load studio data with metadata + current_presets = config.studio_presets() + + keys_to_file = config.file_keys_from_schema(self.schema) + for key_sequence in keys_to_file: + # Skip first key + key_sequence = key_sequence[1:] + subpath = "/".join(key_sequence) + ".json" + origin_values = current_presets + for key in key_sequence: + if key not in origin_values: + origin_values = {} + break + origin_values = origin_values[key] + + new_values = all_values + for key in key_sequence: + new_values = new_values[key] + origin_values.update(new_values) + + output_path = os.path.join( + config.studio_presets_path, subpath + ) + dirpath = os.path.dirname(output_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + with open(output_path, "w") as file_stream: + json.dump(origin_values, file_stream, indent=4) diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index c4ec7a4347..6c6c31408e 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -177,6 +177,11 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal(object) @@ -321,6 +326,11 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal(object) @@ -473,6 +483,11 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal(object) @@ -617,6 +632,11 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal(object) @@ -757,6 +777,11 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class RawJsonInput(QtWidgets.QPlainTextEdit): tab_length = 4 @@ -955,6 +980,11 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 @@ -1248,6 +1278,11 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overriden: + return NOT_SET + return self.config_value() + class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): value_changed = QtCore.Signal(object) @@ -1473,6 +1508,18 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.input_fields.append(item) return item + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET + + values = {} + for input_field in self.input_fields: + value = input_field.overrides() + if value is NOT_SET: + continue + values.update(value) + return {self.key: values} + class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): # TODO is not overridable by itself @@ -1612,6 +1659,18 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): ) self.update_style() + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET + + values = {} + for input_field in self.input_fields: + value = input_field.overrides() + if value is NOT_SET: + continue + values.update(value) + return {self.key: values} + class DictFormWidget(QtWidgets.QWidget): value_changed = QtCore.Signal(object) @@ -1628,7 +1687,7 @@ class DictFormWidget(QtWidgets.QWidget): self.any_parent_is_group = any_parent_is_group self.is_modified = False - self.is_overriden = False + self._is_overriden = False self.is_group = False super(DictFormWidget, self).__init__(parent) @@ -1646,13 +1705,9 @@ class DictFormWidget(QtWidgets.QWidget): return self.value_changed.emit(self) - def item_value(self): - output = {} - for input_field in self.input_fields.values(): - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output + @property + def is_overriden(self): + return self._parent.is_overriden @property def child_modified(self): @@ -1676,9 +1731,6 @@ class DictFormWidget(QtWidgets.QWidget): def ignore_value_changes(self): return self._parent.ignore_value_changes - def config_value(self): - return self.item_value() - def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] key = child_configuration["key"] @@ -1697,6 +1749,28 @@ class DictFormWidget(QtWidgets.QWidget): self.input_fields[key] = item return item + def item_value(self): + output = {} + for input_field in self.input_fields.values(): + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return self.item_value() + + def overrides(self): + if not self.is_overiden and not self.child_overriden: + return NOT_SET + + values = {} + for input_field in self.input_fields: + value = input_field.overrides() + if value is not NOT_SET: + values.update(value) + return values + class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 @@ -2064,6 +2138,11 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + def overrides(self): + if not self.is_overiden: + return NOT_SET + return self.config_value() + TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["text-singleline"] = TextSingleLineWidget From 76992b0629c6e99a0fb68e2084516c933bcd6dbe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 19 Aug 2020 15:13:41 +0200 Subject: [PATCH 081/580] overrides are collected with metadata info --- pype/tools/config_setting/widgets/__init__.py | 2 +- pype/tools/config_setting/widgets/base.py | 17 +- pype/tools/config_setting/widgets/inputs.py | 1050 ++++++++--------- pype/tools/config_setting/widgets/lib.py | 11 +- 4 files changed, 537 insertions(+), 543 deletions(-) diff --git a/pype/tools/config_setting/widgets/__init__.py b/pype/tools/config_setting/widgets/__init__.py index b295759a36..9fbce6e1cf 100644 --- a/pype/tools/config_setting/widgets/__init__.py +++ b/pype/tools/config_setting/widgets/__init__.py @@ -1,4 +1,4 @@ -from .lib import CustomNone, NOT_SET +from .lib import NOT_SET, AS_WIDGET, METADATA_KEY from .base import * diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index c131966f6c..156f1f80e4 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -1,12 +1,10 @@ import os import json -import copy from Qt import QtWidgets, QtCore, QtGui from . import config from .widgets import UnsavedChangesDialog -from .lib import NOT_SET +from .lib import NOT_SET, METADATA_KEY from avalon import io -from queue import Queue class TypeToKlass: @@ -394,12 +392,19 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._save_overrides() def _save_overrides(self): - output = {} + data = {} + groups = [] for item in self.input_fields: - value = item.overrides() + value, is_group = item.overrides() if value is not NOT_SET: - output.update(value) + data.update(value) + if is_group: + groups.extend(value.keys()) + + if groups: + data[METADATA_KEY] = {"groups": groups} + output = convert_to_override(data) print(json.dumps(output, indent=4)) def _save_defaults(self): diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index 6c6c31408e..bb2d76fc71 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -8,7 +8,7 @@ from .widgets import ( ModifiedIntSpinBox, ModifiedFloatSpinBox ) -from .lib import NOT_SET, AS_WIDGET +from .lib import NOT_SET, AS_WIDGET, METADATA_KEY class SchemeGroupHierarchyBug(Exception): @@ -19,7 +19,14 @@ class SchemeGroupHierarchyBug(Exception): super(SchemeGroupHierarchyBug, self).__init__(msg) -class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class InputWidget: + def overrides(self): + if not self.is_overriden: + return NOT_SET, False + return self.config_value(), self.is_group + + +class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -177,13 +184,8 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - -class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -326,13 +328,8 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - -class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -483,13 +480,8 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - -class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -632,13 +624,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - -class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -777,11 +764,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - class RawJsonInput(QtWidgets.QPlainTextEdit): tab_length = 4 @@ -840,7 +822,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.update_style(is_valid) -class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -980,11 +962,6 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 @@ -1146,7 +1123,7 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: self.item_value()} -class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -1278,499 +1255,6 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - def overrides(self): - if not self.is_overriden: - return NOT_SET - return self.config_value() - - -class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, values, parent_keys, parent, label_widget=None - ): - if values is AS_WIDGET: - raise TypeError("Can't use \"{}\" as widget item.".format( - self.__class__.__name__ - )) - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - self.any_parent_is_group = any_parent_is_group - - self._is_modified = False - self._is_overriden = False - self.is_group = is_group - - self._state = None - self._child_state = None - - super(DictExpandWidget, self).__init__(parent) - self.setObjectName("DictExpandWidget") - top_part = ClickableWidget(parent=self) - - button_size = QtCore.QSize(5, 5) - button_toggle = QtWidgets.QToolButton(parent=top_part) - button_toggle.setProperty("btn-type", "expand-toggle") - button_toggle.setIconSize(button_size) - button_toggle.setArrowType(QtCore.Qt.RightArrow) - button_toggle.setCheckable(True) - button_toggle.setChecked(False) - - label = input_data["label"] - button_toggle_text = QtWidgets.QLabel(label, parent=top_part) - button_toggle_text.setObjectName("ExpandLabel") - - layout = QtWidgets.QHBoxLayout(top_part) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(button_toggle) - layout.addWidget(button_toggle_text) - top_part.setLayout(layout) - - main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(9, 9, 9, 9) - - content_widget = QtWidgets.QWidget(self) - content_widget.setVisible(False) - - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 3, 3) - - main_layout.addWidget(top_part) - main_layout.addWidget(content_widget) - self.setLayout(main_layout) - - self.setAttribute(QtCore.Qt.WA_StyledBackground) - - self.top_part = top_part - self.button_toggle = button_toggle - self.button_toggle_text = button_toggle_text - - self.content_widget = content_widget - self.content_layout = content_layout - - self.top_part.clicked.connect(self._top_part_clicked) - self.button_toggle.clicked.connect(self.toggle_content) - - self.input_fields = [] - - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) - - def _top_part_clicked(self): - self.toggle_content(not self.button_toggle.isChecked()) - - def toggle_content(self, *args): - if len(args) > 0: - checked = args[0] - else: - checked = self.button_toggle.isChecked() - arrow_type = QtCore.Qt.RightArrow - if checked: - arrow_type = QtCore.Qt.DownArrow - self.button_toggle.setChecked(checked) - self.button_toggle.setArrowType(arrow_type) - self.content_widget.setVisible(checked) - self.parent().updateGeometry() - - def resizeEvent(self, event): - super(DictExpandWidget, self).resizeEvent(event) - self.content_widget.updateGeometry() - - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - - def apply_overrides(self, override_value): - # Make sure this is set to False - self._is_overriden = False - self._state = None - self._child_state = None - for item in self.input_fields: - if override_value is None: - child_value = None - else: - child_value = override_value.get(item.key) - - item.apply_overrides(child_value) - - self._is_overriden = ( - self.is_group - and self.is_overidable - and ( - override_value is not None - or self.child_overriden - ) - ) - self.update_style() - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_group: - if self.is_overidable: - self._is_overriden = True - - # TODO update items - if item is not None: - for _item in self.input_fields: - if _item is not item: - _item.update_style() - - self.value_changed.emit(self) - - self.update_style() - - def update_style(self, is_overriden=None): - child_modified = self.child_modified - child_state = self.style_state(self.child_overriden, child_modified) - if child_state: - child_state = "child-{}".format(child_state) - - if child_state != self._child_state: - self.setProperty("state", child_state) - self.style().polish(self) - self._child_state = child_state - - state = self.style_state(self.is_overriden, self.is_modified) - if self._state == state: - return - - self.button_toggle_text.setProperty("state", state) - self.button_toggle_text.style().polish(self.button_toggle_text) - - self._state = state - - @property - def is_modified(self): - if self.is_group: - return self.child_modified - return False - - @property - def child_modified(self): - for input_field in self.input_fields: - if input_field.child_modified: - return True - return False - - @property - def child_overriden(self): - for input_field in self.input_fields: - if input_field.child_overriden: - return True - return False - - def item_value(self): - output = {} - for input_field in self.input_fields: - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output - - def config_value(self): - return {self.key: self.item_value()} - - @property - def is_overidable(self): - return self._parent.is_overidable - - def add_children_gui(self, child_configuration, values): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - - item = klass( - child_configuration, values, self.keys, self - ) - item.value_changed.connect(self._on_value_change) - self.content_layout.addWidget(item) - - self.input_fields.append(item) - return item - - def overrides(self): - if not self.is_overriden and not self.child_overriden: - return NOT_SET - - values = {} - for input_field in self.input_fields: - value = input_field.overrides() - if value is NOT_SET: - continue - values.update(value) - return {self.key: values} - - -class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): - # TODO is not overridable by itself - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, values, parent_keys, parent, label_widget=None - ): - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - self.any_parent_is_group = any_parent_is_group - - self._is_overriden = False - self.is_modified = False - self.is_group = is_group - - super(DictInvisible, self).__init__(parent) - self.setObjectName("DictInvisible") - - self.setAttribute(QtCore.Qt.WA_StyledBackground) - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - self.input_fields = [] - - if "key" not in input_data: - print(json.dumps(input_data, indent=4)) - - self.key = input_data["key"] - self.keys = list(parent_keys) - self.keys.append(self.key) - - for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) - - def update_style(self, *args, **kwargs): - return - - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - - @property - def is_overidable(self): - return self._parent.is_overidable - - @property - def child_modified(self): - for input_field in self.input_fields: - if input_field.child_modified: - return True - return False - - @property - def child_overriden(self): - for input_field in self.input_fields: - if input_field.child_overriden: - return True - return False - - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - - def item_value(self): - output = {} - for input_field in self.input_fields: - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output - - def config_value(self): - return {self.key: self.item_value()} - - def add_children_gui(self, child_configuration, values): - item_type = child_configuration["type"] - if item_type == "schema": - for _schema in child_configuration["children"]: - children = config.gui_schema(_schema) - self.add_children_gui(children, values) - return - - klass = TypeToKlass.types.get(item_type) - item = klass( - child_configuration, values, self.keys, self - ) - self.layout().addWidget(item) - - item.value_changed.connect(self._on_value_change) - - self.input_fields.append(item) - return item - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_group: - if self.is_overidable: - self._is_overriden = True - # TODO update items - if item is not None: - is_overriden = self.is_overriden - for _item in self.input_fields: - if _item is not item: - _item.update_style(is_overriden) - - self.value_changed.emit(self) - - def apply_overrides(self, override_value): - self._is_overriden = False - for item in self.input_fields: - if override_value is None: - child_value = None - else: - child_value = override_value.get(item.key) - item.apply_overrides(child_value) - - self._is_overriden = ( - self.is_group - and self.is_overidable - and ( - override_value is not None - or self.child_overriden - ) - ) - self.update_style() - - def overrides(self): - if not self.is_overriden and not self.child_overriden: - return NOT_SET - - values = {} - for input_field in self.input_fields: - value = input_field.overrides() - if value is NOT_SET: - continue - values.update(value) - return {self.key: values} - - -class DictFormWidget(QtWidgets.QWidget): - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, values, parent_keys, parent, label_widget=None - ): - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self.any_parent_is_group = any_parent_is_group - - self.is_modified = False - self._is_overriden = False - self.is_group = False - - super(DictFormWidget, self).__init__(parent) - - self.input_fields = {} - self.content_layout = QtWidgets.QFormLayout(self) - - self.keys = list(parent_keys) - - for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - self.value_changed.emit(self) - - @property - def is_overriden(self): - return self._parent.is_overriden - - @property - def child_modified(self): - for input_field in self.input_fields.values(): - if input_field.child_modified: - return True - return False - - @property - def child_overriden(self): - for input_field in self.input_fields.values(): - if input_field.child_overriden: - return True - return False - - @property - def is_overidable(self): - return self._parent.is_overidable - - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - - def add_children_gui(self, child_configuration, values): - item_type = child_configuration["type"] - key = child_configuration["key"] - # Pop label to not be set in child - label = child_configuration["label"] - - klass = TypeToKlass.types.get(item_type) - - label_widget = QtWidgets.QLabel(label) - - item = klass( - child_configuration, values, self.keys, self, label_widget - ) - item.value_changed.connect(self._on_value_change) - self.content_layout.addRow(label_widget, item) - self.input_fields[key] = item - return item - - def item_value(self): - output = {} - for input_field in self.input_fields.values(): - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output - - def config_value(self): - return self.item_value() - - def overrides(self): - if not self.is_overiden and not self.child_overriden: - return NOT_SET - - values = {} - for input_field in self.input_fields: - value = input_field.overrides() - if value is not NOT_SET: - values.update(value) - return values - class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): _btn_size = 20 @@ -2008,7 +1492,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): return output -class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): +class ModifiableDict(ExpandingWidget, PypeConfigurationWidget, InputWidget): # Should be used only for dictionary with one datatype as value # TODO this is actually input field (do not care if is group or not) value_changed = QtCore.Signal(object) @@ -2138,10 +1622,506 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} + +class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + if values is AS_WIDGET: + raise TypeError("Can't use \"{}\" as widget item.".format( + self.__class__.__name__ + )) + self._parent = parent + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + + self._is_modified = False + self._is_overriden = False + self.is_group = is_group + + self._state = None + self._child_state = None + + super(DictExpandWidget, self).__init__(parent) + self.setObjectName("DictExpandWidget") + top_part = ClickableWidget(parent=self) + + button_size = QtCore.QSize(5, 5) + button_toggle = QtWidgets.QToolButton(parent=top_part) + button_toggle.setProperty("btn-type", "expand-toggle") + button_toggle.setIconSize(button_size) + button_toggle.setArrowType(QtCore.Qt.RightArrow) + button_toggle.setCheckable(True) + button_toggle.setChecked(False) + + label = input_data["label"] + button_toggle_text = QtWidgets.QLabel(label, parent=top_part) + button_toggle_text.setObjectName("ExpandLabel") + + layout = QtWidgets.QHBoxLayout(top_part) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(button_toggle) + layout.addWidget(button_toggle_text) + top_part.setLayout(layout) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(9, 9, 9, 9) + + content_widget = QtWidgets.QWidget(self) + content_widget.setVisible(False) + + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(3, 3, 3, 3) + + main_layout.addWidget(top_part) + main_layout.addWidget(content_widget) + self.setLayout(main_layout) + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + self.top_part = top_part + self.button_toggle = button_toggle + self.button_toggle_text = button_toggle_text + + self.content_widget = content_widget + self.content_layout = content_layout + + self.top_part.clicked.connect(self._top_part_clicked) + self.button_toggle.clicked.connect(self.toggle_content) + + self.input_fields = [] + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + def _top_part_clicked(self): + self.toggle_content(not self.button_toggle.isChecked()) + + def toggle_content(self, *args): + if len(args) > 0: + checked = args[0] + else: + checked = self.button_toggle.isChecked() + arrow_type = QtCore.Qt.RightArrow + if checked: + arrow_type = QtCore.Qt.DownArrow + self.button_toggle.setChecked(checked) + self.button_toggle.setArrowType(arrow_type) + self.content_widget.setVisible(checked) + self.parent().updateGeometry() + + def resizeEvent(self, event): + super(DictExpandWidget, self).resizeEvent(event) + self.content_widget.updateGeometry() + + @property + def is_overriden(self): + return self._is_overriden or self._parent.is_overriden + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + + def apply_overrides(self, override_value): + # Make sure this is set to False + self._is_overriden = False + self._state = None + self._child_state = None + for item in self.input_fields: + if override_value is None: + child_value = None + else: + child_value = override_value.get(item.key) + + item.apply_overrides(child_value) + + self._is_overriden = ( + self.is_group + and self.is_overidable + and ( + override_value is not None + or self.child_overriden + ) + ) + self.update_style() + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + if self.is_group: + if self.is_overidable: + self._is_overriden = True + + # TODO update items + if item is not None: + for _item in self.input_fields: + if _item is not item: + _item.update_style() + + self.value_changed.emit(self) + + self.update_style() + + def update_style(self, is_overriden=None): + child_modified = self.child_modified + child_state = self.style_state(self.child_overriden, child_modified) + if child_state: + child_state = "child-{}".format(child_state) + + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state + + state = self.style_state(self.is_overriden, self.is_modified) + if self._state == state: + return + + self.button_toggle_text.setProperty("state", state) + self.button_toggle_text.style().polish(self.button_toggle_text) + + self._state = state + + @property + def is_modified(self): + if self.is_group: + return self.child_modified + return False + + @property + def child_modified(self): + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False + + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + + def item_value(self): + output = {} + for input_field in self.input_fields: + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return {self.key: self.item_value()} + + @property + def is_overidable(self): + return self._parent.is_overidable + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + item = klass( + child_configuration, values, self.keys, self + ) + item.value_changed.connect(self._on_value_change) + self.content_layout.addWidget(item) + + self.input_fields.append(item) + return item + def overrides(self): - if not self.is_overiden: - return NOT_SET - return self.config_value() + if not self.is_overriden and not self.child_overriden: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(values.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return {self.key: values}, self.is_group + + +class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): + # TODO is not overridable by itself + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + + self._is_overriden = False + self.is_modified = False + self.is_group = is_group + + super(DictInvisible, self).__init__(parent) + self.setObjectName("DictInvisible") + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + self.input_fields = [] + + if "key" not in input_data: + print(json.dumps(input_data, indent=4)) + + self.key = input_data["key"] + self.keys = list(parent_keys) + self.keys.append(self.key) + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + def update_style(self, *args, **kwargs): + return + + @property + def is_overriden(self): + return self._is_overriden or self._parent.is_overriden + + @property + def is_overidable(self): + return self._parent.is_overidable + + @property + def child_modified(self): + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False + + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + + def item_value(self): + output = {} + for input_field in self.input_fields: + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return {self.key: self.item_value()} + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + if item_type == "schema": + for _schema in child_configuration["children"]: + children = config.gui_schema(_schema) + self.add_children_gui(children, values) + return + + klass = TypeToKlass.types.get(item_type) + item = klass( + child_configuration, values, self.keys, self + ) + self.layout().addWidget(item) + + item.value_changed.connect(self._on_value_change) + + self.input_fields.append(item) + return item + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + if self.is_group: + if self.is_overidable: + self._is_overriden = True + # TODO update items + if item is not None: + is_overriden = self.is_overriden + for _item in self.input_fields: + if _item is not item: + _item.update_style(is_overriden) + + self.value_changed.emit(self) + + def apply_overrides(self, override_value): + self._is_overriden = False + for item in self.input_fields: + if override_value is None: + child_value = None + else: + child_value = override_value.get(item.key) + item.apply_overrides(child_value) + + self._is_overriden = ( + self.is_group + and self.is_overidable + and ( + override_value is not None + or self.child_overriden + ) + ) + self.update_style() + + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(values.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return {self.key: values}, self.is_group + + +class DictFormWidget(QtWidgets.QWidget): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + self.any_parent_is_group = any_parent_is_group + + self.is_modified = False + self._is_overriden = False + self.is_group = False + + super(DictFormWidget, self).__init__(parent) + + self.input_fields = {} + self.content_layout = QtWidgets.QFormLayout(self) + + self.keys = list(parent_keys) + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + self.value_changed.emit(self) + + @property + def is_overriden(self): + return self._parent.is_overriden + + @property + def child_modified(self): + for input_field in self.input_fields.values(): + if input_field.child_modified: + return True + return False + + @property + def child_overriden(self): + for input_field in self.input_fields.values(): + if input_field.child_overriden: + return True + return False + + @property + def is_overidable(self): + return self._parent.is_overidable + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + key = child_configuration["key"] + # Pop label to not be set in child + label = child_configuration["label"] + + klass = TypeToKlass.types.get(item_type) + + label_widget = QtWidgets.QLabel(label) + + item = klass( + child_configuration, values, self.keys, self, label_widget + ) + item.value_changed.connect(self._on_value_change) + self.content_layout.addRow(label_widget, item) + self.input_fields[key] = item + return item + + def item_value(self): + output = {} + for input_field in self.input_fields.values(): + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def config_value(self): + return self.item_value() + + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(values.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return {self.key: values}, self.is_group TypeToKlass.types["boolean"] = BooleanWidget diff --git a/pype/tools/config_setting/widgets/lib.py b/pype/tools/config_setting/widgets/lib.py index ac0a353d53..bf6d2d0fbd 100644 --- a/pype/tools/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/widgets/lib.py @@ -41,4 +41,13 @@ class CustomNone: NOT_SET = CustomNone() -AS_WIDGET = CustomNone() +AS_WIDGET = type("AS_WIDGET", (), {}) +METADATA_KEY = type("METADATA_KEY", (), {}) + + +def convert_gui_data_to_overrides(data): + pass + + +def convert_overrides_to_gui_data(data): + pass From f1d5ef05aae4a94a3cbf1877537a7b97b091b03a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 19 Aug 2020 16:47:25 +0200 Subject: [PATCH 082/580] added conversion from override gui data to regular override and back --- pype/tools/config_setting/widgets/base.py | 4 +- pype/tools/config_setting/widgets/config.py | 11 +-- pype/tools/config_setting/widgets/inputs.py | 6 +- pype/tools/config_setting/widgets/lib.py | 80 +++++++++++---------- 4 files changed, 52 insertions(+), 49 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 156f1f80e4..bdacb60559 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -3,7 +3,7 @@ import json from Qt import QtWidgets, QtCore, QtGui from . import config from .widgets import UnsavedChangesDialog -from .lib import NOT_SET, METADATA_KEY +from .lib import NOT_SET, METADATA_KEY, convert_gui_data_to_overrides from avalon import io @@ -404,7 +404,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): if groups: data[METADATA_KEY] = {"groups": groups} - output = convert_to_override(data) + output = convert_gui_data_to_overrides(data) print(json.dumps(output, indent=4)) def _save_defaults(self): diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 8319c3d51d..62a3adb782 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -23,8 +23,9 @@ project_presets_path = os.path.normpath( ) first_run = False -OVERRIDE_KEY = "__overriden__" -POP_KEY = "__popkey__" +OVERRIDEN_KEY = "__overriden_keys__" +# TODO key popping not implemented yet +POP_KEY = "__pop_key__" def load_json(fpath): @@ -178,8 +179,8 @@ def project_preset_overrides(project_name, **kwargs): def merge_overrides(global_dict, override_dict): - if OVERRIDE_KEY in override_dict: - _override = override_dict.pop(OVERRIDE_KEY) + if OVERRIDEN_KEY in override_dict: + _override = override_dict.pop(OVERRIDEN_KEY) if _override: return override_dict @@ -187,7 +188,7 @@ def merge_overrides(global_dict, override_dict): if value == POP_KEY: global_dict.pop(key) - elif key == OVERRIDE_KEY: + elif key == OVERRIDEN_KEY: continue elif key not in global_dict: diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/widgets/inputs.py index bb2d76fc71..1840572cfb 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/widgets/inputs.py @@ -1858,7 +1858,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: values.update(value) if is_group: - groups.extend(values.keys()) + groups.extend(value.keys()) if groups: values[METADATA_KEY] = {"groups": groups} return {self.key: values}, self.is_group @@ -2013,7 +2013,7 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): if value is not NOT_SET: values.update(value) if is_group: - groups.extend(values.keys()) + groups.extend(value.keys()) if groups: values[METADATA_KEY] = {"groups": groups} return {self.key: values}, self.is_group @@ -2118,7 +2118,7 @@ class DictFormWidget(QtWidgets.QWidget): if value is not NOT_SET: values.update(value) if is_group: - groups.extend(values.keys()) + groups.extend(value.keys()) if groups: values[METADATA_KEY] = {"groups": groups} return {self.key: values}, self.is_group diff --git a/pype/tools/config_setting/widgets/lib.py b/pype/tools/config_setting/widgets/lib.py index bf6d2d0fbd..fd3f45b590 100644 --- a/pype/tools/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/widgets/lib.py @@ -1,53 +1,55 @@ -import uuid +from .config import OVERRIDEN_KEY class CustomNone: - """Created object can be used as custom None (not equal to None). - - WARNING: Multiple created objects are not equal either. - Exmple: - >>> a = CustomNone() - >>> a == None - False - >>> b = CustomNone() - >>> a == b - False - >>> a == a - True - """ - - def __init__(self): - """Create uuid as identifier for custom None.""" - self.identifier = str(uuid.uuid4()) - + """Created object can be used as custom None (not equal to None).""" def __bool__(self): """Return False (like default None).""" return False - def __eq__(self, other): - """Equality is compared by identifier value.""" - if type(other) == type(self): - if other.identifier == self.identifier: - return True - return False - - def __str__(self): - """Return value of identifier when converted to string.""" - return "".format(str(self.identifier)) - - def __repr__(self): - """Representation of custom None.""" - return "".format(str(self.identifier)) - NOT_SET = CustomNone() AS_WIDGET = type("AS_WIDGET", (), {}) + METADATA_KEY = type("METADATA_KEY", (), {}) - -def convert_gui_data_to_overrides(data): - pass +OVERRIDE_VERSION = 1 -def convert_overrides_to_gui_data(data): - pass +def convert_gui_data_to_overrides(data, first=True): + if not data or not isinstance(data, dict): + return data + + output = {} + if first: + output["__override_version__"] = OVERRIDE_VERSION + + if METADATA_KEY in data: + metadata = data.pop(METADATA_KEY) + for key, value in metadata.items(): + if key == "groups": + print("**", value) + output[OVERRIDEN_KEY] = value + else: + KeyError("Unknown metadata key \"{}\"".format(key)) + + for key, value in data.items(): + output[key] = convert_gui_data_to_overrides(value, False) + return output + + +def convert_overrides_to_gui_data(data, first=True): + if not data or not isinstance(data, dict): + return data + + output = {} + if OVERRIDEN_KEY in data: + groups = data.pop(OVERRIDEN_KEY) + if METADATA_KEY not in output: + output[METADATA_KEY] = {} + output[METADATA_KEY]["groups"] = groups + + for key, value in data.items(): + output[key] = convert_overrides_to_gui_data(value, False) + + return output From c161a637433bf8b7b0b211dced4c4a99c919ad47 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 19 Aug 2020 18:05:03 +0100 Subject: [PATCH 083/580] Fix alembic settings being reset when updating reference. --- pype/hosts/maya/plugin.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pype/hosts/maya/plugin.py b/pype/hosts/maya/plugin.py index ed244d56df..3b002eed10 100644 --- a/pype/hosts/maya/plugin.py +++ b/pype/hosts/maya/plugin.py @@ -174,6 +174,18 @@ class ReferenceLoader(api.Loader): assert os.path.exists(path), "%s does not exist." % path + # Need to save alembic settings and reapply, cause referencing resets + # them to incoming data. + alembic_attrs = ["speed", "offset", "cycleType"] + alembic_data = {} + if representation["name"] == "abc": + alembic_node = cmds.ls( + cmds.sets(node, query=True), type="AlembicNode" + )[0] + for attr in alembic_attrs: + node_attr = "{}.{}".format(alembic_node, attr) + alembic_data[attr] = cmds.getAttr(node_attr) + try: content = cmds.file(path, loadReference=reference_node, @@ -195,6 +207,21 @@ class ReferenceLoader(api.Loader): self.log.warning("Ignoring file read error:\n%s", exc) + # Reapply alembic settings. + if representation["name"] == "abc": + alembic_node = None + for member in cmds.sets(node, query=True): + shapes = cmds.listRelatives(member, shapes=True) + if shapes: + nodes = cmds.listConnections(shapes[0], type="AlembicNode") + if nodes: + alembic_node = nodes[0] + break + + for attr in alembic_attrs: + value = alembic_data[attr] + cmds.setAttr("{}.{}".format(alembic_node, attr), value) + # Fix PLN-40 for older containers created with Avalon that had the # `.verticesOnlySet` set to True. if cmds.getAttr("{}.verticesOnlySet".format(node)): From 91e65b1f15a3b7b5f795d0e6fbbbc6755a957391 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 20 Aug 2020 00:09:28 +0100 Subject: [PATCH 084/580] Safer alembic node search. --- pype/hosts/maya/plugin.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/pype/hosts/maya/plugin.py b/pype/hosts/maya/plugin.py index 3b002eed10..a5c57f1ab8 100644 --- a/pype/hosts/maya/plugin.py +++ b/pype/hosts/maya/plugin.py @@ -179,12 +179,19 @@ class ReferenceLoader(api.Loader): alembic_attrs = ["speed", "offset", "cycleType"] alembic_data = {} if representation["name"] == "abc": - alembic_node = cmds.ls( - cmds.sets(node, query=True), type="AlembicNode" - )[0] - for attr in alembic_attrs: - node_attr = "{}.{}".format(alembic_node, attr) - alembic_data[attr] = cmds.getAttr(node_attr) + alembic_nodes = cmds.ls( + "{}:*".format(members[0].split(":")[0]), type="AlembicNode" + ) + if alembic_nodes: + for attr in alembic_attrs: + node_attr = "{}.{}".format(alembic_nodes[0], attr) + alembic_data[attr] = cmds.getAttr(node_attr) + else: + cmds.warning( + "No alembic nodes found in {}".format( + cmds.ls("{}:*".format(members[0].split(":")[0])) + ) + ) try: content = cmds.file(path, @@ -209,18 +216,13 @@ class ReferenceLoader(api.Loader): # Reapply alembic settings. if representation["name"] == "abc": - alembic_node = None - for member in cmds.sets(node, query=True): - shapes = cmds.listRelatives(member, shapes=True) - if shapes: - nodes = cmds.listConnections(shapes[0], type="AlembicNode") - if nodes: - alembic_node = nodes[0] - break - - for attr in alembic_attrs: - value = alembic_data[attr] - cmds.setAttr("{}.{}".format(alembic_node, attr), value) + alembic_nodes = cmds.ls( + "{}:*".format(members[0].split(":")[0]), type="AlembicNode" + ) + if alembic_nodes: + for attr in alembic_attrs: + value = alembic_data[attr] + cmds.setAttr("{}.{}".format(alembic_nodes[0], attr), value) # Fix PLN-40 for older containers created with Avalon that had the # `.verticesOnlySet` set to True. From eb74ea9253a42e33e1f034bec2c1d83829e39834 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 10:03:59 +0200 Subject: [PATCH 085/580] get rid of metadata loading --- pype/tools/config_setting/widgets/config.py | 36 +++------------------ 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 62a3adb782..8d9d4fa1d2 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -86,31 +86,16 @@ def load_json(fpath): return {} -def subkey_merge(_dict, value, keys, with_metadata=False): +def subkey_merge(_dict, value, keys): key = keys.pop(0) if not keys: - if with_metadata: - _dict[key] = {"type": "file", "value": value} - else: - _dict[key] = value + _dict[key] = value return _dict if key not in _dict: - if with_metadata: - _dict[key] = {"type": "folder", "value": {}} - else: - _dict[key] = {} + _dict[key] = {} + _dict[key] = subkey_merge(_dict[key], value, keys) - if with_metadata: - sub_dict = _dict[key]["value"] - else: - sub_dict = _dict[key] - - _value = subkey_merge(sub_dict, value, keys, with_metadata) - if with_metadata: - _dict[key]["value"] = _value - else: - _dict[key] = _value return _dict @@ -122,7 +107,6 @@ def load_jsons_from_dir(path, *args, **kwargs): # TODO warning return output - with_metadata = kwargs.get("with_metadata") sub_keys = list(kwargs.pop("subkeys", args)) for sub_key in tuple(sub_keys): _path = os.path.join(path, sub_key) @@ -143,7 +127,7 @@ def load_jsons_from_dir(path, *args, **kwargs): # dict_path = os.path.join(base[base_len:], basename) # dict_keys = dict_path.split(os.path.sep) dict_keys = base[base_len:].split(os.path.sep) + [basename] - output = subkey_merge(output, value, dict_keys, with_metadata) + output = subkey_merge(output, value, dict_keys) for sub_key in sub_keys: output = output[sub_key] @@ -158,16 +142,6 @@ def global_project_presets(**kwargs): return load_jsons_from_dir(project_presets_path, **kwargs) -def studio_presets_with_metadata(*args, **kwargs): - kwargs["with_metadata"] = True - return load_jsons_from_dir(studio_presets_path, *args, **kwargs) - - -def global_project_presets_with_metadata(**kwargs): - kwargs["with_metadata"] = True - return load_jsons_from_dir(project_presets_path, **kwargs) - - def project_preset_overrides(project_name, **kwargs): project_configs_path = os.environ.get("PYPE_PROJECT_CONFIGS") if project_name and project_configs_path: From 4c6e5fefb415eab87ee52fd3b0bceb416f0643bf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 16:05:03 +0200 Subject: [PATCH 086/580] implemented action for pushing frameStart and frameEnd values to task specific custom attributes --- .../action_push_frame_values_to_task.py | 245 ++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 pype/modules/ftrack/actions/action_push_frame_values_to_task.py diff --git a/pype/modules/ftrack/actions/action_push_frame_values_to_task.py b/pype/modules/ftrack/actions/action_push_frame_values_to_task.py new file mode 100644 index 0000000000..3037695452 --- /dev/null +++ b/pype/modules/ftrack/actions/action_push_frame_values_to_task.py @@ -0,0 +1,245 @@ +import json +import collections +import ftrack_api +from pype.modules.ftrack.lib import BaseAction, statics_icon + + +class PushFrameValuesToTaskAction(BaseAction): + """Action for testing purpose or as base for new actions.""" + + identifier = "admin.push_frame_values_to_task" + label = "Pype Admin" + variant = "- Push Frame values to Task" + role_list = ["Pypeclub", "Administrator", "Project Manager"] + icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg") + + entities_query = ( + "select id, name, parent_id, link" + " from TypedContext where project_id is \"{}\"" + ) + cust_attrs_query = ( + "select id, key, object_type_id, is_hierarchical, default" + " from CustomAttributeConfiguration" + " where key in ({})" + ) + cust_attr_value_query = ( + "select value, entity_id from CustomAttributeValue" + " where entity_id in ({}) and configuration_id in ({})" + ) + custom_attribute_keys = ["frameStart", "frameEnd"] + + def discover(self, session, entities, event): + return True + + def launch(self, session, entities, event): + task_attrs_by_key, hier_attrs = self.frame_attributes(session) + missing_keys = [ + key + for key in self.custom_attribute_keys + if key not in task_attrs_by_key + ] + if missing_keys: + if len(missing_keys) == 1: + sub_msg = " \"{}\"".format(missing_keys[0]) + else: + sub_msg = "s {}".format(", ".join([ + "\"{}\"".format(key) + for key in missing_keys + ])) + + msg = "Missing Task's custom attribute{}.".format(sub_msg) + self.log.warning(msg) + return { + "success": False, + "message": msg + } + + self.log.debug("{}: Creating job".format(self.label)) + + user_entity = session.query( + "User where id is {}".format(event["source"]["user"]["id"]) + ).one() + job = session.create("Job", { + "user": user_entity, + "status": "running", + "data": json.dumps({ + "description": "Propagation of Frame attribute values to task." + }) + }) + session.commit() + + try: + project_entity = self.get_project_from_entity(entities[0]) + result = self.propagate_values( + session, + tuple(task_attrs_by_key.values()), + hier_attrs, + project_entity + ) + job["status"] = "done" + session.commit() + + return result + + except Exception: + session.rollback() + job["status"] = "failed" + session.commit() + + msg = "Pushing Custom attribute values to task Failed" + self.log.warning(msg, exc_info=True) + return { + "success": False, + "message": msg + } + + finally: + if job["status"] == "running": + job["status"] = "failed" + session.commit() + + def frame_attributes(self, session): + task_object_type = session.query( + "ObjectType where name is \"Task\"" + ).one() + + attr_names = self.custom_attribute_keys + if isinstance(attr_names, str): + attr_names = [attr_names] + + joined_keys = ",".join([ + "\"{}\"".format(attr_name) + for attr_name in attr_names + ]) + + attribute_entities = session.query( + self.cust_attrs_query.format(joined_keys) + ).all() + + hier_attrs = [] + task_attrs = {} + for attr in attribute_entities: + attr_key = attr["key"] + if attr["is_hierarchical"]: + hier_attrs.append(attr) + elif attr["object_type_id"] == task_object_type["id"]: + task_attrs[attr_key] = attr + return task_attrs, hier_attrs + + def join_keys(self, items): + return ",".join(["\"{}\"".format(item) for item in items]) + + def propagate_values( + self, session, task_attrs, hier_attrs, project_entity + ): + self.log.debug("Querying project's entities \"{}\".".format( + project_entity["full_name"] + )) + entities = session.query( + self.entities_query.format(project_entity["id"]) + ).all() + + self.log.debug("Filtering Task entities.") + task_entities_by_parent_id = collections.defaultdict(list) + for entity in entities: + if entity.entity_type.lower() == "task": + task_entities_by_parent_id[entity["parent_id"]].append(entity) + + self.log.debug("Getting Custom attribute values from tasks' parents.") + hier_values_by_entity_id = self.get_hier_values( + session, + hier_attrs, + list(task_entities_by_parent_id.keys()) + ) + + self.log.debug("Setting parents' values to task.") + self.set_task_attr_values( + session, + task_entities_by_parent_id, + hier_values_by_entity_id, + task_attrs + ) + + return True + + def get_hier_values(self, session, hier_attrs, focus_entity_ids): + joined_entity_ids = self.join_keys(focus_entity_ids) + hier_attr_ids = self.join_keys( + tuple(hier_attr["id"] for hier_attr in hier_attrs) + ) + hier_attrs_key_by_id = { + hier_attr["id"]: hier_attr["key"] + for hier_attr in hier_attrs + } + call_expr = [{ + "action": "query", + "expression": self.cust_attr_value_query.format( + joined_entity_ids, hier_attr_ids + ) + }] + if hasattr(session, "call"): + [values] = session.call(call_expr) + else: + [values] = session._call(call_expr) + + values_per_entity_id = {} + for item in values["data"]: + entity_id = item["entity_id"] + key = hier_attrs_key_by_id[item["configuration_id"]] + + if entity_id not in values_per_entity_id: + values_per_entity_id[entity_id] = {} + value = item["value"] + if value is not None: + values_per_entity_id[entity_id][key] = value + + output = {} + for entity_id in focus_entity_ids: + value = values_per_entity_id.get(entity_id) + if value: + output[entity_id] = value + + return output + + def set_task_attr_values( + self, + session, + task_entities_by_parent_id, + hier_values_by_entity_id, + task_attrs + ): + task_attr_ids_by_key = { + attr["key"]: attr["id"] + for attr in task_attrs + } + + total_parents = len(hier_values_by_entity_id) + idx = 1 + for parent_id, values in hier_values_by_entity_id.items(): + self.log.info(( + "[{}/{}] {} Processing values to children. Values: {}" + ).format(idx, total_parents, parent_id, values)) + + task_entities = task_entities_by_parent_id[parent_id] + for key, value in values.items(): + for task_entity in task_entities: + _entity_key = collections.OrderedDict({ + "configuration_id": task_attr_ids_by_key[key], + "entity_id": task_entity["id"] + }) + + session.recorded_operations.push( + ftrack_api.operation.UpdateEntityOperation( + "ContextCustomAttributeValue", + _entity_key, + "value", + ftrack_api.symbol.NOT_SET, + value + ) + ) + session.commit() + idx += 1 + + +def register(session, plugins_presets={}): + PushFrameValuesToTask(session, plugins_presets).register() From 1431930e6af89df656cced3572598907d13525ad Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 16:05:13 +0200 Subject: [PATCH 087/580] implemented event handler for pushing frameStart and frameEnd values to task specific custom attributes --- .../events/event_push_frame_values_to_task.py | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 pype/modules/ftrack/events/event_push_frame_values_to_task.py diff --git a/pype/modules/ftrack/events/event_push_frame_values_to_task.py b/pype/modules/ftrack/events/event_push_frame_values_to_task.py new file mode 100644 index 0000000000..dd5c5911ec --- /dev/null +++ b/pype/modules/ftrack/events/event_push_frame_values_to_task.py @@ -0,0 +1,148 @@ +import collections +import ftrack_api +from pype.modules.ftrack import BaseEvent + + +class PushFrameValuesToTaskEvent(BaseEvent): + """Action for testing purpose or as base for new actions.""" + cust_attrs_query = ( + "select id, key, object_type_id, is_hierarchical, default" + " from CustomAttributeConfiguration" + " where key in ({}) and object_type_id = {}" + ) + + # Ignore event handler by default + ignore_me = True + + interest_attributes = ["frameStart", "frameEnd"] + _cached_task_object_id = None + + @classmethod + def task_object_id(cls, session): + if cls._cached_task_object_id is None: + task_object_type = session.query( + "ObjectType where name is \"Task\"" + ).one() + cls._cached_task_object_id = task_object_type["id"] + return cls._cached_task_object_id + + def extract_interesting_data(self, session, event): + # Filter if event contain relevant data + entities_info = event["data"].get("entities") + if not entities_info: + return + + interesting_data = {} + for entity_info in entities_info: + # Care only about tasks + if entity_info.get("entityType") != "task": + continue + + # Care only about changes of status + changes = entity_info.get("changes") or {} + if not changes: + continue + + # Care only about changes if specific keys + entity_changes = {} + for key in self.interest_attributes: + if key in changes: + entity_changes[key] = changes[key]["new"] + + if not entity_changes: + continue + + # Do not care about "Task" entity_type + task_object_id = self.task_object_id(session) + if entity_info.get("objectTypeId") == task_object_id: + continue + + interesting_data[entity_info["entityId"]] = entity_changes + return interesting_data + + def join_keys(self, keys): + return ",".join(["\"{}\"".format(key) for key in keys]) + + def get_task_entities(self, session, entities_info): + return session.query( + "Task where parent_id in ({})".format( + self.join_keys(entities_info.keys()) + ) + ).all() + + def task_attrs(self, session): + return session.query(self.cust_attrs_query.format( + self.join_keys(self.interest_attributes), + self.task_object_id(session) + )).all() + + def launch(self, session, event): + interesting_data = self.extract_interesting_data(session, event) + if not interesting_data: + return + + task_entities = self.get_task_entities(session, interesting_data) + if not task_entities: + return + + task_attrs = self.task_attrs(session) + if not task_attrs: + self.log.warning(( + "There is not created Custom Attributes {}" + " for \"Task\" entity type." + ).format(self.join_keys(self.interest_attributes))) + return + + task_attr_id_by_key = { + attr["key"]: attr["id"] + for attr in task_attrs + } + task_entities_by_parent_id = collections.defaultdict(list) + for task_entity in task_entities: + task_entities_by_parent_id[task_entity["parent_id"]].append( + task_entity + ) + + for parent_id, values in interesting_data.items(): + task_entities = task_entities_by_parent_id[parent_id] + for key, value in values.items(): + changed_ids = [] + for task_entity in task_entities: + task_id = task_entity["id"] + changed_ids.append(task_id) + + entity_key = collections.OrderedDict({ + "configuration_id": task_attr_id_by_key[key], + "entity_id": task_id + }) + if value is None: + op = ftrack_api.operation.DeleteEntityOperation( + "CustomAttributeValue", + entity_key + ) + else: + op = ftrack_api.operation.UpdateEntityOperation( + "ContextCustomAttributeValue", + entity_key, + "value", + ftrack_api.symbol.NOT_SET, + value + ) + + session.recorded_operations.push(op) + self.log.info(( + "Changing Custom Attribute \"{}\" to value" + " \"{}\" on entities: {}" + ).format(key, value, self.join_keys(changed_ids))) + try: + session.commit() + except Exception: + session.rollback() + self.log.warning( + "Changing of values failed.", + exc_info=True + ) + + +def register(session, plugins_presets): + PushFrameValuesToTaskEvent(session, plugins_presets).register() From 516fafbfec822e8b5f2957bdd108f157412a5963 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 16:39:16 +0200 Subject: [PATCH 088/580] moved action to server --- .../{actions => events}/action_push_frame_values_to_task.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pype/modules/ftrack/{actions => events}/action_push_frame_values_to_task.py (100%) diff --git a/pype/modules/ftrack/actions/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py similarity index 100% rename from pype/modules/ftrack/actions/action_push_frame_values_to_task.py rename to pype/modules/ftrack/events/action_push_frame_values_to_task.py From 8ae527a154c24d0b0e5634546d759f421f0c0426 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 16:39:47 +0200 Subject: [PATCH 089/580] action converted to server action --- .../action_push_frame_values_to_task.py | 64 ++++++++++++++----- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index 3037695452..bd036411ac 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -1,7 +1,7 @@ import json import collections import ftrack_api -from pype.modules.ftrack.lib import BaseAction, statics_icon +from pype.modules.ftrack.lib import BaseAction class PushFrameValuesToTaskAction(BaseAction): @@ -10,8 +10,6 @@ class PushFrameValuesToTaskAction(BaseAction): identifier = "admin.push_frame_values_to_task" label = "Pype Admin" variant = "- Push Frame values to Task" - role_list = ["Pypeclub", "Administrator", "Project Manager"] - icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg") entities_query = ( "select id, name, parent_id, link" @@ -26,12 +24,56 @@ class PushFrameValuesToTaskAction(BaseAction): "select value, entity_id from CustomAttributeValue" " where entity_id in ({}) and configuration_id in ({})" ) - custom_attribute_keys = ["frameStart", "frameEnd"] + custom_attribute_keys = {"frameStart", "frameEnd"} + discover_role_list = {"Pypeclub", "Administrator", "Project Manager"} + + def register(self): + modified_role_names = set() + for role_name in self.discover_role_list: + modified_role_names.add(role_name.lower()) + self.discover_role_list = modified_role_names + + self.session.event_hub.subscribe( + "topic=ftrack.action.discover", + self._discover, + priority=self.priority + ) + + launch_subscription = ( + "topic=ftrack.action.launch and data.actionIdentifier={0}" + ).format(self.identifier) + self.session.event_hub.subscribe(launch_subscription, self._launch) def discover(self, session, entities, event): - return True + """ Validation """ + # Check if selection is valid + valid_selection = False + for ent in event["data"]["selection"]: + # Ignore entities that are not tasks or projects + if ent["entityType"].lower() in ["show", "task"]: + valid_selection = True + break + + if not valid_selection: + return False + + # Get user and check his roles + user_id = event.get("source", {}).get("user", {}).get("id") + if not user_id: + return False + + user = session.query("User where id is \"{}\"".format(user_id)).first() + if not user: + return False + + for role in user["user_security_roles"]: + lowered_role = role["security_role"]["name"].lower() + if lowered_role in self.discover_role_list: + return True + return False def launch(self, session, entities, event): + # TODO this can be threaded task_attrs_by_key, hier_attrs = self.frame_attributes(session) missing_keys = [ key @@ -103,15 +145,7 @@ class PushFrameValuesToTaskAction(BaseAction): "ObjectType where name is \"Task\"" ).one() - attr_names = self.custom_attribute_keys - if isinstance(attr_names, str): - attr_names = [attr_names] - - joined_keys = ",".join([ - "\"{}\"".format(attr_name) - for attr_name in attr_names - ]) - + joined_keys = self.join_keys(self.custom_attribute_keys) attribute_entities = session.query( self.cust_attrs_query.format(joined_keys) ).all() @@ -242,4 +276,4 @@ class PushFrameValuesToTaskAction(BaseAction): def register(session, plugins_presets={}): - PushFrameValuesToTask(session, plugins_presets).register() + PushFrameValuesToTaskAction(session, plugins_presets).register() From a37da37bd15c6e5aca9c37ea56a57eb163359f11 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 16:42:56 +0200 Subject: [PATCH 090/580] commit all changes at once --- .../modules/ftrack/events/action_push_frame_values_to_task.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index bd036411ac..4f0c7ffeb7 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -253,6 +253,7 @@ class PushFrameValuesToTaskAction(BaseAction): self.log.info(( "[{}/{}] {} Processing values to children. Values: {}" ).format(idx, total_parents, parent_id, values)) + idx += 1 task_entities = task_entities_by_parent_id[parent_id] for key, value in values.items(): @@ -271,8 +272,7 @@ class PushFrameValuesToTaskAction(BaseAction): value ) ) - session.commit() - idx += 1 + session.commit() def register(session, plugins_presets={}): From 97b42d8703150038feb6833832c9da0d39df40ce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 16:46:35 +0200 Subject: [PATCH 091/580] ignore action by default --- pype/modules/ftrack/events/action_push_frame_values_to_task.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index 4f0c7ffeb7..5b7da8bebb 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -7,6 +7,9 @@ from pype.modules.ftrack.lib import BaseAction class PushFrameValuesToTaskAction(BaseAction): """Action for testing purpose or as base for new actions.""" + # Ignore event handler by default + ignore_me = True + identifier = "admin.push_frame_values_to_task" label = "Pype Admin" variant = "- Push Frame values to Task" From 07b34dec926f0135a03327d4c52aa2d2837e5199 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 17:45:59 +0200 Subject: [PATCH 092/580] show only on project --- pype/modules/ftrack/events/action_push_frame_values_to_task.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index 5b7da8bebb..e6276d84ac 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -53,7 +53,7 @@ class PushFrameValuesToTaskAction(BaseAction): valid_selection = False for ent in event["data"]["selection"]: # Ignore entities that are not tasks or projects - if ent["entityType"].lower() in ["show", "task"]: + if ent["entityType"].lower() == "show": valid_selection = True break From fb6de46cd6c186934cd878c6e055dadf86c89d83 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 19:05:56 +0200 Subject: [PATCH 093/580] pushing is also pushing to item itself --- .../action_push_frame_values_to_task.py | 279 ++++++++++++++---- 1 file changed, 221 insertions(+), 58 deletions(-) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index e6276d84ac..d88f4a1016 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -15,8 +15,8 @@ class PushFrameValuesToTaskAction(BaseAction): variant = "- Push Frame values to Task" entities_query = ( - "select id, name, parent_id, link" - " from TypedContext where project_id is \"{}\"" + "select id, name, parent_id, link from TypedContext" + " where project_id is \"{}\" and object_type_id in ({})" ) cust_attrs_query = ( "select id, key, object_type_id, is_hierarchical, default" @@ -27,7 +27,13 @@ class PushFrameValuesToTaskAction(BaseAction): "select value, entity_id from CustomAttributeValue" " where entity_id in ({}) and configuration_id in ({})" ) - custom_attribute_keys = {"frameStart", "frameEnd"} + + pushing_entity_types = {"Shot"} + hierarchical_custom_attribute_keys = {"frameStart", "frameEnd"} + custom_attribute_mapping = { + "frameStart": "fstart", + "frameEnd": "fend" + } discover_role_list = {"Pypeclub", "Administrator", "Project Manager"} def register(self): @@ -76,29 +82,6 @@ class PushFrameValuesToTaskAction(BaseAction): return False def launch(self, session, entities, event): - # TODO this can be threaded - task_attrs_by_key, hier_attrs = self.frame_attributes(session) - missing_keys = [ - key - for key in self.custom_attribute_keys - if key not in task_attrs_by_key - ] - if missing_keys: - if len(missing_keys) == 1: - sub_msg = " \"{}\"".format(missing_keys[0]) - else: - sub_msg = "s {}".format(", ".join([ - "\"{}\"".format(key) - for key in missing_keys - ])) - - msg = "Missing Task's custom attribute{}.".format(sub_msg) - self.log.warning(msg) - return { - "success": False, - "message": msg - } - self.log.debug("{}: Creating job".format(self.label)) user_entity = session.query( @@ -115,12 +98,7 @@ class PushFrameValuesToTaskAction(BaseAction): try: project_entity = self.get_project_from_entity(entities[0]) - result = self.propagate_values( - session, - tuple(task_attrs_by_key.values()), - hier_attrs, - project_entity - ) + result = self.propagate_values(session, project_entity, event) job["status"] = "done" session.commit() @@ -143,12 +121,20 @@ class PushFrameValuesToTaskAction(BaseAction): job["status"] = "failed" session.commit() - def frame_attributes(self, session): + def task_attributes(self, session): task_object_type = session.query( "ObjectType where name is \"Task\"" ).one() - joined_keys = self.join_keys(self.custom_attribute_keys) + hier_attr_names = list( + self.custom_attribute_mapping.keys() + ) + entity_type_specific_names = list( + self.custom_attribute_mapping.values() + ) + joined_keys = self.join_keys( + hier_attr_names + entity_type_specific_names + ) attribute_entities = session.query( self.cust_attrs_query.format(joined_keys) ).all() @@ -158,47 +144,139 @@ class PushFrameValuesToTaskAction(BaseAction): for attr in attribute_entities: attr_key = attr["key"] if attr["is_hierarchical"]: - hier_attrs.append(attr) + if attr_key in hier_attr_names: + hier_attrs.append(attr) elif attr["object_type_id"] == task_object_type["id"]: - task_attrs[attr_key] = attr + if attr_key in entity_type_specific_names: + task_attrs[attr_key] = attr["id"] return task_attrs, hier_attrs def join_keys(self, items): return ",".join(["\"{}\"".format(item) for item in items]) - def propagate_values( - self, session, task_attrs, hier_attrs, project_entity - ): + def propagate_values(self, session, project_entity, event): self.log.debug("Querying project's entities \"{}\".".format( project_entity["full_name"] )) - entities = session.query( - self.entities_query.format(project_entity["id"]) - ).all() + pushing_entity_types = tuple( + ent_type.lower() + for ent_type in self.pushing_entity_types + ) + destination_object_types = [] + all_object_types = session.query("ObjectType").all() + for object_type in all_object_types: + lowered_name = object_type["name"].lower() + if ( + lowered_name == "task" + or lowered_name in pushing_entity_types + ): + destination_object_types.append(object_type) + + destination_object_type_ids = tuple( + obj_type["id"] + for obj_type in destination_object_types + ) + entities = session.query(self.entities_query.format( + project_entity["id"], + self.join_keys(destination_object_type_ids) + )).all() + + entities_by_id = { + entity["id"]: entity + for entity in entities + } self.log.debug("Filtering Task entities.") task_entities_by_parent_id = collections.defaultdict(list) + non_task_entities = [] + non_task_entity_ids = [] for entity in entities: - if entity.entity_type.lower() == "task": - task_entities_by_parent_id[entity["parent_id"]].append(entity) + if entity.entity_type.lower() != "task": + non_task_entities.append(entity) + non_task_entity_ids.append(entity["id"]) + continue + + parent_id = entity["parent_id"] + if parent_id in entities_by_id: + task_entities_by_parent_id[parent_id].append(entity) + + task_attr_id_by_keys, hier_attrs = self.task_attributes(session) self.log.debug("Getting Custom attribute values from tasks' parents.") hier_values_by_entity_id = self.get_hier_values( session, hier_attrs, - list(task_entities_by_parent_id.keys()) + non_task_entity_ids ) self.log.debug("Setting parents' values to task.") - self.set_task_attr_values( + task_missing_keys = self.set_task_attr_values( session, task_entities_by_parent_id, hier_values_by_entity_id, - task_attrs + task_attr_id_by_keys ) + self.log.debug("Setting values to entities themselves.") + missing_keys_by_object_name = self.push_values_to_entities( + session, + non_task_entities, + hier_values_by_entity_id + ) + if task_missing_keys: + missing_keys_by_object_name["Task"] = task_missing_keys + if missing_keys_by_object_name: + self.report(missing_keys_by_object_name, event) return True + def report(self, missing_keys_by_object_name, event): + splitter = {"type": "label", "value": "---"} + + title = "Push Custom Attribute values report:" + + items = [] + items.append({ + "type": "label", + "value": "# Pushing values was not complete" + }) + items.append({ + "type": "label", + "value": ( + "

It was due to missing custom" + " attribute configurations for specific entity type/s." + " These configurations are not created automatically.

" + ) + }) + + log_message_items = [] + log_message_item_template = ( + "Entity type \"{}\" does not have created Custom Attribute/s: {}" + ) + for object_name, missing_attr_names in ( + missing_keys_by_object_name.items() + ): + log_message_items.append(log_message_item_template.format( + object_name, self.join_keys(missing_attr_names) + )) + + items.append(splitter) + items.append({ + "type": "label", + "value": "## Entity type: {}".format(object_name) + }) + + items.append({ + "type": "label", + "value": "

{}

".format("
".join(missing_attr_names)) + }) + + self.log.warning(( + "Couldn't finish pushing attribute values because" + " few entity types miss Custom attribute configurations:\n{}" + ).format("\n".join(log_message_items))) + + self.show_interface(items, title, event) + def get_hier_values(self, session, hier_attrs, focus_entity_ids): joined_entity_ids = self.join_keys(focus_entity_ids) hier_attr_ids = self.join_keys( @@ -243,26 +321,28 @@ class PushFrameValuesToTaskAction(BaseAction): session, task_entities_by_parent_id, hier_values_by_entity_id, - task_attrs + task_attr_id_by_keys ): - task_attr_ids_by_key = { - attr["key"]: attr["id"] - for attr in task_attrs - } + missing_keys = set() total_parents = len(hier_values_by_entity_id) - idx = 1 + idx = 0 for parent_id, values in hier_values_by_entity_id.items(): - self.log.info(( - "[{}/{}] {} Processing values to children. Values: {}" - ).format(idx, total_parents, parent_id, values)) idx += 1 + self.log.info(( + "[{}/{}] {} Processing values to task. Values: {}" + ).format(idx, total_parents, parent_id, values)) task_entities = task_entities_by_parent_id[parent_id] - for key, value in values.items(): + for hier_key, value in values.items(): + key = self.custom_attribute_mapping[hier_key] + if key not in task_attr_id_by_keys: + missing_keys.add(key) + continue + for task_entity in task_entities: _entity_key = collections.OrderedDict({ - "configuration_id": task_attr_ids_by_key[key], + "configuration_id": task_attr_id_by_keys[key], "entity_id": task_entity["id"] }) @@ -277,6 +357,89 @@ class PushFrameValuesToTaskAction(BaseAction): ) session.commit() + return missing_keys + + def push_values_to_entities( + self, + session, + non_task_entities, + hier_values_by_entity_id + ): + object_types = session.query( + "ObjectType where name in ({})".format( + self.join_keys(self.pushing_entity_types) + ) + ).all() + object_type_names_by_id = { + object_type["id"]: object_type["name"] + for object_type in object_types + } + joined_keys = self.join_keys( + self.custom_attribute_mapping.values() + ) + attribute_entities = session.query( + self.cust_attrs_query.format(joined_keys) + ).all() + + attrs_by_obj_id = {} + for attr in attribute_entities: + if attr["is_hierarchical"]: + continue + + obj_id = attr["object_type_id"] + if obj_id not in object_type_names_by_id: + continue + + if obj_id not in attrs_by_obj_id: + attrs_by_obj_id[obj_id] = {} + + attr_key = attr["key"] + attrs_by_obj_id[obj_id][attr_key] = attr["id"] + + entities_by_obj_id = collections.defaultdict(list) + for entity in non_task_entities: + entities_by_obj_id[entity["object_type_id"]].append(entity) + + missing_keys_by_object_id = collections.defaultdict(set) + for obj_type_id, attr_keys in attrs_by_obj_id.items(): + entities = entities_by_obj_id.get(obj_type_id) + if not entities: + continue + + for entity in entities: + values = hier_values_by_entity_id.get(entity["id"]) + if not values: + continue + + for hier_key, value in values.items(): + key = self.custom_attribute_mapping[hier_key] + if key not in attr_keys: + missing_keys_by_object_id[obj_type_id].add(key) + continue + + _entity_key = collections.OrderedDict({ + "configuration_id": attr_keys[key], + "entity_id": entity["id"] + }) + + session.recorded_operations.push( + ftrack_api.operation.UpdateEntityOperation( + "ContextCustomAttributeValue", + _entity_key, + "value", + ftrack_api.symbol.NOT_SET, + value + ) + ) + session.commit() + + missing_keys_by_object_name = {} + for obj_id, missing_keys in missing_keys_by_object_id.items(): + obj_name = object_type_names_by_id[obj_id] + missing_keys_by_object_name[obj_name] = missing_keys + + return missing_keys_by_object_name + def register(session, plugins_presets={}): PushFrameValuesToTaskAction(session, plugins_presets).register() From 044434b35205f10e0d7d415d7d32ecefdbd65257 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 19:32:36 +0200 Subject: [PATCH 094/580] event handle the same way as action --- .../events/event_push_frame_values_to_task.py | 145 ++++++++++++++---- 1 file changed, 114 insertions(+), 31 deletions(-) diff --git a/pype/modules/ftrack/events/event_push_frame_values_to_task.py b/pype/modules/ftrack/events/event_push_frame_values_to_task.py index dd5c5911ec..dd24110c1b 100644 --- a/pype/modules/ftrack/events/event_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/event_push_frame_values_to_task.py @@ -4,18 +4,27 @@ from pype.modules.ftrack import BaseEvent class PushFrameValuesToTaskEvent(BaseEvent): - """Action for testing purpose or as base for new actions.""" - cust_attrs_query = ( - "select id, key, object_type_id, is_hierarchical, default" - " from CustomAttributeConfiguration" - " where key in ({}) and object_type_id = {}" - ) - # Ignore event handler by default ignore_me = True - interest_attributes = ["frameStart", "frameEnd"] + cust_attrs_query = ( + "select id, key, object_type_id, is_hierarchical, default" + " from CustomAttributeConfiguration" + " where key in ({}) and object_type_id in ({})" + ) + + interest_entity_types = {"Shot"} + interest_attributes = {"frameStart", "frameEnd"} + interest_attr_mapping = { + "frameStart": "fstart", + "frameEnd": "fend" + } _cached_task_object_id = None + _cached_interest_object_ids = None + + @staticmethod + def join_keys(keys): + return ",".join(["\"{}\"".format(key) for key in keys]) @classmethod def task_object_id(cls, session): @@ -26,6 +35,20 @@ class PushFrameValuesToTaskEvent(BaseEvent): cls._cached_task_object_id = task_object_type["id"] return cls._cached_task_object_id + @classmethod + def interest_object_ids(cls, session): + if cls._cached_interest_object_ids is None: + object_types = session.query( + "ObjectType where name in ({})".format( + cls.join_keys(cls.interest_entity_types) + ) + ).all() + cls._cached_interest_object_ids = tuple( + object_type["id"] + for object_type in object_types + ) + return cls._cached_interest_object_ids + def extract_interesting_data(self, session, event): # Filter if event contain relevant data entities_info = event["data"].get("entities") @@ -60,60 +83,107 @@ class PushFrameValuesToTaskEvent(BaseEvent): interesting_data[entity_info["entityId"]] = entity_changes return interesting_data - def join_keys(self, keys): - return ",".join(["\"{}\"".format(key) for key in keys]) - - def get_task_entities(self, session, entities_info): - return session.query( - "Task where parent_id in ({})".format( - self.join_keys(entities_info.keys()) + def get_entities(self, session, interesting_data): + entities = session.query( + "TypedContext where id in ({})".format( + self.join_keys(interesting_data.keys()) ) ).all() - def task_attrs(self, session): - return session.query(self.cust_attrs_query.format( - self.join_keys(self.interest_attributes), - self.task_object_id(session) + output = [] + interest_object_ids = self.interest_object_ids(session) + for entity in entities: + if entity["object_type_id"] in interest_object_ids: + output.append(entity) + return output + + def get_task_entities(self, session, interesting_data): + return session.query( + "Task where parent_id in ({})".format( + self.join_keys(interesting_data.keys()) + ) + ).all() + + def attrs_configurations(self, session): + object_ids = list(self.interest_object_ids(session)) + object_ids.append(self.task_object_id(session)) + + attrs = session.query(self.cust_attrs_query.format( + self.join_keys(self.interest_attr_mapping.values()), + self.join_keys(object_ids) )).all() + output = {} + for attr in attrs: + obj_id = attr["object_type_id"] + if obj_id not in output: + output[obj_id] = {} + output[obj_id][attr["key"]] = attr["id"] + return output + def launch(self, session, event): interesting_data = self.extract_interesting_data(session, event) if not interesting_data: return + entities = self.get_entities(session, interesting_data) + if not entities: + return + + entities_by_id = { + entity["id"]: entity + for entity in entities + } + for entity_id in tuple(interesting_data.keys()): + if entity_id not in entities_by_id: + interesting_data.pop(entity_id) + task_entities = self.get_task_entities(session, interesting_data) if not task_entities: return - task_attrs = self.task_attrs(session) - if not task_attrs: + attrs_by_obj_id = self.attrs_configurations(session) + if not attrs_by_obj_id: self.log.warning(( "There is not created Custom Attributes {}" " for \"Task\" entity type." ).format(self.join_keys(self.interest_attributes))) return - task_attr_id_by_key = { - attr["key"]: attr["id"] - for attr in task_attrs - } task_entities_by_parent_id = collections.defaultdict(list) for task_entity in task_entities: task_entities_by_parent_id[task_entity["parent_id"]].append( task_entity ) + missing_keys_by_object_name = collections.defaultdict(set) for parent_id, values in interesting_data.items(): - task_entities = task_entities_by_parent_id[parent_id] + entities = task_entities_by_parent_id.get(parent_id) or [] + entities.append(entities_by_id[parent_id]) + for key, value in values.items(): changed_ids = [] - for task_entity in task_entities: - task_id = task_entity["id"] - changed_ids.append(task_id) + for entity in entities: + entity_attrs_mapping = ( + attrs_by_obj_id.get(entity["object_type_id"]) + ) + if not entity_attrs_mapping: + missing_keys_by_object_name[entity.entity_key].add( + key + ) + continue + configuration_id = entity_attrs_mapping.get(key) + if not configuration_id: + missing_keys_by_object_name[entity.entity_key].add( + key + ) + continue + + changed_ids.append(entity["id"]) entity_key = collections.OrderedDict({ - "configuration_id": task_attr_id_by_key[key], - "entity_id": task_id + "configuration_id": configuration_id, + "entity_id": entity["id"] }) if value is None: op = ftrack_api.operation.DeleteEntityOperation( @@ -142,6 +212,19 @@ class PushFrameValuesToTaskEvent(BaseEvent): "Changing of values failed.", exc_info=True ) + if not missing_keys_by_object_name: + return + + msg_items = [] + for object_name, missing_keys in missing_keys_by_object_name.items(): + msg_items.append( + "{}: ({})".format(object_name, self.join_keys(missing_keys)) + ) + + self.log.warning(( + "Missing Custom Attribute configuration" + " per specific object types: {}" + ).format(", ".join(msg_items))) def register(session, plugins_presets): From a628260c82d6c787960df501560fea8999acbc16 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 19:33:42 +0200 Subject: [PATCH 095/580] moved code in better order --- .../events/event_push_frame_values_to_task.py | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/pype/modules/ftrack/events/event_push_frame_values_to_task.py b/pype/modules/ftrack/events/event_push_frame_values_to_task.py index dd24110c1b..d4056c2ae5 100644 --- a/pype/modules/ftrack/events/event_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/event_push_frame_values_to_task.py @@ -49,78 +49,6 @@ class PushFrameValuesToTaskEvent(BaseEvent): ) return cls._cached_interest_object_ids - def extract_interesting_data(self, session, event): - # Filter if event contain relevant data - entities_info = event["data"].get("entities") - if not entities_info: - return - - interesting_data = {} - for entity_info in entities_info: - # Care only about tasks - if entity_info.get("entityType") != "task": - continue - - # Care only about changes of status - changes = entity_info.get("changes") or {} - if not changes: - continue - - # Care only about changes if specific keys - entity_changes = {} - for key in self.interest_attributes: - if key in changes: - entity_changes[key] = changes[key]["new"] - - if not entity_changes: - continue - - # Do not care about "Task" entity_type - task_object_id = self.task_object_id(session) - if entity_info.get("objectTypeId") == task_object_id: - continue - - interesting_data[entity_info["entityId"]] = entity_changes - return interesting_data - - def get_entities(self, session, interesting_data): - entities = session.query( - "TypedContext where id in ({})".format( - self.join_keys(interesting_data.keys()) - ) - ).all() - - output = [] - interest_object_ids = self.interest_object_ids(session) - for entity in entities: - if entity["object_type_id"] in interest_object_ids: - output.append(entity) - return output - - def get_task_entities(self, session, interesting_data): - return session.query( - "Task where parent_id in ({})".format( - self.join_keys(interesting_data.keys()) - ) - ).all() - - def attrs_configurations(self, session): - object_ids = list(self.interest_object_ids(session)) - object_ids.append(self.task_object_id(session)) - - attrs = session.query(self.cust_attrs_query.format( - self.join_keys(self.interest_attr_mapping.values()), - self.join_keys(object_ids) - )).all() - - output = {} - for attr in attrs: - obj_id = attr["object_type_id"] - if obj_id not in output: - output[obj_id] = {} - output[obj_id][attr["key"]] = attr["id"] - return output - def launch(self, session, event): interesting_data = self.extract_interesting_data(session, event) if not interesting_data: @@ -226,6 +154,78 @@ class PushFrameValuesToTaskEvent(BaseEvent): " per specific object types: {}" ).format(", ".join(msg_items))) + def extract_interesting_data(self, session, event): + # Filter if event contain relevant data + entities_info = event["data"].get("entities") + if not entities_info: + return + + interesting_data = {} + for entity_info in entities_info: + # Care only about tasks + if entity_info.get("entityType") != "task": + continue + + # Care only about changes of status + changes = entity_info.get("changes") or {} + if not changes: + continue + + # Care only about changes if specific keys + entity_changes = {} + for key in self.interest_attributes: + if key in changes: + entity_changes[key] = changes[key]["new"] + + if not entity_changes: + continue + + # Do not care about "Task" entity_type + task_object_id = self.task_object_id(session) + if entity_info.get("objectTypeId") == task_object_id: + continue + + interesting_data[entity_info["entityId"]] = entity_changes + return interesting_data + + def get_entities(self, session, interesting_data): + entities = session.query( + "TypedContext where id in ({})".format( + self.join_keys(interesting_data.keys()) + ) + ).all() + + output = [] + interest_object_ids = self.interest_object_ids(session) + for entity in entities: + if entity["object_type_id"] in interest_object_ids: + output.append(entity) + return output + + def get_task_entities(self, session, interesting_data): + return session.query( + "Task where parent_id in ({})".format( + self.join_keys(interesting_data.keys()) + ) + ).all() + + def attrs_configurations(self, session): + object_ids = list(self.interest_object_ids(session)) + object_ids.append(self.task_object_id(session)) + + attrs = session.query(self.cust_attrs_query.format( + self.join_keys(self.interest_attr_mapping.values()), + self.join_keys(object_ids) + )).all() + + output = {} + for attr in attrs: + obj_id = attr["object_type_id"] + if obj_id not in output: + output[obj_id] = {} + output[obj_id][attr["key"]] = attr["id"] + return output + def register(session, plugins_presets): PushFrameValuesToTaskEvent(session, plugins_presets).register() From 293ceb8e0bffda6dd4f1975633c915f5457ccb6f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 19:33:53 +0200 Subject: [PATCH 096/580] fixed few minor bugs --- .../ftrack/events/event_push_frame_values_to_task.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pype/modules/ftrack/events/event_push_frame_values_to_task.py b/pype/modules/ftrack/events/event_push_frame_values_to_task.py index d4056c2ae5..32993ef938 100644 --- a/pype/modules/ftrack/events/event_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/event_push_frame_values_to_task.py @@ -67,8 +67,6 @@ class PushFrameValuesToTaskEvent(BaseEvent): interesting_data.pop(entity_id) task_entities = self.get_task_entities(session, interesting_data) - if not task_entities: - return attrs_by_obj_id = self.attrs_configurations(session) if not attrs_by_obj_id: @@ -89,21 +87,22 @@ class PushFrameValuesToTaskEvent(BaseEvent): entities = task_entities_by_parent_id.get(parent_id) or [] entities.append(entities_by_id[parent_id]) - for key, value in values.items(): + for hier_key, value in values.items(): changed_ids = [] for entity in entities: + key = self.interest_attr_mapping[hier_key] entity_attrs_mapping = ( attrs_by_obj_id.get(entity["object_type_id"]) ) if not entity_attrs_mapping: - missing_keys_by_object_name[entity.entity_key].add( + missing_keys_by_object_name[entity.entity_type].add( key ) continue configuration_id = entity_attrs_mapping.get(key) if not configuration_id: - missing_keys_by_object_name[entity.entity_key].add( + missing_keys_by_object_name[entity.entity_type].add( key ) continue From 009a02f104019c64e94a7cacc4b7c8748c56d018 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 20 Aug 2020 19:39:49 +0200 Subject: [PATCH 097/580] removed unnecessary logs --- .../ftrack/events/action_push_frame_values_to_task.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index d88f4a1016..dec34a58cb 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -326,13 +326,7 @@ class PushFrameValuesToTaskAction(BaseAction): missing_keys = set() total_parents = len(hier_values_by_entity_id) - idx = 0 for parent_id, values in hier_values_by_entity_id.items(): - idx += 1 - self.log.info(( - "[{}/{}] {} Processing values to task. Values: {}" - ).format(idx, total_parents, parent_id, values)) - task_entities = task_entities_by_parent_id[parent_id] for hier_key, value in values.items(): key = self.custom_attribute_mapping[hier_key] From 576beb744687294bd12f48ce64d7a9ac8d1361bf Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 20 Aug 2020 20:34:50 +0200 Subject: [PATCH 098/580] removed unused variable --- pype/modules/ftrack/events/action_push_frame_values_to_task.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pype/modules/ftrack/events/action_push_frame_values_to_task.py b/pype/modules/ftrack/events/action_push_frame_values_to_task.py index dec34a58cb..a55c1e46a6 100644 --- a/pype/modules/ftrack/events/action_push_frame_values_to_task.py +++ b/pype/modules/ftrack/events/action_push_frame_values_to_task.py @@ -324,8 +324,6 @@ class PushFrameValuesToTaskAction(BaseAction): task_attr_id_by_keys ): missing_keys = set() - - total_parents = len(hier_values_by_entity_id) for parent_id, values in hier_values_by_entity_id.items(): task_entities = task_entities_by_parent_id[parent_id] for hier_key, value in values.items(): From b855038889b8b7ccb7e0e3cc849f7f896297c5a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 12:56:14 +0200 Subject: [PATCH 099/580] change project overides that are only one file --- .../kuba_each_case/global/creator.json | 8 -------- .../kuba_each_case/global/intents.json | 3 --- .../kuba_each_case/plugins/maya/publish.json | 8 -------- .../kuba_each_case/project_presets.json | 18 ++++++++++++++++++ 4 files changed, 18 insertions(+), 19 deletions(-) delete mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json delete mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json delete mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json create mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json deleted file mode 100644 index d14e779f01..0000000000 --- a/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/creator.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Model": ["model"], - "Render Globals": ["light", "render"], - "Layout": ["layout"], - "Set Dress": ["setdress"], - "Look": ["look"], - "Rig": ["rigging"] -} diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json deleted file mode 100644 index bf147c7a19..0000000000 --- a/pype/tools/config_setting/config/project_overrides/kuba_each_case/global/intents.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "default": "test" -} diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json deleted file mode 100644 index 46fc343b6c..0000000000 --- a/pype/tools/config_setting/config/project_overrides/kuba_each_case/plugins/maya/publish.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "ValidateModelName": { - "enabled": true - }, - "ValidateAssemblyName": { - "enabled": false - } -} diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json new file mode 100644 index 0000000000..599a5dcbea --- /dev/null +++ b/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json @@ -0,0 +1,18 @@ +{ + "__override_version__": 1, + "plugins": { + "maya": { + "__overriden_keys__": [ + "publish" + ], + "publish": { + "ValidateModelName": { + "enabled": true + }, + "ValidateAssemblyName": { + "enabled": false + } + } + } + } +} From d01d9d55da1d5e1715cdf3a25a360114c71308ce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 12:56:35 +0200 Subject: [PATCH 100/580] config can work with single file overrides --- pype/tools/config_setting/widgets/config.py | 34 +++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 8d9d4fa1d2..321a97a4b8 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -18,8 +18,9 @@ config_path = os.path.dirname(os.path.dirname(__file__)) studio_presets_path = os.path.normpath( os.path.join(config_path, "config", "studio_presets") ) +project_configurations_dir = "project_presets" project_presets_path = os.path.normpath( - os.path.join(config_path, "config", "project_presets") + os.path.join(config_path, "config", project_configurations_dir) ) first_run = False @@ -118,15 +119,18 @@ def load_jsons_from_dir(path, *args, **kwargs): base_len = len(path) + 1 for base, _directories, filenames in os.walk(path): + base_items_str = base[base_len:] + if not base_items_str: + base_items = [] + else: + base_items = base_items_str.split(os.path.sep) + for filename in filenames: basename, ext = os.path.splitext(filename) if ext == ".json": full_path = os.path.join(base, filename) value = load_json(full_path) - - # dict_path = os.path.join(base[base_len:], basename) - # dict_keys = dict_path.split(os.path.sep) - dict_keys = base[base_len:].split(os.path.sep) + [basename] + dict_keys = base_items + [basename] output = subkey_merge(output, value, dict_keys) for sub_key in sub_keys: @@ -145,27 +149,31 @@ def global_project_presets(**kwargs): def project_preset_overrides(project_name, **kwargs): project_configs_path = os.environ.get("PYPE_PROJECT_CONFIGS") if project_name and project_configs_path: - return load_jsons_from_dir( + result = load_jsons_from_dir( os.path.join(project_configs_path, project_name), **kwargs ) + print(json.dumps(result, indent=4)) + if result: + result = result.get(project_configurations_dir) or {} + return result return {} def merge_overrides(global_dict, override_dict): if OVERRIDEN_KEY in override_dict: - _override = override_dict.pop(OVERRIDEN_KEY) - if _override: - return override_dict + overriden_keys = set(override_dict.pop(OVERRIDEN_KEY)) + else: + overriden_keys = set() for key, value in override_dict.items(): if value == POP_KEY: global_dict.pop(key) - elif key == OVERRIDEN_KEY: - continue - - elif key not in global_dict: + elif ( + key in overriden_keys + or key not in global_dict + ): global_dict[key] = value elif isinstance(value, dict) and isinstance(global_dict[key], dict): From 742c2b069b28203ec1703f36109d5497f00e1690 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 13:12:04 +0200 Subject: [PATCH 101/580] removed debug print --- pype/tools/config_setting/widgets/lib.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/config_setting/widgets/lib.py b/pype/tools/config_setting/widgets/lib.py index fd3f45b590..d733396d59 100644 --- a/pype/tools/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/widgets/lib.py @@ -28,7 +28,6 @@ def convert_gui_data_to_overrides(data, first=True): metadata = data.pop(METADATA_KEY) for key, value in metadata.items(): if key == "groups": - print("**", value) output[OVERRIDEN_KEY] = value else: KeyError("Unknown metadata key \"{}\"".format(key)) From f8492befdfe8b4a0c5f73139f61a046ec1fac645 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 15:38:09 +0200 Subject: [PATCH 102/580] fixed getting overrides --- pype/tools/config_setting/widgets/config.py | 34 +++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 321a97a4b8..7bce18b7f4 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -18,9 +18,9 @@ config_path = os.path.dirname(os.path.dirname(__file__)) studio_presets_path = os.path.normpath( os.path.join(config_path, "config", "studio_presets") ) -project_configurations_dir = "project_presets" +PROJECT_CONFIGURATION_DIR = "project_presets" project_presets_path = os.path.normpath( - os.path.join(config_path, "config", project_configurations_dir) + os.path.join(config_path, "config", PROJECT_CONFIGURATION_DIR) ) first_run = False @@ -146,18 +146,20 @@ def global_project_presets(**kwargs): return load_jsons_from_dir(project_presets_path, **kwargs) +def path_to_project_overrides(project_name): + project_configs_path = os.environ["PYPE_PROJECT_CONFIGS"] + dirpath = os.path.join(project_configs_path, project_name) + return os.path.join(dirpath, PROJECT_CONFIGURATION_DIR + ".json") + + def project_preset_overrides(project_name, **kwargs): - project_configs_path = os.environ.get("PYPE_PROJECT_CONFIGS") - if project_name and project_configs_path: - result = load_jsons_from_dir( - os.path.join(project_configs_path, project_name), - **kwargs - ) - print(json.dumps(result, indent=4)) - if result: - result = result.get(project_configurations_dir) or {} - return result - return {} + if not project_name: + return {} + + path_to_json = path_to_project_overrides(project_name) + if not os.path.exists(path_to_json): + return {} + return load_json(path_to_json) def merge_overrides(global_dict, override_dict): @@ -227,7 +229,7 @@ def replace_inner_schemas(schema_data, schema_collection): return schema_data -class ShemaMissingFileInfo(Exception): +class SchemaMissingFileInfo(Exception): def __init__(self, invalid): full_path_keys = [] for item in invalid: @@ -237,7 +239,7 @@ class ShemaMissingFileInfo(Exception): "Schema has missing definition of output file (\"is_file\" key)" " for keys. [{}]" ).format(", ".join(full_path_keys)) - super(ShemaMissingFileInfo, self).__init__(msg) + super(SchemaMissingFileInfo, self).__init__(msg) def file_keys_from_schema(schema_data): @@ -290,7 +292,7 @@ def validate_all_has_ending_file(schema_data, is_top=True): if not is_top: return invalid - raise ShemaMissingFileInfo(invalid) + raise SchemaMissingFileInfo(invalid) def validate_schema(schema_data): From 33fc39bf6265eac2713f704efc540c4f04d3a3ac Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 21 Aug 2020 14:38:10 +0100 Subject: [PATCH 103/580] Update subset families on integration --- pype/plugins/global/publish/integrate_new.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index a3c2ffe52b..cc106ad8a2 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -680,6 +680,12 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): instance.data.get('subsetGroup')}} ) + # Update families on subset. + io.update_many( + {"type": "subset", "_id": io.ObjectId(subset["_id"])}, + {"$set": {"data.families": instance.data.get("families", [])}} + ) + return subset def create_version(self, subset, version_number, data=None): From 1043b70550ac42409329dc6e6b43fce8d2517028 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 15:38:26 +0200 Subject: [PATCH 104/580] added override saving --- .../projects_schema/project_gui_schema.json | 3 +-- pype/tools/config_setting/widgets/base.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json b/pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json index 366400e5ff..0405524b40 100644 --- a/pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json +++ b/pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json @@ -1,7 +1,6 @@ { - "key": "studio", + "key": "project", "type": "dict-invisible", - "label": "Studio", "children": [ { "type": "schema", diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index bdacb60559..259ec9e02c 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -74,8 +74,6 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): content_layout.setAlignment(QtCore.Qt.AlignTop) content_widget.setLayout(content_layout) - # scroll_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - # scroll_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) scroll_widget.setWidgetResizable(True) scroll_widget.setWidget(content_widget) @@ -404,8 +402,17 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): if groups: data[METADATA_KEY] = {"groups": groups} - output = convert_gui_data_to_overrides(data) - print(json.dumps(output, indent=4)) + output_data = convert_gui_data_to_overrides(data) + + overrides_json_path = config.path_to_project_overrides( + self.project_name + ) + dirpath = os.path.dirname(overrides_json_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + with open(overrides_json_path, "w") as file_stream: + json.dump(output_data, file_stream, indent=4) def _save_defaults(self): output = {} @@ -429,7 +436,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): all_values = _all_values # Skip first key - all_values = all_values["studio"] + all_values = all_values["project"] # Load studio data with metadata current_presets = config.studio_presets() From 4ce1f70f88909ff0d60dbb6f45d42580c0428d88 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 15:57:50 +0200 Subject: [PATCH 105/580] saving works properly --- .../kuba_each_case/project_presets.json | 2 +- pype/tools/config_setting/widgets/base.py | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json index 599a5dcbea..b9da242453 100644 --- a/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json +++ b/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json @@ -15,4 +15,4 @@ } } } -} +} \ No newline at end of file diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 259ec9e02c..2421c02a25 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -390,18 +390,17 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): self._save_overrides() def _save_overrides(self): - data = {} - groups = [] + _data = {} for item in self.input_fields: value, is_group = item.overrides() if value is not NOT_SET: - data.update(value) - + _data.update(value) if is_group: - groups.extend(value.keys()) + raise Exception( + "Top item can't be overriden in Project widget." + ) - if groups: - data[METADATA_KEY] = {"groups": groups} + data = _data.get("project") or {} output_data = convert_gui_data_to_overrides(data) overrides_json_path = config.path_to_project_overrides( From 993b0ab21fdc60461176894f461f936721231152 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 16:03:27 +0200 Subject: [PATCH 106/580] default project configurations works --- pype/tools/config_setting/widgets/base.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 2421c02a25..0563f942be 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -357,6 +357,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): schema = config.gui_schema("projects_schema", "project_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) + self.schema = schema def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] @@ -422,10 +423,6 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): _output = {key: output} output = _output - print(json.dumps(output, indent=4)) - return - - # TODO check implementation copied from studio all_values = {} for item in self.input_fields: all_values.update(item.config_value()) @@ -438,7 +435,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): all_values = all_values["project"] # Load studio data with metadata - current_presets = config.studio_presets() + current_presets = config.global_project_presets() keys_to_file = config.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: @@ -458,7 +455,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): origin_values.update(new_values) output_path = os.path.join( - config.studio_presets_path, subpath + config.project_presets_path, subpath ) dirpath = os.path.dirname(output_path) if not os.path.exists(dirpath): From 1c47579334406a1b650c05d49b3dcf99ae8e0023 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 16:08:55 +0200 Subject: [PATCH 107/580] modified getting paths --- pype/tools/config_setting/widgets/config.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index 7bce18b7f4..b071d81afe 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -4,29 +4,25 @@ import logging import copy # DEBUG SETUP -os.environ["AVALON_PROJECT"] = "kuba_each_case" +os.environ["PYPE_CONFIG"] = os.path.dirname(os.path.dirname(__file__)) os.environ["PYPE_PROJECT_CONFIGS"] = os.path.join( - os.path.dirname(os.path.dirname(__file__)), - "config", - "project_overrides" + os.environ["PYPE_CONFIG"], "config", "project_overrides" ) -# log = logging.getLogger(__name__) -config_path = os.path.dirname(os.path.dirname(__file__)) studio_presets_path = os.path.normpath( - os.path.join(config_path, "config", "studio_presets") + os.path.join(os.environ["PYPE_CONFIG"], "config", "studio_presets") ) PROJECT_CONFIGURATION_DIR = "project_presets" project_presets_path = os.path.normpath( - os.path.join(config_path, "config", PROJECT_CONFIGURATION_DIR) + os.path.join(os.environ["PYPE_CONFIG"], "config", PROJECT_CONFIGURATION_DIR) ) first_run = False -OVERRIDEN_KEY = "__overriden_keys__" # TODO key popping not implemented yet POP_KEY = "__pop_key__" +OVERRIDEN_KEY = "__overriden_keys__" def load_json(fpath): From 57cac7135ddb644ba6e3ec9a08efb0d34452febb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 16:10:24 +0200 Subject: [PATCH 108/580] changed global variables --- pype/tools/config_setting/widgets/base.py | 4 ++-- pype/tools/config_setting/widgets/config.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/widgets/base.py index 0563f942be..0fc9c5cabf 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/widgets/base.py @@ -147,7 +147,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): origin_values.update(new_values) output_path = os.path.join( - config.studio_presets_path, subpath + config.STUDIO_PRESETS_PATH, subpath ) dirpath = os.path.dirname(output_path) if not os.path.exists(dirpath): @@ -455,7 +455,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): origin_values.update(new_values) output_path = os.path.join( - config.project_presets_path, subpath + config.PROJECT_PRESETS_PATH, subpath ) dirpath = os.path.dirname(output_path) if not os.path.exists(dirpath): diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py index b071d81afe..34eec69fc7 100644 --- a/pype/tools/config_setting/widgets/config.py +++ b/pype/tools/config_setting/widgets/config.py @@ -11,13 +11,13 @@ os.environ["PYPE_PROJECT_CONFIGS"] = os.path.join( log = logging.getLogger(__name__) -studio_presets_path = os.path.normpath( +STUDIO_PRESETS_PATH = os.path.normpath( os.path.join(os.environ["PYPE_CONFIG"], "config", "studio_presets") ) PROJECT_CONFIGURATION_DIR = "project_presets" -project_presets_path = os.path.normpath( - os.path.join(os.environ["PYPE_CONFIG"], "config", PROJECT_CONFIGURATION_DIR) -) +PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( + os.environ["PYPE_CONFIG"], "config", PROJECT_CONFIGURATION_DIR +)) first_run = False # TODO key popping not implemented yet @@ -135,11 +135,11 @@ def load_jsons_from_dir(path, *args, **kwargs): def studio_presets(*args, **kwargs): - return load_jsons_from_dir(studio_presets_path, *args, **kwargs) + return load_jsons_from_dir(STUDIO_PRESETS_PATH, *args, **kwargs) def global_project_presets(**kwargs): - return load_jsons_from_dir(project_presets_path, **kwargs) + return load_jsons_from_dir(PROJECT_PRESETS_PATH, **kwargs) def path_to_project_overrides(project_name): From b37037007e6b7b300e98cb3cdf96809f452ce2eb Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 21 Aug 2020 15:43:52 +0100 Subject: [PATCH 109/580] Fix optional skip reviews on renders. --- pype/plugins/global/publish/submit_publish_job.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/submit_publish_job.py b/pype/plugins/global/publish/submit_publish_job.py index 2fe6735e90..bb8473dcf6 100644 --- a/pype/plugins/global/publish/submit_publish_job.py +++ b/pype/plugins/global/publish/submit_publish_job.py @@ -729,7 +729,8 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): "pixelAspect": data.get("pixelAspect", 1), "resolutionWidth": data.get("resolutionWidth", 1920), "resolutionHeight": data.get("resolutionHeight", 1080), - "multipartExr": data.get("multipartExr", False) + "multipartExr": data.get("multipartExr", False), + "review": data.get("review", True) } if "prerender" in instance.data["families"]: From 104027c17c494969fb0ae1c78e57b1eb910f80a1 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 21 Aug 2020 16:22:41 +0100 Subject: [PATCH 110/580] Integrate family as well --- pype/plugins/global/publish/integrate_new.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index cc106ad8a2..142e72e3ac 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -681,9 +681,11 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): ) # Update families on subset. + families = [instance.data["family"]] + families.extend(instance.data.get("families", [])) io.update_many( {"type": "subset", "_id": io.ObjectId(subset["_id"])}, - {"$set": {"data.families": instance.data.get("families", [])}} + {"$set": {"data.families": families}} ) return subset From 0d711c3b7f8c28cd92a3674eeff880766c7f8054 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 21 Aug 2020 16:25:48 +0100 Subject: [PATCH 111/580] Get linked assets from "inputs". --- pype/lib.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index 7cf4e2f1a5..601c85f521 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -746,8 +746,9 @@ class PypeHook: def get_linked_assets(asset_entity): """Return linked assets for `asset_entity`.""" - # TODO implement - return [] + inputs = asset_entity["data"].get("inputs", []) + inputs = [io.find_one({"_id": x}) for x in inputs] + return inputs def map_subsets_by_family(subsets): From 1ac12eadb2d3e2a4c0530e830e195c30e4cf9970 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 17:38:03 +0200 Subject: [PATCH 112/580] reorganized config setting tool to usable as tool --- pype/tools/config_setting/__init__.py | 7 + pype/tools/config_setting/__main__.py | 18 + .../config_setting/config_setting/__init__.py | 10 + .../ftrack_projects_gui_schema.json | 0 .../projects_schema/plugins_gui_schema.json | 0 .../projects_schema/project_gui_schema.json | 0 .../projects_schema/test_project_schema.json | 0 .../applications_gui_schema.json | 0 .../studio_schema/studio_gui_schema.json | 0 .../studio_schema/tools_gui_schema.json | 0 .../{ => config_setting}/style/__init__.py | 0 .../{ => config_setting}/style/pype_icon.png | Bin .../{ => config_setting}/style/style.css | 0 .../config_setting/widgets/__init__.py | 19 + .../{ => config_setting}/widgets/base.py | 28 +- .../{ => config_setting}/widgets/inputs.py | 6 +- .../config_setting/widgets/lib.py | 182 ++++++++++ .../{ => config_setting}/widgets/main.py | 0 .../{ => config_setting}/widgets/tests.py | 0 .../{ => config_setting}/widgets/widgets.py | 0 pype/tools/config_setting/interface.py | 56 --- pype/tools/config_setting/widgets/__init__.py | 6 - pype/tools/config_setting/widgets/config.py | 325 ------------------ pype/tools/config_setting/widgets/lib.py | 54 --- 24 files changed, 251 insertions(+), 460 deletions(-) create mode 100644 pype/tools/config_setting/__init__.py create mode 100644 pype/tools/config_setting/__main__.py create mode 100644 pype/tools/config_setting/config_setting/__init__.py rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/projects_schema/plugins_gui_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/projects_schema/project_gui_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/projects_schema/test_project_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/studio_schema/applications_gui_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/studio_schema/studio_gui_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/config_gui_schema/studio_schema/tools_gui_schema.json (100%) rename pype/tools/config_setting/{ => config_setting}/style/__init__.py (100%) rename pype/tools/config_setting/{ => config_setting}/style/pype_icon.png (100%) rename pype/tools/config_setting/{ => config_setting}/style/style.css (100%) create mode 100644 pype/tools/config_setting/config_setting/widgets/__init__.py rename pype/tools/config_setting/{ => config_setting}/widgets/base.py (95%) rename pype/tools/config_setting/{ => config_setting}/widgets/inputs.py (99%) create mode 100644 pype/tools/config_setting/config_setting/widgets/lib.py rename pype/tools/config_setting/{ => config_setting}/widgets/main.py (100%) rename pype/tools/config_setting/{ => config_setting}/widgets/tests.py (100%) rename pype/tools/config_setting/{ => config_setting}/widgets/widgets.py (100%) delete mode 100644 pype/tools/config_setting/interface.py delete mode 100644 pype/tools/config_setting/widgets/__init__.py delete mode 100644 pype/tools/config_setting/widgets/config.py delete mode 100644 pype/tools/config_setting/widgets/lib.py diff --git a/pype/tools/config_setting/__init__.py b/pype/tools/config_setting/__init__.py new file mode 100644 index 0000000000..c3bd49449d --- /dev/null +++ b/pype/tools/config_setting/__init__.py @@ -0,0 +1,7 @@ +from config_setting import style, MainWidget + + +__all__ = ( + "style", + "MainWidget" +) diff --git a/pype/tools/config_setting/__main__.py b/pype/tools/config_setting/__main__.py new file mode 100644 index 0000000000..171b85a775 --- /dev/null +++ b/pype/tools/config_setting/__main__.py @@ -0,0 +1,18 @@ +import os +import sys + +import config_setting +from Qt import QtWidgets, QtGui + + +if __name__ == "__main__": + app = QtWidgets.QApplication(sys.argv) + + stylesheet = config_setting.style.load_stylesheet() + app.setStyleSheet(stylesheet) + app.setWindowIcon(QtGui.QIcon(config_setting.style.app_icon_path())) + + widget = config_setting.MainWidget() + widget.show() + + sys.exit(app.exec_()) diff --git a/pype/tools/config_setting/config_setting/__init__.py b/pype/tools/config_setting/config_setting/__init__.py new file mode 100644 index 0000000000..835754e6a1 --- /dev/null +++ b/pype/tools/config_setting/config_setting/__init__.py @@ -0,0 +1,10 @@ +from . import style +# from . import widgets +from .widgets import MainWidget + + +__all__ = ( + "style", + # "widgets", + "MainWidget" +) diff --git a/pype/tools/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/project_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/projects_schema/project_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/project_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/projects_schema/test_project_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/test_project_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/projects_schema/test_project_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/test_project_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json diff --git a/pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json diff --git a/pype/tools/config_setting/style/__init__.py b/pype/tools/config_setting/config_setting/style/__init__.py similarity index 100% rename from pype/tools/config_setting/style/__init__.py rename to pype/tools/config_setting/config_setting/style/__init__.py diff --git a/pype/tools/config_setting/style/pype_icon.png b/pype/tools/config_setting/config_setting/style/pype_icon.png similarity index 100% rename from pype/tools/config_setting/style/pype_icon.png rename to pype/tools/config_setting/config_setting/style/pype_icon.png diff --git a/pype/tools/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css similarity index 100% rename from pype/tools/config_setting/style/style.css rename to pype/tools/config_setting/config_setting/style/style.css diff --git a/pype/tools/config_setting/config_setting/widgets/__init__.py b/pype/tools/config_setting/config_setting/widgets/__init__.py new file mode 100644 index 0000000000..0197917596 --- /dev/null +++ b/pype/tools/config_setting/config_setting/widgets/__init__.py @@ -0,0 +1,19 @@ +from .lib import ( + NOT_SET, + AS_WIDGET, + METADATA_KEY, + OVERRIDE_VERSION, + convert_gui_data_to_overrides, + convert_overrides_to_gui_data, + TypeToKlass +) + + +from .base import ( + PypeConfigurationWidget, + StudioWidget, + ProjectWidget +) +from .main import MainWidget + +from .inputs import * diff --git a/pype/tools/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py similarity index 95% rename from pype/tools/config_setting/widgets/base.py rename to pype/tools/config_setting/config_setting/widgets/base.py index 0fc9c5cabf..dcbaf743a9 100644 --- a/pype/tools/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -1,16 +1,12 @@ import os import json from Qt import QtWidgets, QtCore, QtGui -from . import config +from pype.api import config from .widgets import UnsavedChangesDialog -from .lib import NOT_SET, METADATA_KEY, convert_gui_data_to_overrides +from . import lib from avalon import io -class TypeToKlass: - types = {} - - class PypeConfigurationWidget: default_state = "" @@ -23,7 +19,7 @@ class PypeConfigurationWidget: def value_from_values(self, values, keys=None): if not values: - return NOT_SET + return lib.NOT_SET if keys is None: keys = self.keys @@ -36,7 +32,7 @@ class PypeConfigurationWidget: ) if key not in value: - return NOT_SET + return lib.NOT_SET value = value[key] return value @@ -109,7 +105,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.input_fields.clear() values = {"studio": config.studio_presets()} - schema = config.gui_schema("studio_schema", "studio_gui_schema") + schema = lib.gui_schema("studio_schema", "studio_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) self.schema = schema @@ -129,7 +125,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): # Load studio data with metadata current_presets = config.studio_presets() - keys_to_file = config.file_keys_from_schema(self.schema) + keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: # Skip first key key_sequence = key_sequence[1:] @@ -158,7 +154,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) + klass = lib.TypeToKlass.types.get(item_type) item = klass( child_configuration, values, self.keys, self ) @@ -354,14 +350,14 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): def reset(self): values = config.global_project_presets() - schema = config.gui_schema("projects_schema", "project_gui_schema") + schema = lib.gui_schema("projects_schema", "project_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) self.schema = schema def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) + klass = lib.TypeToKlass.types.get(item_type) item = klass( child_configuration, values, self.keys, self @@ -394,7 +390,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): _data = {} for item in self.input_fields: value, is_group = item.overrides() - if value is not NOT_SET: + if value is not lib.NOT_SET: _data.update(value) if is_group: raise Exception( @@ -402,7 +398,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): ) data = _data.get("project") or {} - output_data = convert_gui_data_to_overrides(data) + output_data = lib.convert_gui_data_to_overrides(data) overrides_json_path = config.path_to_project_overrides( self.project_name @@ -437,7 +433,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): # Load studio data with metadata current_presets = config.global_project_presets() - keys_to_file = config.file_keys_from_schema(self.schema) + keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: # Skip first key key_sequence = key_sequence[1:] diff --git a/pype/tools/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py similarity index 99% rename from pype/tools/config_setting/widgets/inputs.py rename to pype/tools/config_setting/config_setting/widgets/inputs.py index 1840572cfb..63415a16d3 100644 --- a/pype/tools/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1,14 +1,14 @@ import json from Qt import QtWidgets, QtCore, QtGui -from . import config -from .base import PypeConfigurationWidget, TypeToKlass +from pype.api import config +from .base import PypeConfigurationWidget from .widgets import ( ClickableWidget, ExpandingWidget, ModifiedIntSpinBox, ModifiedFloatSpinBox ) -from .lib import NOT_SET, AS_WIDGET, METADATA_KEY +from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass class SchemeGroupHierarchyBug(Exception): diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py new file mode 100644 index 0000000000..454c0b07ed --- /dev/null +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -0,0 +1,182 @@ +import os +import json +import copy +from pype.api import config + +OVERRIDEN_KEY = config.OVERRIDEN_KEY + + +# Singleton database of available inputs +class TypeToKlass: + types = {} + + +NOT_SET = type("NOT_SET", (), {}) +AS_WIDGET = type("AS_WIDGET", (), {}) +METADATA_KEY = type("METADATA_KEY", (), {}) +OVERRIDE_VERSION = 1 + + +def convert_gui_data_to_overrides(data, first=True): + if not data or not isinstance(data, dict): + return data + + output = {} + if first: + output["__override_version__"] = OVERRIDE_VERSION + + if METADATA_KEY in data: + metadata = data.pop(METADATA_KEY) + for key, value in metadata.items(): + if key == "groups": + output[OVERRIDEN_KEY] = value + else: + KeyError("Unknown metadata key \"{}\"".format(key)) + + for key, value in data.items(): + output[key] = convert_gui_data_to_overrides(value, False) + return output + + +def convert_overrides_to_gui_data(data, first=True): + if not data or not isinstance(data, dict): + return data + + output = {} + if OVERRIDEN_KEY in data: + groups = data.pop(OVERRIDEN_KEY) + if METADATA_KEY not in output: + output[METADATA_KEY] = {} + output[METADATA_KEY]["groups"] = groups + + for key, value in data.items(): + output[key] = convert_overrides_to_gui_data(value, False) + + return output + + + +def replace_inner_schemas(schema_data, schema_collection): + if schema_data["type"] == "schema": + raise ValueError("First item in schema data can't be schema.") + + children = schema_data.get("children") + if not children: + return schema_data + + new_children = [] + for child in children: + if child["type"] != "schema": + new_child = replace_inner_schemas(child, schema_collection) + new_children.append(new_child) + continue + + for schema_name in child["children"]: + new_child = replace_inner_schemas( + schema_collection[schema_name], + schema_collection + ) + new_children.append(new_child) + + schema_data["children"] = new_children + return schema_data + + +class SchemaMissingFileInfo(Exception): + def __init__(self, invalid): + full_path_keys = [] + for item in invalid: + full_path_keys.append("\"{}\"".format("/".join(item))) + + msg = ( + "Schema has missing definition of output file (\"is_file\" key)" + " for keys. [{}]" + ).format(", ".join(full_path_keys)) + super(SchemaMissingFileInfo, self).__init__(msg) + + +def file_keys_from_schema(schema_data): + output = [] + keys = [] + key = schema_data.get("key") + if key: + keys.append(key) + + for child in schema_data["children"]: + if child.get("is_file"): + _keys = copy.deepcopy(keys) + _keys.append(child["key"]) + output.append(_keys) + continue + + for result in file_keys_from_schema(child): + _keys = copy.deepcopy(keys) + _keys.extend(result) + output.append(_keys) + return output + + +def validate_all_has_ending_file(schema_data, is_top=True): + if schema_data.get("is_file"): + return None + + children = schema_data.get("children") + if not children: + return [[schema_data["key"]]] + + invalid = [] + keyless = "key" not in schema_data + for child in children: + result = validate_all_has_ending_file(child, False) + if result is None: + continue + + if keyless: + invalid.extend(result) + else: + for item in result: + new_invalid = [schema_data["key"]] + new_invalid.extend(item) + invalid.append(new_invalid) + + if not invalid: + return None + + if not is_top: + return invalid + + raise SchemaMissingFileInfo(invalid) + + +def validate_schema(schema_data): + # TODO validator for key uniquenes + # TODO validator that is_group key is not before is_file child + # TODO validator that is_group or is_file is not on child without key + validate_all_has_ending_file(schema_data) + + +def gui_schema(subfolder, main_schema_name): + subfolder, main_schema_name + dirpath = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + "config_gui_schema", + subfolder + ) + + loaded_schemas = {} + for filename in os.listdir(dirpath): + basename, ext = os.path.splitext(filename) + if ext != ".json": + continue + + filepath = os.path.join(dirpath, filename) + with open(filepath, "r") as json_stream: + schema_data = json.load(json_stream) + loaded_schemas[basename] = schema_data + + main_schema = replace_inner_schemas( + loaded_schemas[main_schema_name], + loaded_schemas + ) + validate_schema(main_schema) + return main_schema diff --git a/pype/tools/config_setting/widgets/main.py b/pype/tools/config_setting/config_setting/widgets/main.py similarity index 100% rename from pype/tools/config_setting/widgets/main.py rename to pype/tools/config_setting/config_setting/widgets/main.py diff --git a/pype/tools/config_setting/widgets/tests.py b/pype/tools/config_setting/config_setting/widgets/tests.py similarity index 100% rename from pype/tools/config_setting/widgets/tests.py rename to pype/tools/config_setting/config_setting/widgets/tests.py diff --git a/pype/tools/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py similarity index 100% rename from pype/tools/config_setting/widgets/widgets.py rename to pype/tools/config_setting/config_setting/widgets/widgets.py diff --git a/pype/tools/config_setting/interface.py b/pype/tools/config_setting/interface.py deleted file mode 100644 index a8c05f5af3..0000000000 --- a/pype/tools/config_setting/interface.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -import sys - - -def folder_up(path, times=1): - if times <= 0: - return path - return folder_up(os.path.dirname(path), times - 1) - - -PYPE_SETUP_PATH = folder_up(os.path.realpath(__file__), 6) -os.environ["PYPE_CONFIG"] = os.path.join( - PYPE_SETUP_PATH, "repos", "pype-config" -) -os.environ["AVALON_MONGO"] = "mongodb://localhost:2707" -sys_paths = ( - "C:/Users/Public/pype_env2/Lib/site-packages", - PYPE_SETUP_PATH, - os.path.join(PYPE_SETUP_PATH, "repos", "pype"), - os.path.join(PYPE_SETUP_PATH, "repos", "avalon-core"), - os.path.join(PYPE_SETUP_PATH, "repos", "pyblish-base") -) -for path in sys_paths: - sys.path.append(path) - -from widgets import main -import style -from Qt import QtWidgets, QtGui - - -class MyApp(QtWidgets.QApplication): - def __init__(self, *args, **kwargs): - super(MyApp, self).__init__(*args, **kwargs) - stylesheet = style.load_stylesheet() - self.setStyleSheet(stylesheet) - self.setWindowIcon(QtGui.QIcon(style.app_icon_path())) - - -if __name__ == "__main__": - app = MyApp(sys.argv) - - # main_widget = QtWidgets.QWidget() - # main_widget.setWindowIcon(QtGui.QIcon(style.app_icon_path())) - # - # layout = QtWidgets.QVBoxLayout(main_widget) - # - # widget = main.MainWidget(main_widget) - - # layout.addWidget(widget) - # main_widget.setLayout(layout) - # main_widget.show() - - widget = main.MainWidget() - widget.show() - - sys.exit(app.exec_()) diff --git a/pype/tools/config_setting/widgets/__init__.py b/pype/tools/config_setting/widgets/__init__.py deleted file mode 100644 index 9fbce6e1cf..0000000000 --- a/pype/tools/config_setting/widgets/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .lib import NOT_SET, AS_WIDGET, METADATA_KEY - - -from .base import * -from .main import * -from .inputs import * diff --git a/pype/tools/config_setting/widgets/config.py b/pype/tools/config_setting/widgets/config.py deleted file mode 100644 index 34eec69fc7..0000000000 --- a/pype/tools/config_setting/widgets/config.py +++ /dev/null @@ -1,325 +0,0 @@ -import os -import json -import logging -import copy - -# DEBUG SETUP -os.environ["PYPE_CONFIG"] = os.path.dirname(os.path.dirname(__file__)) -os.environ["PYPE_PROJECT_CONFIGS"] = os.path.join( - os.environ["PYPE_CONFIG"], "config", "project_overrides" -) - -log = logging.getLogger(__name__) - -STUDIO_PRESETS_PATH = os.path.normpath( - os.path.join(os.environ["PYPE_CONFIG"], "config", "studio_presets") -) -PROJECT_CONFIGURATION_DIR = "project_presets" -PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( - os.environ["PYPE_CONFIG"], "config", PROJECT_CONFIGURATION_DIR -)) -first_run = False - -# TODO key popping not implemented yet -POP_KEY = "__pop_key__" -OVERRIDEN_KEY = "__overriden_keys__" - - -def load_json(fpath): - # Load json data - with open(fpath, "r") as opened_file: - lines = opened_file.read().splitlines() - - # prepare json string - standard_json = "" - for line in lines: - # Remove all whitespace on both sides - line = line.strip() - - # Skip blank lines - if len(line) == 0: - continue - - standard_json += line - - # Check if has extra commas - extra_comma = False - if ",]" in standard_json or ",}" in standard_json: - extra_comma = True - standard_json = standard_json.replace(",]", "]") - standard_json = standard_json.replace(",}", "}") - - global first_run - if extra_comma and first_run: - log.error("Extra comma in json file: \"{}\"".format(fpath)) - - # return empty dict if file is empty - if standard_json == "": - if first_run: - log.error("Empty json file: \"{}\"".format(fpath)) - return {} - - # Try to parse string - try: - return json.loads(standard_json) - - except json.decoder.JSONDecodeError: - # Return empty dict if it is first time that decode error happened - if not first_run: - return {} - - # Repreduce the exact same exception but traceback contains better - # information about position of error in the loaded json - try: - with open(fpath, "r") as opened_file: - json.load(opened_file) - - except json.decoder.JSONDecodeError: - log.warning( - "File has invalid json format \"{}\"".format(fpath), - exc_info=True - ) - - return {} - - -def subkey_merge(_dict, value, keys): - key = keys.pop(0) - if not keys: - _dict[key] = value - return _dict - - if key not in _dict: - _dict[key] = {} - _dict[key] = subkey_merge(_dict[key], value, keys) - - return _dict - - -def load_jsons_from_dir(path, *args, **kwargs): - output = {} - - path = os.path.normpath(path) - if not os.path.exists(path): - # TODO warning - return output - - sub_keys = list(kwargs.pop("subkeys", args)) - for sub_key in tuple(sub_keys): - _path = os.path.join(path, sub_key) - if not os.path.exists(_path): - break - - path = _path - sub_keys.pop(0) - - base_len = len(path) + 1 - for base, _directories, filenames in os.walk(path): - base_items_str = base[base_len:] - if not base_items_str: - base_items = [] - else: - base_items = base_items_str.split(os.path.sep) - - for filename in filenames: - basename, ext = os.path.splitext(filename) - if ext == ".json": - full_path = os.path.join(base, filename) - value = load_json(full_path) - dict_keys = base_items + [basename] - output = subkey_merge(output, value, dict_keys) - - for sub_key in sub_keys: - output = output[sub_key] - return output - - -def studio_presets(*args, **kwargs): - return load_jsons_from_dir(STUDIO_PRESETS_PATH, *args, **kwargs) - - -def global_project_presets(**kwargs): - return load_jsons_from_dir(PROJECT_PRESETS_PATH, **kwargs) - - -def path_to_project_overrides(project_name): - project_configs_path = os.environ["PYPE_PROJECT_CONFIGS"] - dirpath = os.path.join(project_configs_path, project_name) - return os.path.join(dirpath, PROJECT_CONFIGURATION_DIR + ".json") - - -def project_preset_overrides(project_name, **kwargs): - if not project_name: - return {} - - path_to_json = path_to_project_overrides(project_name) - if not os.path.exists(path_to_json): - return {} - return load_json(path_to_json) - - -def merge_overrides(global_dict, override_dict): - if OVERRIDEN_KEY in override_dict: - overriden_keys = set(override_dict.pop(OVERRIDEN_KEY)) - else: - overriden_keys = set() - - for key, value in override_dict.items(): - if value == POP_KEY: - global_dict.pop(key) - - elif ( - key in overriden_keys - or key not in global_dict - ): - global_dict[key] = value - - elif isinstance(value, dict) and isinstance(global_dict[key], dict): - global_dict[key] = merge_overrides(global_dict[key], value) - - else: - global_dict[key] = value - return global_dict - - -def apply_overrides(global_presets, project_overrides): - global_presets = copy.deepcopy(global_presets) - if not project_overrides: - return global_presets - return merge_overrides(global_presets, project_overrides) - - -def project_presets(project_name=None, **kwargs): - global_presets = global_project_presets(**kwargs) - - if not project_name: - project_name = os.environ.get("AVALON_PROJECT") - project_overrides = project_preset_overrides(project_name, **kwargs) - - return apply_overrides(global_presets, project_overrides) - - -def replace_inner_schemas(schema_data, schema_collection): - if schema_data["type"] == "schema": - raise ValueError("First item in schema data can't be schema.") - - children = schema_data.get("children") - if not children: - return schema_data - - new_children = [] - for child in children: - if child["type"] != "schema": - new_child = replace_inner_schemas(child, schema_collection) - new_children.append(new_child) - continue - - for schema_name in child["children"]: - new_child = replace_inner_schemas( - schema_collection[schema_name], - schema_collection - ) - new_children.append(new_child) - - schema_data["children"] = new_children - return schema_data - - -class SchemaMissingFileInfo(Exception): - def __init__(self, invalid): - full_path_keys = [] - for item in invalid: - full_path_keys.append("\"{}\"".format("/".join(item))) - - msg = ( - "Schema has missing definition of output file (\"is_file\" key)" - " for keys. [{}]" - ).format(", ".join(full_path_keys)) - super(SchemaMissingFileInfo, self).__init__(msg) - - -def file_keys_from_schema(schema_data): - output = [] - keys = [] - key = schema_data.get("key") - if key: - keys.append(key) - - for child in schema_data["children"]: - if child.get("is_file"): - _keys = copy.deepcopy(keys) - _keys.append(child["key"]) - output.append(_keys) - continue - - for result in file_keys_from_schema(child): - _keys = copy.deepcopy(keys) - _keys.extend(result) - output.append(_keys) - return output - - -def validate_all_has_ending_file(schema_data, is_top=True): - if schema_data.get("is_file"): - return None - - children = schema_data.get("children") - if not children: - return [[schema_data["key"]]] - - invalid = [] - keyless = "key" not in schema_data - for child in children: - result = validate_all_has_ending_file(child, False) - if result is None: - continue - - if keyless: - invalid.extend(result) - else: - for item in result: - new_invalid = [schema_data["key"]] - new_invalid.extend(item) - invalid.append(new_invalid) - - if not invalid: - return None - - if not is_top: - return invalid - - raise SchemaMissingFileInfo(invalid) - - -def validate_schema(schema_data): - # TODO validator for key uniquenes - # TODO validator that is_group key is not before is_file child - # TODO validator that is_group or is_file is not on child without key - validate_all_has_ending_file(schema_data) - - -def gui_schema(subfolder, main_schema_name): - subfolder, main_schema_name - dirpath = os.path.join( - os.path.dirname(os.path.dirname(__file__)), - "config_gui_schema", - subfolder - ) - - loaded_schemas = {} - for filename in os.listdir(dirpath): - basename, ext = os.path.splitext(filename) - if ext != ".json": - continue - - filepath = os.path.join(dirpath, filename) - with open(filepath, "r") as json_stream: - schema_data = json.load(json_stream) - loaded_schemas[basename] = schema_data - - main_schema = replace_inner_schemas( - loaded_schemas[main_schema_name], - loaded_schemas - ) - validate_schema(main_schema) - return main_schema diff --git a/pype/tools/config_setting/widgets/lib.py b/pype/tools/config_setting/widgets/lib.py deleted file mode 100644 index d733396d59..0000000000 --- a/pype/tools/config_setting/widgets/lib.py +++ /dev/null @@ -1,54 +0,0 @@ -from .config import OVERRIDEN_KEY - - -class CustomNone: - """Created object can be used as custom None (not equal to None).""" - def __bool__(self): - """Return False (like default None).""" - return False - - -NOT_SET = CustomNone() -AS_WIDGET = type("AS_WIDGET", (), {}) - -METADATA_KEY = type("METADATA_KEY", (), {}) - -OVERRIDE_VERSION = 1 - - -def convert_gui_data_to_overrides(data, first=True): - if not data or not isinstance(data, dict): - return data - - output = {} - if first: - output["__override_version__"] = OVERRIDE_VERSION - - if METADATA_KEY in data: - metadata = data.pop(METADATA_KEY) - for key, value in metadata.items(): - if key == "groups": - output[OVERRIDEN_KEY] = value - else: - KeyError("Unknown metadata key \"{}\"".format(key)) - - for key, value in data.items(): - output[key] = convert_gui_data_to_overrides(value, False) - return output - - -def convert_overrides_to_gui_data(data, first=True): - if not data or not isinstance(data, dict): - return data - - output = {} - if OVERRIDEN_KEY in data: - groups = data.pop(OVERRIDEN_KEY) - if METADATA_KEY not in output: - output[METADATA_KEY] = {} - output[METADATA_KEY]["groups"] = groups - - for key, value in data.items(): - output[key] = convert_overrides_to_gui_data(value, False) - - return output From 428382e070a66758104431527e1c24e0c3fd4ae3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 17:38:22 +0200 Subject: [PATCH 113/580] config temporarily moved to ~/pype/pype directory --- pype/api.py | 2 +- pype/config.py | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 pype/config.py diff --git a/pype/api.py b/pype/api.py index 44a31f2626..e2705f81ea 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,8 +1,8 @@ +from . import config from pypeapp import ( Logger, Anatomy, project_overrides_dir_path, - config, execute ) diff --git a/pype/config.py b/pype/config.py new file mode 100644 index 0000000000..b3e860d72f --- /dev/null +++ b/pype/config.py @@ -0,0 +1,193 @@ +import os +import json +import logging +import copy + +log = logging.getLogger(__name__) + +STUDIO_PRESETS_PATH = os.path.normpath( + os.path.join(os.environ["PYPE_CONFIG"], "config", "studio_presets") +) +PROJECT_CONFIGURATION_DIR = "project_presets" +PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( + os.environ["PYPE_CONFIG"], "config", PROJECT_CONFIGURATION_DIR +)) +first_run = False + +# TODO key popping not implemented yet +POP_KEY = "__pop_key__" +OVERRIDEN_KEY = "__overriden_keys__" + + +def load_json(fpath): + # Load json data + with open(fpath, "r") as opened_file: + lines = opened_file.read().splitlines() + + # prepare json string + standard_json = "" + for line in lines: + # Remove all whitespace on both sides + line = line.strip() + + # Skip blank lines + if len(line) == 0: + continue + + standard_json += line + + # Check if has extra commas + extra_comma = False + if ",]" in standard_json or ",}" in standard_json: + extra_comma = True + standard_json = standard_json.replace(",]", "]") + standard_json = standard_json.replace(",}", "}") + + global first_run + if extra_comma and first_run: + log.error("Extra comma in json file: \"{}\"".format(fpath)) + + # return empty dict if file is empty + if standard_json == "": + if first_run: + log.error("Empty json file: \"{}\"".format(fpath)) + return {} + + # Try to parse string + try: + return json.loads(standard_json) + + except json.decoder.JSONDecodeError: + # Return empty dict if it is first time that decode error happened + if not first_run: + return {} + + # Repreduce the exact same exception but traceback contains better + # information about position of error in the loaded json + try: + with open(fpath, "r") as opened_file: + json.load(opened_file) + + except json.decoder.JSONDecodeError: + log.warning( + "File has invalid json format \"{}\"".format(fpath), + exc_info=True + ) + + return {} + + +def subkey_merge(_dict, value, keys): + key = keys.pop(0) + if not keys: + _dict[key] = value + return _dict + + if key not in _dict: + _dict[key] = {} + _dict[key] = subkey_merge(_dict[key], value, keys) + + return _dict + + +def load_jsons_from_dir(path, *args, **kwargs): + output = {} + + path = os.path.normpath(path) + if not os.path.exists(path): + # TODO warning + return output + + sub_keys = list(kwargs.pop("subkeys", args)) + for sub_key in tuple(sub_keys): + _path = os.path.join(path, sub_key) + if not os.path.exists(_path): + break + + path = _path + sub_keys.pop(0) + + base_len = len(path) + 1 + for base, _directories, filenames in os.walk(path): + base_items_str = base[base_len:] + if not base_items_str: + base_items = [] + else: + base_items = base_items_str.split(os.path.sep) + + for filename in filenames: + basename, ext = os.path.splitext(filename) + if ext == ".json": + full_path = os.path.join(base, filename) + value = load_json(full_path) + dict_keys = base_items + [basename] + output = subkey_merge(output, value, dict_keys) + + for sub_key in sub_keys: + output = output[sub_key] + return output + + +def studio_presets(*args, **kwargs): + return load_jsons_from_dir(STUDIO_PRESETS_PATH, *args, **kwargs) + + +def global_project_presets(**kwargs): + return load_jsons_from_dir(PROJECT_PRESETS_PATH, **kwargs) + + +def path_to_project_overrides(project_name): + project_configs_path = os.environ["PYPE_PROJECT_CONFIGS"] + dirpath = os.path.join(project_configs_path, project_name) + return os.path.join(dirpath, PROJECT_CONFIGURATION_DIR + ".json") + + +def project_preset_overrides(project_name, **kwargs): + if not project_name: + return {} + + path_to_json = path_to_project_overrides(project_name) + if not os.path.exists(path_to_json): + return {} + return load_json(path_to_json) + + +def merge_overrides(global_dict, override_dict): + if OVERRIDEN_KEY in override_dict: + overriden_keys = set(override_dict.pop(OVERRIDEN_KEY)) + else: + overriden_keys = set() + + for key, value in override_dict.items(): + if value == POP_KEY: + global_dict.pop(key) + + elif ( + key in overriden_keys + or key not in global_dict + ): + global_dict[key] = value + + elif isinstance(value, dict) and isinstance(global_dict[key], dict): + global_dict[key] = merge_overrides(global_dict[key], value) + + else: + global_dict[key] = value + return global_dict + + +def apply_overrides(global_presets, project_overrides): + global_presets = copy.deepcopy(global_presets) + if not project_overrides: + return global_presets + return merge_overrides(global_presets, project_overrides) + + +def project_presets(project_name=None, **kwargs): + global_presets = global_project_presets(**kwargs) + + if not project_name: + project_name = os.environ.get("AVALON_PROJECT") + project_overrides = project_preset_overrides(project_name, **kwargs) + + return apply_overrides(global_presets, project_overrides) From 8f84f78d5d57d5e80014b888219c5761edd144de Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 17:47:26 +0200 Subject: [PATCH 114/580] modified imports --- pype/tools/config_setting/__main__.py | 1 - .../config_setting/config_setting/__init__.py | 2 -- .../config_setting/widgets/__init__.py | 25 ++++++------------- .../widgets/{main.py => window.py} | 0 4 files changed, 7 insertions(+), 21 deletions(-) rename pype/tools/config_setting/config_setting/widgets/{main.py => window.py} (100%) diff --git a/pype/tools/config_setting/__main__.py b/pype/tools/config_setting/__main__.py index 171b85a775..aa6f707443 100644 --- a/pype/tools/config_setting/__main__.py +++ b/pype/tools/config_setting/__main__.py @@ -1,4 +1,3 @@ -import os import sys import config_setting diff --git a/pype/tools/config_setting/config_setting/__init__.py b/pype/tools/config_setting/config_setting/__init__.py index 835754e6a1..0c2fd6d4bb 100644 --- a/pype/tools/config_setting/config_setting/__init__.py +++ b/pype/tools/config_setting/config_setting/__init__.py @@ -1,10 +1,8 @@ from . import style -# from . import widgets from .widgets import MainWidget __all__ = ( "style", - # "widgets", "MainWidget" ) diff --git a/pype/tools/config_setting/config_setting/widgets/__init__.py b/pype/tools/config_setting/config_setting/widgets/__init__.py index 0197917596..0682f00324 100644 --- a/pype/tools/config_setting/config_setting/widgets/__init__.py +++ b/pype/tools/config_setting/config_setting/widgets/__init__.py @@ -1,19 +1,8 @@ -from .lib import ( - NOT_SET, - AS_WIDGET, - METADATA_KEY, - OVERRIDE_VERSION, - convert_gui_data_to_overrides, - convert_overrides_to_gui_data, - TypeToKlass -) +from .window import MainWidget +# TODO properly register inputs to TypeToKlass class +from . import inputs - -from .base import ( - PypeConfigurationWidget, - StudioWidget, - ProjectWidget -) -from .main import MainWidget - -from .inputs import * +__all__ = [ + "MainWidget", + "inputs" +] diff --git a/pype/tools/config_setting/config_setting/widgets/main.py b/pype/tools/config_setting/config_setting/widgets/window.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/main.py rename to pype/tools/config_setting/config_setting/widgets/window.py From 1a5389dc5e16ea5968d8d6d9991e1bee5e0f2099 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 18:44:28 +0200 Subject: [PATCH 115/580] cleaned attribute definitions --- .../config_setting/widgets/base.py | 50 +--- .../config_setting/widgets/inputs.py | 264 +++++------------- .../config_setting/widgets/lib.py | 1 - 3 files changed, 80 insertions(+), 235 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index dcbaf743a9..af979c0f9f 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -7,50 +7,7 @@ from . import lib from avalon import io -class PypeConfigurationWidget: - default_state = "" - - def config_value(self): - raise NotImplementedError( - "Method `config_value` is not implemented for `{}`.".format( - self.__class__.__name__ - ) - ) - - def value_from_values(self, values, keys=None): - if not values: - return lib.NOT_SET - - if keys is None: - keys = self.keys - - value = values - for key in keys: - if not isinstance(value, dict): - raise TypeError( - "Expected dictionary got {}.".format(str(type(value))) - ) - - if key not in value: - return lib.NOT_SET - value = value[key] - return value - - def style_state(self, is_overriden, is_modified): - items = [] - if is_overriden: - items.append("overriden") - if is_modified: - items.append("modified") - return "-".join(items) or self.default_state - - def add_children_gui(self, child_configuration, values): - raise NotImplementedError(( - "Method `add_children_gui` is not implemented for `{}`." - ).format(self.__class__.__name__)) - - -class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class StudioWidget(QtWidgets.QWidget): is_overidable = False is_overriden = False is_group = False @@ -149,6 +106,7 @@ class StudioWidget(QtWidgets.QWidget, PypeConfigurationWidget): if not os.path.exists(dirpath): os.makedirs(dirpath) + print("Saving data to: ", output_path) with open(output_path, "w") as file_stream: json.dump(origin_values, file_stream, indent=4) @@ -286,7 +244,7 @@ class ProjectListWidget(QtWidgets.QWidget): ) -class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class ProjectWidget(QtWidgets.QWidget): is_overriden = False is_group = False any_parent_is_group = False @@ -407,6 +365,7 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): if not os.path.exists(dirpath): os.makedirs(dirpath) + print("Saving data to: ", overrides_json_path) with open(overrides_json_path, "w") as file_stream: json.dump(output_data, file_stream, indent=4) @@ -457,5 +416,6 @@ class ProjectWidget(QtWidgets.QWidget, PypeConfigurationWidget): if not os.path.exists(dirpath): os.makedirs(dirpath) + print("Saving data to: ", output_path) with open(output_path, "w") as file_stream: json.dump(origin_values, file_stream, indent=4) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 63415a16d3..4e49406e26 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1,7 +1,6 @@ import json from Qt import QtWidgets, QtCore, QtGui from pype.api import config -from .base import PypeConfigurationWidget from .widgets import ( ClickableWidget, ExpandingWidget, @@ -19,14 +18,73 @@ class SchemeGroupHierarchyBug(Exception): super(SchemeGroupHierarchyBug, self).__init__(msg) -class InputWidget: +class ConfigWidget: + default_state = "" + + @property + def is_overidable(self): + return self._parent.is_overidable + + @property + def ignore_value_changes(self): + return self._parent.ignore_value_changes + + def config_value(self): + raise NotImplementedError( + "Method `config_value` is not implemented for `{}`.".format( + self.__class__.__name__ + ) + ) + + def value_from_values(self, values, keys=None): + if not values: + return NOT_SET + + if keys is None: + keys = self.keys + + value = values + for key in keys: + if not isinstance(value, dict): + raise TypeError( + "Expected dictionary got {}.".format(str(type(value))) + ) + + if key not in value: + return NOT_SET + value = value[key] + return value + + def style_state(self, is_overriden, is_modified): + items = [] + if is_overriden: + items.append("overriden") + if is_modified: + items.append("modified") + return "-".join(items) or self.default_state + + def add_children_gui(self, child_configuration, values): + raise NotImplementedError(( + "Method `add_children_gui` is not implemented for `{}`." + ).format(self.__class__.__name__)) + + +class InputWidget(ConfigWidget): def overrides(self): if not self.is_overriden: return NOT_SET, False return self.config_value(), self.is_group + @property + def child_modified(self): + return self.is_modified -class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): + @property + def child_overriden(self): + return self._is_overriden + + +class BooleanWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -120,30 +178,14 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): self.set_value(value) self.update_style() - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -185,7 +227,7 @@ class BooleanWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): return {self.key: self.item_value()} -class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): +class IntegerWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -243,30 +285,14 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): self.int_input.valueChanged.connect(self._on_value_change) - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def set_value(self, value, *, default_value=False): self.int_input.setValue(value) if default_value: @@ -329,7 +355,7 @@ class IntegerWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): return {self.key: self.item_value()} -class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): +class FloatWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -397,30 +423,14 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): self.float_input.valueChanged.connect(self._on_value_change) - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def set_value(self, value, *, default_value=False): self.float_input.setValue(value) if default_value: @@ -481,7 +491,7 @@ class FloatWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): return {self.key: self.item_value()} -class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): +class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -539,30 +549,14 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidg self.text_input.textChanged.connect(self._on_value_change) - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def set_value(self, value, *, default_value=False): self.text_input.setText(value) if default_value: @@ -625,7 +619,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidg return {self.key: self.item_value()} -class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): +class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -681,30 +675,14 @@ class TextMultiLineWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidge self.text_input.textChanged.connect(self._on_value_change) - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: @@ -822,7 +800,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.update_style(is_valid) -class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): +class RawJsonWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -879,30 +857,14 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): self.text_input.textChanged.connect(self._on_value_change) - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: @@ -963,7 +925,7 @@ class RawJsonWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): return {self.key: self.item_value()} -class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): +class TextListItem(QtWidgets.QWidget, ConfigWidget): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1013,7 +975,7 @@ class TextListItem(QtWidgets.QWidget, PypeConfigurationWidget): return self.text_input.text() -class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): @@ -1123,7 +1085,7 @@ class TextListSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: self.item_value()} -class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): +class TextListWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) def __init__( @@ -1180,30 +1142,14 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): self.default_value = self.item_value() self.override_value = None - @property - def child_modified(self): - return self.is_modified - - @property - def child_overriden(self): - return self._is_overriden - @property def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1256,7 +1202,7 @@ class TextListWidget(QtWidgets.QWidget, PypeConfigurationWidget, InputWidget): return {self.key: self.item_value()} -class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): +class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1323,18 +1269,10 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): def any_parent_is_group(self): return self._parent.any_parent_is_group - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def is_key_modified(self): return self._key() != self.default_key @@ -1375,7 +1313,7 @@ class ModifiableDictItem(QtWidgets.QWidget, PypeConfigurationWidget): return {key: value} -class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): @@ -1408,10 +1346,6 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): self.default_value = self.config_value() self.override_value = None - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._parent.is_overriden @@ -1420,10 +1354,6 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_group(self): return self._parent.is_group - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - @property def any_parent_is_group(self): return self._parent.any_parent_is_group @@ -1492,7 +1422,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, PypeConfigurationWidget): return output -class ModifiableDict(ExpandingWidget, PypeConfigurationWidget, InputWidget): +class ModifiableDict(ExpandingWidget, InputWidget): # Should be used only for dictionary with one datatype as value # TODO this is actually input field (do not care if is group or not) value_changed = QtCore.Signal(object) @@ -1554,34 +1484,14 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget, InputWidget): self.update_style() - @property - def child_modified(self): - return self.is_modified - @property def is_modified(self): return self._is_modified - @property - def child_overriden(self): - return self._is_overriden - - @property - def is_overidable(self): - return self._parent.is_overidable - @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def is_modified(self): - return self._is_modified - - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def apply_overrides(self, override_value): self._state = None self._is_modified = False @@ -1623,7 +1533,7 @@ class ModifiableDict(ExpandingWidget, PypeConfigurationWidget, InputWidget): return {self.key: self.item_value()} -class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): +class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) def __init__( @@ -1734,10 +1644,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -1830,10 +1736,6 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): def config_value(self): return {self.key: self.item_value()} - @property - def is_overidable(self): - return self._parent.is_overidable - def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) @@ -1864,7 +1766,7 @@ class DictExpandWidget(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: values}, self.is_group -class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): +class DictInvisible(QtWidgets.QWidget, ConfigWidget): # TODO is not overridable by itself value_changed = QtCore.Signal(object) @@ -1915,10 +1817,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): def is_overriden(self): return self._is_overriden or self._parent.is_overriden - @property - def is_overidable(self): - return self._parent.is_overidable - @property def child_modified(self): for input_field in self.input_fields: @@ -1933,10 +1831,6 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): return True return False - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def item_value(self): output = {} for input_field in self.input_fields: @@ -2019,7 +1913,7 @@ class DictInvisible(QtWidgets.QWidget, PypeConfigurationWidget): return {self.key: values}, self.is_group -class DictFormWidget(QtWidgets.QWidget): +class DictFormWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) def __init__( @@ -2070,14 +1964,6 @@ class DictFormWidget(QtWidgets.QWidget): return True return False - @property - def is_overidable(self): - return self._parent.is_overidable - - @property - def ignore_value_changes(self): - return self._parent.ignore_value_changes - def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] key = child_configuration["key"] diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index 454c0b07ed..c6379b4816 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -55,7 +55,6 @@ def convert_overrides_to_gui_data(data, first=True): return output - def replace_inner_schemas(schema_data, schema_collection): if schema_data["type"] == "schema": raise ValueError("First item in schema data can't be schema.") From 8f4cb392f8ba967491bcfb9febd19ea1510219db Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 18:56:12 +0200 Subject: [PATCH 116/580] _is_overriden is global attribute --- .../config_setting/widgets/inputs.py | 70 ++----------------- 1 file changed, 7 insertions(+), 63 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4e49406e26..8f6908eb3a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -20,6 +20,11 @@ class SchemeGroupHierarchyBug(Exception): class ConfigWidget: default_state = "" + _is_overriden = False + + @property + def is_overriden(self): + return self._is_overriden or self._parent.is_overriden @property def is_overidable(self): @@ -107,7 +112,6 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False self._was_overriden = False - self._is_overriden = False self._state = None @@ -182,10 +186,6 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -250,7 +250,6 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False self._was_overriden = False - self._is_overriden = False self._state = None @@ -289,10 +288,6 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def set_value(self, value, *, default_value=False): self.int_input.setValue(value) if default_value: @@ -378,7 +373,6 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False self._was_overriden = False - self._is_overriden = False self._state = None @@ -427,10 +421,6 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def set_value(self, value, *, default_value=False): self.float_input.setValue(value) if default_value: @@ -514,7 +504,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False self._was_overriden = False - self._is_overriden = False self._state = None @@ -553,10 +542,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def set_value(self, value, *, default_value=False): self.text_input.setText(value) if default_value: @@ -642,7 +627,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False self._was_overriden = False - self._is_overriden = False self._state = None @@ -679,10 +663,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: @@ -823,7 +803,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False self._was_overriden = False - self._is_overriden = False self._state = None @@ -861,10 +840,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: @@ -1107,7 +1082,6 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self.is_group = is_group self._was_overriden = False - self._is_overriden = False self._state = None @@ -1146,10 +1120,6 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): def is_modified(self): return self._is_modified or (self._was_overriden != self.is_overriden) - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1269,10 +1239,6 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): def any_parent_is_group(self): return self._parent.any_parent_is_group - @property - def is_overriden(self): - return self._parent.is_overriden - def is_key_modified(self): return self._key() != self.default_key @@ -1346,10 +1312,6 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): self.default_value = self.config_value() self.override_value = None - @property - def is_overriden(self): - return self._parent.is_overriden - @property def is_group(self): return self._parent.is_group @@ -1448,7 +1410,6 @@ class ModifiableDict(ExpandingWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._is_overriden = False self._was_overriden = False self._state = None @@ -1488,10 +1449,6 @@ class ModifiableDict(ExpandingWidget, InputWidget): def is_modified(self): return self._is_modified - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def apply_overrides(self, override_value): self._state = None self._is_modified = False @@ -1533,6 +1490,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): return {self.key: self.item_value()} +# Dictionaries class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) @@ -1556,7 +1514,6 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): self.any_parent_is_group = any_parent_is_group self._is_modified = False - self._is_overriden = False self.is_group = is_group self._state = None @@ -1640,10 +1597,6 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): super(DictExpandWidget, self).resizeEvent(event) self.content_widget.updateGeometry() - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -1785,7 +1738,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): self.any_parent_is_group = any_parent_is_group - self._is_overriden = False self.is_modified = False self.is_group = is_group @@ -1813,10 +1765,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): def update_style(self, *args, **kwargs): return - @property - def is_overriden(self): - return self._is_overriden or self._parent.is_overriden - @property def child_modified(self): for input_field in self.input_fields: @@ -1913,6 +1861,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): return {self.key: values}, self.is_group +# Proxy for form layout class DictFormWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) @@ -1928,7 +1877,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigWidget): self.any_parent_is_group = any_parent_is_group self.is_modified = False - self._is_overriden = False self.is_group = False super(DictFormWidget, self).__init__(parent) @@ -1946,10 +1894,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigWidget): return self.value_changed.emit(self) - @property - def is_overriden(self): - return self._parent.is_overriden - @property def child_modified(self): for input_field in self.input_fields.values(): From 949c844cc1b85648a99e3f82336a55f161f50230 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 19:01:32 +0200 Subject: [PATCH 117/580] was overriden as global attribute --- .../config_setting/widgets/inputs.py | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8f6908eb3a..bbc5387c02 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -21,11 +21,16 @@ class SchemeGroupHierarchyBug(Exception): class ConfigWidget: default_state = "" _is_overriden = False + _was_overriden = False @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden + @property + def was_overriden(self): + return self._was_overriden + @property def is_overidable(self): return self._parent.is_overidable @@ -111,7 +116,6 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None @@ -184,7 +188,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -249,7 +253,6 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None @@ -286,7 +289,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def set_value(self, value, *, default_value=False): self.int_input.setValue(value) @@ -372,7 +375,6 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None @@ -419,7 +421,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def set_value(self, value, *, default_value=False): self.float_input.setValue(value) @@ -503,7 +505,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None @@ -540,7 +541,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def set_value(self, value, *, default_value=False): self.text_input.setText(value) @@ -626,7 +627,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None @@ -661,7 +661,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) @@ -802,7 +802,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None @@ -838,7 +837,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) @@ -1081,7 +1080,6 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self.is_group = is_group - self._was_overriden = False self._state = None @@ -1118,7 +1116,7 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): @property def is_modified(self): - return self._is_modified or (self._was_overriden != self.is_overriden) + return self._is_modified or (self.was_overriden != self.is_overriden) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -1410,7 +1408,6 @@ class ModifiableDict(ExpandingWidget, InputWidget): self.is_group = is_group self._is_modified = False - self._was_overriden = False self._state = None super(ModifiableDict, self).__init__(input_data["label"], parent) From aaab8b4bf014fee3f6a728121b1c3d78788ebfe7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 19:08:40 +0200 Subject: [PATCH 118/580] working path to config --- pype/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/config.py b/pype/config.py index b3e860d72f..488492d722 100644 --- a/pype/config.py +++ b/pype/config.py @@ -6,11 +6,11 @@ import copy log = logging.getLogger(__name__) STUDIO_PRESETS_PATH = os.path.normpath( - os.path.join(os.environ["PYPE_CONFIG"], "config", "studio_presets") + os.path.join(os.environ["PYPE_CONFIG"], "studio_presets") ) PROJECT_CONFIGURATION_DIR = "project_presets" PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( - os.environ["PYPE_CONFIG"], "config", PROJECT_CONFIGURATION_DIR + os.environ["PYPE_CONFIG"], PROJECT_CONFIGURATION_DIR )) first_run = False From 91158eaed98af947a2a487595d5f9c0cfe19c9ac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 19:10:00 +0200 Subject: [PATCH 119/580] is modified is global attribute --- .../config_setting/widgets/inputs.py | 49 ++----------------- 1 file changed, 5 insertions(+), 44 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index bbc5387c02..72dd0932e7 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -21,8 +21,13 @@ class SchemeGroupHierarchyBug(Exception): class ConfigWidget: default_state = "" _is_overriden = False + _is_modified = False _was_overriden = False + @property + def is_modified(self): + return self._is_modified or (self.was_overriden != self.is_overriden) + @property def is_overriden(self): return self._is_overriden or self._parent.is_overriden @@ -115,7 +120,6 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): is_group = True self.is_group = is_group - self._is_modified = False self._state = None @@ -186,10 +190,6 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self.set_value(value) self.update_style() - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -252,7 +252,6 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): is_group = True self.is_group = is_group - self._is_modified = False self._state = None @@ -287,10 +286,6 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): self.int_input.valueChanged.connect(self._on_value_change) - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def set_value(self, value, *, default_value=False): self.int_input.setValue(value) if default_value: @@ -374,7 +369,6 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): is_group = True self.is_group = is_group - self._is_modified = False self._state = None @@ -419,10 +413,6 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self.float_input.valueChanged.connect(self._on_value_change) - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def set_value(self, value, *, default_value=False): self.float_input.setValue(value) if default_value: @@ -504,7 +494,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): is_group = True self.is_group = is_group - self._is_modified = False self._state = None @@ -539,10 +528,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): self.text_input.textChanged.connect(self._on_value_change) - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def set_value(self, value, *, default_value=False): self.text_input.setText(value) if default_value: @@ -626,7 +611,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): is_group = True self.is_group = is_group - self._is_modified = False self._state = None @@ -659,10 +643,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self.text_input.textChanged.connect(self._on_value_change) - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: @@ -801,7 +781,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): is_group = True self.is_group = is_group - self._is_modified = False self._state = None @@ -835,10 +814,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.text_input.textChanged.connect(self._on_value_change) - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def set_value(self, value, *, default_value=False): self.text_input.setPlainText(value) if default_value: @@ -1078,7 +1053,6 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): if not any_parent_is_group and not is_group: is_group = True - self._is_modified = False self.is_group = is_group self._state = None @@ -1114,10 +1088,6 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self.default_value = self.item_value() self.override_value = None - @property - def is_modified(self): - return self._is_modified or (self.was_overriden != self.is_overriden) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1407,7 +1377,6 @@ class ModifiableDict(ExpandingWidget, InputWidget): self.any_parent_is_group = any_parent_is_group self.is_group = is_group - self._is_modified = False self._state = None super(ModifiableDict, self).__init__(input_data["label"], parent) @@ -1442,10 +1411,6 @@ class ModifiableDict(ExpandingWidget, InputWidget): self.update_style() - @property - def is_modified(self): - return self._is_modified - def apply_overrides(self, override_value): self._state = None self._is_modified = False @@ -1510,7 +1475,6 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): self.any_parent_is_group = any_parent_is_group - self._is_modified = False self.is_group = is_group self._state = None @@ -1734,8 +1698,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): raise SchemeGroupHierarchyBug() self.any_parent_is_group = any_parent_is_group - - self.is_modified = False self.is_group = is_group super(DictInvisible, self).__init__(parent) @@ -1873,7 +1835,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigWidget): self.any_parent_is_group = any_parent_is_group - self.is_modified = False self.is_group = False super(DictFormWidget, self).__init__(parent) From 0acbc5459eb65acc5b216913578e6df5692b1a23 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 19:17:41 +0200 Subject: [PATCH 120/580] config_value is global method --- .../config_setting/widgets/inputs.py | 57 +++++++------------ 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 72dd0932e7..ee8c800b29 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -44,13 +44,26 @@ class ConfigWidget: def ignore_value_changes(self): return self._parent.ignore_value_changes - def config_value(self): + def reset_attributes(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + + self.reset_children_attributes() + + def reset_children_attributes(self): raise NotImplementedError( - "Method `config_value` is not implemented for `{}`.".format( - self.__class__.__name__ - ) + "Method `reset_children_attributes` not implemented!" ) + def item_value(self): + raise NotImplementedError( + "Method `item_value` not implemented!" + ) + + def config_value(self): + return {self.key: self.item_value()} + def value_from_values(self, values, keys=None): if not values: return NOT_SET @@ -98,6 +111,9 @@ class InputWidget(ConfigWidget): def child_overriden(self): return self._is_overriden + def reset_children_attributes(self): + return + class BooleanWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) @@ -227,9 +243,6 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.checkbox.isChecked() - def config_value(self): - return {self.key: self.item_value()} - class IntegerWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) @@ -344,9 +357,6 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.int_input.value() - def config_value(self): - return {self.key: self.item_value()} - class FloatWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) @@ -469,9 +479,6 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.float_input.value() - def config_value(self): - return {self.key: self.item_value()} - class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) @@ -586,9 +593,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.text_input.text() - def config_value(self): - return {self.key: self.item_value()} - class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) @@ -699,9 +703,6 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.text_input.toPlainText() - def config_value(self): - return {self.key: self.item_value()} - class RawJsonInput(QtWidgets.QPlainTextEdit): tab_length = 4 @@ -870,9 +871,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.text_input.toPlainText() - def config_value(self): - return {self.key: self.item_value()} - class TextListItem(QtWidgets.QWidget, ConfigWidget): _btn_size = 20 @@ -1030,9 +1028,6 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): return output - def config_value(self): - return {self.key: self.item_value()} - class TextListWidget(QtWidgets.QWidget, InputWidget): value_changed = QtCore.Signal(object) @@ -1136,9 +1131,6 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): def item_value(self): return self.value_widget.config_value() - def config_value(self): - return {self.key: self.item_value()} - class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): _btn_size = 20 @@ -1448,9 +1440,6 @@ class ModifiableDict(ExpandingWidget, InputWidget): def item_value(self): return self.value_widget.config_value() - def config_value(self): - return {self.key: self.item_value()} - # Dictionaries class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): @@ -1647,9 +1636,6 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): output.update(input_field.config_value()) return output - def config_value(self): - return {self.key: self.item_value()} - def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) @@ -1746,9 +1732,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): output.update(input_field.config_value()) return output - def config_value(self): - return {self.key: self.item_value()} - def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] if item_type == "schema": From b402c8d0135057809ce2ce9a61999934d1ea4293 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 19:35:44 +0200 Subject: [PATCH 121/580] removed overrides --- .../kuba_each_case/project_presets.json | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json diff --git a/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json b/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json deleted file mode 100644 index b9da242453..0000000000 --- a/pype/tools/config_setting/config/project_overrides/kuba_each_case/project_presets.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "__override_version__": 1, - "plugins": { - "maya": { - "__overriden_keys__": [ - "publish" - ], - "publish": { - "ValidateModelName": { - "enabled": true - }, - "ValidateAssemblyName": { - "enabled": false - } - } - } - } -} \ No newline at end of file From 71c2bb3ec1a5da3b68b5709db3bc6c287c3b0d11 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 22:32:44 +0200 Subject: [PATCH 122/580] moved type up --- .../applications_gui_schema.json | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json index 12fbb3cc26..bbf74a8f3f 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json @@ -9,144 +9,144 @@ "type": "dict-form", "children": [ { - "key": "blender_2.80", "type": "boolean", + "key": "blender_2.80", "label": "Blender 2.80" }, { - "key": "blender_2.81", "type": "boolean", + "key": "blender_2.81", "label": "Blender 2.81" }, { - "key": "blender_2.82", "type": "boolean", + "key": "blender_2.82", "label": "Blender 2.82" }, { - "key": "blender_2.83", "type": "boolean", + "key": "blender_2.83", "label": "Blender 2.83" }, { - "key": "celaction_local", "type": "boolean", + "key": "celaction_local", "label": "Celaction Local" }, { - "key": "celaction_remote", "type": "boolean", + "key": "celaction_remote", "label": "Celaction Remote" }, { - "key": "harmony_17", "type": "boolean", + "key": "harmony_17", "label": "Harmony 17" }, { - "key": "houdini_16", "type": "boolean", + "key": "houdini_16", "label": "Houdini 16" }, { - "key": "houdini_17", "type": "boolean", + "key": "houdini_17", "label": "Houdini 17" }, { - "key": "houdini_18", "type": "boolean", + "key": "houdini_18", "label": "Houdini 18" }, { - "key": "maya_2017", "type": "boolean", + "key": "maya_2017", "label": "Autodest Maya 2017" }, { - "key": "maya_2018", "type": "boolean", + "key": "maya_2018", "label": "Autodest Maya 2018" }, { - "key": "maya_2019", "type": "boolean", + "key": "maya_2019", "label": "Autodest Maya 2019" }, { - "key": "maya_2020", "type": "boolean", + "key": "maya_2020", "label": "Autodest Maya 2020" }, { "key": "nuke_10.0", "type": "boolean", "label": "Nuke 10.0" }, { - "key": "nuke_11.2", "type": "boolean", + "key": "nuke_11.2", "label": "Nuke 11.2" }, { - "key": "nuke_11.3", "type": "boolean", + "key": "nuke_11.3", "label": "Nuke 11.3" }, { - "key": "nuke_12.0", "type": "boolean", + "key": "nuke_12.0", "label": "Nuke 12.0" }, { - "key": "nukex_10.0", "type": "boolean", + "key": "nukex_10.0", "label": "NukeX 10.0" }, { - "key": "nukex_11.2", "type": "boolean", + "key": "nukex_11.2", "label": "NukeX 11.2" }, { - "key": "nukex_11.3", "type": "boolean", + "key": "nukex_11.3", "label": "NukeX 11.3" }, { - "key": "nukex_12.0", "type": "boolean", + "key": "nukex_12.0", "label": "NukeX 12.0" }, { - "key": "nukestudio_10.0", "type": "boolean", + "key": "nukestudio_10.0", "label": "NukeStudio 10.0" }, { - "key": "nukestudio_11.2", "type": "boolean", + "key": "nukestudio_11.2", "label": "NukeStudio 11.2" }, { - "key": "nukestudio_11.3", "type": "boolean", + "key": "nukestudio_11.3", "label": "NukeStudio 11.3" }, { - "key": "nukestudio_12.0", "type": "boolean", + "key": "nukestudio_12.0", "label": "NukeStudio 12.0" }, { - "key": "houdini_16.5", "type": "boolean", + "key": "houdini_16.5", "label": "Houdini 16.5" }, { - "key": "houdini_17", "type": "boolean", + "key": "houdini_17", "label": "Houdini 17" }, { - "key": "houdini_18", "type": "boolean", + "key": "houdini_18", "label": "Houdini 18" }, { - "key": "premiere_2019", "type": "boolean", + "key": "premiere_2019", "label": "Premiere 2019" }, { - "key": "premiere_2020", "type": "boolean", + "key": "premiere_2020", "label": "Premiere 2020" }, { - "key": "premiere_2020", "type": "boolean", + "key": "premiere_2020", "label": "Premiere 2020" }, { + "type": "boolean", "key": "resolve_16", - "type": "boolean", "label": "BM DaVinci Resolve 16" }, { - "key": "storyboardpro_7", "type": "boolean", + "key": "storyboardpro_7", "label": "Storyboard Pro 7" }, { - "key": "unreal_4.24", "type": "boolean", + "key": "unreal_4.24", "label": "Unreal Editor 4.24" } ] From 5f0ea1378c5d9c5fc34fdcc91f7fd03698f77584 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Sun, 23 Aug 2020 19:16:50 +0200 Subject: [PATCH 123/580] indexes should be removed properly now for artist view --- pype/tools/pyblish_pype/model.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pype/tools/pyblish_pype/model.py b/pype/tools/pyblish_pype/model.py index fdcdffd33f..3c9d4806ac 100644 --- a/pype/tools/pyblish_pype/model.py +++ b/pype/tools/pyblish_pype/model.py @@ -870,13 +870,18 @@ class ArtistProxy(QtCore.QAbstractProxyModel): self.rowsInserted.emit(self.parent(), new_from, new_to + 1) def _remove_rows(self, parent_row, from_row, to_row): - removed_rows = [] increment_num = self.mapping_from[parent_row][from_row] + + to_end_index = len(self.mapping_from[parent_row]) - 1 + for _idx in range(0, parent_row): + to_end_index += len(self.mapping_from[_idx]) + + removed_rows = 0 _emit_last = None for row_num in reversed(range(from_row, to_row + 1)): row = self.mapping_from[parent_row].pop(row_num) _emit_last = row - removed_rows.append(row) + removed_rows += 1 _emit_first = int(increment_num) mapping_from_len = len(self.mapping_from) @@ -896,11 +901,8 @@ class ArtistProxy(QtCore.QAbstractProxyModel): self.mapping_from[idx_i][idx_j] = increment_num increment_num += 1 - first_to_row = None - for row in removed_rows: - if first_to_row is None: - first_to_row = row - self.mapping_to.pop(row) + for idx in range(removed_rows): + self.mapping_to.pop(to_end_index - idx) return (_emit_first, _emit_last) From a5e6979a86009d56a52a7ccf41651e4a51277dac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 10:52:52 +0200 Subject: [PATCH 124/580] renamed gui schemas files and added intent --- ...i_schema.json => 0_studio_gui_schema.json} | 5 +++-- ...ma.json => 1_applications_gui_schema.json} | 0 .../studio_schema/1_intents_gui_schema.json | 19 +++++++++++++++++++ ...ui_schema.json => 1_tools_gui_schema.json} | 0 .../config_setting/widgets/base.py | 2 +- 5 files changed, 23 insertions(+), 3 deletions(-) rename pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/{studio_gui_schema.json => 0_studio_gui_schema.json} (83%) rename pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/{applications_gui_schema.json => 1_applications_gui_schema.json} (100%) create mode 100644 pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json rename pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/{tools_gui_schema.json => 1_tools_gui_schema.json} (100%) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json similarity index 83% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index 088c407804..868fbea82e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -10,8 +10,9 @@ "children": [{ "type": "schema", "children": [ - "applications_gui_schema", - "tools_gui_schema" + "1_applications_gui_schema", + "1_tools_gui_schema", + "1_intents_gui_schema" ] }] }, { diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/applications_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json new file mode 100644 index 0000000000..1469ffc5fc --- /dev/null +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json @@ -0,0 +1,19 @@ +{ + "key": "intent", + "type": "dict-expanding", + "label": "Intent Setting", + "is_group": true, + "is_file": true, + "children": [ + { + "type": "dict-modifiable", + "key": "items", + "label": "Intent Key/Label", + "object_type": "text-singleline" + }, { + "type": "text-singleline", + "key": "default", + "label": "Default intent" + } + ] +} diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/tools_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index af979c0f9f..a794ea64f3 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -62,7 +62,7 @@ class StudioWidget(QtWidgets.QWidget): self.input_fields.clear() values = {"studio": config.studio_presets()} - schema = lib.gui_schema("studio_schema", "studio_gui_schema") + schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) self.schema = schema From df0eae7719495b8cf8bc7740b20e68067cf39e81 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 11:39:38 +0200 Subject: [PATCH 125/580] added tray items --- .../studio_schema/0_studio_gui_schema.json | 15 +-- .../studio_schema/1_muster.json | 12 ++ .../studio_schema/1_tray_items.json | 106 ++++++++++++++++++ 3 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json create mode 100644 pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index 868fbea82e..9063dfcc8e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -10,22 +10,13 @@ "children": [{ "type": "schema", "children": [ + "1_tray_items", "1_applications_gui_schema", "1_tools_gui_schema", - "1_intents_gui_schema" + "1_intents_gui_schema", + "1_muster" ] }] - }, { - "key": "muster", - "type": "dict-invisible", - "is_group": true, - "children": [{ - "key": "templates_mapping", - "label": "Muster", - "is_file": true, - "type": "dict-modifiable", - "object_type": "int" - }] } ] } diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json new file mode 100644 index 0000000000..224f2efc71 --- /dev/null +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json @@ -0,0 +1,12 @@ +{ + "key": "muster", + "type": "dict-invisible", + "is_group": true, + "children": [{ + "key": "templates_mapping", + "label": "Muster", + "is_file": true, + "type": "dict-modifiable", + "object_type": "int" + }] +} diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json new file mode 100644 index 0000000000..0456e52985 --- /dev/null +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -0,0 +1,106 @@ +{ + "key": "tray_modules", + "type": "dict-expanding", + "label": "Modules", + "is_file": true, + "is_group": true, + "children": [ + { + "key": "item_usage", + "type": "dict-invisible", + "children": [ + { + "type": "dict-form", + "children": [ + { + "type": "boolean", + "key": "User settings", + "label": "User settings" + }, { + "type": "boolean", + "key": "Ftrack", + "label": "Ftrack" + }, { + "type": "boolean", + "key": "Muster", + "label": "Muster" + }, { + "type": "boolean", + "key": "Avalon", + "label": "Avalon" + }, { + "type": "boolean", + "key": "Clockify", + "label": "Clockify" + }, { + "type": "boolean", + "key": "Standalone Publish", + "label": "Standalone Publish" + }, { + "type": "boolean", + "key": "Logging", + "label": "Logging" + }, { + "type": "boolean", + "key": "Idle Manager", + "label": "Idle Manager" + }, { + "type": "boolean", + "key": "Rest Api", + "label": "Rest Api" + }, { + "type": "boolean", + "key": "Adobe Communicator", + "label": "Adobe Communicator" + } + ] + } + ] + }, { + "key": "attributes", + "type": "dict-expanding", + "label": "Module attributes", + "children": [ + { + "type": "dict-expanding", + "key": "Rest Api", + "label": "Rest Api", + "MISINGKEYCONF": {"exclude_ports": []}, + "children": [ + { + "type": "int", + "key": "default_port", + "label": "Default Port" + } + ] + }, { + "type": "dict-expanding", + "key": "Timers Manager", + "label": "Timers Manager", + "children": [ + { + "type": "float", + "key": "full_time", + "label": "Max idle time" + }, { + "type": "float", + "key": "message_time", + "label": "When dialog will show" + } + ] + }, { + "type": "dict-expanding", + "key": "Clockify", + "label": "Clockify", + "children": [ + { + "type": "text-singleline", + "key": "workspace_name", + "label": "Workspace name" + } + ] + } + ] + } + ] +} From f32aa4fd84abfa09e53bc4ceb5c07f3bf3d4f391 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 11:48:40 +0200 Subject: [PATCH 126/580] do not show the attributes label --- .../config_gui_schema/studio_schema/1_tray_items.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index 0456e52985..e6f9a41e51 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -58,8 +58,7 @@ ] }, { "key": "attributes", - "type": "dict-expanding", - "label": "Module attributes", + "type": "dict-invisible", "children": [ { "type": "dict-expanding", From 4a375737e346540d0c93422177b9a54c758079ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 12:18:17 +0200 Subject: [PATCH 127/580] moved muster back to studio --- .../studio_schema/0_studio_gui_schema.json | 14 ++++++++++++-- .../config_gui_schema/studio_schema/1_muster.json | 12 ------------ 2 files changed, 12 insertions(+), 14 deletions(-) delete mode 100644 pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index 9063dfcc8e..2fd63c7cdc 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -13,10 +13,20 @@ "1_tray_items", "1_applications_gui_schema", "1_tools_gui_schema", - "1_intents_gui_schema", - "1_muster" + "1_intents_gui_schema" ] }] + }, { + "key": "muster", + "type": "dict-invisible", + "children": [{ + "is_group": true, + "is_file": true, + "key": "templates_mapping", + "label": "Muster - Templates mapping", + "type": "dict-modifiable", + "object_type": "int" + }] } ] } diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json deleted file mode 100644 index 224f2efc71..0000000000 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_muster.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "key": "muster", - "type": "dict-invisible", - "is_group": true, - "children": [{ - "key": "templates_mapping", - "label": "Muster", - "is_file": true, - "type": "dict-modifiable", - "object_type": "int" - }] -} From fce265af47a8bb297e0d4b86b1bef88eccc4d1f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 12:52:46 +0200 Subject: [PATCH 128/580] renamed presets to configurations --- pype/config.py | 12 ++++----- .../config_setting/widgets/base.py | 26 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pype/config.py b/pype/config.py index 488492d722..454835e005 100644 --- a/pype/config.py +++ b/pype/config.py @@ -6,7 +6,7 @@ import copy log = logging.getLogger(__name__) STUDIO_PRESETS_PATH = os.path.normpath( - os.path.join(os.environ["PYPE_CONFIG"], "studio_presets") + os.path.join(os.environ["PYPE_CONFIG"], "studio_configurations") ) PROJECT_CONFIGURATION_DIR = "project_presets" PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( @@ -128,11 +128,11 @@ def load_jsons_from_dir(path, *args, **kwargs): return output -def studio_presets(*args, **kwargs): +def studio_configurations(*args, **kwargs): return load_jsons_from_dir(STUDIO_PRESETS_PATH, *args, **kwargs) -def global_project_presets(**kwargs): +def global_project_configurations(**kwargs): return load_jsons_from_dir(PROJECT_PRESETS_PATH, **kwargs) @@ -142,7 +142,7 @@ def path_to_project_overrides(project_name): return os.path.join(dirpath, PROJECT_CONFIGURATION_DIR + ".json") -def project_preset_overrides(project_name, **kwargs): +def project_configurations_overrides(project_name, **kwargs): if not project_name: return {} @@ -184,10 +184,10 @@ def apply_overrides(global_presets, project_overrides): def project_presets(project_name=None, **kwargs): - global_presets = global_project_presets(**kwargs) + global_presets = global_project_configurations(**kwargs) if not project_name: project_name = os.environ.get("AVALON_PROJECT") - project_overrides = project_preset_overrides(project_name, **kwargs) + project_overrides = project_configurations_overrides(project_name, **kwargs) return apply_overrides(global_presets, project_overrides) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index a794ea64f3..23eabdb531 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -61,7 +61,7 @@ class StudioWidget(QtWidgets.QWidget): widget.deleteLater() self.input_fields.clear() - values = {"studio": config.studio_presets()} + values = {"studio": config.studio_configurations()} schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) @@ -80,14 +80,14 @@ class StudioWidget(QtWidgets.QWidget): all_values = all_values["studio"] # Load studio data with metadata - current_presets = config.studio_presets() + current_configurations = config.studio_configurations() keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: # Skip first key key_sequence = key_sequence[1:] subpath = "/".join(key_sequence) + ".json" - origin_values = current_presets + origin_values = current_configurations for key in key_sequence: if key not in origin_values: origin_values = {} @@ -280,13 +280,13 @@ class ProjectWidget(QtWidgets.QWidget): footer_layout.addWidget(spacer_widget, 1) footer_layout.addWidget(save_btn, 0) - presets_widget = QtWidgets.QWidget() - presets_layout = QtWidgets.QVBoxLayout(presets_widget) - presets_layout.setContentsMargins(0, 0, 0, 0) - presets_layout.setSpacing(0) + configurations_widget = QtWidgets.QWidget() + configurations_layout = QtWidgets.QVBoxLayout(configurations_widget) + configurations_layout.setContentsMargins(0, 0, 0, 0) + configurations_layout.setSpacing(0) - presets_layout.addWidget(scroll_widget, 1) - presets_layout.addWidget(footer_widget, 0) + configurations_layout.addWidget(scroll_widget, 1) + configurations_layout.addWidget(footer_widget, 0) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -294,7 +294,7 @@ class ProjectWidget(QtWidgets.QWidget): self.setLayout(layout) layout.addWidget(project_list_widget, 0) - layout.addWidget(presets_widget, 1) + layout.addWidget(configurations_widget, 1) save_btn.clicked.connect(self._save) project_list_widget.project_changed.connect(self._on_project_change) @@ -307,7 +307,7 @@ class ProjectWidget(QtWidgets.QWidget): self.reset() def reset(self): - values = config.global_project_presets() + values = config.global_project_configurations() schema = lib.gui_schema("projects_schema", "project_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) @@ -390,14 +390,14 @@ class ProjectWidget(QtWidgets.QWidget): all_values = all_values["project"] # Load studio data with metadata - current_presets = config.global_project_presets() + current_configurations = config.global_project_configurations() keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: # Skip first key key_sequence = key_sequence[1:] subpath = "/".join(key_sequence) + ".json" - origin_values = current_presets + origin_values = current_configurations for key in key_sequence: if key not in origin_values: origin_values = {} From eb3406751119d6581bc9380b08110849f05217c6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 13:01:04 +0200 Subject: [PATCH 129/580] changed input from vertical to horizontal layout --- .../config_setting/widgets/inputs.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ee8c800b29..3a862b7a3e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -141,9 +141,9 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): super(BooleanWidget, self).__init__(parent) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout.setSpacing(5) self.checkbox = QtWidgets.QCheckBox() self.checkbox.setAttribute(QtCore.Qt.WA_StyledBackground) @@ -270,9 +270,9 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): super(IntegerWidget, self).__init__(parent) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout.setSpacing(5) self.int_input = ModifiedIntSpinBox() @@ -384,9 +384,9 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): super(FloatWidget, self).__init__(parent) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout.setSpacing(5) self.float_input = ModifiedFloatSpinBox() @@ -506,9 +506,9 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): super(TextSingleLineWidget, self).__init__(parent) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout.setSpacing(5) self.text_input = QtWidgets.QLineEdit() @@ -620,9 +620,9 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): super(TextMultiLineWidget, self).__init__(parent) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout.setSpacing(5) self.text_input = QtWidgets.QPlainTextEdit() if not label_widget: From f62d7b8cac476378fb109e64996eeb9d7a5d814c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 14:42:25 +0200 Subject: [PATCH 130/580] removed temp configurations --- .../studio_presets/ftrack/server_plugins.json | 1 - .../studio_presets/ftrack/user_plugins.json | 5 --- .../studio_presets/global/applications.json | 43 ------------------- .../config/studio_presets/global/intents.json | 9 ---- .../config/studio_presets/global/tools.json | 6 --- .../studio_presets/global/tray_items.json | 25 ----------- .../muster/templates_mapping.json | 19 -------- 7 files changed, 108 deletions(-) delete mode 100644 pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json delete mode 100644 pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json delete mode 100644 pype/tools/config_setting/config/studio_presets/global/applications.json delete mode 100644 pype/tools/config_setting/config/studio_presets/global/intents.json delete mode 100644 pype/tools/config_setting/config/studio_presets/global/tools.json delete mode 100644 pype/tools/config_setting/config/studio_presets/global/tray_items.json delete mode 100644 pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json diff --git a/pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json b/pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/tools/config_setting/config/studio_presets/ftrack/server_plugins.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json b/pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json deleted file mode 100644 index 1ba8e9b511..0000000000 --- a/pype/tools/config_setting/config/studio_presets/ftrack/user_plugins.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "TestAction": { - "ignore_me": true - } -} diff --git a/pype/tools/config_setting/config/studio_presets/global/applications.json b/pype/tools/config_setting/config/studio_presets/global/applications.json deleted file mode 100644 index 21693e5fee..0000000000 --- a/pype/tools/config_setting/config/studio_presets/global/applications.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "blender_2.80": true, - "blender_2.81": true, - "blender_2.82": true, - "blender_2.83": true, - "harmony_17": true, - "houdini_16": true, - "houdini_17": true, - "houdini_18": true, - "maya_2016": true, - "maya_2017": true, - "maya_2018": true, - "maya_2019": true, - "maya_2020": true, - "nuke_10.0": true, - "nuke_11.0": true, - "nuke_11.2": true, - "nuke_11.3": true, - "nuke_12.0": true, - "nukex_10.0": true, - "nukex_11.0": true, - "nukex_11.2": true, - "nukex_11.3": true, - "nukex_12.0": true, - "nukestudio_10.0": true, - "nukestudio_11.0": true, - "nukestudio_11.2": true, - "nukestudio_11.3": true, - "nukestudio_12.0": true, - "photoshop_2020": true, - "premiere_2019": true, - "premiere_2020": true, - "python_2": true, - "python_3": true, - "resolve_16": true, - "shell": true, - "storyboardpro_7": true, - "unreal_4.21": true, - "celaction_local": true, - "celaction_remote": true, - "houdini_16.5": false, - "unreal_4.24": true -} \ No newline at end of file diff --git a/pype/tools/config_setting/config/studio_presets/global/intents.json b/pype/tools/config_setting/config/studio_presets/global/intents.json deleted file mode 100644 index c853e27b7f..0000000000 --- a/pype/tools/config_setting/config/studio_presets/global/intents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "default": "wip", - "items": { - "": "", - "wip": "WIP", - "test": "TEST", - "final": "FINAL" - } -} diff --git a/pype/tools/config_setting/config/studio_presets/global/tools.json b/pype/tools/config_setting/config/studio_presets/global/tools.json deleted file mode 100644 index 53aab7b2ca..0000000000 --- a/pype/tools/config_setting/config/studio_presets/global/tools.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "mtoa_3.0.1": false, - "mtoa_3.1.1": false, - "mtoa_3.2.0": false, - "yeti_2.1.2": false -} \ No newline at end of file diff --git a/pype/tools/config_setting/config/studio_presets/global/tray_items.json b/pype/tools/config_setting/config/studio_presets/global/tray_items.json deleted file mode 100644 index a42bf67c38..0000000000 --- a/pype/tools/config_setting/config/studio_presets/global/tray_items.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "usage": { - "User settings": false, - "Ftrack": false, - "Muster": false, - "Avalon": true, - "Clockify": false, - "Standalone Publish": true, - "Logging": true, - "Idle Manager": true, - "Timers Manager": true, - "Rest Api": true, - "Premiere Communicator": true - }, - "attributes": { - "Rest Api": { - "default_port": 8021, - "exclude_ports": [] - }, - "Timers Manager": { - "full_time": 15, - "message_time": 0.5 - } - } -} diff --git a/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json b/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json deleted file mode 100644 index 0c09113515..0000000000 --- a/pype/tools/config_setting/config/studio_presets/muster/templates_mapping.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "3delight": 41, - "arnold": 46, - "arnold_sf": 57, - "gelato": 30, - "harware": 3, - "krakatoa": 51, - "file_layers": 7, - "mentalray": 2, - "mentalray_sf": 6, - "redshift": 55, - "renderman": 29, - "software": 1, - "software_sf": 5, - "turtle": 10, - "vector": 4, - "vray": 37, - "ffmpeg": 48 -} \ No newline at end of file From b13c05919a50a4df8546a2b47ed7c1de0e39ede6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 14:58:07 +0200 Subject: [PATCH 131/580] changed names of project schemas --- ..._schema.json => 0_project_gui_schema.json} | 5 ++- ...json => 1_ftrack_projects_gui_schema.json} | 0 ..._schema.json => 1_plugins_gui_schema.json} | 10 +++--- .../projects_schema/test_project_schema.json | 34 ------------------- .../config_setting/widgets/base.py | 2 +- 5 files changed, 8 insertions(+), 43 deletions(-) rename pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/{project_gui_schema.json => 0_project_gui_schema.json} (58%) rename pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/{ftrack_projects_gui_schema.json => 1_ftrack_projects_gui_schema.json} (100%) rename pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/{plugins_gui_schema.json => 1_plugins_gui_schema.json} (100%) delete mode 100644 pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/test_project_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json similarity index 58% rename from pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/project_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json index 0405524b40..c281ce3c79 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/project_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json @@ -5,9 +5,8 @@ { "type": "schema", "children": [ - "test_project_schema", - "ftrack_projects_gui_schema", - "plugins_gui_schema" + "1_ftrack_projects_gui_schema", + "1_plugins_gui_schema" ] } ] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/ftrack_projects_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 1eaecbb8e5..1d1f299b55 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -1,23 +1,23 @@ { - "key": "plugins", "type": "dict-expanding", + "key": "plugins", "label": "Plugins", "children": [ { - "key": "maya", "type": "dict-expanding", + "key": "maya", "label": "Maya", "children": [ { - "key": "publish", "type": "dict-expanding", + "key": "publish", "label": "Publish plugins", "is_group": true, "is_file": true, "children": [ { - "key": "ValidateModelName", "type": "dict-invisible", + "key": "ValidateModelName", "label": "Validate Model Name", "children": [ { @@ -27,8 +27,8 @@ } ] }, { - "key": "ValidateAssemblyName", "type": "dict-invisible", + "key": "ValidateAssemblyName", "label": "Validate Assembly Name", "children": [ { diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/test_project_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/test_project_schema.json deleted file mode 100644 index 43c9a647f4..0000000000 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/test_project_schema.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "key": "test_inputs", - "type": "dict-expanding", - "label": "Test inputs", - "is_group": true, - "is_file": true, - "children": [ - { - "key": "boolean", - "type": "boolean", - "label": "Boolean" - }, { - "key": "test_singleline", - "type": "text-singleline", - "label": "Text singleline" - }, { - "key": "test_multiline", - "type": "text-multiline", - "label": "Text multiline" - }, { - "key": "raw_json", - "type": "raw-json", - "label": "Raw json" - }, { - "key": "int", - "type": "int", - "label": "Int" - }, { - "key": "float", - "type": "float", - "label": "Float" - } - ] -} diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 23eabdb531..7bbd95b135 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -308,7 +308,7 @@ class ProjectWidget(QtWidgets.QWidget): def reset(self): values = config.global_project_configurations() - schema = lib.gui_schema("projects_schema", "project_gui_schema") + schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) self.schema = schema From 332fe3f668b9eef7251539ae47d9b40b2d628b78 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 14:58:24 +0200 Subject: [PATCH 132/580] DictExpandWidget inherits ExpandingWidget --- .../config_setting/widgets/inputs.py | 60 ++----------------- 1 file changed, 4 insertions(+), 56 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3a862b7a3e..9bcc54655b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1442,7 +1442,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): # Dictionaries -class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): +class DictExpandWidget(ExpandingWidget, ConfigWidget): value_changed = QtCore.Signal(object) def __init__( @@ -1469,31 +1469,8 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): self._state = None self._child_state = None - super(DictExpandWidget, self).__init__(parent) + super(DictExpandWidget, self).__init__(input_data["label"], parent) self.setObjectName("DictExpandWidget") - top_part = ClickableWidget(parent=self) - - button_size = QtCore.QSize(5, 5) - button_toggle = QtWidgets.QToolButton(parent=top_part) - button_toggle.setProperty("btn-type", "expand-toggle") - button_toggle.setIconSize(button_size) - button_toggle.setArrowType(QtCore.Qt.RightArrow) - button_toggle.setCheckable(True) - button_toggle.setChecked(False) - - label = input_data["label"] - button_toggle_text = QtWidgets.QLabel(label, parent=top_part) - button_toggle_text.setObjectName("ExpandLabel") - - layout = QtWidgets.QHBoxLayout(top_part) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(button_toggle) - layout.addWidget(button_toggle_text) - top_part.setLayout(layout) - - main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(9, 9, 9, 9) content_widget = QtWidgets.QWidget(self) content_widget.setVisible(False) @@ -1501,22 +1478,13 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(3, 3, 3, 3) - main_layout.addWidget(top_part) - main_layout.addWidget(content_widget) - self.setLayout(main_layout) + self.set_content_widget(content_widget) self.setAttribute(QtCore.Qt.WA_StyledBackground) - self.top_part = top_part - self.button_toggle = button_toggle - self.button_toggle_text = button_toggle_text - self.content_widget = content_widget self.content_layout = content_layout - self.top_part.clicked.connect(self._top_part_clicked) - self.button_toggle.clicked.connect(self.toggle_content) - self.input_fields = [] self.key = input_data["key"] @@ -1527,26 +1495,6 @@ class DictExpandWidget(QtWidgets.QWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) - def _top_part_clicked(self): - self.toggle_content(not self.button_toggle.isChecked()) - - def toggle_content(self, *args): - if len(args) > 0: - checked = args[0] - else: - checked = self.button_toggle.isChecked() - arrow_type = QtCore.Qt.RightArrow - if checked: - arrow_type = QtCore.Qt.DownArrow - self.button_toggle.setChecked(checked) - self.button_toggle.setArrowType(arrow_type) - self.content_widget.setVisible(checked) - self.parent().updateGeometry() - - def resizeEvent(self, event): - super(DictExpandWidget, self).resizeEvent(event) - self.content_widget.updateGeometry() - def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -1901,8 +1849,8 @@ TypeToKlass.types["text-multiline"] = TextMultiLineWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["int"] = IntegerWidget TypeToKlass.types["float"] = FloatWidget +TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["dict-expanding"] = DictExpandWidget TypeToKlass.types["dict-form"] = DictFormWidget TypeToKlass.types["dict-invisible"] = DictInvisible -TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["list-text"] = TextListWidget From 93c30ed32049ecd8eb4b117b634049d6656ed8fe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 14:59:49 +0200 Subject: [PATCH 133/580] added expanding policy of default input labels --- .../config_setting/widgets/inputs.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9bcc54655b..0497cb7763 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -151,9 +151,9 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): label = input_data["label"] label_widget = QtWidgets.QLabel(label) label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) - layout.addWidget(label_widget) + layout.addWidget(label_widget, 0) - layout.addWidget(self.checkbox) + layout.addWidget(self.checkbox, 1) if not self._as_widget: self.label_widget = label_widget @@ -279,8 +279,8 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget) - layout.addWidget(self.int_input) + layout.addWidget(label_widget, 0) + layout.addWidget(self.int_input, 1) if not self._as_widget: self.label_widget = label_widget @@ -403,8 +403,8 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget) - layout.addWidget(self.float_input) + layout.addWidget(label_widget, 0) + layout.addWidget(self.float_input, 1) if not self._as_widget: self.label_widget = label_widget @@ -515,8 +515,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget) - layout.addWidget(self.text_input) + layout.addWidget(label_widget, 0) + layout.addWidget(self.text_input, 1) if not self._as_widget: self.label_widget = label_widget @@ -628,8 +628,8 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget) - layout.addWidget(self.text_input) + layout.addWidget(label_widget, 0) + layout.addWidget(self.text_input, 1) self.label_widget = label_widget From f0c7dedb4d021860a0991a07e16b3c3814e11c5e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 16:02:31 +0200 Subject: [PATCH 134/580] adde nonexpanding widget --- .../config_setting/widgets/inputs.py | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0497cb7763..0ceec27d67 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1553,6 +1553,132 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): self.button_toggle_text.setProperty("state", state) self.button_toggle_text.style().polish(self.button_toggle_text) +class DictWidget(QtWidgets.QWidget, ConfigWidget): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + if values is AS_WIDGET: + raise TypeError("Can't use \"{}\" as widget item.".format( + self.__class__.__name__ + )) + self._parent = parent + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + is_group = input_data.get("is_group", False) + if is_group and any_parent_is_group: + raise SchemeGroupHierarchyBug() + + self.any_parent_is_group = any_parent_is_group + + self.is_group = is_group + + self._state = None + self._child_state = None + + super(DictWidget, self).__init__(parent) + self.setObjectName("DictWidget") + + body_widget = QtWidgets.QWidget(self) + + label_widget = QtWidgets.QLabel( + input_data["label"], parent=body_widget + ) + label_widget.setObjectName("ExpandLabel") + + content_widget = QtWidgets.QWidget(body_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(3, 3, 3, 3) + + body_layout = QtWidgets.QVBoxLayout(body_widget) + body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setSpacing(5) + body_layout.addWidget(label_widget) + body_layout.addWidget(content_widget) + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(5, 5, 5, 5) + main_layout.setSpacing(0) + main_layout.addWidget(body_widget) + + self.label_widget = label_widget + self.content_widget = content_widget + self.content_layout = content_layout + + self.input_fields = [] + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + + def apply_overrides(self, override_value): + # Make sure this is set to False + self._is_overriden = False + self._state = None + self._child_state = None + for item in self.input_fields: + if override_value is None: + child_value = None + else: + child_value = override_value.get(item.key) + + item.apply_overrides(child_value) + + self._is_overriden = ( + self.is_group + and self.is_overidable + and ( + override_value is not None + or self.child_overriden + ) + ) + self.update_style() + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + if self.is_group: + if self.is_overidable: + self._is_overriden = True + + # TODO update items + if item is not None: + for _item in self.input_fields: + if _item is not item: + _item.update_style() + + self.value_changed.emit(self) + + self.update_style() + + def update_style(self, is_overriden=None): + child_modified = self.child_modified + child_state = self.style_state(self.child_overriden, child_modified) + if child_state: + child_state = "child-{}".format(child_state) + + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state + + state = self.style_state(self.is_overriden, self.is_modified) + if self._state == state: + return + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) self._state = state @@ -1850,6 +1976,7 @@ TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["int"] = IntegerWidget TypeToKlass.types["float"] = FloatWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict +TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-expanding"] = DictExpandWidget TypeToKlass.types["dict-form"] = DictFormWidget TypeToKlass.types["dict-invisible"] = DictInvisible From 8c6ff3b7f825b54a2ed23cc6b52707921cf13d8f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 16:04:04 +0200 Subject: [PATCH 135/580] fixed dict expanding --- .../config_setting/widgets/inputs.py | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0ceec27d67..61c6385323 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1551,8 +1551,69 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): if self._state == state: return - self.button_toggle_text.setProperty("state", state) - self.button_toggle_text.style().polish(self.button_toggle_text) + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + self._state = state + + @property + def is_modified(self): + if self.is_group: + return self.child_modified + return False + + @property + def child_modified(self): + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False + + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + + def item_value(self): + output = {} + for input_field in self.input_fields: + # TODO maybe merge instead of update should be used + # NOTE merge is custom function which merges 2 dicts + output.update(input_field.config_value()) + return output + + def add_children_gui(self, child_configuration, values): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + item = klass( + child_configuration, values, self.keys, self + ) + item.value_changed.connect(self._on_value_change) + self.content_layout.addWidget(item) + + self.input_fields.append(item) + return item + + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(value.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return {self.key: values}, self.is_group + + class DictWidget(QtWidgets.QWidget, ConfigWidget): value_changed = QtCore.Signal(object) From 4776eaca79c5c3b62c793dfcadbce51d33d18172 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 16:17:34 +0200 Subject: [PATCH 136/580] Added few plugins --- .../projects_schema/1_plugins_gui_schema.json | 129 +++++++++++++++++- 1 file changed, 124 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 1d1f299b55..e2717bca37 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -4,6 +4,21 @@ "label": "Plugins", "children": [ { + "type": "dict-expanding", + "key": "celaction", + "label": "CelAction", + "children": [] + }, { + "type": "dict-expanding", + "key": "ftrack", + "label": "Ftrack", + "children": [] + }, { + "type": "dict-expanding", + "key": "global", + "label": "Global", + "children": [] + }, { "type": "dict-expanding", "key": "maya", "label": "Maya", @@ -12,28 +27,29 @@ "type": "dict-expanding", "key": "publish", "label": "Publish plugins", - "is_group": true, "is_file": true, "children": [ { - "type": "dict-invisible", + "type": "dict", "key": "ValidateModelName", "label": "Validate Model Name", + "is_group": true, "children": [ { - "key": "enabled", "type": "boolean", + "key": "enabled", "label": "Enabled" } ] }, { - "type": "dict-invisible", + "type": "dict", "key": "ValidateAssemblyName", "label": "Validate Assembly Name", + "is_group": true, "children": [ { - "key": "enabled", "type": "boolean", + "key": "enabled", "label": "Enabled" } ] @@ -41,6 +57,109 @@ ] } ] + }, { + "type": "dict-expanding", + "key": "nuke", + "label": "Nuke", + "children": [] + }, { + "type": "dict-expanding", + "key": "nukestudio", + "label": "NukeStudio", + "children": [ + { + "type": "dict-expanding", + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "key": "CollectInstanceVersion", + "label": "Collect Instance Version", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": false + } + ] + }, { + "type": "dict", + "key": "ExtractReviewCutUpVideo", + "label": "Extract Review Cut Up Video", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": true + }, { + "type": "list-text", + "key": "tags_addition", + "label": "Tags addition", + "default": [] + } + ] + } + ] + } + ] + }, { + "type": "dict-expanding", + "key": "resolve", + "label": "DaVinci Resolve", + "children": [ + { + "type": "dict-expanding", + "key": "create", + "label": "Creator plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "key": "CreateShotClip", + "label": "Create Shot Clip", + "is_group": true, + "children": [ + { + "type": "text-singleline", + "key": "clipName", + "label": "Clip name template", + "default": "{track}{sequence}{shot}" + }, { + "type": "text-singleline", + "key": "folder", + "label": "Folder", + "default": "takes" + }, { + "type": "text-singleline", + "key": "steps", + "label": "Steps", + "default": 20 + } + ] + } + + ] + } + ] + }, { + "type": "dict-expanding", + "key": "standalonepublisher", + "label": "StandalonePublisher", + "children": [ + { + "type": "dict-expanding", + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [] + } + ] } ] } From 044c644c3bcd871af62bd6932e27d8341d3363ff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 16:21:11 +0200 Subject: [PATCH 137/580] project_presets changed to project_configurations --- pype/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/config.py b/pype/config.py index 454835e005..c65e336e00 100644 --- a/pype/config.py +++ b/pype/config.py @@ -8,7 +8,7 @@ log = logging.getLogger(__name__) STUDIO_PRESETS_PATH = os.path.normpath( os.path.join(os.environ["PYPE_CONFIG"], "studio_configurations") ) -PROJECT_CONFIGURATION_DIR = "project_presets" +PROJECT_CONFIGURATION_DIR = "project_configurations" PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( os.environ["PYPE_CONFIG"], PROJECT_CONFIGURATION_DIR )) From f0217db5da872ffd07b0ea8919b86d15e230df49 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 16:52:04 +0200 Subject: [PATCH 138/580] fixed overrides --- pype/tools/config_setting/config_setting/widgets/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 7bbd95b135..a59b497b2b 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -329,7 +329,7 @@ class ProjectWidget(QtWidgets.QWidget): overrides = None self.is_overidable = False else: - overrides = config.project_preset_overrides(project_name) + overrides = config.project_configurations_overrides(project_name) self.is_overidable = True self.project_name = project_name From 7134b5b9fc2bbb61803c13ba2236d450b974ac78 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 16:52:14 +0200 Subject: [PATCH 139/580] added few plugins --- .../projects_schema/1_plugins_gui_schema.json | 187 +++++++++++++++++- 1 file changed, 183 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index e2717bca37..c12825c3ec 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -7,17 +7,41 @@ "type": "dict-expanding", "key": "celaction", "label": "CelAction", - "children": [] + "children": [ + { + "type": "dict-expanding", + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [] + } + ] }, { "type": "dict-expanding", "key": "ftrack", "label": "Ftrack", - "children": [] + "children": [ + { + "type": "dict-expanding", + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [] + } + ] }, { "type": "dict-expanding", "key": "global", "label": "Global", - "children": [] + "children": [ + { + "type": "dict-expanding", + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [] + } + ] }, { "type": "dict-expanding", "key": "maya", @@ -61,7 +85,162 @@ "type": "dict-expanding", "key": "nuke", "label": "Nuke", - "children": [] + "children": [ + { + "type": "dict-expanding", + "key": "create", + "label": "Create plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "key": "CreateWriteRender", + "label": "CreateWriteRender", + "is_group": true, + "children": [ + { + "type": "text-singleline", + "key": "fpath_template", + "label": "Path template", + "default": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" + } + ] + }, { + "type": "dict", + "key": "CreateWritePrerender", + "label": "CreateWritePrerender", + "is_group": true, + "children": [ + { + "type": "text-singleline", + "key": "fpath_template", + "label": "Path template", + "default": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" + } + ] + } + ] + }, { + "type": "dict-expanding", + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "key": "ExtractThumbnail", + "label": "ExtractThumbnail", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": false + }, { + "type": "raw-json", + "key": "nodes", + "label": "Nodes" + } + ] + }, { + "type": "dict", + "key": "ValidateNukeWriteKnobs", + "label": "ValidateNukeWriteKnobs", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": false + }, { + "type": "raw-json", + "key": "knobs", + "label": "Knobs" + } + ] + }, { + "type": "dict", + "key": "ExtractReviewDataLut", + "label": "ExtractReviewDataLut", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": false + } + ] + }, { + "type": "dict", + "key": "ExtractReviewDataMov", + "label": "ExtractReviewDataMov", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": true + }, { + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw", + "default": false + } + ] + }, { + "type": "dict", + "key": "ExtractSlateFrame", + "label": "ExtractSlateFrame", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw", + "default": false + } + ] + }, { + "type": "dict", + "key": "NukeSubmitDeadline", + "label": "NukeSubmitDeadline", + "is_group": true, + "children": [ + { + "type": "int", + "key": "deadline_priority", + "label": "deadline_priority", + "default": 50 + }, { + "type": "text-singleline", + "key": "deadline_pool", + "label": "deadline_pool", + "default": "" + }, { + "type": "text-singleline", + "key": "deadline_pool_secondary", + "label": "deadline_pool_secondary", + "default": "" + }, { + "type": "int", + "key": "deadline_chunk_size", + "label": "deadline_chunk_size", + "default": 1 + } + ] + } + ] + }, { + "type": "raw-json", + "key": "workfile_build", + "label": "Workfile Build logic", + "is_file": true + } + ] }, { "type": "dict-expanding", "key": "nukestudio", From 1dea23f1cc407cbb1eb78c90c41e36f30f29e240 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 17:09:42 +0200 Subject: [PATCH 140/580] added workfile build to maya plugins --- .../projects_schema/1_plugins_gui_schema.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index c12825c3ec..4b6583dd63 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -79,6 +79,11 @@ ] } ] + }, { + "type": "raw-json", + "key": "workfile_build", + "label": "Workfile Build logic", + "is_file": true } ] }, { From dbd50e0ad24e76f9c15a429f43620f0439c37031 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 18:59:51 +0200 Subject: [PATCH 141/580] added global presets --- .../projects_schema/1_plugins_gui_schema.json | 218 +++++++++++++++++- 1 file changed, 215 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 4b6583dd63..458695da18 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -13,7 +13,52 @@ "key": "publish", "label": "Publish plugins", "is_file": true, - "children": [] + "children": [ + { + "type": "dict", + "key": "ExtractCelactionDeadline", + "label": "ExtractCelactionDeadline", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": true + }, { + "type": "text-singleline", + "key": "deadline_department", + "label": "Deadline apartment", + "default": "" + }, { + "type": "int", + "key": "deadline_priority", + "label": "Deadline priority", + "default": 50 + }, { + "type": "text-singleline", + "key": "deadline_pool", + "label": "Deadline pool", + "default": "" + }, { + "type": "text-singleline", + "key": "deadline_pool_secondary", + "label": "Deadline pool (secondary)", + "default": "" + }, { + "type": "text-singleline", + "key": "deadline_group", + "label": "Deadline Group", + "default": "" + }, { + "type": "int", + "key": "deadline_chunk_size", + "label": "Deadline Chunk size", + "default": 10 + } + ] + } + ] } ] }, { @@ -26,7 +71,31 @@ "key": "publish", "label": "Publish plugins", "is_file": true, - "children": [] + "children": [ + { + "type": "dict", + "key": "IntegrateFtrackNote", + "label": "IntegrateFtrackNote", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text-singleline", + "key": "note_with_intent_template", + "label": "Note with intent template", + "default": "{intent}: {comment}" + }, { + "type": "list-text", + "key": "note_labels", + "label": "Note labels", + "default": [] + } + ] + } + ] } ] }, { @@ -39,7 +108,150 @@ "key": "publish", "label": "Publish plugins", "is_file": true, - "children": [] + "children": [ + { + "type": "dict", + "key": "IntegrateMasterVersion", + "label": "IntegrateMasterVersion", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + }, { + "type": "dict", + "key": "ExtractJpegEXR", + "label": "ExtractJpegEXR", + "is_group": true, + "children": [ + { + "type": "dict-invisible", + "key": "ffmpeg_args", + "children": [ + { + "type": "list-text", + "key": "input", + "label": "FFmpeg input arguments", + "default": [] + }, { + "type": "list-text", + "key": "output", + "label": "FFmpeg output arguments", + "default": [] + } + ] + } + ] + }, { + "type": "dict", + "key": "ExtractReview", + "label": "ExtractReview", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "raw-json", + "key": "profiles", + "label": "Profiles" + } + ] + }, { + "type": "dict", + "key": "ExtractBurnin", + "label": "ExtractBurnin", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "dict-expanding", + "key": "options", + "label": "Burnin formating options", + "children": [ + { + "type": "int", + "key": "font_size", + "label": "Font size", + "default": 42 + }, { + "type": "int", + "key": "opacity", + "label": "Font opacity", + "default": 1 + }, { + "type": "int", + "key": "bg_opacity", + "label": "Background opacity", + "default": 1 + }, { + "type": "int", + "key": "x_offset", + "label": "X Offset", + "default": 5 + }, { + "type": "int", + "key": "y_offset", + "label": "Y Offset", + "default": 5 + }, { + "type": "int", + "key": "bg_padding", + "label": "Padding aroung text", + "default": 5 + } + ] + }, { + "type": "raw-json", + "key": "profiles", + "label": "Burnin profiles" + } + ] + }, { + "type": "dict", + "key": "IntegrateAssetNew", + "label": "IntegrateAssetNew", + "is_group": true, + "children": [ + { + "type": "raw-json", + "key": "template_name_profiles", + "label": "template_name_profiles" + } + ] + }, { + "type": "dict", + "key": "ProcessSubmittedJobOnFarm", + "label": "ProcessSubmittedJobOnFarm", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text-singleline", + "key": "deadline_department", + "label": "Deadline department" + }, { + "type": "text-singleline", + "key": "deadline_pool", + "label": "Deadline Pool" + }, { + "type": "text-singleline", + "key": "deadline_group", + "label": "Deadline Group" + } + ] + } + ] } ] }, { From 4301c5dcdcfee138deee8544c065b132113a3a89 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 19:04:06 +0200 Subject: [PATCH 142/580] updated maya plugins --- .../projects_schema/1_plugins_gui_schema.json | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 458695da18..2b4dfafc56 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -275,6 +275,15 @@ "type": "boolean", "key": "enabled", "label": "Enabled" + }, { + "type": "text-singleline", + "key": "material_file", + "label": "Material File" + }, { + "type": "text-singleline", + "key": "regex", + "label": "Validation regex", + "default": "(.*)_(\\d)*_(?P.*)_(GEO)" } ] }, { @@ -289,6 +298,35 @@ "label": "Enabled" } ] + }, { + "type": "dict", + "key": "ValidateShaderName", + "label": "ValidateShaderName", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text-singleline", + "key": "regex", + "label": "Validation regex", + "default": "(?P.*)_(.*)_SHD" + } + ] + }, { + "type": "dict", + "key": "ValidateMeshHasOverlappingUVs", + "label": "ValidateMeshHasOverlappingUVs", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] } ] }, { From 5bdee32e7ef7d7fec0909aad23a9703f8e82679e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 19:12:46 +0200 Subject: [PATCH 143/580] few minor fixes --- .../config_setting/config_setting/widgets/base.py | 3 +-- .../config_setting/config_setting/widgets/inputs.py | 10 +--------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index a59b497b2b..74e0543870 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -307,7 +307,7 @@ class ProjectWidget(QtWidgets.QWidget): self.reset() def reset(self): - values = config.global_project_configurations() + values = {"project": config.global_project_configurations()} schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = schema.get("keys", []) self.add_children_gui(schema, values) @@ -316,7 +316,6 @@ class ProjectWidget(QtWidgets.QWidget): def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] klass = lib.TypeToKlass.types.get(item_type) - item = klass( child_configuration, values, self.keys, self ) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 61c6385323..0f1ef844d3 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1832,9 +1832,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): self.input_fields = [] - if "key" not in input_data: - print(json.dumps(input_data, indent=4)) - self.key = input_data["key"] self.keys = list(parent_keys) self.keys.append(self.key) @@ -1869,13 +1866,8 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] - if item_type == "schema": - for _schema in child_configuration["children"]: - children = config.gui_schema(_schema) - self.add_children_gui(children, values) - return - klass = TypeToKlass.types.get(item_type) + item = klass( child_configuration, values, self.keys, self ) From a575ed37291fe80ce448f99085f0c51760ee0724 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 19:17:06 +0200 Subject: [PATCH 144/580] minor fix in raw json --- .../projects_schema/1_plugins_gui_schema.json | 2 +- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 2b4dfafc56..e6582d82b1 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -570,7 +570,7 @@ "label": "Folder", "default": "takes" }, { - "type": "text-singleline", + "type": "int", "key": "steps", "label": "Steps", "default": 20 diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0f1ef844d3..6100087ac7 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -719,6 +719,8 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.is_valid = None def set_value(self, value, *, default_value=False): + if not isinstance(value, str): + value = json.dumps(value, indent=4) self.setPlainText(value) def setPlainText(self, *args, **kwargs): @@ -808,7 +810,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): value = self.value_from_values(values) if value is not NOT_SET: - self.text_input.setPlainText(value) + self.text_input.set_value(value) self.default_value = self.item_value() self.override_value = None @@ -816,7 +818,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.text_input.textChanged.connect(self._on_value_change) def set_value(self, value, *, default_value=False): - self.text_input.setPlainText(value) + self.text_input.set_value(value) if default_value: self.default_value = self.item_value() self._on_value_change() From 49a4e73fc65193c73d430d87409b641ac266dd7b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 19:26:01 +0200 Subject: [PATCH 145/580] removed ftrack overrides as not ready yet --- .../config_gui_schema/projects_schema/0_project_gui_schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json index c281ce3c79..10641d5eda 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json @@ -5,7 +5,6 @@ { "type": "schema", "children": [ - "1_ftrack_projects_gui_schema", "1_plugins_gui_schema" ] } From b648b3c72e1199a3f282f8030d9d5c47cfb35681 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 25 Aug 2020 08:35:09 +0100 Subject: [PATCH 146/580] Add "preview" to image plane representations --- pype/plugins/maya/load/load_image_plane.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/plugins/maya/load/load_image_plane.py b/pype/plugins/maya/load/load_image_plane.py index 08f7c99156..17a6866f80 100644 --- a/pype/plugins/maya/load/load_image_plane.py +++ b/pype/plugins/maya/load/load_image_plane.py @@ -12,7 +12,7 @@ class ImagePlaneLoader(api.Loader): families = ["plate", "render"] label = "Create imagePlane on selected camera." - representations = ["mov", "exr"] + representations = ["mov", "exr", "preview"] icon = "image" color = "orange" @@ -83,7 +83,8 @@ class ImagePlaneLoader(api.Loader): image_plane_shape.frameOut.set(end_frame) image_plane_shape.useFrameExtension.set(1) - if context["representation"]["name"] == "mov": + movie_representations = ["mov", "preview"] + if context["representation"]["name"] in movie_representations: # Need to get "type" by string, because its a method as well. pc.Attribute(image_plane_shape + ".type").set(2) From e35ef732b84f8d7e9603dc50c7aca70e3b957920 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 10:49:02 +0200 Subject: [PATCH 147/580] fixed content margins on right side --- .../config_setting/config_setting/widgets/inputs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 6100087ac7..2cb1be3c63 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -932,7 +932,7 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): self.setObjectName("TextListSubWidget") layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(5, 5, 5, 5) + layout.setContentsMargins(5, 5, 0, 5) layout.setSpacing(5) self.setLayout(layout) @@ -1251,7 +1251,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): self.setObjectName("ModifiableDictSubWidget") layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(5, 5, 5, 5) + layout.setContentsMargins(5, 5, 0, 5) layout.setSpacing(5) self.setLayout(layout) @@ -1478,7 +1478,7 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): content_widget.setVisible(False) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 3, 3) + content_layout.setContentsMargins(3, 3, 0, 3) self.set_content_widget(content_widget) @@ -1655,7 +1655,7 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): content_widget = QtWidgets.QWidget(body_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 3, 3) + content_layout.setContentsMargins(3, 3, 0, 3) body_layout = QtWidgets.QVBoxLayout(body_widget) body_layout.setContentsMargins(0, 0, 0, 0) @@ -1666,7 +1666,7 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): self.setAttribute(QtCore.Qt.WA_StyledBackground) main_layout = QtWidgets.QHBoxLayout(self) - main_layout.setContentsMargins(5, 5, 5, 5) + main_layout.setContentsMargins(5, 5, 0, 5) main_layout.setSpacing(0) main_layout.addWidget(body_widget) From 7cd5b58b653b51379d675867c69a428a2a8b2194 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 10:50:42 +0200 Subject: [PATCH 148/580] modified style --- .../config_setting/style/style.css | 34 +++++++++---------- .../config_setting/widgets/inputs.py | 3 +- .../config_setting/widgets/widgets.py | 4 +-- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index a0c5db86a1..9bd74de282 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -2,6 +2,7 @@ QWidget { color: #bfccd6; background-color: #293742; font-size: 12px; + border-radius: 0px; } QCheckBox::indicator { @@ -58,44 +59,43 @@ QPushButton[btn-type="expand-toggle"] { } #RawJsonInput[state="invalid"] { - border-color: #ff5511; + border-left-color: #ff5511; } #DictKey[state="modified"] { - border-color: #137cbd; + border-left-color: #137cbd; } #DictKey[state="overriden"] { - border-color: #00f; + border-left-color: #00f; } #DictKey[state="overriden-modified"] { - border-color: #0f0; + border-left-color: #0f0; } -#ExpandLabel { +#DictLabel { background: transparent; + font-weight: bold; } -#DictExpandWidget, #ModifiableDict, #ExpandingWidget { - border: 1px solid #455c6e; - border-radius: 3px; +#ExpandingWidget, #ModifiableDict, #DictWidget { + border-left: 3px solid #455c6e; background: #1d272f; } -#DictExpandWidget[state="child-modified"], #ModifiableDict[state="child-modified"] { - border-color: #137cbd; +#ExpandingWidget[state="child-modified"], #ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { + border-left-color: #137cbd; } -#DictExpandWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"] { - border-color: #ff8c1a; +#ExpandingWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"] { + border-left-color: #ff8c1a; } -#DictExpandWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"] { - border-color: #00b386; +#ExpandingWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"] { + border-left-color: #00b386; } #TextListSubWidget { - border: 1px solid #455c6e; - border-radius: 3px; - background: #1d272f; + border-left: 3px solid #455c6e; + /* background: #1d272f; */ } diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 2cb1be3c63..9023d36826 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1472,7 +1472,6 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): self._child_state = None super(DictExpandWidget, self).__init__(input_data["label"], parent) - self.setObjectName("DictExpandWidget") content_widget = QtWidgets.QWidget(self) content_widget.setVisible(False) @@ -1651,7 +1650,7 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): label_widget = QtWidgets.QLabel( input_data["label"], parent=body_widget ) - label_widget.setObjectName("ExpandLabel") + label_widget.setObjectName("DictLabel") content_widget = QtWidgets.QWidget(body_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 3d5528e17a..a15edf58ff 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -54,7 +54,7 @@ class ExpandingWidget(QtWidgets.QWidget): button_toggle.setChecked(False) label_widget = QtWidgets.QLabel(label, parent=top_part) - label_widget.setObjectName("ExpandLabel") + label_widget.setObjectName("DictLabel") layout = QtWidgets.QHBoxLayout(top_part) layout.setContentsMargins(0, 0, 0, 0) @@ -74,7 +74,7 @@ class ExpandingWidget(QtWidgets.QWidget): def set_content_widget(self, content_widget): main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(9, 9, 9, 9) + main_layout.setContentsMargins(9, 9, 0, 9) content_widget.setVisible(False) From f4cdb85c14ef49987d4e154d28d567fbaeba687e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 10:57:48 +0200 Subject: [PATCH 149/580] fixed project list styles --- .../config_setting/config_setting/style/style.css | 12 ++++++++++-- .../config_setting/config_setting/widgets/base.py | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 9bd74de282..2ea765f442 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -56,6 +56,16 @@ QPushButton[btn-type="text-list"]:hover { QPushButton[btn-type="expand-toggle"] { background: transparent; + background: #1d272f; +} + +#ProjectListWidget QListView { + border: 1px solid #aaaaaa; + background: #1d272f; +} +#ProjectListWidget QLabel { + background: transparent; + font-weight: bold; } #RawJsonInput[state="invalid"] { @@ -80,7 +90,6 @@ QPushButton[btn-type="expand-toggle"] { #ExpandingWidget, #ModifiableDict, #DictWidget { border-left: 3px solid #455c6e; - background: #1d272f; } #ExpandingWidget[state="child-modified"], #ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { @@ -97,5 +106,4 @@ QPushButton[btn-type="expand-toggle"] { #TextListSubWidget { border-left: 3px solid #455c6e; - /* background: #1d272f; */ } diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 74e0543870..5f48b416c1 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -140,8 +140,10 @@ class ProjectListWidget(QtWidgets.QWidget): self.current_project = None super(ProjectListWidget, self).__init__(parent) + self.setObjectName("ProjectListWidget") label_widget = QtWidgets.QLabel("Projects") + project_list = ProjectListView(self) project_list.setModel(QtGui.QStandardItemModel()) @@ -282,7 +284,7 @@ class ProjectWidget(QtWidgets.QWidget): configurations_widget = QtWidgets.QWidget() configurations_layout = QtWidgets.QVBoxLayout(configurations_widget) - configurations_layout.setContentsMargins(0, 0, 0, 0) + configurations_layout.setContentsMargins(0, 0, 5, 0) configurations_layout.setSpacing(0) configurations_layout.addWidget(scroll_widget, 1) From 62ed17c597398fb6212ea48fd4fb230300d234b7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 10:58:11 +0200 Subject: [PATCH 150/580] removed unused imports --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9023d36826..0f106c6408 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1,8 +1,6 @@ import json from Qt import QtWidgets, QtCore, QtGui -from pype.api import config from .widgets import ( - ClickableWidget, ExpandingWidget, ModifiedIntSpinBox, ModifiedFloatSpinBox From e9551c7fc476e788f70b4b3c86371e6e0e8491ac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 11:03:37 +0200 Subject: [PATCH 151/580] group widgets has borders --- pype/tools/config_setting/config_setting/style/style.css | 4 ++++ pype/tools/config_setting/config_setting/widgets/base.py | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 2ea765f442..aa1f6293d7 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -59,6 +59,10 @@ QPushButton[btn-type="expand-toggle"] { background: #1d272f; } +#GroupWidget { + border: 1px solid #aaaaaa; +} + #ProjectListWidget QListView { border: 1px solid #aaaaaa; background: #1d272f; diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 5f48b416c1..4fe3866096 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -20,6 +20,7 @@ class StudioWidget(QtWidgets.QWidget): self.input_fields = [] scroll_widget = QtWidgets.QScrollArea(self) + scroll_widget.setObjectName("GroupWidget") content_widget = QtWidgets.QWidget(scroll_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(3, 3, 3, 3) @@ -43,7 +44,7 @@ class StudioWidget(QtWidgets.QWidget): footer_layout.addWidget(save_btn, 0) layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) + layout.setContentsMargins(5, 0, 5, 0) layout.setSpacing(0) self.setLayout(layout) @@ -261,6 +262,7 @@ class ProjectWidget(QtWidgets.QWidget): self.input_fields = [] scroll_widget = QtWidgets.QScrollArea(self) + scroll_widget.setObjectName("GroupWidget") content_widget = QtWidgets.QWidget(scroll_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(3, 3, 3, 3) @@ -284,7 +286,7 @@ class ProjectWidget(QtWidgets.QWidget): configurations_widget = QtWidgets.QWidget() configurations_layout = QtWidgets.QVBoxLayout(configurations_widget) - configurations_layout.setContentsMargins(0, 0, 5, 0) + configurations_layout.setContentsMargins(5, 0, 5, 0) configurations_layout.setSpacing(0) configurations_layout.addWidget(scroll_widget, 1) From b51e24318efb2dcb1bc0a3145877fed73bafda69 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 11:14:17 +0200 Subject: [PATCH 152/580] overriden-modified has same color as modified --- .../config_setting/style/style.css | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index aa1f6293d7..961bfa0d03 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -25,7 +25,7 @@ QLabel[state="modified"] { } QLabel[state="overriden-modified"] { - color: #00b386; + color: #137cbd; } QLabel[state="overriden"] { @@ -37,13 +37,18 @@ QWidget[input-state="modified"] { } QWidget[input-state="overriden-modified"] { - border-color: #00b386; + border-color: #137cbd; } QWidget[input-state="overriden"] { border-color: #ff8c1a; } +QPushButton { + border: 1px solid #aaaaaa; + border-radius: 3px; + padding: 5px; +} QPushButton[btn-type="text-list"] { border: 1px solid #bfccd6; border-radius: 10px; @@ -93,19 +98,24 @@ QPushButton[btn-type="expand-toggle"] { } #ExpandingWidget, #ModifiableDict, #DictWidget { - border-left: 3px solid #455c6e; + border-style: solid; + border-color: #455c6e; + border-left-width: 3px; + border-bottom-width: 0px; + border-right-width: 0px; + border-top-width: 0px; } #ExpandingWidget[state="child-modified"], #ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { - border-left-color: #137cbd; + border-color: #137cbd; } #ExpandingWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"] { - border-left-color: #ff8c1a; + border-color: #ff8c1a; } #ExpandingWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"] { - border-left-color: #00b386; + border-color: #137cbd; } #TextListSubWidget { From 43d2a70d0d10a7872fd8d86ce854ec5dde96ac8c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 11:32:21 +0200 Subject: [PATCH 153/580] inputs has different background --- pype/tools/config_setting/config_setting/style/style.css | 1 + pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 961bfa0d03..b040425a02 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -14,6 +14,7 @@ QCheckBox::indicator:focus { QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit { border: 1px solid #aaaaaa; border-radius: 3px; + background: #1d272f; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus { diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0f106c6408..c64e0e43cc 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -796,8 +796,8 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget) - layout.addWidget(self.text_input) + layout.addWidget(label_widget, 0) + layout.addWidget(self.text_input, 1) self.label_widget = label_widget From 34416f46ddeeb16ec44dee7873341a14da9e38ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 13:20:07 +0200 Subject: [PATCH 154/580] adde more transparency --- .../config_setting/config_setting/style/style.css | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index b040425a02..e7224533da 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -11,15 +11,18 @@ QCheckBox::indicator:focus { color: #ff0000; } -QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit { +QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit, QTextEdit { border: 1px solid #aaaaaa; border-radius: 3px; - background: #1d272f; + background-color: #1d272f; } -QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus { +QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { border: 1px solid #ffffff; } +QLabel, QToolButton { + background: transparent; +} QLabel[state="modified"] { color: #137cbd; @@ -61,7 +64,6 @@ QPushButton[btn-type="text-list"]:hover { } QPushButton[btn-type="expand-toggle"] { - background: transparent; background: #1d272f; } @@ -94,7 +96,6 @@ QPushButton[btn-type="expand-toggle"] { } #DictLabel { - background: transparent; font-weight: bold; } From 1390637bb1ce6949935c97b862eb72a011e4f822 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 13:21:23 +0200 Subject: [PATCH 155/580] tried to extend raw json input --- .../config_setting/config_setting/widgets/inputs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c64e0e43cc..4e63a4a501 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -752,6 +752,11 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.setProperty("state", state) self.style().polish(self) + def resizeEvent(self, event): + self.updateGeometry() + super().resizeEvent(event) + + def value(self): return self.toPlainText() @@ -791,7 +796,11 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) - self.text_input = RawJsonInput() + self.text_input = RawJsonInput(self) + self.text_input.setSizePolicy( + QtWidgets.QSizePolicy.Minimum, + QtWidgets.QSizePolicy.MinimumExpanding + ) if not label_widget: label = input_data["label"] From cdc407f7ad341132d1b4b1d55809901b37cfa60f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 13:24:48 +0200 Subject: [PATCH 156/580] Hound fixes --- pype/config.py | 4 +++- pype/tools/config_setting/config_setting/widgets/inputs.py | 1 - pype/tools/config_setting/config_setting/widgets/tests.py | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pype/config.py b/pype/config.py index c65e336e00..416704649c 100644 --- a/pype/config.py +++ b/pype/config.py @@ -188,6 +188,8 @@ def project_presets(project_name=None, **kwargs): if not project_name: project_name = os.environ.get("AVALON_PROJECT") - project_overrides = project_configurations_overrides(project_name, **kwargs) + project_overrides = project_configurations_overrides( + project_name, **kwargs + ) return apply_overrides(global_presets, project_overrides) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4e63a4a501..19286a19b5 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -756,7 +756,6 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.updateGeometry() super().resizeEvent(event) - def value(self): return self.toPlainText() diff --git a/pype/tools/config_setting/config_setting/widgets/tests.py b/pype/tools/config_setting/config_setting/widgets/tests.py index 53b67de3a1..16c97a85ef 100644 --- a/pype/tools/config_setting/config_setting/widgets/tests.py +++ b/pype/tools/config_setting/config_setting/widgets/tests.py @@ -63,8 +63,6 @@ class AddibleComboBox(QtWidgets.QComboBox): # self.addItems([text]) # index = self.findText(text) - - def populate(self, items): self.clear() # self.addItems([""]) # ensure first item is placeholder From 6d31920609220ad8e584a7d96f34a405314d660b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 13:31:05 +0200 Subject: [PATCH 157/580] added hovering on labels --- .../config_setting/style/style.css | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index e7224533da..af4808b443 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -24,17 +24,14 @@ QLabel, QToolButton { background: transparent; } -QLabel[state="modified"] { - color: #137cbd; -} +QLabel:hover {color: #ffffff;} -QLabel[state="overriden-modified"] { - color: #137cbd; -} - -QLabel[state="overriden"] { - color: #ff8c1a; -} +QLabel[state="modified"] {color: #137cbd;} +QLabel[state="modified"]:hover {color: #1798e8;} +QLabel[state="overriden-modified"] {color: #137cbd;} +QLabel[state="overriden-modified"]:hover {color: #1798e8;} +QLabel[state="overriden"] {color: #ff8c1a;} +QLabel[state="overriden"]:hover {color: #ffa64d;} QWidget[input-state="modified"] { border-color: #137cbd; From 422930ea8782a68f5ed008b9be55c1c72deed9aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 13:54:17 +0200 Subject: [PATCH 158/580] fixed raw json height sizes --- .../config_setting/widgets/inputs.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 19286a19b5..bd945f18e8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -716,6 +716,21 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.is_valid = None + def sizeHint(self): + document = self.document() + layout = document.documentLayout() + + height = document.documentMargin() + 2 * self.frameWidth() + 1 + block = document.begin() + while block != document.end(): + height += layout.blockBoundingRect(block).height() + block = block.next() + + value = super().sizeHint() + value.setHeight(height) + + return value + def set_value(self, value, *, default_value=False): if not isinstance(value, str): value = json.dumps(value, indent=4) From 1ac0c781338ab5734016cab12b8a3ae771fb3dfa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 14:16:21 +0200 Subject: [PATCH 159/580] text list widget does not have modification line next to it --- .../config_setting/config_setting/style/style.css | 4 ---- .../config_setting/config_setting/widgets/inputs.py | 10 +++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index af4808b443..0099e6ed76 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -116,7 +116,3 @@ QPushButton[btn-type="expand-toggle"] { #ExpandingWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"] { border-color: #137cbd; } - -#TextListSubWidget { - border-left: 3px solid #455c6e; -} diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index bd945f18e8..0d07383d3c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -953,8 +953,8 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): self.setObjectName("TextListSubWidget") layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(5, 5, 0, 5) - layout.setSpacing(5) + layout.setContentsMargins(0, 5, 0, 5) + layout.setSpacing(3) self.setLayout(layout) self.input_fields = [] @@ -1088,9 +1088,9 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(label_widget) self.label_widget = label_widget - # keys = list(parent_keys) - # keys.append(input_data["key"]) - # self.keys = keys + keys = list(parent_keys) + keys.append(input_data["key"]) + self.keys = keys self.value_widget = TextListSubWidget( input_data, values, parent_keys, self From b7807f81f05697fc70a8a65a5cd2877a4720717e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 15:07:25 +0200 Subject: [PATCH 160/580] fix super --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0d07383d3c..e9104e6c0c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -726,7 +726,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): height += layout.blockBoundingRect(block).height() block = block.next() - value = super().sizeHint() + value = super(RawJsonInput, self).sizeHint() value.setHeight(height) return value @@ -769,7 +769,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): def resizeEvent(self, event): self.updateGeometry() - super().resizeEvent(event) + super(RawJsonInput, self).resizeEvent(event) def value(self): return self.toPlainText() From 6a585b082a744157addb859487cc2f06d27284b2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 15:29:47 +0200 Subject: [PATCH 161/580] renamed default_value to global_value --- .../config_setting/widgets/inputs.py | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e9104e6c0c..140d67c0ad 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -164,18 +164,18 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.checkbox.setChecked(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None self.checkbox.stateChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): # Ignore value change because if `self.isChecked()` has same # value as `value` the `_on_value_change` is not triggered self.checkbox.setChecked(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() @@ -183,7 +183,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): if self.is_overidable and self.override_value is not None: self.set_value(self.override_value) else: - self.set_value(self.default_value) + self.set_value(self.global_value) def clear_value(self): self.reset_value() @@ -195,7 +195,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): if override_value is None: self._is_overriden = False self._was_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True self._was_overriden = True @@ -216,7 +216,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): is_modified = _value != self.override_value if is_modified is None: - is_modified = _value != self.default_value + is_modified = _value != self.global_value self._is_modified = is_modified @@ -292,22 +292,22 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.int_input.setValue(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None self.int_input.valueChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): self.int_input.setValue(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def clear_value(self): self.set_value(0) def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def apply_overrides(self, override_value): self._is_modified = False @@ -316,7 +316,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): if override_value is None: self._is_overriden = False self._was_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True self._was_overriden = True @@ -329,7 +329,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -416,19 +416,19 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.float_input.setValue(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None self.float_input.valueChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): self.float_input.setValue(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def apply_overrides(self, override_value): self._is_modified = False @@ -436,7 +436,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is None: self._is_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True value = override_value @@ -451,7 +451,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -528,19 +528,19 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.text_input.setText(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None self.text_input.textChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): self.text_input.setText(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def apply_overrides(self, override_value): self._is_modified = False @@ -549,7 +549,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): if override_value is None: self._is_overriden = False self._was_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True self._was_overriden = True @@ -565,7 +565,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -640,19 +640,19 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.text_input.setPlainText(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None self.text_input.textChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): self.text_input.setPlainText(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def apply_overrides(self, override_value): self._is_modified = False @@ -660,7 +660,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is None: self._is_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True value = override_value @@ -675,7 +675,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -731,7 +731,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): return value - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): if not isinstance(value, str): value = json.dumps(value, indent=4) self.setPlainText(value) @@ -833,19 +833,19 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.text_input.set_value(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None self.text_input.textChanged.connect(self._on_value_change) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): self.text_input.set_value(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def clear_value(self): self.set_value("") @@ -856,7 +856,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is None: self._is_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True value = override_value @@ -868,7 +868,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -969,22 +969,22 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): if value is not NOT_SET: self.set_value(value) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): for input_field in self.input_fields: self.remove_row(input_field) for item_text in value: self.add_row(text=item_text) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def clear_value(self): self.set_value([]) @@ -1103,13 +1103,13 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(self.value_widget) self.setLayout(layout) - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None def _on_value_change(self, item=None): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -1117,14 +1117,14 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self.value_changed.emit(self) - def set_value(self, value, *, default_value=False): + def set_value(self, value, *, global_value=False): self.value_widget.set_value(value) - if default_value: - self.default_value = self.item_value() + if global_value: + self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.default_value) + self.set_value(self.global_value) def clear_value(self): self.set_value([]) @@ -1135,7 +1135,7 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is None: self._is_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True value = override_value @@ -1200,7 +1200,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): self.value_input.value_changed.connect(self._on_value_change) self.default_key = self._key() - self.default_value = self.value_input.item_value() + self.global_value = self.value_input.item_value() self.override_key = None self.override_value = None @@ -1292,7 +1292,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): if self.count() == 0: self.add_row() - self.default_value = self.config_value() + self.global_value = self.config_value() self.override_value = None @property @@ -1335,7 +1335,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): if value is not None and key is not None: item_widget.default_key = key item_widget.key_input.setText(key) - item_widget.value_input.set_value(value, default_value=True) + item_widget.value_input.set_value(value, global_value=True) else: self._on_value_change() self.parent().updateGeometry() @@ -1407,7 +1407,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): self.key = input_data["key"] - self.default_value = self.item_value() + self.global_value = self.item_value() self.override_value = None def _on_value_change(self, item=None): @@ -1420,7 +1420,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): if self.is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.default_value + self._is_modified = self.item_value() != self.global_value self.value_changed.emit(self) @@ -1433,7 +1433,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): if override_value is None: self._is_overriden = False self._was_overriden = False - value = self.default_value + value = self.global_value else: self._is_overriden = True self._was_overriden = True From 4aca6fd3378615ae8adcf237a05dafce28194ca5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 16:08:14 +0200 Subject: [PATCH 162/580] override value is NOT_SET by default instead of None --- .../config_setting/widgets/base.py | 2 +- .../config_setting/widgets/inputs.py | 62 +++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 4fe3866096..94754bda0d 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -329,7 +329,7 @@ class ProjectWidget(QtWidgets.QWidget): def _on_project_change(self): project_name = self.project_list_widget.project_name() if project_name is None: - overrides = None + overrides = lib.NOT_SET self.is_overidable = False else: overrides = config.project_configurations_overrides(project_name) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 140d67c0ad..1697271b4d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -165,7 +165,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self.checkbox.setChecked(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET self.checkbox.stateChanged.connect(self._on_value_change) @@ -180,7 +180,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self._on_value_change() def reset_value(self): - if self.is_overidable and self.override_value is not None: + if self.is_overidable and self.override_value is not NOT_SET: self.set_value(self.override_value) else: self.set_value(self.global_value) @@ -192,7 +192,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False value = self.global_value @@ -293,7 +293,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): self.int_input.setValue(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET self.int_input.valueChanged.connect(self._on_value_change) @@ -313,7 +313,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False value = self.global_value @@ -417,7 +417,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self.float_input.setValue(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET self.float_input.valueChanged.connect(self._on_value_change) @@ -434,7 +434,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False value = self.global_value else: @@ -529,7 +529,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): self.text_input.setText(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET self.text_input.textChanged.connect(self._on_value_change) @@ -546,7 +546,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False value = self.global_value @@ -641,7 +641,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self.text_input.setPlainText(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET self.text_input.textChanged.connect(self._on_value_change) @@ -658,7 +658,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False value = self.global_value else: @@ -834,7 +834,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.text_input.set_value(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET self.text_input.textChanged.connect(self._on_value_change) @@ -854,7 +854,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False value = self.global_value else: @@ -970,7 +970,7 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): self.set_value(value) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET def set_value(self, value, *, global_value=False): for input_field in self.input_fields: @@ -1104,7 +1104,7 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self.setLayout(layout) self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -1133,7 +1133,7 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self._is_modified = False self._state = None self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False value = self.global_value else: @@ -1203,7 +1203,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): self.global_value = self.value_input.item_value() self.override_key = None - self.override_value = None + self.override_value = NOT_SET self.is_single = False @@ -1293,7 +1293,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): self.add_row() self.global_value = self.config_value() - self.override_value = None + self.override_value = NOT_SET @property def is_group(self): @@ -1408,7 +1408,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): self.key = input_data["key"] self.global_value = self.item_value() - self.override_value = None + self.override_value = NOT_SET def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -1430,7 +1430,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): self._state = None self._is_modified = False self.override_value = override_value - if override_value is None: + if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False value = self.global_value @@ -1523,10 +1523,10 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): self._state = None self._child_state = None for item in self.input_fields: - if override_value is None: - child_value = None + if override_value is NOT_SET: + child_value = NOT_SET else: - child_value = override_value.get(item.key) + child_value = override_value.get(item.key, NOT_SET) item.apply_overrides(child_value) @@ -1534,7 +1534,7 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): self.is_group and self.is_overidable and ( - override_value is not None + override_value is not NOT_SET or self.child_overriden ) ) @@ -1710,10 +1710,10 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): self._state = None self._child_state = None for item in self.input_fields: - if override_value is None: - child_value = None + if override_value is NOT_SET: + child_value = NOT_SET else: - child_value = override_value.get(item.key) + child_value = override_value.get(item.key, NOT_SET) item.apply_overrides(child_value) @@ -1721,7 +1721,7 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): self.is_group and self.is_overidable and ( - override_value is not None + override_value is not NOT_SET or self.child_overriden ) ) @@ -1919,10 +1919,10 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): def apply_overrides(self, override_value): self._is_overriden = False for item in self.input_fields: - if override_value is None: - child_value = None + if override_value is NOT_SET: + child_value = NOT_SET else: - child_value = override_value.get(item.key) + child_value = override_value.get(item.key, NOT_SET) item.apply_overrides(child_value) self._is_overriden = ( From 6342f02574ec0a0560e659161953d793bf9bd1cc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 17:00:03 +0200 Subject: [PATCH 163/580] it is possible to right click on widgets, actions do nothing --- .../config_setting/widgets/inputs.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 1697271b4d..baf524d5da 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -94,6 +94,41 @@ class ConfigWidget: "Method `add_children_gui` is not implemented for `{}`." ).format(self.__class__.__name__)) + def _discard_changes(self): + print("_discard_changes") + + def _remove_overrides(self): + print("_remove_overrides") + + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.RightButton: + menu = QtWidgets.QMenu() + + actions_mapping = {} + if self.child_modified: + action = QtWidgets.QAction("Discard changes") + actions_mapping[action] = self._discard_changes + menu.addAction(action) + + if self.child_overriden: + # TODO better label + action = QtWidgets.QAction("Remove override") + actions_mapping[action] = self._remove_overrides + menu.addAction(action) + + if not actions_mapping: + action = QtWidgets.QAction("< No action >") + actions_mapping[action] = None + menu.addAction(action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + return + super(self.__class__, self).mouseReleaseEvent(event) + class InputWidget(ConfigWidget): def overrides(self): From 31d75aa5cc24c7fdcf86ff5c9f10941d2b3ecd46 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 18:09:02 +0200 Subject: [PATCH 164/580] styles are automatically updated on _ignore_value_changes changed to False --- .../config_setting/widgets/base.py | 33 +++++++++++++++++-- .../config_setting/widgets/inputs.py | 20 +++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 94754bda0d..2018b4bde3 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -12,11 +12,12 @@ class StudioWidget(QtWidgets.QWidget): is_overriden = False is_group = False any_parent_is_group = False - ignore_value_changes = False def __init__(self, parent=None): super(StudioWidget, self).__init__(parent) + self._ignore_value_changes = False + self.input_fields = [] scroll_widget = QtWidgets.QScrollArea(self) @@ -55,6 +56,20 @@ class StudioWidget(QtWidgets.QWidget): self.reset() + @property + def ignore_value_changes(self): + return self._ignore_value_changes + + @ignore_value_changes.setter + def ignore_value_changes(self, value): + self._ignore_value_changes = value + if value is False: + self.hierarchical_style_update() + + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + def reset(self): if self.content_layout.count() != 0: for widget in self.input_fields: @@ -256,7 +271,7 @@ class ProjectWidget(QtWidgets.QWidget): super(ProjectWidget, self).__init__(parent) self.is_overidable = False - self.ignore_value_changes = False + self._ignore_value_changes = False self.project_name = None self.input_fields = [] @@ -310,6 +325,20 @@ class ProjectWidget(QtWidgets.QWidget): self.reset() + @property + def ignore_value_changes(self): + return self._ignore_value_changes + + @ignore_value_changes.setter + def ignore_value_changes(self, value): + self._ignore_value_changes = value + if value is False: + self.hierarchical_style_update() + + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + def reset(self): values = {"project": config.global_project_configurations()} schema = lib.gui_schema("projects_schema", "0_project_gui_schema") diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index baf524d5da..c5afe1a7e7 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -53,6 +53,9 @@ class ConfigWidget: raise NotImplementedError( "Method `reset_children_attributes` not implemented!" ) + @ignore_value_changes.setter + def ignore_value_changes(self, value): + self._parent.ignore_value_changes = value def item_value(self): raise NotImplementedError( @@ -136,6 +139,9 @@ class InputWidget(ConfigWidget): return NOT_SET, False return self.config_value(), self.is_group + def hierarchical_style_update(self): + self.update_style() + @property def child_modified(self): return self.is_modified @@ -1780,6 +1786,11 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): self.update_style() + def hierarchical_style_update(self): + self.update_style() + for input_field in self.input_fields: + input_field.hierarchical_style_update() + def update_style(self, is_overriden=None): child_modified = self.child_modified child_state = self.style_state(self.child_overriden, child_modified) @@ -1951,6 +1962,11 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): self.value_changed.emit(self) + def hierarchical_style_update(self): + self.update_style() + for input_field in self.input_fields: + input_field.hierarchical_style_update() + def apply_overrides(self, override_value): self._is_overriden = False for item in self.input_fields: @@ -2051,6 +2067,10 @@ class DictFormWidget(QtWidgets.QWidget, ConfigWidget): self.input_fields[key] = item return item + def hierarchical_style_update(self): + for input_field in self.input_fields.items(): + input_field.hierarchical_style_update() + def item_value(self): output = {} for input_field in self.input_fields.values(): From 6a6a50978460f5302b782b653d08c0cbfb7ac9cf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:09:19 +0200 Subject: [PATCH 165/580] global_value split into global_value and start_value --- .../config_setting/widgets/inputs.py | 144 +++++++++++------- 1 file changed, 91 insertions(+), 53 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c5afe1a7e7..2bda38e207 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -194,6 +194,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(self.checkbox, 1) + value = NOT_SET if not self._as_widget: self.label_widget = label_widget self.key = input_data["key"] @@ -201,11 +202,16 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): keys.append(self.key) self.keys = keys + default_value = input_data.get("default", NOT_SET) value = self.value_from_values(values) if value is not NOT_SET: self.checkbox.setChecked(value) - self.global_value = self.item_value() + elif default_value is not NOT_SET: + self.checkbox.setChecked(default_value) + + self.global_value = value + self.start_value = self.item_value() self.override_value = NOT_SET self.checkbox.stateChanged.connect(self._on_value_change) @@ -236,7 +242,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False - value = self.global_value + value = self.start_value else: self._is_overriden = True self._was_overriden = True @@ -321,6 +327,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(label_widget, 0) layout.addWidget(self.int_input, 1) + value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -333,7 +340,8 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.int_input.setValue(value) - self.global_value = self.item_value() + self.global_value = value + self.start_value = self.item_value() self.override_value = NOT_SET self.int_input.valueChanged.connect(self._on_value_change) @@ -341,6 +349,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): def set_value(self, value, *, global_value=False): self.int_input.setValue(value) if global_value: + self.start_value = self.item_value() self.global_value = self.item_value() self._on_value_change() @@ -348,7 +357,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): self.set_value(0) def reset_value(self): - self.set_value(self.global_value) + self.set_value(self.start_value) def apply_overrides(self, override_value): self._is_modified = False @@ -445,6 +454,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(label_widget, 0) layout.addWidget(self.float_input, 1) + value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -457,7 +467,8 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.float_input.setValue(value) - self.global_value = self.item_value() + self.start_value = self.item_value() + self.global_value = value self.override_value = NOT_SET self.float_input.valueChanged.connect(self._on_value_change) @@ -465,6 +476,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): def set_value(self, value, *, global_value=False): self.float_input.setValue(value) if global_value: + self.start_value = self.item_value() self.global_value = self.item_value() self._on_value_change() @@ -477,7 +489,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is NOT_SET: self._is_overriden = False - value = self.global_value + value = self.start_value else: self._is_overriden = True value = override_value @@ -557,6 +569,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(label_widget, 0) layout.addWidget(self.text_input, 1) + value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -569,7 +582,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): if value is not NOT_SET: self.text_input.setText(value) - self.global_value = self.item_value() + self.global_value = value + self.start_value = self.item_value() self.override_value = NOT_SET self.text_input.textChanged.connect(self._on_value_change) @@ -577,11 +591,12 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): def set_value(self, value, *, global_value=False): self.text_input.setText(value) if global_value: + self.start_value = self.item_value() self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.global_value) + self.set_value(self.start_value) def apply_overrides(self, override_value): self._is_modified = False @@ -590,7 +605,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False - value = self.global_value + value = self.start_value else: self._is_overriden = True self._was_overriden = True @@ -664,24 +679,27 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): layout.setSpacing(5) self.text_input = QtWidgets.QPlainTextEdit() - if not label_widget: + if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) layout.addWidget(self.text_input, 1) - self.label_widget = label_widget + value = NOT_SET + if not self._as_widget: + self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys - value = self.value_from_values(values) - if value is not NOT_SET: - self.text_input.setPlainText(value) + value = self.value_from_values(values) + if value is not NOT_SET: + self.text_input.setPlainText(value) - self.global_value = self.item_value() + self.global_value = value + self.start_value = self.item_value() self.override_value = NOT_SET self.text_input.textChanged.connect(self._on_value_change) @@ -689,11 +707,12 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): def set_value(self, value, *, global_value=False): self.text_input.setPlainText(value) if global_value: + self.start_value = self.item_value() self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.global_value) + self.set_value(self.start_value) def apply_overrides(self, override_value): self._is_modified = False @@ -701,7 +720,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is NOT_SET: self._is_overriden = False - value = self.global_value + value = self.start_value else: self._is_overriden = True value = override_value @@ -857,24 +876,27 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): QtWidgets.QSizePolicy.MinimumExpanding ) - if not label_widget: + if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) layout.addWidget(self.text_input, 1) - self.label_widget = label_widget + value = NOT_SET + if not self._as_widget: + self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys - value = self.value_from_values(values) - if value is not NOT_SET: - self.text_input.set_value(value) + value = self.value_from_values(values) + if value is not NOT_SET: + self.text_input.set_value(value) - self.global_value = self.item_value() + self.global_value = value + self.start_value = self.item_value() self.override_value = NOT_SET self.text_input.textChanged.connect(self._on_value_change) @@ -882,11 +904,12 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): def set_value(self, value, *, global_value=False): self.text_input.set_value(value) if global_value: + self.start_value = self.item_value() self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.global_value) + self.set_value(self.start_value) def clear_value(self): self.set_value("") @@ -897,7 +920,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): self.override_value = override_value if override_value is NOT_SET: self._is_overriden = False - value = self.global_value + value = self.start_value else: self._is_overriden = True value = override_value @@ -1010,7 +1033,8 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): if value is not NOT_SET: self.set_value(value) - self.global_value = self.item_value() + self.global_value = value + self.start_value = self.item_value() self.override_value = NOT_SET def set_value(self, value, *, global_value=False): @@ -1021,11 +1045,23 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): self.add_row(text=item_text) if global_value: - self.global_value = self.item_value() + self.global_value = value + self.start_value = self.item_value() self._on_value_change() + def apply_overrides(self, override_value): + self.override_value = override_value + if override_value is NOT_SET: + self._is_overriden = False + value = self.start_value + else: + self._is_overriden = True + value = override_value + + self.set_value(value) + def reset_value(self): - self.set_value(self.global_value) + self.set_value(self.start_value) def clear_value(self): self.set_value([]) @@ -1144,8 +1180,17 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): layout.addWidget(self.value_widget) self.setLayout(layout) - self.global_value = self.item_value() - self.override_value = NOT_SET + @property + def start_value(self): + return self.value_widget.start_value + + @property + def global_value(self): + return self.value_widget.global_value + + @property + def override_value(self): + return self.value_widget.override_value def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -1159,29 +1204,20 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): self.value_changed.emit(self) def set_value(self, value, *, global_value=False): - self.value_widget.set_value(value) + self.value_widget.set_value(value, global_value=global_value) if global_value: - self.global_value = self.item_value() self._on_value_change() def reset_value(self): - self.set_value(self.global_value) + self.value_widget.reset_value() def clear_value(self): - self.set_value([]) + self.value_widget.clear_value() def apply_overrides(self, override_value): + self.value_widget.apply_overrides(override_value) self._is_modified = False self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - value = self.global_value - else: - self._is_overriden = True - value = override_value - - self.set_value(value) self.update_style() def update_style(self): @@ -1240,10 +1276,11 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): self.key_input.textChanged.connect(self._on_value_change) self.value_input.value_changed.connect(self._on_value_change) + # TODO This doesn't make sence! self.default_key = self._key() self.global_value = self.value_input.item_value() - self.override_key = None + self.override_key = NOT_SET self.override_value = NOT_SET self.is_single = False @@ -1333,7 +1370,8 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): if self.count() == 0: self.add_row() - self.global_value = self.config_value() + self.global_value = value + self.start_value = self.config_value() self.override_value = NOT_SET @property From 8361db1f79620e77ebb484c79bc3d4b4a770d822 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:09:38 +0200 Subject: [PATCH 166/580] removed unused methods --- .../config_setting/config_setting/widgets/inputs.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 2bda38e207..7abbd87863 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -42,17 +42,6 @@ class ConfigWidget: def ignore_value_changes(self): return self._parent.ignore_value_changes - def reset_attributes(self): - self._is_overriden = False - self._is_modified = False - self._was_overriden = False - - self.reset_children_attributes() - - def reset_children_attributes(self): - raise NotImplementedError( - "Method `reset_children_attributes` not implemented!" - ) @ignore_value_changes.setter def ignore_value_changes(self, value): self._parent.ignore_value_changes = value From e1209b2f13e29a8f5cdef2dc158cbaf847e1ca86 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:09:51 +0200 Subject: [PATCH 167/580] fix value_from_values --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 7abbd87863..04a13ca487 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -55,7 +55,7 @@ class ConfigWidget: return {self.key: self.item_value()} def value_from_values(self, values, keys=None): - if not values: + if not values or values is AS_WIDGET: return NOT_SET if keys is None: From 6c77e43d6b334d5a3c3937b41b221ca1437e6a42 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:10:30 +0200 Subject: [PATCH 168/580] made preparation for abstract methods --- .../config_setting/widgets/inputs.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 04a13ca487..3b07bb1c99 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -86,11 +86,23 @@ class ConfigWidget: "Method `add_children_gui` is not implemented for `{}`." ).format(self.__class__.__name__)) - def _discard_changes(self): - print("_discard_changes") + def discard_changes(self, is_source=False): + print("discard_changes") + # raise NotImplementedError( + # "Method `discard_changes` not implemented!" + # ) - def _remove_overrides(self): - print("_remove_overrides") + def remove_overrides(self, is_source=False): + print("remove_overrides") + # raise NotImplementedError( + # "Method `remove_overrides` not implemented!" + # ) + + def hierarchical_style_update(self): + print("hierarchical_style_update") + # raise NotImplementedError( + # "Method `hierarchical_style_update` not implemented!" + # ) def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.RightButton: From 403c2f4888a9e7c6401032e22c62847ec8e9e42d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:10:46 +0200 Subject: [PATCH 169/580] preparation for discard changes --- .../config_setting/widgets/inputs.py | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3b07bb1c99..7fce3606f5 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -111,13 +111,13 @@ class ConfigWidget: actions_mapping = {} if self.child_modified: action = QtWidgets.QAction("Discard changes") - actions_mapping[action] = self._discard_changes + actions_mapping[action] = self.discard_changes menu.addAction(action) if self.child_overriden: # TODO better label action = QtWidgets.QAction("Remove override") - actions_mapping[action] = self._remove_overrides + actions_mapping[action] = self.remove_overrides menu.addAction(action) if not actions_mapping: @@ -129,7 +129,7 @@ class ConfigWidget: if result: to_run = actions_mapping[result] if to_run: - to_run() + to_run(True) return super(self.__class__, self).mouseReleaseEvent(event) @@ -143,6 +143,24 @@ class InputWidget(ConfigWidget): def hierarchical_style_update(self): self.update_style() + def discard_changes(self, is_source=False): + if ( + self.is_overidable + and self.override_value is not NOT_SET + and self._was_overriden is True + ): + self.set_value(self.override_value) + else: + self.set_value(self.start_value) + + if not self.is_overidable: + self._is_modified = self.global_value != self.item_value() + self._is_overriden = False + return + + self._is_modified = False + self._is_overriden = self._was_overriden + @property def child_modified(self): return self.is_modified From 82949978488a627f4031c36d242fb4b3c9c7f2c4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:11:39 +0200 Subject: [PATCH 170/580] implemented discard changes for most of input widgets --- .../config_setting/widgets/inputs.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 7fce3606f5..b593248470 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1615,6 +1615,19 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def discard_changes(self, is_source=False): + if is_source: + self.ignore_value_changes = True + + for item in self.input_fields: + item.discard_changes() + + if is_source: + self.ignore_value_changes = False + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -1636,6 +1649,7 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): or self.child_overriden ) ) + self._was_overriden = bool(self._is_overriden) self.update_style() def _on_value_change(self, item=None): @@ -1802,6 +1816,19 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def discard_changes(self, is_source=False): + if is_source: + self.ignore_value_changes = True + + for item in self.input_fields: + item.discard_changes() + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + + if is_source: + self.ignore_value_changes = False + def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False From 43da05a6183b6270b252c08c613e84fb164ed315 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:12:09 +0200 Subject: [PATCH 171/580] added forgotten hierarchical style update --- .../config_setting/config_setting/widgets/inputs.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b593248470..5e4fe0bbf3 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -245,14 +245,8 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): self._on_value_change() - def reset_value(self): - if self.is_overidable and self.override_value is not NOT_SET: - self.set_value(self.override_value) - else: - self.set_value(self.global_value) - def clear_value(self): - self.reset_value() + self.set_value(False) def apply_overrides(self, override_value): self._is_modified = False @@ -1670,6 +1664,11 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): self.update_style() + def hierarchical_style_update(self): + self.update_style() + for input_field in self.input_fields: + input_field.hierarchical_style_update() + def update_style(self, is_overriden=None): child_modified = self.child_modified child_state = self.style_state(self.child_overriden, child_modified) From 82570533d0512f7c263fd02892feeb850bff2fca Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:14:46 +0200 Subject: [PATCH 172/580] hierarchical_style_update and discard_changes are abstract methods now --- .../config_setting/widgets/inputs.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 5e4fe0bbf3..33facc1a18 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -87,10 +87,9 @@ class ConfigWidget: ).format(self.__class__.__name__)) def discard_changes(self, is_source=False): - print("discard_changes") - # raise NotImplementedError( - # "Method `discard_changes` not implemented!" - # ) + raise NotImplementedError( + "Method `discard_changes` not implemented!" + ) def remove_overrides(self, is_source=False): print("remove_overrides") @@ -99,10 +98,9 @@ class ConfigWidget: # ) def hierarchical_style_update(self): - print("hierarchical_style_update") - # raise NotImplementedError( - # "Method `hierarchical_style_update` not implemented!" - # ) + raise NotImplementedError( + "Method `hierarchical_style_update` not implemented!" + ) def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.RightButton: From e343cd65cfb6c3682d41ff110fe6ce795fbbc1d3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:36:27 +0200 Subject: [PATCH 173/580] wrapped discard_changes remove_overrides to proxy methods setting ignore value changes --- .../config_setting/widgets/inputs.py | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 33facc1a18..379b27cdb6 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -86,12 +86,22 @@ class ConfigWidget: "Method `add_children_gui` is not implemented for `{}`." ).format(self.__class__.__name__)) - def discard_changes(self, is_source=False): + def _discard_changes(self): + self.ignore_value_changes = True + self.discard_changes() + self.ignore_value_changes = False + + def discard_changes(self): raise NotImplementedError( - "Method `discard_changes` not implemented!" + "{} Method `discard_changes` not implemented!".format(repr(self)) ) - def remove_overrides(self, is_source=False): + def _remove_overrides(self): + self.ignore_value_changes = True + self.remove_overrides() + self.ignore_value_changes = False + + def remove_overrides(self): print("remove_overrides") # raise NotImplementedError( # "Method `remove_overrides` not implemented!" @@ -109,13 +119,16 @@ class ConfigWidget: actions_mapping = {} if self.child_modified: action = QtWidgets.QAction("Discard changes") - actions_mapping[action] = self.discard_changes + actions_mapping[action] = self._discard_changes menu.addAction(action) - if self.child_overriden: + if ( + not self.any_parent_overriden() + and (self.is_overriden or self.child_overriden) + ): # TODO better label action = QtWidgets.QAction("Remove override") - actions_mapping[action] = self.remove_overrides + actions_mapping[action] = self._remove_overrides menu.addAction(action) if not actions_mapping: @@ -127,7 +140,7 @@ class ConfigWidget: if result: to_run = actions_mapping[result] if to_run: - to_run(True) + to_run() return super(self.__class__, self).mouseReleaseEvent(event) From f80cd9492e2338cb80d3d9940cdfb70af8818b75 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:37:09 +0200 Subject: [PATCH 174/580] implemented missing discard changes --- .../config_setting/widgets/inputs.py | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 379b27cdb6..feae2d2943 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -154,7 +154,7 @@ class InputWidget(ConfigWidget): def hierarchical_style_update(self): self.update_style() - def discard_changes(self, is_source=False): + def discard_changes(self): if ( self.is_overidable and self.override_value is not NOT_SET @@ -1620,16 +1620,10 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) - def discard_changes(self, is_source=False): - if is_source: - self.ignore_value_changes = True - + def discard_changes(self): for item in self.input_fields: item.discard_changes() - if is_source: - self.ignore_value_changes = False - self._is_modified = self.child_modified self._is_overriden = self._was_overriden @@ -1826,19 +1820,13 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) - def discard_changes(self, is_source=False): - if is_source: - self.ignore_value_changes = True - + def discard_changes(self): for item in self.input_fields: item.discard_changes() self._is_modified = self.child_modified self._is_overriden = self._was_overriden - if is_source: - self.ignore_value_changes = False - def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -2061,6 +2049,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): for input_field in self.input_fields: input_field.hierarchical_style_update() + def discard_changes(self): + for item in self.input_fields: + item.discard_changes() + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + def apply_overrides(self, override_value): self._is_overriden = False for item in self.input_fields: From dba9c98060de3a650e54412e4b82ffcf3d68de89 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:37:37 +0200 Subject: [PATCH 175/580] added any_parent_overriden for remove overrides action --- .../config_setting/widgets/base.py | 42 ++++++++++++++++--- .../config_setting/widgets/inputs.py | 5 +++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 2018b4bde3..c0246dd8a2 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -9,9 +9,9 @@ from avalon import io class StudioWidget(QtWidgets.QWidget): is_overidable = False - is_overriden = False - is_group = False - any_parent_is_group = False + _is_overriden = False + _is_group = False + _any_parent_is_group = False def __init__(self, parent=None): super(StudioWidget, self).__init__(parent) @@ -56,6 +56,21 @@ class StudioWidget(QtWidgets.QWidget): self.reset() + def any_parent_overriden(self): + return False + + @property + def is_overriden(self): + return self._is_overriden + + @property + def is_group(self): + return self._is_group + + @property + def any_parent_is_group(self): + return self._any_parent_is_group + @property def ignore_value_changes(self): return self._ignore_value_changes @@ -263,9 +278,9 @@ class ProjectListWidget(QtWidgets.QWidget): class ProjectWidget(QtWidgets.QWidget): - is_overriden = False - is_group = False - any_parent_is_group = False + _is_overriden = False + _is_group = False + _any_parent_is_group = False def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) @@ -325,6 +340,21 @@ class ProjectWidget(QtWidgets.QWidget): self.reset() + def any_parent_overriden(self): + return False + + @property + def is_overriden(self): + return self._is_overriden + + @property + def is_group(self): + return self._is_group + + @property + def any_parent_is_group(self): + return self._any_parent_is_group + @property def ignore_value_changes(self): return self._ignore_value_changes diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index feae2d2943..f946b4cac8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -38,6 +38,11 @@ class ConfigWidget: def is_overidable(self): return self._parent.is_overidable + def any_parent_overriden(self): + if self._parent._is_overriden: + return True + return self._parent.any_parent_overriden() + @property def ignore_value_changes(self): return self._parent.ignore_value_changes From 9923427df8e5d285bc89df945830fe73d182cfb7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:37:56 +0200 Subject: [PATCH 176/580] added remove overrides for inputs --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f946b4cac8..ff0a871e17 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -159,6 +159,12 @@ class InputWidget(ConfigWidget): def hierarchical_style_update(self): self.update_style() + def remove_overrides(self): + self.set_value(self.start_value) + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + def discard_changes(self): if ( self.is_overidable From 71e61a6c68d86ac2b9c253fd46a8d7665d028372 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:40:16 +0200 Subject: [PATCH 177/580] remove_overrides is abstract --- .../config_setting/widgets/inputs.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ff0a871e17..d67d32990a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -87,9 +87,11 @@ class ConfigWidget: return "-".join(items) or self.default_state def add_children_gui(self, child_configuration, values): - raise NotImplementedError(( - "Method `add_children_gui` is not implemented for `{}`." - ).format(self.__class__.__name__)) + raise NotImplementedError( + "{} Method `add_children_gui` is not implemented!.".format( + repr(self) + ) + ) def _discard_changes(self): self.ignore_value_changes = True @@ -98,7 +100,9 @@ class ConfigWidget: def discard_changes(self): raise NotImplementedError( - "{} Method `discard_changes` not implemented!".format(repr(self)) + "{} Method `discard_changes` not implemented!".format( + repr(self) + ) ) def _remove_overrides(self): @@ -107,10 +111,11 @@ class ConfigWidget: self.ignore_value_changes = False def remove_overrides(self): - print("remove_overrides") - # raise NotImplementedError( - # "Method `remove_overrides` not implemented!" - # ) + raise NotImplementedError( + "{} Method `remove_overrides` not implemented!".format( + repr(self) + ) + ) def hierarchical_style_update(self): raise NotImplementedError( From 2a65a2ccb97a42b4bcaed9925a259fba1a011d46 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 19:42:31 +0200 Subject: [PATCH 178/580] remove overrides should work now --- .../config_setting/widgets/inputs.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d67d32990a..3e344cd703 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1636,6 +1636,13 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + for item in self.input_fields: + item.remove_overrides() + def discard_changes(self): for item in self.input_fields: item.discard_changes() @@ -1836,6 +1843,13 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + for item in self.input_fields: + item.remove_overrides() + def discard_changes(self): for item in self.input_fields: item.discard_changes() @@ -2065,6 +2079,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): for input_field in self.input_fields: input_field.hierarchical_style_update() + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + for item in self.input_fields: + item.remove_overrides() + def discard_changes(self): for item in self.input_fields: item.discard_changes() From cdf32eb15051b75b17ed2187daefabc0a5fff43a Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 26 Aug 2020 10:16:20 +0100 Subject: [PATCH 179/580] Containerize audio loading. --- pype/plugins/maya/load/load_audio.py | 49 +++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/pype/plugins/maya/load/load_audio.py b/pype/plugins/maya/load/load_audio.py index e1860d0ca6..ca38082ed0 100644 --- a/pype/plugins/maya/load/load_audio.py +++ b/pype/plugins/maya/load/load_audio.py @@ -1,6 +1,9 @@ from maya import cmds, mel +import pymel.core as pc from avalon import api +from avalon.maya.pipeline import containerise +from avalon.maya import lib class AudioLoader(api.Loader): @@ -24,4 +27,48 @@ class AudioLoader(api.Loader): displaySound=True ) - return [sound_node] + asset = context["asset"]["name"] + namespace = namespace or lib.unique_namespace( + asset + "_", + prefix="_" if asset[0].isdigit() else "", + suffix="_", + ) + + return containerise( + name=name, + namespace=namespace, + nodes=[sound_node], + context=context, + loader=self.__class__.__name__ + ) + + def update(self, container, representation): + audio_node = None + for node in pc.PyNode(container["objectName"]).members(): + if node.nodeType() == "audio": + audio_node = node + + assert audio_node is not None, "Audio node not found." + + path = api.get_representation_path(representation) + audio_node.filename.set(path) + cmds.setAttr( + container["objectName"] + ".representation", + str(representation["_id"]), + type="string" + ) + + def switch(self, container, representation): + self.update(container, representation) + + def remove(self, container): + members = cmds.sets(container['objectName'], query=True) + cmds.lockNode(members, lock=False) + cmds.delete([container['objectName']] + members) + + # Clean up the namespace + try: + cmds.namespace(removeNamespace=container['namespace'], + deleteNamespaceContent=True) + except RuntimeError: + pass From a3d82fc92c5ac27f348077685d36b7acb3517cc3 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 26 Aug 2020 11:03:00 +0100 Subject: [PATCH 180/580] Enable previews for Ftrack review. --- pype/plugins/nukestudio/publish/collect_reviews.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/nukestudio/publish/collect_reviews.py b/pype/plugins/nukestudio/publish/collect_reviews.py index aa8c60767c..c158dee876 100644 --- a/pype/plugins/nukestudio/publish/collect_reviews.py +++ b/pype/plugins/nukestudio/publish/collect_reviews.py @@ -99,7 +99,7 @@ class CollectReviews(api.InstancePlugin): "step": 1, "fps": rev_inst.data.get("fps"), "name": "preview", - "tags": ["preview"], + "tags": ["preview", "ftrackreview"], "ext": ext } From 76d65ca6d3dcb8772800a3013005dec25c93fe00 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 26 Aug 2020 11:06:49 +0100 Subject: [PATCH 181/580] Thumbnail parent Assetversion was not found when its not linked to a task. assetversion["task"] returns None instead of raising exception. --- .../ftrack/actions/action_thumbnail_to_parent.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pype/modules/ftrack/actions/action_thumbnail_to_parent.py b/pype/modules/ftrack/actions/action_thumbnail_to_parent.py index 8710fa9dcf..fb473f9aa5 100644 --- a/pype/modules/ftrack/actions/action_thumbnail_to_parent.py +++ b/pype/modules/ftrack/actions/action_thumbnail_to_parent.py @@ -41,9 +41,9 @@ class ThumbToParent(BaseAction): parent = None thumbid = None if entity.entity_type.lower() == 'assetversion': - try: - parent = entity['task'] - except Exception: + parent = entity['task'] + + if parent is None: par_ent = entity['link'][-2] parent = session.get(par_ent['type'], par_ent['id']) else: @@ -51,7 +51,7 @@ class ThumbToParent(BaseAction): parent = entity['parent'] except Exception as e: msg = ( - "Durin Action 'Thumb to Parent'" + "During Action 'Thumb to Parent'" " went something wrong" ) self.log.error(msg) @@ -62,7 +62,10 @@ class ThumbToParent(BaseAction): parent['thumbnail_id'] = thumbid status = 'done' else: - status = 'failed' + raise Exception( + "Parent or thumbnail id not found. Parent: {}. " + "Thumbnail id: {}".format(parent, thumbid) + ) # inform the user that the job is done job['status'] = status or 'done' From 76e0b5a7ae1037f24816fe1094e88b52997570ce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 12:44:20 +0200 Subject: [PATCH 182/580] allow show icon in bar instead of python icon --- pype/tools/tray/pype_tray.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py index 9537b62581..a4cf4eabfe 100644 --- a/pype/tools/tray/pype_tray.py +++ b/pype/tools/tray/pype_tray.py @@ -537,6 +537,14 @@ class PypeTrayApplication(QtWidgets.QApplication): super(self.__class__, self).__init__(sys.argv) # Allows to close widgets without exiting app self.setQuitOnLastWindowClosed(False) + + # Allow show icon istead of python icon in task bar (Windows) + if os.name == "nt": + import ctypes + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID( + u"pype_tray" + ) + # Sets up splash splash_widget = self.set_splash() From bda8cb88017a7c61b225d3bcc4187323d3c27e7f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 12:44:32 +0200 Subject: [PATCH 183/580] login thread is not qthread based --- pype/modules/ftrack/tray/login_tools.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pype/modules/ftrack/tray/login_tools.py b/pype/modules/ftrack/tray/login_tools.py index 02982294f2..e7d22fbc19 100644 --- a/pype/modules/ftrack/tray/login_tools.py +++ b/pype/modules/ftrack/tray/login_tools.py @@ -2,7 +2,7 @@ from http.server import BaseHTTPRequestHandler, HTTPServer from urllib import parse import webbrowser import functools -from Qt import QtCore +import threading from pype.api import resources @@ -55,20 +55,17 @@ class LoginServerHandler(BaseHTTPRequestHandler): ) -class LoginServerThread(QtCore.QThread): +class LoginServerThread(threading.Thread): '''Login server thread.''' - # Login signal. - loginSignal = QtCore.Signal(object, object, object) - - def start(self, url): - '''Start thread.''' + def __init__(self, url, callback): self.url = url - super(LoginServerThread, self).start() + self.callback = callback + super(LoginServerThread, self).__init__() def _handle_login(self, api_user, api_key): '''Login to server with *api_user* and *api_key*.''' - self.loginSignal.emit(self.url, api_user, api_key) + self.callback(api_user, api_key) def run(self): '''Listen for events.''' From e0e4b4eb9f1050ed6778af3b5860447c7c78b738 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 12:44:50 +0200 Subject: [PATCH 184/580] login dialog was rewriten from base --- pype/modules/ftrack/tray/login_dialog.py | 446 ++++++++++++----------- 1 file changed, 224 insertions(+), 222 deletions(-) diff --git a/pype/modules/ftrack/tray/login_dialog.py b/pype/modules/ftrack/tray/login_dialog.py index e0614513a3..9ffd21fd30 100644 --- a/pype/modules/ftrack/tray/login_dialog.py +++ b/pype/modules/ftrack/tray/login_dialog.py @@ -7,309 +7,311 @@ from pype.api import resources from Qt import QtCore, QtGui, QtWidgets -class Login_Dialog_ui(QtWidgets.QWidget): - +class CredentialsDialog(QtWidgets.QDialog): SIZE_W = 300 SIZE_H = 230 - loginSignal = QtCore.Signal(object, object, object) - _login_server_thread = None - inputs = [] - buttons = [] - labels = [] + login_changed = QtCore.Signal() + logout_signal = QtCore.Signal() - def __init__(self, parent=None, is_event=False): + def __init__(self, parent=None): + super(CredentialsDialog, self).__init__(parent) - super(Login_Dialog_ui, self).__init__() + self.setWindowTitle("Pype - Ftrack Login") - self.parent = parent - self.is_event = is_event + self._login_server_thread = None + self._is_logged = False + self._in_advance_mode = False - if hasattr(parent, 'icon'): - self.setWindowIcon(self.parent.icon) - elif hasattr(parent, 'parent') and hasattr(parent.parent, 'icon'): - self.setWindowIcon(self.parent.parent.icon) - else: - icon = QtGui.QIcon(resources.pype_icon_filepath()) - self.setWindowIcon(icon) + icon = QtGui.QIcon(resources.pype_icon_filepath()) + self.setWindowIcon(icon) self.setWindowFlags( QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint ) - self.loginSignal.connect(self.loginWithCredentials) - self._translate = QtCore.QCoreApplication.translate - - self.font = QtGui.QFont() - self.font.setFamily("DejaVu Sans Condensed") - self.font.setPointSize(9) - self.font.setBold(True) - self.font.setWeight(50) - self.font.setKerning(True) - - self.resize(self.SIZE_W, self.SIZE_H) self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) - self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100)) + self.setMaximumSize(QtCore.QSize(self.SIZE_W + 100, self.SIZE_H + 100)) self.setStyleSheet(style.load_stylesheet()) - self.setLayout(self._main()) - self.setWindowTitle('Pype - Ftrack Login') + self.ui_init() - def _main(self): - self.main = QtWidgets.QVBoxLayout() - self.main.setObjectName("main") - - self.form = QtWidgets.QFormLayout() - self.form.setContentsMargins(10, 15, 10, 5) - self.form.setObjectName("form") - - self.ftsite_label = QtWidgets.QLabel("FTrack URL:") - self.ftsite_label.setFont(self.font) - self.ftsite_label.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.ftsite_label.setTextFormat(QtCore.Qt.RichText) - self.ftsite_label.setObjectName("user_label") + def ui_init(self): + self.ftsite_label = QtWidgets.QLabel("Ftrack URL:") + self.user_label = QtWidgets.QLabel("Username:") + self.api_label = QtWidgets.QLabel("API Key:") self.ftsite_input = QtWidgets.QLineEdit() - self.ftsite_input.setEnabled(True) - self.ftsite_input.setFrame(True) - self.ftsite_input.setEnabled(False) self.ftsite_input.setReadOnly(True) - self.ftsite_input.setObjectName("ftsite_input") - - self.user_label = QtWidgets.QLabel("Username:") - self.user_label.setFont(self.font) - self.user_label.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.user_label.setTextFormat(QtCore.Qt.RichText) - self.user_label.setObjectName("user_label") + self.ftsite_input.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) self.user_input = QtWidgets.QLineEdit() - self.user_input.setEnabled(True) - self.user_input.setFrame(True) - self.user_input.setObjectName("user_input") - self.user_input.setPlaceholderText( - self._translate("main", "user.name") - ) + self.user_input.setPlaceholderText("user.name") self.user_input.textChanged.connect(self._user_changed) - self.api_label = QtWidgets.QLabel("API Key:") - self.api_label.setFont(self.font) - self.api_label.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.api_label.setTextFormat(QtCore.Qt.RichText) - self.api_label.setObjectName("api_label") - self.api_input = QtWidgets.QLineEdit() - self.api_input.setEnabled(True) - self.api_input.setFrame(True) - self.api_input.setObjectName("api_input") - self.api_input.setPlaceholderText(self._translate( - "main", "e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - )) + self.api_input.setPlaceholderText( + "e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + ) self.api_input.textChanged.connect(self._api_changed) + input_layout = QtWidgets.QFormLayout() + input_layout.setContentsMargins(10, 15, 10, 5) + + input_layout.addRow(self.ftsite_label, self.ftsite_input) + input_layout.addRow(self.user_label, self.user_input) + input_layout.addRow(self.api_label, self.api_input) + + self.btn_advanced = QtWidgets.QPushButton("Advanced") + self.btn_advanced.clicked.connect(self._on_advanced_clicked) + + self.btn_simple = QtWidgets.QPushButton("Simple") + self.btn_simple.clicked.connect(self._on_simple_clicked) + + self.btn_login = QtWidgets.QPushButton("Login") + self.btn_login.setToolTip( + "Set Username and API Key with entered values" + ) + self.btn_login.clicked.connect(self._on_login_clicked) + + self.btn_ftrack_login = QtWidgets.QPushButton("Ftrack login") + self.btn_ftrack_login.setToolTip("Open browser for Login to Ftrack") + self.btn_ftrack_login.clicked.connect(self._on_ftrack_login_clicked) + + self.btn_logout = QtWidgets.QPushButton("Logout") + self.btn_logout.clicked.connect(self._on_logout_clicked) + + self.btn_close = QtWidgets.QPushButton("Close") + self.btn_close.setToolTip("Close this window") + self.btn_close.clicked.connect(self._close_widget) + + btns_layout = QtWidgets.QHBoxLayout() + btns_layout.addWidget(self.btn_advanced) + btns_layout.addWidget(self.btn_simple) + btns_layout.addStretch(1) + btns_layout.addWidget(self.btn_ftrack_login) + btns_layout.addWidget(self.btn_login) + btns_layout.addWidget(self.btn_logout) + btns_layout.addWidget(self.btn_close) + + self.note_label = QtWidgets.QLabel(( + "NOTE: Click on \"{}\" button to log with your default browser" + " or click on \"{}\" button to enter API key manually." + ).format(self.btn_ftrack_login.text(), self.btn_advanced.text())) + + self.note_label.setWordWrap(True) + self.note_label.hide() + self.error_label = QtWidgets.QLabel("") - self.error_label.setFont(self.font) - self.error_label.setTextFormat(QtCore.Qt.RichText) - self.error_label.setObjectName("error_label") self.error_label.setWordWrap(True) self.error_label.hide() - self.form.addRow(self.ftsite_label, self.ftsite_input) - self.form.addRow(self.user_label, self.user_input) - self.form.addRow(self.api_label, self.api_input) - self.form.addRow(self.error_label) + label_layout = QtWidgets.QVBoxLayout() + label_layout.setContentsMargins(10, 5, 10, 5) + label_layout.addWidget(self.note_label) + label_layout.addWidget(self.error_label) - self.btnGroup = QtWidgets.QHBoxLayout() - self.btnGroup.addStretch(1) - self.btnGroup.setObjectName("btnGroup") + main = QtWidgets.QVBoxLayout(self) + main.addLayout(input_layout) + main.addLayout(label_layout) + main.addStretch(1) + main.addLayout(btns_layout) - self.btnEnter = QtWidgets.QPushButton("Login") - self.btnEnter.setToolTip( - 'Set Username and API Key with entered values' - ) - self.btnEnter.clicked.connect(self.enter_credentials) + self.fill_ftrack_url() - self.btnClose = QtWidgets.QPushButton("Close") - self.btnClose.setToolTip('Close this window') - self.btnClose.clicked.connect(self._close_widget) + self.set_is_logged(self._is_logged) - self.btnFtrack = QtWidgets.QPushButton("Ftrack") - self.btnFtrack.setToolTip('Open browser for Login to Ftrack') - self.btnFtrack.clicked.connect(self.open_ftrack) + self.setLayout(main) - self.btnGroup.addWidget(self.btnFtrack) - self.btnGroup.addWidget(self.btnEnter) - self.btnGroup.addWidget(self.btnClose) + def fill_ftrack_url(self): + url = os.getenv("FTRACK_SERVER") + checked_url = self.check_url(url) - self.main.addLayout(self.form) - self.main.addLayout(self.btnGroup) + if checked_url is None: + checked_url = "" + self.btn_login.setEnabled(False) + self.btn_ftrack_login.setEnabled(False) - self.inputs.append(self.api_input) - self.inputs.append(self.user_input) - self.inputs.append(self.ftsite_input) + self.api_input.setEnabled(False) + self.user_input.setEnabled(False) + self.ftsite_input.setEnabled(False) - self.enter_site() - return self.main + self.ftsite_input.setText(checked_url) - def enter_site(self): - try: - url = os.getenv('FTRACK_SERVER') - newurl = self.checkUrl(url) + def set_advanced_mode(self, is_advanced): + self._in_advance_mode = is_advanced - if newurl is None: - self.btnEnter.setEnabled(False) - self.btnFtrack.setEnabled(False) - for input in self.inputs: - input.setEnabled(False) - newurl = url + self.error_label.setVisible(False) - self.ftsite_input.setText(newurl) + is_logged = self._is_logged - except Exception: - self.setError("FTRACK_SERVER is not set in templates") - self.btnEnter.setEnabled(False) - self.btnFtrack.setEnabled(False) - for input in self.inputs: - input.setEnabled(False) + self.note_label.setVisible(not is_logged and not is_advanced) + self.btn_ftrack_login.setVisible(not is_logged and not is_advanced) + self.btn_advanced.setVisible(not is_logged and not is_advanced) - def setError(self, msg): + self.btn_login.setVisible(not is_logged and is_advanced) + self.btn_simple.setVisible(not is_logged and is_advanced) + + self.user_label.setVisible(is_logged or is_advanced) + self.user_input.setVisible(is_logged or is_advanced) + self.api_label.setVisible(is_logged or is_advanced) + self.api_input.setVisible(is_logged or is_advanced) + if is_advanced: + self.user_input.setFocus() + else: + self.btn_ftrack_login.setFocus() + + def set_is_logged(self, is_logged): + self._is_logged = is_logged + + self.user_input.setReadOnly(is_logged) + self.api_input.setReadOnly(is_logged) + self.user_input.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) + self.api_input.setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor)) + + self.btn_logout.setVisible(is_logged) + + self.set_advanced_mode(self._in_advance_mode) + + def set_error(self, msg): self.error_label.setText(msg) self.error_label.show() + def _on_logout_clicked(self): + self.user_input.setText("") + self.api_input.setText("") + self.set_is_logged(False) + self.logout_signal.emit() + + def _on_simple_clicked(self): + self.set_advanced_mode(False) + + def _on_advanced_clicked(self): + self.set_advanced_mode(True) + def _user_changed(self): - self.user_input.setStyleSheet("") + self._not_invalid_input(self.user_input) def _api_changed(self): - self.api_input.setStyleSheet("") + self._not_invalid_input(self.api_input) - def _invalid_input(self, entity): - entity.setStyleSheet("border: 1px solid red;") + def _not_invalid_input(self, input_widget): + input_widget.setStyleSheet("") - def enter_credentials(self): + def _invalid_input(self, input_widget): + input_widget.setStyleSheet("border: 1px solid red;") + + def _on_login_clicked(self): username = self.user_input.text().strip() - apiKey = self.api_input.text().strip() - msg = "You didn't enter " + api_key = self.api_input.text().strip() missing = [] if username == "": missing.append("Username") self._invalid_input(self.user_input) - if apiKey == "": + if api_key == "": missing.append("API Key") self._invalid_input(self.api_input) if len(missing) > 0: - self.setError("{0} {1}".format(msg, " and ".join(missing))) + self.set_error("You didn't enter {}".format(" and ".join(missing))) return - verification = credentials.check_credentials(username, apiKey) - - if verification: - credentials.save_credentials(username, apiKey, self.is_event) - credentials.set_env(username, apiKey) - if self.parent is not None: - self.parent.loginChange() - self._close_widget() - else: + if not self.login_with_credentials(username, api_key): self._invalid_input(self.user_input) self._invalid_input(self.api_input) - self.setError( + self.set_error( "We're unable to sign in to Ftrack with these credentials" ) - def open_ftrack(self): - url = self.ftsite_input.text() - self.loginWithCredentials(url, None, None) - - def checkUrl(self, url): - url = url.strip('/ ') - + def _on_ftrack_login_clicked(self): + url = self.check_url(self.ftsite_input.text()) if not url: - self.setError("There is no URL set in Templates") - return - - if 'http' not in url: - if url.endswith('ftrackapp.com'): - url = 'https://' + url - else: - url = 'https://{0}.ftrackapp.com'.format(url) - try: - result = requests.get( - url, - # Old python API will not work with redirect. - allow_redirects=False - ) - except requests.exceptions.RequestException: - self.setError( - 'The server URL set in Templates could not be reached.' - ) - return - - if ( - result.status_code != 200 or 'FTRACK_VERSION' not in result.headers - ): - self.setError( - 'The server URL set in Templates is not a valid ftrack server.' - ) - return - return url - - def loginWithCredentials(self, url, username, apiKey): - url = url.strip('/ ') - - if not url: - self.setError( - 'You need to specify a valid server URL, ' - 'for example https://server-name.ftrackapp.com' - ) - return - - if 'http' not in url: - if url.endswith('ftrackapp.com'): - url = 'https://' + url - else: - url = 'https://{0}.ftrackapp.com'.format(url) - try: - result = requests.get( - url, - # Old python API will not work with redirect. - allow_redirects=False - ) - except requests.exceptions.RequestException: - self.setError( - 'The server URL you provided could not be reached.' - ) - return - - if ( - result.status_code != 200 or 'FTRACK_VERSION' not in result.headers - ): - self.setError( - 'The server URL you provided is not a valid ftrack server.' - ) return # If there is an existing server thread running we need to stop it. if self._login_server_thread: - self._login_server_thread.quit() + self._login_server_thread.stop() + self._login_server_thread.join() self._login_server_thread = None # If credentials are not properly set, try to get them using a http # server. - if not username or not apiKey: - self._login_server_thread = login_tools.LoginServerThread() - self._login_server_thread.loginSignal.connect(self.loginSignal) - self._login_server_thread.start(url) + self._login_server_thread = login_tools.LoginServerThread( + url, self._result_of_ftrack_thread + ) + self._login_server_thread.start() + + def _result_of_ftrack_thread(self, username, api_key): + if not self.login_with_credentials(username, api_key): + self._invalid_input(self.api_input) + self.set_error(( + "Somthing happened with Ftrack login." + " Try enter Username and API key manually." + )) + else: + self.set_is_logged(True) + + def login_with_credentials(self, username, api_key): + verification = credentials.check_credentials(username, api_key) + if verification: + credentials.save_credentials(username, api_key, False) + credentials.set_env(username, api_key) + self.set_credentials(username, api_key) + self.login_changed.emit() + return verification + + def set_credentials(self, username, api_key, is_logged=True): + self.user_input.setText(username) + self.api_input.setText(api_key) + + self.error_label.hide() + + self._not_invalid_input(self.ftsite_input) + self._not_invalid_input(self.user_input) + self._not_invalid_input(self.api_input) + + if is_logged is not None: + self.set_is_logged(is_logged) + + def check_url(self, url): + if url is not None: + url = url.strip("/ ") + + if not url: + self.set_error(( + "You need to specify a valid server URL, " + "for example https://server-name.ftrackapp.com" + )) return - verification = credentials.check_credentials(username, apiKey) + if "http" not in url: + if url.endswith("ftrackapp.com"): + url = "https://" + url + else: + url = "https://{}.ftrackapp.com".format(url) + try: + result = requests.get( + url, + # Old python API will not work with redirect. + allow_redirects=False + ) + except requests.exceptions.RequestException: + self.set_error( + "Specified URL could not be reached." + ) + return - if verification is True: - credentials.save_credentials(username, apiKey, self.is_event) - credentials.set_env(username, apiKey) - if self.parent is not None: - self.parent.loginChange() - self._close_widget() + if ( + result.status_code != 200 + or "FTRACK_VERSION" not in result.headers + ): + self.set_error( + "Specified URL does not lead to a valid Ftrack server." + ) + return + return url def closeEvent(self, event): event.ignore() From 15cb7393297f3ba30a50e2d610ddfd2cd7a1efe1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 12:45:16 +0200 Subject: [PATCH 185/580] ftrack module modified to be able handle new ftrack login dialog --- pype/modules/ftrack/tray/ftrack_module.py | 110 +++++++++++++--------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/pype/modules/ftrack/tray/ftrack_module.py b/pype/modules/ftrack/tray/ftrack_module.py index 674e8cbd4f..99f382b11e 100644 --- a/pype/modules/ftrack/tray/ftrack_module.py +++ b/pype/modules/ftrack/tray/ftrack_module.py @@ -2,7 +2,7 @@ import os import time import datetime import threading -from Qt import QtCore, QtWidgets +from Qt import QtCore, QtWidgets, QtGui import ftrack_api from ..ftrack_server.lib import check_ftrack_url @@ -10,7 +10,7 @@ from ..ftrack_server import socket_thread from ..lib import credentials from . import login_dialog -from pype.api import Logger +from pype.api import Logger, resources log = Logger().get_logger("FtrackModule", "ftrack") @@ -19,7 +19,7 @@ log = Logger().get_logger("FtrackModule", "ftrack") class FtrackModule: def __init__(self, main_parent=None, parent=None): self.parent = parent - self.widget_login = login_dialog.Login_Dialog_ui(self) + self.thread_action_server = None self.thread_socket_server = None self.thread_timer = None @@ -29,8 +29,22 @@ class FtrackModule: self.bool_action_thread_running = False self.bool_timer_event = False + self.widget_login = login_dialog.CredentialsDialog() + self.widget_login.login_changed.connect(self.on_login_change) + self.widget_login.logout_signal.connect(self.on_logout) + + self.action_credentials = None + self.icon_logged = QtGui.QIcon( + resources.get_resource("icons", "circle_green.png") + ) + self.icon_not_logged = QtGui.QIcon( + resources.get_resource("icons", "circle_orange.png") + ) + def show_login_widget(self): self.widget_login.show() + self.widget_login.activateWindow() + self.widget_login.raise_() def validate(self): validation = False @@ -39,9 +53,10 @@ class FtrackModule: ft_api_key = cred.get("api_key") validation = credentials.check_credentials(ft_user, ft_api_key) if validation: + self.widget_login.set_credentials(ft_user, ft_api_key) credentials.set_env(ft_user, ft_api_key) log.info("Connected to Ftrack successfully") - self.loginChange() + self.on_login_change() return validation @@ -60,15 +75,24 @@ class FtrackModule: return validation # Necessary - login_dialog works with this method after logging in - def loginChange(self): + def on_login_change(self): self.bool_logged = True + + self.action_credentials.setIcon(self.icon_logged) + self.action_credentials.setToolTip( + "Logged as user \"{}\"".format(self.widget_login.user_input.text()) + ) + self.set_menu_visibility() self.start_action_server() - def logout(self): + def on_logout(self): credentials.clear_credentials() self.stop_action_server() + self.action_credentials.setIcon(self.icon_not_logged) + self.action_credentials.setToolTip("Logged out") + log.info("Logged out of Ftrack") self.bool_logged = False self.set_menu_visibility() @@ -218,43 +242,45 @@ class FtrackModule: # Definition of Tray menu def tray_menu(self, parent_menu): # Menu for Tray App - self.menu = QtWidgets.QMenu('Ftrack', parent_menu) - self.menu.setProperty('submenu', 'on') - - # Actions - server - self.smActionS = self.menu.addMenu("Action server") - - self.aRunActionS = QtWidgets.QAction( - "Run action server", self.smActionS - ) - self.aResetActionS = QtWidgets.QAction( - "Reset action server", self.smActionS - ) - self.aStopActionS = QtWidgets.QAction( - "Stop action server", self.smActionS - ) - - self.aRunActionS.triggered.connect(self.start_action_server) - self.aResetActionS.triggered.connect(self.reset_action_server) - self.aStopActionS.triggered.connect(self.stop_action_server) - - self.smActionS.addAction(self.aRunActionS) - self.smActionS.addAction(self.aResetActionS) - self.smActionS.addAction(self.aStopActionS) + tray_menu = QtWidgets.QMenu("Ftrack", parent_menu) # Actions - basic - self.aLogin = QtWidgets.QAction("Login", self.menu) - self.aLogin.triggered.connect(self.validate) - self.aLogout = QtWidgets.QAction("Logout", self.menu) - self.aLogout.triggered.connect(self.logout) + action_credentials = QtWidgets.QAction("Credentials", tray_menu) + action_credentials.triggered.connect(self.show_login_widget) + if self.bool_logged: + icon = self.icon_logged + else: + icon = self.icon_not_logged + action_credentials.setIcon(icon) + tray_menu.addAction(action_credentials) + self.action_credentials = action_credentials - self.menu.addAction(self.aLogin) - self.menu.addAction(self.aLogout) + # Actions - server + tray_server_menu = tray_menu.addMenu("Action server") + self.action_server_run = QtWidgets.QAction( + "Run action server", tray_server_menu + ) + self.action_server_reset = QtWidgets.QAction( + "Reset action server", tray_server_menu + ) + self.action_server_stop = QtWidgets.QAction( + "Stop action server", tray_server_menu + ) + + self.action_server_run.triggered.connect(self.start_action_server) + self.action_server_reset.triggered.connect(self.reset_action_server) + self.action_server_stop.triggered.connect(self.stop_action_server) + + tray_server_menu.addAction(self.action_server_run) + tray_server_menu.addAction(self.action_server_reset) + tray_server_menu.addAction(self.action_server_stop) + + self.tray_server_menu = tray_server_menu self.bool_logged = False self.set_menu_visibility() - parent_menu.addMenu(self.menu) + parent_menu.addMenu(tray_menu) def tray_start(self): self.validate() @@ -264,19 +290,15 @@ class FtrackModule: # Definition of visibility of each menu actions def set_menu_visibility(self): - - self.smActionS.menuAction().setVisible(self.bool_logged) - self.aLogin.setVisible(not self.bool_logged) - self.aLogout.setVisible(self.bool_logged) - + self.tray_server_menu.menuAction().setVisible(self.bool_logged) if self.bool_logged is False: if self.bool_timer_event is True: self.stop_timer_thread() return - self.aRunActionS.setVisible(not self.bool_action_server_running) - self.aResetActionS.setVisible(self.bool_action_thread_running) - self.aStopActionS.setVisible(self.bool_action_server_running) + self.action_server_run.setVisible(not self.bool_action_server_running) + self.action_server_reset.setVisible(self.bool_action_thread_running) + self.action_server_stop.setVisible(self.bool_action_server_running) if self.bool_timer_event is False: self.start_timer_thread() From c49ad39965dfdf9d8cce447128ae5f399635d6c5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 12:46:21 +0200 Subject: [PATCH 186/580] more secure icon changes --- pype/modules/ftrack/tray/ftrack_module.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pype/modules/ftrack/tray/ftrack_module.py b/pype/modules/ftrack/tray/ftrack_module.py index 99f382b11e..0b011c5b33 100644 --- a/pype/modules/ftrack/tray/ftrack_module.py +++ b/pype/modules/ftrack/tray/ftrack_module.py @@ -78,10 +78,13 @@ class FtrackModule: def on_login_change(self): self.bool_logged = True - self.action_credentials.setIcon(self.icon_logged) - self.action_credentials.setToolTip( - "Logged as user \"{}\"".format(self.widget_login.user_input.text()) - ) + if self.action_credentials: + self.action_credentials.setIcon(self.icon_logged) + self.action_credentials.setToolTip( + "Logged as user \"{}\"".format( + self.widget_login.user_input.text() + ) + ) self.set_menu_visibility() self.start_action_server() @@ -90,8 +93,9 @@ class FtrackModule: credentials.clear_credentials() self.stop_action_server() - self.action_credentials.setIcon(self.icon_not_logged) - self.action_credentials.setToolTip("Logged out") + if self.action_credentials: + self.action_credentials.setIcon(self.icon_not_logged) + self.action_credentials.setToolTip("Logged out") log.info("Logged out of Ftrack") self.bool_logged = False From ca05176ce5d1becbf3972be6d87cf0b856bb5369 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 12:54:40 +0200 Subject: [PATCH 187/580] thread does not have stop method --- pype/modules/ftrack/tray/login_dialog.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/modules/ftrack/tray/login_dialog.py b/pype/modules/ftrack/tray/login_dialog.py index 9ffd21fd30..b142f31891 100644 --- a/pype/modules/ftrack/tray/login_dialog.py +++ b/pype/modules/ftrack/tray/login_dialog.py @@ -232,7 +232,6 @@ class CredentialsDialog(QtWidgets.QDialog): # If there is an existing server thread running we need to stop it. if self._login_server_thread: - self._login_server_thread.stop() self._login_server_thread.join() self._login_server_thread = None From b98db04a8671abff9fd1f21f4f7cb47b224892c4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 13:01:03 +0200 Subject: [PATCH 188/580] close widget when successfully logged in --- pype/modules/ftrack/tray/login_dialog.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/modules/ftrack/tray/login_dialog.py b/pype/modules/ftrack/tray/login_dialog.py index b142f31891..b703c4cd14 100644 --- a/pype/modules/ftrack/tray/login_dialog.py +++ b/pype/modules/ftrack/tray/login_dialog.py @@ -224,6 +224,8 @@ class CredentialsDialog(QtWidgets.QDialog): self.set_error( "We're unable to sign in to Ftrack with these credentials" ) + else: + self._close_widget() def _on_ftrack_login_clicked(self): url = self.check_url(self.ftsite_input.text()) @@ -251,6 +253,7 @@ class CredentialsDialog(QtWidgets.QDialog): )) else: self.set_is_logged(True) + self._close_widget() def login_with_credentials(self, username, api_key): verification = credentials.check_credentials(username, api_key) From 2f05d7cb197aa7c91ec0ac37585cbf36f882b373 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 13:08:37 +0200 Subject: [PATCH 189/580] fixed closing widget --- pype/modules/ftrack/tray/login_dialog.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pype/modules/ftrack/tray/login_dialog.py b/pype/modules/ftrack/tray/login_dialog.py index b703c4cd14..7730ee1609 100644 --- a/pype/modules/ftrack/tray/login_dialog.py +++ b/pype/modules/ftrack/tray/login_dialog.py @@ -35,6 +35,8 @@ class CredentialsDialog(QtWidgets.QDialog): self.setMaximumSize(QtCore.QSize(self.SIZE_W + 100, self.SIZE_H + 100)) self.setStyleSheet(style.load_stylesheet()) + self.login_changed.connect(self._on_login) + self.ui_init() def ui_init(self): @@ -202,6 +204,10 @@ class CredentialsDialog(QtWidgets.QDialog): def _invalid_input(self, input_widget): input_widget.setStyleSheet("border: 1px solid red;") + def _on_login(self): + self.set_is_logged(True) + self._close_widget() + def _on_login_clicked(self): username = self.user_input.text().strip() api_key = self.api_input.text().strip() @@ -224,8 +230,6 @@ class CredentialsDialog(QtWidgets.QDialog): self.set_error( "We're unable to sign in to Ftrack with these credentials" ) - else: - self._close_widget() def _on_ftrack_login_clicked(self): url = self.check_url(self.ftsite_input.text()) @@ -251,9 +255,6 @@ class CredentialsDialog(QtWidgets.QDialog): "Somthing happened with Ftrack login." " Try enter Username and API key manually." )) - else: - self.set_is_logged(True) - self._close_widget() def login_with_credentials(self, username, api_key): verification = credentials.check_credentials(username, api_key) From f66d14e582d540bf262dc3d3d5cacf60f96bede0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 17:55:53 +0200 Subject: [PATCH 190/580] scrollers are a littlebit better --- .../config_setting/style/style.css | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 0099e6ed76..73715d892d 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -116,3 +116,118 @@ QPushButton[btn-type="expand-toggle"] { #ExpandingWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"] { border-color: #137cbd; } + +QScrollBar:horizontal { + height: 15px; + margin: 3px 15px 3px 15px; + border: 1px transparent #1d272f; + border-radius: 4px; + background-color: #1d272f; +} + +QScrollBar::handle:horizontal { + background-color: #61839e; + min-width: 5px; + border-radius: 4px; +} + +QScrollBar::add-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(:/qss_icons/rc/right_arrow_disabled.png); + width: 10px; + height: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(:/qss_icons/rc/left_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on { + border-image: url(:/qss_icons/rc/right_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { + border-image: url(:/qss_icons/rc/left_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { + background: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +QScrollBar:vertical { + background-color: #1d272f; + width: 15px; + margin: 15px 3px 15px 3px; + border: 1px transparent #1d272f; + border-radius: 4px; +} + +QScrollBar::handle:vertical { + background-color: #61839e; + min-height: 5px; + border-radius: 4px; +} + +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(:/qss_icons/rc/up_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(:/qss_icons/rc/down_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on { + + border-image: url(:/qss_icons/rc/up_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { + border-image: url(:/qss_icons/rc/down_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { + background: none; +} + + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} From d1ffd17f5f925be45d66d499478ea112285418da Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 17:56:03 +0200 Subject: [PATCH 191/580] qmenu items are visible --- .../config_setting/config_setting/style/style.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 73715d892d..9bf8828920 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -5,6 +5,19 @@ QWidget { border-radius: 0px; } +QMenu { + border: 1px solid #555555; + background-color: #1d272f; +} + +QMenu::item { + padding: 5px 10px 5px 10px; +} + +QMenu::item:selected { + background-color: #202e3a; +} + QCheckBox::indicator { } QCheckBox::indicator:focus { From b274cfed16dc39c5945914f8e7bd8626872abf3c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 18:04:39 +0200 Subject: [PATCH 192/580] mae qmenu in same style --- pype/tools/config_setting/config_setting/style/style.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 9bf8828920..c5f1f33500 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -12,10 +12,12 @@ QMenu { QMenu::item { padding: 5px 10px 5px 10px; + border-left: 5px solid #313131; } QMenu::item:selected { - background-color: #202e3a; + border-left-color: #61839e; + background-color: #222d37; } QCheckBox::indicator { From e5960d7fa0fab9b294b611cd3b98ca2987564f78 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 18:42:08 +0200 Subject: [PATCH 193/580] added validation for is_group --- .../config_setting/widgets/lib.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index c6379b4816..e7173f1c56 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -94,6 +94,19 @@ class SchemaMissingFileInfo(Exception): super(SchemaMissingFileInfo, self).__init__(msg) +class SchemeGroupHierarchyBug(Exception): + def __init__(self, invalid): + full_path_keys = [] + for item in invalid: + full_path_keys.append("\"{}\"".format("/".join(item))) + + msg = ( + "Items with attribute \"is_group\" can't have another item with" + " \"is_group\" attribute as child. Error happened for keys: [{}]" + ).format(", ".join(full_path_keys)) + super(SchemeGroupHierarchyBug, self).__init__(msg) + + def file_keys_from_schema(schema_data): output = [] keys = [] @@ -147,11 +160,55 @@ def validate_all_has_ending_file(schema_data, is_top=True): raise SchemaMissingFileInfo(invalid) +def validate_is_group_is_unique_in_hierarchy( + schema_data, any_parent_is_group=False, keys=None +): + is_top = keys is None + if keys is None: + keys = [] + + keyless = "key" not in schema_data + + if not keyless: + keys.append(schema_data["key"]) + + invalid = [] + is_group = schema_data.get("is_group") + if is_group and any_parent_is_group: + invalid.append(copy.deepcopy(keys)) + + if is_group: + any_parent_is_group = is_group + + children = schema_data.get("children") + if not children: + return invalid + + for child in children: + result = validate_is_group_is_unique_in_hierarchy( + child, any_parent_is_group, copy.deepcopy(keys) + ) + if not result: + continue + + invalid.extend(result) + + if invalid and is_group and keys not in invalid: + invalid.append(copy.deepcopy(keys)) + + if not is_top: + return invalid + + if invalid: + raise SchemeGroupHierarchyBug(invalid) + + def validate_schema(schema_data): # TODO validator for key uniquenes # TODO validator that is_group key is not before is_file child # TODO validator that is_group or is_file is not on child without key validate_all_has_ending_file(schema_data) + validate_is_group_is_unique_in_hierarchy(schema_data) def gui_schema(subfolder, main_schema_name): From 28c4a69ea13804b96744a3a56afeb5cd0a24ea7b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 19:52:35 +0200 Subject: [PATCH 194/580] added ConfigWidget for reimplementing Qt methods --- .../config_setting/widgets/widgets.py | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index a15edf58ff..89f6782cfd 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -1,4 +1,4 @@ -from Qt import QtWidgets, QtCore +from Qt import QtWidgets, QtCore, QtGui class ModifiedIntSpinBox(QtWidgets.QSpinBox): @@ -38,7 +38,43 @@ class ClickableWidget(QtWidgets.QLabel): super(ClickableWidget, self).mouseReleaseEvent(event) -class ExpandingWidget(QtWidgets.QWidget): +class ConfigWidget(QtWidgets.QWidget): + allow_actions = True + + def mouseReleaseEvent(self, event): + if self.allow_actions and event.button() == QtCore.Qt.RightButton: + menu = QtWidgets.QMenu() + + actions_mapping = {} + if self.child_modified: + action = QtWidgets.QAction("Discard changes") + actions_mapping[action] = self._discard_changes + menu.addAction(action) + + if ( + not self.any_parent_overriden() + and (self.is_overriden or self.child_overriden) + ): + # TODO better label + action = QtWidgets.QAction("Remove override") + actions_mapping[action] = self._remove_overrides + menu.addAction(action) + + if not actions_mapping: + action = QtWidgets.QAction("< No action >") + actions_mapping[action] = None + menu.addAction(action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + return + super(ConfigWidget, self).mouseReleaseEvent(event) + + +class ExpandingWidget(ConfigWidget): def __init__(self, label, parent): super(ExpandingWidget, self).__init__(parent) self.setObjectName("ExpandingWidget") From d320924b9e9831d41fe49a204805e8c7ec9855b2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 19:55:02 +0200 Subject: [PATCH 195/580] ConfigWidget and InputWidget renamed to ConfigObject and InputWidget --- .../config_setting/widgets/inputs.py | 72 ++++++------------- 1 file changed, 21 insertions(+), 51 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3e344cd703..e30f437cd9 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1,6 +1,7 @@ import json from Qt import QtWidgets, QtCore, QtGui from .widgets import ( + ConfigWidget, ExpandingWidget, ModifiedIntSpinBox, ModifiedFloatSpinBox @@ -16,7 +17,7 @@ class SchemeGroupHierarchyBug(Exception): super(SchemeGroupHierarchyBug, self).__init__(msg) -class ConfigWidget: +class ConfigObject: default_state = "" _is_overriden = False _is_modified = False @@ -122,40 +123,8 @@ class ConfigWidget: "Method `hierarchical_style_update` not implemented!" ) - def mouseReleaseEvent(self, event): - if event.button() == QtCore.Qt.RightButton: - menu = QtWidgets.QMenu() - actions_mapping = {} - if self.child_modified: - action = QtWidgets.QAction("Discard changes") - actions_mapping[action] = self._discard_changes - menu.addAction(action) - - if ( - not self.any_parent_overriden() - and (self.is_overriden or self.child_overriden) - ): - # TODO better label - action = QtWidgets.QAction("Remove override") - actions_mapping[action] = self._remove_overrides - menu.addAction(action) - - if not actions_mapping: - action = QtWidgets.QAction("< No action >") - actions_mapping[action] = None - menu.addAction(action) - - result = menu.exec_(QtGui.QCursor.pos()) - if result: - to_run = actions_mapping[result] - if to_run: - to_run() - return - super(self.__class__, self).mouseReleaseEvent(event) - - -class InputWidget(ConfigWidget): +class InputObject(ConfigObject): def overrides(self): if not self.is_overriden: return NOT_SET, False @@ -200,7 +169,7 @@ class InputWidget(ConfigWidget): return -class BooleanWidget(QtWidgets.QWidget, InputWidget): +class BooleanWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -329,7 +298,7 @@ class BooleanWidget(QtWidgets.QWidget, InputWidget): return self.checkbox.isChecked() -class IntegerWidget(QtWidgets.QWidget, InputWidget): +class IntegerWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -446,7 +415,7 @@ class IntegerWidget(QtWidgets.QWidget, InputWidget): return self.int_input.value() -class FloatWidget(QtWidgets.QWidget, InputWidget): +class FloatWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -571,7 +540,7 @@ class FloatWidget(QtWidgets.QWidget, InputWidget): return self.float_input.value() -class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): +class TextSingleLineWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -580,7 +549,6 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): self._parent = parent self._as_widget = values is AS_WIDGET - any_parent_is_group = parent.is_group if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group @@ -688,7 +656,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputWidget): return self.text_input.text() -class TextMultiLineWidget(QtWidgets.QWidget, InputWidget): +class TextMultiLineWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -880,7 +848,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.update_style(is_valid) -class RawJsonWidget(QtWidgets.QWidget, InputWidget): +class RawJsonWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -999,7 +967,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputWidget): return self.text_input.toPlainText() -class TextListItem(QtWidgets.QWidget, ConfigWidget): +class TextListItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1049,7 +1017,7 @@ class TextListItem(QtWidgets.QWidget, ConfigWidget): return self.text_input.text() -class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): +class TextListSubWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): @@ -1169,7 +1137,7 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigWidget): return output -class TextListWidget(QtWidgets.QWidget, InputWidget): +class TextListWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -1272,7 +1240,7 @@ class TextListWidget(QtWidgets.QWidget, InputWidget): return self.value_widget.config_value() -class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): +class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1380,7 +1348,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigWidget): return {key: value} -class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): +class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): @@ -1486,7 +1454,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigWidget): return output -class ModifiableDict(ExpandingWidget, InputWidget): +class ModifiableDict(ExpandingWidget, InputObject): # Should be used only for dictionary with one datatype as value # TODO this is actually input field (do not care if is group or not) value_changed = QtCore.Signal(object) @@ -1584,7 +1552,7 @@ class ModifiableDict(ExpandingWidget, InputWidget): # Dictionaries -class DictExpandWidget(ExpandingWidget, ConfigWidget): +class DictExpandWidget(ExpandingWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__( @@ -1775,7 +1743,7 @@ class DictExpandWidget(ExpandingWidget, ConfigWidget): return {self.key: values}, self.is_group -class DictWidget(QtWidgets.QWidget, ConfigWidget): +class DictWidget(ConfigWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__( @@ -1981,9 +1949,10 @@ class DictWidget(QtWidgets.QWidget, ConfigWidget): return {self.key: values}, self.is_group -class DictInvisible(QtWidgets.QWidget, ConfigWidget): +class DictInvisible(ConfigWidget, ConfigObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) + allow_actions = False def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -2130,8 +2099,9 @@ class DictInvisible(QtWidgets.QWidget, ConfigWidget): # Proxy for form layout -class DictFormWidget(QtWidgets.QWidget, ConfigWidget): +class DictFormWidget(ConfigWidget, ConfigObject): value_changed = QtCore.Signal(object) + allow_actions = False def __init__( self, input_data, values, parent_keys, parent, label_widget=None From 7887cb3d7215379e532cc7f10188c8a1707832d8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 19:55:28 +0200 Subject: [PATCH 196/580] FormWIdget can handle mouse right clicks for its items --- .../config_setting/widgets/inputs.py | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e30f437cd9..64a5a90b45 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2098,6 +2098,12 @@ class DictInvisible(ConfigWidget, ConfigObject): return {self.key: values}, self.is_group +class FormLabel(QtWidgets.QLabel): + def __init__(self, *args, **kwargs): + super(FormLabel, self).__init__(*args, **kwargs) + self.item = None + + # Proxy for form layout class DictFormWidget(ConfigWidget, ConfigObject): value_changed = QtCore.Signal(object) @@ -2126,6 +2132,16 @@ class DictFormWidget(ConfigWidget, ConfigObject): for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.RightButton: + position = self.mapFromGlobal(QtGui.QCursor().pos()) + widget = self.childAt(position) + if widget and isinstance(widget, FormLabel): + widget.item.mouseReleaseEvent(event) + event.accept() + return + super(DictFormWidget, self).mouseReleaseEvent(event) + def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -2153,18 +2169,20 @@ class DictFormWidget(ConfigWidget, ConfigObject): klass = TypeToKlass.types.get(item_type) - label_widget = QtWidgets.QLabel(label) + label_widget = FormLabel(label, self) item = klass( child_configuration, values, self.keys, self, label_widget ) + label_widget.item = item + item.value_changed.connect(self._on_value_change) self.content_layout.addRow(label_widget, item) self.input_fields[key] = item return item def hierarchical_style_update(self): - for input_field in self.input_fields.items(): + for input_field in self.input_fields.values(): input_field.hierarchical_style_update() def item_value(self): From 1c40104d512837360ea6ea4a20703cc369195a9a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 20:01:56 +0200 Subject: [PATCH 197/580] removed SchemeGroupHierarchyBug as is already validated when loading schemas --- .../config_setting/widgets/inputs.py | 127 ++---------------- 1 file changed, 12 insertions(+), 115 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 64a5a90b45..09174b7c0e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -9,14 +9,6 @@ from .widgets import ( from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass -class SchemeGroupHierarchyBug(Exception): - def __init__(self, msg=None): - if not msg: - # TODO better message - msg = "SCHEME BUG: Attribute `is_group` is mixed in the hierarchy" - super(SchemeGroupHierarchyBug, self).__init__(msg) - - class ConfigObject: default_state = "" _is_overriden = False @@ -175,21 +167,10 @@ class BooleanWidget(ConfigWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): - self._as_widget = values is AS_WIDGET self._parent = parent + self._as_widget = values is AS_WIDGET - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -307,18 +288,7 @@ class IntegerWidget(ConfigWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -424,18 +394,7 @@ class FloatWidget(ConfigWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -549,17 +508,7 @@ class TextSingleLineWidget(ConfigWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -665,18 +614,7 @@ class TextMultiLineWidget(ConfigWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -857,18 +795,7 @@ class RawJsonWidget(ConfigWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -1145,18 +1072,7 @@ class TextListWidget(ConfigWidget, InputObject): ): self._parent = parent - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None @@ -1469,16 +1385,9 @@ class ModifiableDict(ExpandingWidget, InputObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - - if not any_parent_is_group and not is_group: - is_group = True - self.any_parent_is_group = any_parent_is_group - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None super(ModifiableDict, self).__init__(input_data["label"], parent) @@ -1568,13 +1477,9 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - self.any_parent_is_group = any_parent_is_group - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None self._child_state = None @@ -1759,13 +1664,9 @@ class DictWidget(ConfigWidget, ConfigObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - self.any_parent_is_group = any_parent_is_group - self.is_group = is_group + self.is_group = input_data.get("is_group", False) self._state = None self._child_state = None @@ -1963,12 +1864,8 @@ class DictInvisible(ConfigWidget, ConfigObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - is_group = input_data.get("is_group", False) - if is_group and any_parent_is_group: - raise SchemeGroupHierarchyBug() - self.any_parent_is_group = any_parent_is_group - self.is_group = is_group + self.is_group = input_data.get("is_group", False) super(DictInvisible, self).__init__(parent) self.setObjectName("DictInvisible") From bb78d47d482afcd494bf27b8822cd05d53c235f2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 20:02:09 +0200 Subject: [PATCH 198/580] implemented discard changes for form layout --- pype/tools/config_setting/config_setting/widgets/inputs.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 09174b7c0e..d4806b4a5d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2039,6 +2039,13 @@ class DictFormWidget(ConfigWidget, ConfigObject): return super(DictFormWidget, self).mouseReleaseEvent(event) + def discard_changes(self): + for item in self.input_fields.values(): + item.discard_changes() + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + def _on_value_change(self, item=None): if self.ignore_value_changes: return From a295c6420f9756e79e8b9be2005b849049e8f0c5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 20:24:44 +0200 Subject: [PATCH 199/580] removed duplicated keys --- .../1_applications_gui_schema.json | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json index bbf74a8f3f..2e60ed360d 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json @@ -36,18 +36,6 @@ "type": "boolean", "key": "harmony_17", "label": "Harmony 17" - }, { - "type": "boolean", - "key": "houdini_16", - "label": "Houdini 16" - }, { - "type": "boolean", - "key": "houdini_17", - "label": "Houdini 17" - }, { - "type": "boolean", - "key": "houdini_18", - "label": "Houdini 18" }, { "type": "boolean", "key": "maya_2017", @@ -112,6 +100,10 @@ "type": "boolean", "key": "nukestudio_12.0", "label": "NukeStudio 12.0" + }, { + "type": "boolean", + "key": "houdini_16", + "label": "Houdini 16" }, { "type": "boolean", "key": "houdini_16.5", @@ -132,10 +124,6 @@ "type": "boolean", "key": "premiere_2020", "label": "Premiere 2020" - }, { - "type": "boolean", - "key": "premiere_2020", - "label": "Premiere 2020" }, { "type": "boolean", "key": "resolve_16", From 25404fbadceb0e3afe0e7167a3e623ff9de90733 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 20:28:52 +0200 Subject: [PATCH 200/580] implemented validation for duplicated keys --- .../config_setting/widgets/lib.py | 70 ++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index e7173f1c56..fe4e514aaf 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -2,7 +2,7 @@ import os import json import copy from pype.api import config - +from queue import Queue OVERRIDEN_KEY = config.OVERRIDEN_KEY @@ -107,6 +107,21 @@ class SchemeGroupHierarchyBug(Exception): super(SchemeGroupHierarchyBug, self).__init__(msg) +class SchemaDuplicatedKeys(Exception): + def __init__(self, invalid): + items = [] + for key_path, keys in invalid.items(): + joined_keys = ", ".join([ + "\"{}\"".format(key) for key in keys + ]) + items.append("\"{}\" ({})".format(key_path, joined_keys)) + + msg = ( + "Schema items contain duplicated keys in one hierarchy level. {}" + ).format(" || ".join(items)) + super(SchemaDuplicatedKeys, self).__init__(msg) + + def file_keys_from_schema(schema_data): output = [] keys = [] @@ -203,12 +218,63 @@ def validate_is_group_is_unique_in_hierarchy( raise SchemeGroupHierarchyBug(invalid) +def validate_keys_are_unique(schema_data, keys=None): + is_top = keys is None + if keys is None: + keys = [schema_data["key"]] + else: + keys.append(schema_data["key"]) + + children = schema_data.get("children") + if not children: + return + + child_queue = Queue() + for child in children: + child_queue.put(child) + + child_inputs = [] + while not child_queue.empty(): + child = child_queue.get() + if "key" not in child: + _children = child.get("children") or [] + for _child in _children: + child_queue.put(_child) + else: + child_inputs.append(child) + + duplicated_keys = set() + child_keys = set() + for child in child_inputs: + key = child["key"] + if key in child_keys: + duplicated_keys.add(key) + else: + child_keys.add(key) + + invalid = {} + if duplicated_keys: + joined_keys = "/".join(keys) + invalid[joined_keys] = duplicated_keys + + for child in child_inputs: + result = validate_keys_are_unique(child, copy.deepcopy(keys)) + if result: + invalid.update(result) + + if not is_top: + return invalid + + if invalid: + raise SchemaDuplicatedKeys(invalid) + + def validate_schema(schema_data): - # TODO validator for key uniquenes # TODO validator that is_group key is not before is_file child # TODO validator that is_group or is_file is not on child without key validate_all_has_ending_file(schema_data) validate_is_group_is_unique_in_hierarchy(schema_data) + validate_keys_are_unique(schema_data) def gui_schema(subfolder, main_schema_name): From 850ab0a820698d21af891f7a6fc1f9e4a10ca5f6 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 27 Aug 2020 11:01:46 +0100 Subject: [PATCH 201/580] Fix collect reviews - The code logic resulted in the last track review in the context being the review file for all shots. Comparing shot naming as well to isolate to correct clip instance. - Remove "- review" from label cause its already in subset. --- pype/plugins/nukestudio/publish/collect_reviews.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pype/plugins/nukestudio/publish/collect_reviews.py b/pype/plugins/nukestudio/publish/collect_reviews.py index c158dee876..3167c66170 100644 --- a/pype/plugins/nukestudio/publish/collect_reviews.py +++ b/pype/plugins/nukestudio/publish/collect_reviews.py @@ -63,10 +63,14 @@ class CollectReviews(api.InstancePlugin): self.log.debug("Track item on plateMain") rev_inst = None for inst in instance.context[:]: - if inst.data["track"] in track: - rev_inst = inst - self.log.debug("Instance review: {}".format( - rev_inst.data["name"])) + if inst.data["track"] != track: + continue + + if inst.data["item"].name() != instance.data["item"].name(): + continue + + rev_inst = inst + break if rev_inst is None: raise RuntimeError(( @@ -82,7 +86,7 @@ class CollectReviews(api.InstancePlugin): ext = os.path.splitext(file)[-1][1:] # change label - instance.data["label"] = "{0} - {1} - ({2}) - review".format( + instance.data["label"] = "{0} - {1} - ({2})".format( instance.data['asset'], instance.data["subset"], ext ) From e074bc7733fa9464bbb0abef8f4011f56dcba6b3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:01:19 +0200 Subject: [PATCH 202/580] added hovering actions --- .../config_setting/config_setting/style/style.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index c5f1f33500..9478892b60 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -119,16 +119,29 @@ QPushButton[btn-type="expand-toggle"] { border-right-width: 0px; border-top-width: 0px; } +#ExpandingWidget:hover, #ModifiableDict:hover, #DictWidget:hover { + border-color: #62839d; +} + #ExpandingWidget[state="child-modified"], #ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { + border-color: #106aa2; +} +#ExpandingWidget[state="child-modified"]:hover, #ModifiableDict[state="child-modified"]:hover, #DictWidget[state="child-modified"]:hover { border-color: #137cbd; } #ExpandingWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"] { + border-color: #e67300; +} +#ExpandingWidget[state="child-overriden"]:hover, #ModifiableDict[state="child-overriden"]:hover, #DictWidget[state="child-overriden"]:hover { border-color: #ff8c1a; } #ExpandingWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"] { + border-color: #106aa2; +} +#ExpandingWidget[state="child-overriden-modified"]:hover, #ModifiableDict[state="child-overriden-modified"]:hover, #DictWidget[state="child-overriden-modified"]:hover { border-color: #137cbd; } From ae30e3c3befb9fecc32bc823ad52c8229d48f814 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:07:06 +0200 Subject: [PATCH 203/580] fixed raw json item value --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d4806b4a5d..8036eb5e1b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -777,6 +777,10 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): self.updateGeometry() super(RawJsonInput, self).resizeEvent(event) + def item_value(self): + value = self.value() + return json.loads(value) + def value(self): return self.toPlainText() @@ -891,7 +895,7 @@ class RawJsonWidget(ConfigWidget, InputObject): widget.style().polish(widget) def item_value(self): - return self.text_input.toPlainText() + return self.text_input.item_value() class TextListItem(QtWidgets.QWidget, ConfigObject): From b8ea2eea3a153f5abe0624735b445be50a14941c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:12:54 +0200 Subject: [PATCH 204/580] fixed text list items --- pype/tools/config_setting/config_setting/widgets/inputs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8036eb5e1b..67f1ac81ec 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -977,12 +977,13 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): self.override_value = NOT_SET def set_value(self, value, *, global_value=False): - for input_field in self.input_fields: - self.remove_row(input_field) - + previous_inputs = tuple(self.input_fields) for item_text in value: self.add_row(text=item_text) + for input_field in previous_inputs: + self.remove_row(input_field) + if global_value: self.global_value = value self.start_value = self.item_value() From 3c71ae5d2a28546c7e523cf9f3042cc2429ae589 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:21:36 +0200 Subject: [PATCH 205/580] raw json works better --- .../config_setting/widgets/inputs.py | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 67f1ac81ec..d800f8c635 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -709,6 +709,7 @@ class TextMultiLineWidget(ConfigWidget, InputObject): class RawJsonInput(QtWidgets.QPlainTextEdit): + value_changed = QtCore.Signal(object) tab_length = 4 def __init__(self, *args, **kwargs): @@ -720,7 +721,9 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): ).horizontalAdvance(" ") * self.tab_length ) + self._state = None self.is_valid = None + self.textChanged.connect(self._on_value_change) def sizeHint(self): document = self.document() @@ -742,13 +745,9 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): value = json.dumps(value, indent=4) self.setPlainText(value) - def setPlainText(self, *args, **kwargs): - super(RawJsonInput, self).setPlainText(*args, **kwargs) - self.validate() - - def focusOutEvent(self, event): - super(RawJsonInput, self).focusOutEvent(event) + def _on_value_change(self): self.validate() + self.value_changed.emit(self) def validate_value(self, value): if isinstance(value, str) and not value: @@ -760,16 +759,18 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): except Exception: return False - def update_style(self, is_valid=None): - if is_valid is None: + def update_style(self): + if self.is_valid is None: return self.validate() - if is_valid != self.is_valid: - self.is_valid = is_valid - if is_valid: - state = "" - else: - state = "invalid" + if self.is_valid: + state = "" + else: + state = "invalid" + + if self._state is None or self._state != state: + self._state = state + self.setProperty("state", state) self.style().polish(self) @@ -778,16 +779,12 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): super(RawJsonInput, self).resizeEvent(event) def item_value(self): - value = self.value() - return json.loads(value) - - def value(self): - return self.toPlainText() + return json.loads(self.toPlainText()) def validate(self): - value = self.value() - is_valid = self.validate_value(value) - self.update_style(is_valid) + value = self.toPlainText() + self.is_valid = self.validate_value(value) + self.update_style() class RawJsonWidget(ConfigWidget, InputObject): @@ -838,7 +835,7 @@ class RawJsonWidget(ConfigWidget, InputObject): self.start_value = self.item_value() self.override_value = NOT_SET - self.text_input.textChanged.connect(self._on_value_change) + self.text_input.value_changed.connect(self._on_value_change) def set_value(self, value, *, global_value=False): self.text_input.set_value(value) @@ -871,7 +868,11 @@ class RawJsonWidget(ConfigWidget, InputObject): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.global_value + if self.text_input.is_valid: + self._is_modified = self.item_value() != self.global_value + else: + self._is_modified = True + if self.is_overidable: self._is_overriden = True From 9af852b0cfd21eb03e9812dffe2fa83fd32e0737 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:24:34 +0200 Subject: [PATCH 206/580] invalid looks better --- pype/tools/config_setting/config_setting/style/style.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 9478892b60..ce014f0768 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -93,7 +93,8 @@ QPushButton[btn-type="expand-toggle"] { } #RawJsonInput[state="invalid"] { - border-left-color: #ff5511; + border-color: #ab2e46; + border-width: 2px; } #DictKey[state="modified"] { From 3fdcff6185771979966f47348e27e25d65f04f78 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:28:11 +0200 Subject: [PATCH 207/580] reset state on set value in json raw input --- pype/tools/config_setting/config_setting/widgets/inputs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d800f8c635..6568543799 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -741,6 +741,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): return value def set_value(self, value, *, global_value=False): + self._state = None if not isinstance(value, str): value = json.dumps(value, indent=4) self.setPlainText(value) From 39a1a560aa485a456eb7d4435a6686fdee780f7e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:41:45 +0200 Subject: [PATCH 208/580] fixed json files with list inside --- pype/tools/config_setting/config_setting/widgets/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index c0246dd8a2..d5f9a05aea 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -469,7 +469,10 @@ class ProjectWidget(QtWidgets.QWidget): new_values = all_values for key in key_sequence: new_values = new_values[key] - origin_values.update(new_values) + if isinstance(new_values, dict): + origin_values.update(new_values) + else: + origin_values = new_values output_path = os.path.join( config.PROJECT_PRESETS_PATH, subpath From 5fe6a1e25d5e624980dd4d8a7577e04e586f5e5a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 17:08:53 +0200 Subject: [PATCH 209/580] fixed list input --- pype/tools/config_setting/config_setting/widgets/inputs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 6568543799..c7d02471a7 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1096,8 +1096,9 @@ class TextListWidget(ConfigWidget, InputObject): layout.addWidget(label_widget) self.label_widget = label_widget + self.key = input_data["key"] keys = list(parent_keys) - keys.append(input_data["key"]) + keys.append(self.key) self.keys = keys self.value_widget = TextListSubWidget( @@ -1107,7 +1108,7 @@ class TextListWidget(ConfigWidget, InputObject): self.value_widget.value_changed.connect(self._on_value_change) # self.value_widget.se - self.key = input_data["key"] + layout.addWidget(self.value_widget) self.setLayout(layout) @@ -1160,7 +1161,7 @@ class TextListWidget(ConfigWidget, InputObject): self.label_widget.style().polish(self.label_widget) def item_value(self): - return self.value_widget.config_value() + return self.value_widget.item_value() class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): From 66f99b321194493a5933be3fa5ac18adc745daa7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 17:46:41 +0200 Subject: [PATCH 210/580] list item does not have focus on btns --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c7d02471a7..4cba89f251 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -914,6 +914,8 @@ class TextListItem(QtWidgets.QWidget, ConfigObject): self.text_input = QtWidgets.QLineEdit() self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") + self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) self.add_btn.setProperty("btn-type", "text-list") self.remove_btn.setProperty("btn-type", "text-list") From 893173e1b8511d4f89754c5b53897eade89687e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 17:46:57 +0200 Subject: [PATCH 211/580] list items has right order --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4cba89f251..d353b6e53e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1037,6 +1037,12 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): self.layout().insertWidget(row, item_widget) self.input_fields.insert(row, item_widget) + previous_input = None + for input_field in self.input_fields: + if previous_input is not None: + self.setTabOrder(previous_input, input_field.text_input) + previous_input = input_field.text_input + # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` if text is not None: From 9fbdfcc1cf4a87e2a84ff85c18ff027b3ed7ad60 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 17:50:16 +0200 Subject: [PATCH 212/580] fixed tab order of key->value for modifieble dict item --- pype/tools/config_setting/config_setting/widgets/inputs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d353b6e53e..74505bebca 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1187,7 +1187,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): ItemKlass = TypeToKlass.types[object_type] - self.key_input = QtWidgets.QLineEdit() + self.key_input = QtWidgets.QLineEdit(self) self.key_input.setObjectName("DictKey") self.value_input = ItemKlass( @@ -1200,6 +1200,9 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") + self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.add_btn.setProperty("btn-type", "text-list") self.remove_btn.setProperty("btn-type", "text-list") From a3b6d64004bb249ab6524e4c3dd4bdfdc68bae07 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 18:22:05 +0200 Subject: [PATCH 213/580] fixed most issues with tab order in modifiable dict --- .../config_setting/widgets/inputs.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 74505bebca..172b93e4ba 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -181,6 +181,9 @@ class BooleanWidget(ConfigWidget, InputObject): layout.setSpacing(5) self.checkbox = QtWidgets.QCheckBox() + + self.setFocusProxy(self.checkbox) + self.checkbox.setAttribute(QtCore.Qt.WA_StyledBackground) if not self._as_widget and not label_widget: label = input_data["label"] @@ -300,6 +303,8 @@ class IntegerWidget(ConfigWidget, InputObject): self.int_input = ModifiedIntSpinBox() + self.setFocusProxy(self.int_input) + if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) @@ -406,6 +411,8 @@ class FloatWidget(ConfigWidget, InputObject): self.float_input = ModifiedFloatSpinBox() + self.setFocusProxy(self.float_input) + decimals = input_data.get("decimals", 5) maximum = input_data.get("maximum") minimum = input_data.get("minimum") @@ -520,6 +527,8 @@ class TextSingleLineWidget(ConfigWidget, InputObject): self.text_input = QtWidgets.QLineEdit() + self.setFocusProxy(self.text_input) + if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) @@ -625,6 +634,9 @@ class TextMultiLineWidget(ConfigWidget, InputObject): layout.setSpacing(5) self.text_input = QtWidgets.QPlainTextEdit() + + self.setFocusProxy(self.text_input) + if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) @@ -813,6 +825,8 @@ class RawJsonWidget(ConfigWidget, InputObject): QtWidgets.QSizePolicy.MinimumExpanding ) + self.setFocusProxy(self.text_input) + if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) @@ -1211,6 +1225,8 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) + self.setFocusProxy(self.value_input) + self.add_btn.setFixedSize(self._btn_size, self._btn_size) self.remove_btn.setFixedSize(self._btn_size, self._btn_size) self.add_btn.clicked.connect(self.on_add_clicked) @@ -1352,6 +1368,17 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): self.layout().insertWidget(row, item_widget) self.input_fields.insert(row, item_widget) + previous_input = None + for input_field in self.input_fields: + if previous_input is not None: + self.setTabOrder( + previous_input, input_field.key_input + ) + previous_input = input_field.value_input.focusProxy() + self.setTabOrder( + input_field.key_input, previous_input + ) + # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` if value is not None and key is not None: From 401d1ad6132d7fd4dcc781150e41ca7785f9a73a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:04:04 +0200 Subject: [PATCH 214/580] make sure ignore_value_changes will raise proper error --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 172b93e4ba..050966dd63 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -38,6 +38,10 @@ class ConfigObject: @property def ignore_value_changes(self): + if not hasattr(self, "_parent"): + raise NotImplementedError( + "Object {} does not have `_parent` attribute".format(self) + ) return self._parent.ignore_value_changes @ignore_value_changes.setter From e2061c230f8023e0e150ec65afbb793bb6294248 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:04:24 +0200 Subject: [PATCH 215/580] set parenting to real input widgets --- .../config_setting/config_setting/widgets/inputs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 050966dd63..8f4d15912d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -184,7 +184,7 @@ class BooleanWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.checkbox = QtWidgets.QCheckBox() + self.checkbox = QtWidgets.QCheckBox(self) self.setFocusProxy(self.checkbox) @@ -305,7 +305,7 @@ class IntegerWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.int_input = ModifiedIntSpinBox() + self.int_input = ModifiedIntSpinBox(self) self.setFocusProxy(self.int_input) @@ -413,7 +413,7 @@ class FloatWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.float_input = ModifiedFloatSpinBox() + self.float_input = ModifiedFloatSpinBox(self) self.setFocusProxy(self.float_input) @@ -529,7 +529,7 @@ class TextSingleLineWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.text_input = QtWidgets.QLineEdit() + self.text_input = QtWidgets.QLineEdit(self) self.setFocusProxy(self.text_input) @@ -637,7 +637,7 @@ class TextMultiLineWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.text_input = QtWidgets.QPlainTextEdit() + self.text_input = QtWidgets.QPlainTextEdit(self) self.setFocusProxy(self.text_input) From 3edb2f4080f0bfadbd41732b8f32eec673afe458 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:05:30 +0200 Subject: [PATCH 216/580] TextListWidget changed to ListWidget --- .../config_setting/widgets/inputs.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8f4d15912d..67e44023e7 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1097,7 +1097,7 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): return output -class TextListWidget(ConfigWidget, InputObject): +class ListWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -1109,8 +1109,8 @@ class TextListWidget(ConfigWidget, InputObject): self._state = None - super(TextListWidget, self).__init__(parent) - self.setObjectName("TextListWidget") + super(ListWidget, self).__init__(parent) + self.setObjectName("ListWidget") layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -1127,17 +1127,16 @@ class TextListWidget(ConfigWidget, InputObject): keys.append(self.key) self.keys = keys - self.value_widget = TextListSubWidget( + self.value_widget = ListSubWidget( input_data, values, parent_keys, self ) self.value_widget.setAttribute(QtCore.Qt.WA_StyledBackground) - self.value_widget.value_changed.connect(self._on_value_change) - - # self.value_widget.se layout.addWidget(self.value_widget) self.setLayout(layout) + self.value_widget.value_changed.connect(self._on_value_change) + @property def start_value(self): return self.value_widget.start_value @@ -2178,4 +2177,4 @@ TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-expanding"] = DictExpandWidget TypeToKlass.types["dict-form"] = DictFormWidget TypeToKlass.types["dict-invisible"] = DictInvisible -TypeToKlass.types["list-text"] = TextListWidget +TypeToKlass.types["list"] = ListWidget From 4cfc0a7c1210024c709fe56c3b9cd45548d87731 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:06:46 +0200 Subject: [PATCH 217/580] TextListItem changed to ListItem --- .../config_setting/widgets/inputs.py | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 67e44023e7..e10a4a841d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -918,37 +918,50 @@ class RawJsonWidget(ConfigWidget, InputObject): return self.text_input.item_value() -class TextListItem(QtWidgets.QWidget, ConfigObject): +class ListItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, parent): - super(TextListItem, self).__init__(parent) + def __init__(self, object_type, parent): + self._parent = parent + + super(ListItem, self).__init__(parent) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - self.text_input = QtWidgets.QLineEdit() + ItemKlass = TypeToKlass.types[object_type] + self.value_input = ItemKlass( + {}, + AS_WIDGET, + [], + self, + None + ) + self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") + self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.add_btn.setFixedSize(self._btn_size, self._btn_size) + self.remove_btn.setFixedSize(self._btn_size, self._btn_size) + self.add_btn.setProperty("btn-type", "text-list") self.remove_btn.setProperty("btn-type", "text-list") - layout.addWidget(self.text_input, 1) + layout.addWidget(self.value_input, 1) layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) - self.add_btn.setFixedSize(self._btn_size, self._btn_size) - self.remove_btn.setFixedSize(self._btn_size, self._btn_size) self.add_btn.clicked.connect(self.on_add_clicked) self.remove_btn.clicked.connect(self.on_remove_clicked) - self.text_input.textChanged.connect(self._on_value_change) + self.value_input.value_changed.connect(self._on_value_change) + self.value_input.item_value() self.is_single = False def _on_value_change(self, item=None): @@ -962,12 +975,12 @@ class TextListItem(QtWidgets.QWidget, ConfigObject): def on_remove_clicked(self): if self.is_single: - self.text_input.setText("") + self.value_input.clear() else: self.parent().remove_row(self) def config_value(self): - return self.text_input.text() + return self.value_input.item_value() class TextListSubWidget(QtWidgets.QWidget, ConfigObject): From d82118cd8e8cc869ca04481d15a88e71fecb0373 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:07:06 +0200 Subject: [PATCH 218/580] TextListSubWidget changed to ListSubWidget --- .../config_setting/widgets/inputs.py | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e10a4a841d..2f0d85fd4e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -983,12 +983,14 @@ class ListItem(QtWidgets.QWidget, ConfigObject): return self.value_input.item_value() -class TextListSubWidget(QtWidgets.QWidget, ConfigObject): +class ListSubWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__(self, input_data, values, parent_keys, parent): - super(TextListSubWidget, self).__init__(parent) - self.setObjectName("TextListSubWidget") + self._parent = parent + + super(ListSubWidget, self).__init__(parent) + self.setObjectName("ListSubWidget") layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 5, 0, 5) @@ -996,7 +998,7 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): self.setLayout(layout) self.input_fields = [] - self.add_row() + self.object_type = input_data["object_type"] self.key = input_data["key"] keys = list(parent_keys) @@ -1005,7 +1007,11 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): value = self.value_from_values(values) if value is not NOT_SET: - self.set_value(value) + for item_value in value: + self.add_row(value=item_value) + + if self.count() == 0: + self.add_row() self.global_value = value self.start_value = self.item_value() @@ -1013,8 +1019,8 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): def set_value(self, value, *, global_value=False): previous_inputs = tuple(self.input_fields) - for item_text in value: - self.add_row(text=item_text) + for item_value in value: + self.add_row(value=item_value) for input_field in previous_inputs: self.remove_row(input_field) @@ -1047,9 +1053,9 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): def count(self): return len(self.input_fields) - def add_row(self, row=None, text=None): + def add_row(self, row=None, value=None): # Create new item - item_widget = TextListItem(self) + item_widget = ListItem(self.object_type, self) # Set/unset if new item is single item current_count = self.count() @@ -1071,13 +1077,15 @@ class TextListSubWidget(QtWidgets.QWidget, ConfigObject): previous_input = None for input_field in self.input_fields: if previous_input is not None: - self.setTabOrder(previous_input, input_field.text_input) - previous_input = input_field.text_input + self.setTabOrder( + previous_input, input_field.value_input.focusProxy() + ) + previous_input = input_field.value_input.focusProxy() # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` - if text is not None: - item_widget.text_input.setText(text) + if value is not None: + item_widget.value_input.set_value(value, global_value=True) else: self._on_value_change() self.parent().updateGeometry() From 710c97f9a1ee0af00a66c5f0e9cd275b6db21df1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:08:25 +0200 Subject: [PATCH 219/580] use "list" instead of "list-text" --- .../projects_schema/1_plugins_gui_schema.json | 12 ++++++++---- .../studio_schema/0_studio_gui_schema.json | 10 +++++----- .../studio_schema/1_intents_gui_schema.json | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index e6582d82b1..9f40c7871b 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -88,7 +88,8 @@ "label": "Note with intent template", "default": "{intent}: {comment}" }, { - "type": "list-text", + "type": "list", + "object_type": "text-singleline", "key": "note_labels", "label": "Note labels", "default": [] @@ -132,12 +133,14 @@ "key": "ffmpeg_args", "children": [ { - "type": "list-text", + "type": "list", + "object_type": "text-singleline", "key": "input", "label": "FFmpeg input arguments", "default": [] }, { - "type": "list-text", + "type": "list", + "object_type": "text-singleline", "key": "output", "label": "FFmpeg output arguments", "default": [] @@ -532,7 +535,8 @@ "label": "Enabled", "default": true }, { - "type": "list-text", + "type": "list", + "object_type": "text-singleline", "key": "tags_addition", "label": "Tags addition", "default": [] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index 2fd63c7cdc..921122166b 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -4,8 +4,8 @@ "label": "Studio", "children": [ { - "key": "global", "type": "dict-invisible", + "key": "global", "label": "Global", "children": [{ "type": "schema", @@ -17,15 +17,15 @@ ] }] }, { - "key": "muster", "type": "dict-invisible", + "key": "muster", "children": [{ + "type": "dict-modifiable", + "object_type": "int", "is_group": true, "is_file": true, "key": "templates_mapping", - "label": "Muster - Templates mapping", - "type": "dict-modifiable", - "object_type": "int" + "label": "Muster - Templates mapping" }] } ] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json index 1469ffc5fc..37d525cfb6 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json @@ -7,9 +7,9 @@ "children": [ { "type": "dict-modifiable", + "object_type": "text-singleline", "key": "items", - "label": "Intent Key/Label", - "object_type": "text-singleline" + "label": "Intent Key/Label" }, { "type": "text-singleline", "key": "default", From b7a847563e0cdddad0c509a3ddb21193297e5009 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 28 Aug 2020 10:53:18 +0100 Subject: [PATCH 220/580] Revamp Build Workfile in Nuke. --- pype/hosts/nuke/lib.py | 305 ---------------------------------------- pype/hosts/nuke/menu.py | 31 ++-- 2 files changed, 21 insertions(+), 315 deletions(-) diff --git a/pype/hosts/nuke/lib.py b/pype/hosts/nuke/lib.py index 8c0e37b15d..19a0784327 100644 --- a/pype/hosts/nuke/lib.py +++ b/pype/hosts/nuke/lib.py @@ -1,7 +1,6 @@ import os import re import sys -import getpass from collections import OrderedDict from avalon import api, io, lib @@ -1060,310 +1059,6 @@ def get_write_node_template_attr(node): return avalon.nuke.lib.fix_data_for_node_create(correct_data) -class BuildWorkfile(WorkfileSettings): - """ - Building first version of workfile. - - Settings are taken from presets and db. It will add all subsets - in last version for defined representaions - - Arguments: - variable (type): description - - """ - xpos = 0 - ypos = 0 - xpos_size = 80 - ypos_size = 90 - xpos_gap = 50 - ypos_gap = 50 - pos_layer = 10 - - def __init__(self, - root_path=None, - root_node=None, - nodes=None, - to_script=None, - **kwargs): - """ - A short description. - - A bit longer description. - - Argumetns: - root_path (str): description - root_node (nuke.Node): description - nodes (list): list of nuke.Node - nodes_effects (dict): dictionary with subsets - - Example: - nodes_effects = { - "plateMain": { - "nodes": [ - [("Class", "Reformat"), - ("resize", "distort"), - ("flip", True)], - - [("Class", "Grade"), - ("blackpoint", 0.5), - ("multiply", 0.4)] - ] - }, - } - - """ - - WorkfileSettings.__init__(self, - root_node=root_node, - nodes=nodes, - **kwargs) - self.to_script = to_script - # collect data for formating - self.data_tmp = { - "project": {"name": self._project["name"], - "code": self._project["data"].get("code", "")}, - "asset": self._asset or os.environ["AVALON_ASSET"], - "task": kwargs.get("task") or api.Session["AVALON_TASK"], - "hierarchy": kwargs.get("hierarchy") or pype.get_hierarchy(), - "version": kwargs.get("version", {}).get("name", 1), - "user": getpass.getuser(), - "comment": "firstBuild", - "ext": "nk" - } - - # get presets from anatomy - anatomy = get_anatomy() - # format anatomy - anatomy_filled = anatomy.format(self.data_tmp) - - # get dir and file for workfile - self.work_dir = anatomy_filled["work"]["folder"] - self.work_file = anatomy_filled["work"]["file"] - - def save_script_as(self, path=None): - # first clear anything in open window - nuke.scriptClear() - - if not path: - dir = self.work_dir - path = os.path.join( - self.work_dir, - self.work_file).replace("\\", "/") - else: - dir = os.path.dirname(path) - - # check if folder is created - if not os.path.exists(dir): - os.makedirs(dir) - - # save script to path - nuke.scriptSaveAs(path) - - def process(self, - regex_filter=None, - version=None, - representations=["exr", "dpx", "lutJson", "mov", - "preview", "png", "jpeg", "jpg"]): - """ - A short description. - - A bit longer description. - - Args: - regex_filter (raw string): regex pattern to filter out subsets - version (int): define a particular version, None gets last - representations (list): - - Returns: - type: description - - Raises: - Exception: description - - """ - - if not self.to_script: - # save the script - self.save_script_as() - - # create viewer and reset frame range - viewer = self.get_nodes(nodes_filter=["Viewer"]) - if not viewer: - vn = nuke.createNode("Viewer") - vn["xpos"].setValue(self.xpos) - vn["ypos"].setValue(self.ypos) - else: - vn = viewer[-1] - - # move position - self.position_up() - - wn = self.write_create() - wn["xpos"].setValue(self.xpos) - wn["ypos"].setValue(self.ypos) - wn["render"].setValue(True) - vn.setInput(0, wn) - - # adding backdrop under write - self.create_backdrop(label="Render write \n\n\n\nOUTPUT", - color='0xcc1102ff', layer=-1, - nodes=[wn]) - - # move position - self.position_up(4) - - # set frame range for new viewer - self.reset_frame_range_handles() - - # get all available representations - subsets = pype.get_subsets(self._asset, - regex_filter=regex_filter, - version=version, - representations=representations) - - for name, subset in subsets.items(): - log.debug("___________________") - log.debug(name) - log.debug(subset["version"]) - - nodes_backdrop = list() - for name, subset in subsets.items(): - if "lut" in name: - continue - log.info("Building Loader to: `{}`".format(name)) - version = subset["version"] - log.info("Version to: `{}`".format(version["name"])) - representations = subset["representaions"] - for repr in representations: - rn = self.read_loader(repr) - rn["xpos"].setValue(self.xpos) - rn["ypos"].setValue(self.ypos) - wn.setInput(0, rn) - - # get editional nodes - lut_subset = [s for n, s in subsets.items() - if "lut{}".format(name.lower()) in n.lower()] - log.debug(">> lut_subset: `{}`".format(lut_subset)) - - if len(lut_subset) > 0: - lsub = lut_subset[0] - fxn = self.effect_loader(lsub["representaions"][-1]) - fxn_ypos = fxn["ypos"].value() - fxn["ypos"].setValue(fxn_ypos - 100) - nodes_backdrop.append(fxn) - - nodes_backdrop.append(rn) - # move position - self.position_right() - - # adding backdrop under all read nodes - self.create_backdrop(label="Loaded Reads", - color='0x2d7702ff', layer=-1, - nodes=nodes_backdrop) - - def read_loader(self, representation): - """ - Gets Loader plugin for image sequence or mov - - Arguments: - representation (dict): avalon db entity - - """ - context = representation["context"] - - loader_name = "LoadSequence" - if "mov" in context["representation"]: - loader_name = "LoadMov" - - loader_plugin = None - for Loader in api.discover(api.Loader): - if Loader.__name__ != loader_name: - continue - - loader_plugin = Loader - - return api.load(Loader=loader_plugin, - representation=representation["_id"]) - - def effect_loader(self, representation): - """ - Gets Loader plugin for effects - - Arguments: - representation (dict): avalon db entity - - """ - loader_name = "LoadLuts" - - loader_plugin = None - for Loader in api.discover(api.Loader): - if Loader.__name__ != loader_name: - continue - - loader_plugin = Loader - - return api.load(Loader=loader_plugin, - representation=representation["_id"]) - - def write_create(self): - """ - Create render write - - Arguments: - representation (dict): avalon db entity - - """ - task = self.data_tmp["task"] - sanitized_task = re.sub('[^0-9a-zA-Z]+', '', task) - subset_name = "render{}Main".format( - sanitized_task.capitalize()) - - Create_name = "CreateWriteRender" - - creator_plugin = None - for Creator in api.discover(api.Creator): - if Creator.__name__ != Create_name: - continue - - creator_plugin = Creator - - # return api.create() - return creator_plugin(subset_name, self._asset).process() - - def create_backdrop(self, label="", color=None, layer=0, - nodes=None): - """ - Create Backdrop node - - Arguments: - color (str): nuke compatible string with color code - layer (int): layer of node usually used (self.pos_layer - 1) - label (str): the message - nodes (list): list of nodes to be wrapped into backdrop - - """ - assert isinstance(nodes, list), "`nodes` should be a list of nodes" - layer = self.pos_layer + layer - - create_backdrop(label=label, color=color, layer=layer, nodes=nodes) - - def position_reset(self, xpos=0, ypos=0): - self.xpos = xpos - self.ypos = ypos - - def position_right(self, multiply=1): - self.xpos += (self.xpos_size * multiply) + self.xpos_gap - - def position_left(self, multiply=1): - self.xpos -= (self.xpos_size * multiply) + self.xpos_gap - - def position_down(self, multiply=1): - self.ypos -= (self.ypos_size * multiply) + self.ypos_gap - - def position_up(self, multiply=1): - self.ypos -= (self.ypos_size * multiply) + self.ypos_gap - - class ExporterReview: """ Base class object for generating review data from Nuke diff --git a/pype/hosts/nuke/menu.py b/pype/hosts/nuke/menu.py index 7306add9fe..b1ef7f47c4 100644 --- a/pype/hosts/nuke/menu.py +++ b/pype/hosts/nuke/menu.py @@ -2,10 +2,12 @@ import nuke from avalon.api import Session from pype.hosts.nuke import lib +from ...lib import BuildWorkfile from pype.api import Logger log = Logger().get_logger(__name__, "nuke") + def install(): menubar = nuke.menu("Nuke") menu = menubar.findItem(Session["AVALON_LABEL"]) @@ -20,7 +22,11 @@ def install(): log.debug("Changing Item: {}".format(rm_item)) # rm_item[1].setEnabled(False) menu.removeItem(rm_item[1].name()) - menu.addCommand(new_name, lambda: workfile_settings().reset_resolution(), index=(rm_item[0])) + menu.addCommand( + new_name, + lambda: workfile_settings().reset_resolution(), + index=(rm_item[0]) + ) # replace reset frame range from avalon core to pype's name = "Reset Frame Range" @@ -31,33 +37,38 @@ def install(): log.debug("Changing Item: {}".format(rm_item)) # rm_item[1].setEnabled(False) menu.removeItem(rm_item[1].name()) - menu.addCommand(new_name, lambda: workfile_settings().reset_frame_range_handles(), index=(rm_item[0])) + menu.addCommand( + new_name, + lambda: workfile_settings().reset_frame_range_handles(), + index=(rm_item[0]) + ) # add colorspace menu item - name = "Set colorspace" + name = "Set Colorspace" menu.addCommand( name, lambda: workfile_settings().set_colorspace(), - index=(rm_item[0]+2) + index=(rm_item[0] + 2) ) log.debug("Adding menu item: {}".format(name)) # add workfile builder menu item - name = "Build First Workfile.." + name = "Build Workfile" menu.addCommand( - name, lambda: lib.BuildWorkfile().process(), - index=(rm_item[0]+7) + name, lambda: BuildWorkfile().process(), + index=(rm_item[0] + 7) ) log.debug("Adding menu item: {}".format(name)) # add item that applies all setting above - name = "Apply all settings" + name = "Apply All Settings" menu.addCommand( - name, lambda: workfile_settings().set_context_settings(), index=(rm_item[0]+3) + name, + lambda: workfile_settings().set_context_settings(), + index=(rm_item[0] + 3) ) log.debug("Adding menu item: {}".format(name)) - def uninstall(): menubar = nuke.menu("Nuke") From 98f7be5f9047f25a87b4401ca90573549e1fd667 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:26:16 +0200 Subject: [PATCH 221/580] added log to objects --- .../tools/config_setting/config_setting/widgets/inputs.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 2f0d85fd4e..573d66556e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1,4 +1,5 @@ import json +import logging from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ConfigWidget, @@ -14,6 +15,13 @@ class ConfigObject: _is_overriden = False _is_modified = False _was_overriden = False + _log = None + + @property + def log(self): + if self._log is None: + self._log = logging.getLogger(self.__class__.__name__) + return self._log @property def is_modified(self): From 95a68cca5755b56cd00822a21d1e7c353ce6173e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:28:00 +0200 Subject: [PATCH 222/580] child_modified and child_overriden are abstract --- .../config_setting/config_setting/widgets/inputs.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 573d66556e..405ad3502d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -56,6 +56,19 @@ class ConfigObject: def ignore_value_changes(self, value): self._parent.ignore_value_changes = value + @property + def child_modified(self): + """Any children item is modified.""" + raise NotImplementedError( + "{} does not have implemented `child_modified`".format(self) + ) + + @property + def child_overriden(self): + """Any children item is overriden.""" + raise NotImplementedError( + "{} does not have implemented `child_overriden`".format(self) + ) def item_value(self): raise NotImplementedError( "Method `item_value` not implemented!" From 8032a38a1a80cbd52c6f8c008520e5f5cb5eb975 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:28:35 +0200 Subject: [PATCH 223/580] added few docstrings --- .../config_setting/config_setting/widgets/inputs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 405ad3502d..eb713d5fd9 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -25,27 +25,33 @@ class ConfigObject: @property def is_modified(self): + """Has object any changes that require saving.""" return self._is_modified or (self.was_overriden != self.is_overriden) @property def is_overriden(self): + """Is object overriden so should be saved to overrides.""" return self._is_overriden or self._parent.is_overriden @property def was_overriden(self): + """Initial state after applying overrides.""" return self._was_overriden @property def is_overidable(self): + """Should care about overrides.""" return self._parent.is_overidable def any_parent_overriden(self): + """Any of parent object up to top hiearchy is overriden.""" if self._parent._is_overriden: return True return self._parent.any_parent_overriden() @property def ignore_value_changes(self): + """Most of attribute changes are ignored on value change when True.""" if not hasattr(self, "_parent"): raise NotImplementedError( "Object {} does not have `_parent` attribute".format(self) @@ -54,6 +60,7 @@ class ConfigObject: @ignore_value_changes.setter def ignore_value_changes(self, value): + """Setter for global parent item to apply changes for all inputs.""" self._parent.ignore_value_changes = value @property @@ -70,14 +77,17 @@ class ConfigObject: "{} does not have implemented `child_overriden`".format(self) ) def item_value(self): + """Value of an item without key.""" raise NotImplementedError( "Method `item_value` not implemented!" ) def config_value(self): + """Output for saving changes or overrides.""" return {self.key: self.item_value()} def value_from_values(self, values, keys=None): + """Global getter of value based on loaded values.""" if not values or values is AS_WIDGET: return NOT_SET From 1d82c562d0a0717abe3815ec16c6919edfcaf84e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:28:55 +0200 Subject: [PATCH 224/580] added is invalid attribute --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index eb713d5fd9..310717e47a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -15,6 +15,7 @@ class ConfigObject: _is_overriden = False _is_modified = False _was_overriden = False + _is_invalid = False _log = None @property @@ -38,6 +39,11 @@ class ConfigObject: """Initial state after applying overrides.""" return self._was_overriden + @property + def is_invalid(self): + """Value set in is not valid.""" + return self._is_invalid + @property def is_overidable(self): """Should care about overrides.""" From 51ad1d39372fbd2a102d1049c2520e1e313647f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:36:57 +0200 Subject: [PATCH 225/580] remove line that is not needed --- pype/tools/config_setting/config_setting/widgets/inputs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 310717e47a..b97bde5a2e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -998,7 +998,6 @@ class ListItem(QtWidgets.QWidget, ConfigObject): self.value_input.value_changed.connect(self._on_value_change) - self.value_input.item_value() self.is_single = False def _on_value_change(self, item=None): From 03c1aeac2e31df13c6232a6dc0791c95da63b2b9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:48:20 +0200 Subject: [PATCH 226/580] RawJsonInput is much simpler --- .../config_setting/widgets/inputs.py | 58 +++++-------------- 1 file changed, 15 insertions(+), 43 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b97bde5a2e..aacef27f66 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -762,7 +762,6 @@ class TextMultiLineWidget(ConfigWidget, InputObject): class RawJsonInput(QtWidgets.QPlainTextEdit): - value_changed = QtCore.Signal(object) tab_length = 4 def __init__(self, *args, **kwargs): @@ -774,10 +773,6 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): ).horizontalAdvance(" ") * self.tab_length ) - self._state = None - self.is_valid = None - self.textChanged.connect(self._on_value_change) - def sizeHint(self): document = self.document() layout = document.documentLayout() @@ -788,58 +783,35 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): height += layout.blockBoundingRect(block).height() block = block.next() - value = super(RawJsonInput, self).sizeHint() - value.setHeight(height) + hint = super(RawJsonInput, self).sizeHint() + hint.setHeight(height) - return value + return hint def set_value(self, value, *, global_value=False): - self._state = None + if not value or value is NOT_SET: + value = "" if not isinstance(value, str): - value = json.dumps(value, indent=4) + try: + value = json.dumps(value, indent=4) + except Exception: + value = "" self.setPlainText(value) - def _on_value_change(self): - self.validate() - self.value_changed.emit(self) - - def validate_value(self, value): - if isinstance(value, str) and not value: - return True + def json_value(self): + return json.loads(self.toPlainText()) + def has_invalid_value(self): try: - json.loads(value) - return True - except Exception: + self.json_value() return False - - def update_style(self): - if self.is_valid is None: - return self.validate() - - if self.is_valid: - state = "" - else: - state = "invalid" - - if self._state is None or self._state != state: - self._state = state - - self.setProperty("state", state) - self.style().polish(self) + except Exception: + return True def resizeEvent(self, event): self.updateGeometry() super(RawJsonInput, self).resizeEvent(event) - def item_value(self): - return json.loads(self.toPlainText()) - - def validate(self): - value = self.toPlainText() - self.is_valid = self.validate_value(value) - self.update_style() - class RawJsonWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) From 111912cf0fd3097158e71490ae5821e7516b8609 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:49:34 +0200 Subject: [PATCH 227/580] RawJsonWidget modified to be able to handle simpler input --- .../config_setting/widgets/inputs.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index aacef27f66..0a1dd5551b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -858,12 +858,13 @@ class RawJsonWidget(ConfigWidget, InputObject): value = self.value_from_values(values) if value is not NOT_SET: self.text_input.set_value(value) + self._is_invalid = self.text_input.has_invalid_value() self.global_value = value self.start_value = self.item_value() self.override_value = NOT_SET - self.text_input.value_changed.connect(self._on_value_change) + self.text_input.textChanged.connect(self._on_value_change) def set_value(self, value, *, global_value=False): self.text_input.set_value(value) @@ -896,10 +897,11 @@ class RawJsonWidget(ConfigWidget, InputObject): if self.ignore_value_changes: return - if self.text_input.is_valid: - self._is_modified = self.item_value() != self.global_value - else: + self._is_invalid = self.text_input.has_invalid_value() + if self._is_invalid: self._is_modified = True + else: + self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True @@ -924,7 +926,9 @@ class RawJsonWidget(ConfigWidget, InputObject): widget.style().polish(widget) def item_value(self): - return self.text_input.item_value() + if self.is_invalid: + return NOT_SET + return self.text_input.json_value() class ListItem(QtWidgets.QWidget, ConfigObject): From 358362ed6c30e4780a29456bd56504d0d9a9acc8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:50:15 +0200 Subject: [PATCH 228/580] state also works with invalid --- .../config_setting/widgets/inputs.py | 61 +++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0a1dd5551b..878ae8f05e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -112,12 +112,15 @@ class ConfigObject: value = value[key] return value - def style_state(self, is_overriden, is_modified): + def style_state(self, is_invalid, is_overriden, is_modified): items = [] - if is_overriden: - items.append("overriden") - if is_modified: - items.append("modified") + if is_invalid: + items.append("invalid") + else: + if is_overriden: + items.append("overriden") + if is_modified: + items.append("modified") return "-".join(items) or self.default_state def add_children_gui(self, child_configuration, values): @@ -306,7 +309,9 @@ class BooleanWidget(ConfigWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -413,7 +418,9 @@ class IntegerWidget(ConfigWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -529,7 +536,9 @@ class FloatWidget(ConfigWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -637,7 +646,9 @@ class TextSingleLineWidget(ConfigWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -743,7 +754,9 @@ class TextMultiLineWidget(ConfigWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -911,7 +924,9 @@ class RawJsonWidget(ConfigWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -1211,7 +1226,9 @@ class ListWidget(ConfigWidget, InputObject): self.update_style() def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -1521,7 +1538,9 @@ class ModifiableDict(ExpandingWidget, InputObject): self.update_style() def update_style(self): - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -1654,7 +1673,9 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): def update_style(self, is_overriden=None): child_modified = self.child_modified - child_state = self.style_state(self.child_overriden, child_modified) + child_state = self.style_state( + self.child_invalid, self.child_overriden, child_modified + ) if child_state: child_state = "child-{}".format(child_state) @@ -1663,7 +1684,9 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): self.style().polish(self) self._child_state = child_state - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return @@ -1856,7 +1879,9 @@ class DictWidget(ConfigWidget, ConfigObject): def update_style(self, is_overriden=None): child_modified = self.child_modified - child_state = self.style_state(self.child_overriden, child_modified) + child_state = self.style_state( + self.child_invalid, self.child_overriden, child_modified + ) if child_state: child_state = "child-{}".format(child_state) @@ -1865,7 +1890,9 @@ class DictWidget(ConfigWidget, ConfigObject): self.style().polish(self) self._child_state = child_state - state = self.style_state(self.is_overriden, self.is_modified) + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) if self._state == state: return From 55175426c48fce8cfecaf00f299eb80579360f0a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:50:38 +0200 Subject: [PATCH 229/580] implemented child invalid to be able show them --- .../config_setting/widgets/inputs.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 878ae8f05e..9c515ece8c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -82,6 +82,14 @@ class ConfigObject: raise NotImplementedError( "{} does not have implemented `child_overriden`".format(self) ) + + @property + def child_invalid(self): + """Any children item does not have valid value.""" + raise NotImplementedError( + "{} does not have implemented `child_invalid`".format(self) + ) + def item_value(self): """Value of an item without key.""" raise NotImplementedError( @@ -201,6 +209,10 @@ class InputObject(ConfigObject): def child_overriden(self): return self._is_overriden + @property + def child_invalid(self): + return self.is_invalid + def reset_children_attributes(self): return @@ -1715,6 +1727,13 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): return True return False + @property + def child_invalid(self): + for input_field in self.input_fields: + if input_field.child_invalid: + return True + return False + def item_value(self): output = {} for input_field in self.input_fields: @@ -1921,6 +1940,13 @@ class DictWidget(ConfigWidget, ConfigObject): return True return False + @property + def child_invalid(self): + for input_field in self.input_fields: + if input_field.child_invalid: + return True + return False + def item_value(self): output = {} for input_field in self.input_fields: @@ -2011,6 +2037,13 @@ class DictInvisible(ConfigWidget, ConfigObject): return True return False + @property + def child_invalid(self): + for input_field in self.input_fields: + if input_field.child_invalid: + return True + return False + def item_value(self): output = {} for input_field in self.input_fields: From 88dd72f76182dddc2d30b513910c5c0b5a383713 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 13:03:20 +0200 Subject: [PATCH 230/580] added hover color to buttons and separated item-tool btn --- pype/tools/config_setting/config_setting/style/style.css | 8 ++++++-- .../tools/config_setting/config_setting/widgets/inputs.py | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index ce014f0768..01e6503e6e 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -65,14 +65,18 @@ QPushButton { border-radius: 3px; padding: 5px; } -QPushButton[btn-type="text-list"] { +QPushButton:hover { + background-color: #31424e; +} +QPushButton[btn-type="tool-item"] { border: 1px solid #bfccd6; border-radius: 10px; } -QPushButton[btn-type="text-list"]:hover { +QPushButton[btn-type="tool-item"]:hover { border-color: #137cbd; color: #137cbd; + background-color: transparent; } QPushButton[btn-type="expand-toggle"] { diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9c515ece8c..aada384286 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -989,8 +989,8 @@ class ListItem(QtWidgets.QWidget, ConfigObject): self.add_btn.setFixedSize(self._btn_size, self._btn_size) self.remove_btn.setFixedSize(self._btn_size, self._btn_size) - self.add_btn.setProperty("btn-type", "text-list") - self.remove_btn.setProperty("btn-type", "text-list") + self.add_btn.setProperty("btn-type", "tool-item") + self.remove_btn.setProperty("btn-type", "tool-item") layout.addWidget(self.value_input, 1) layout.addWidget(self.add_btn, 0) @@ -1282,8 +1282,8 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - self.add_btn.setProperty("btn-type", "text-list") - self.remove_btn.setProperty("btn-type", "text-list") + self.add_btn.setProperty("btn-type", "tool-item") + self.remove_btn.setProperty("btn-type", "tool-item") layout.addWidget(self.key_input, 0) layout.addWidget(self.value_input, 1) From dd7772d36881c0f9c7b9454cb786180198e64ce6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 13:03:35 +0200 Subject: [PATCH 231/580] fixed dict widget invalid style --- pype/tools/config_setting/config_setting/widgets/inputs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index aada384286..afe805c69f 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1898,8 +1898,9 @@ class DictWidget(ConfigWidget, ConfigObject): def update_style(self, is_overriden=None): child_modified = self.child_modified + child_invalid = self.child_invalid child_state = self.style_state( - self.child_invalid, self.child_overriden, child_modified + child_invalid, self.child_overriden, child_modified ) if child_state: child_state = "child-{}".format(child_state) @@ -1910,7 +1911,7 @@ class DictWidget(ConfigWidget, ConfigObject): self._child_state = child_state state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + child_invalid, self.is_overriden, self.is_modified ) if self._state == state: return From a05e45acebd2894ffdf0544ba4f84a2acaedbd2c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 13:03:50 +0200 Subject: [PATCH 232/580] added invalid colors to style --- .../config_setting/style/style.css | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 01e6503e6e..c575ed64c3 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -47,6 +47,8 @@ QLabel[state="overriden-modified"] {color: #137cbd;} QLabel[state="overriden-modified"]:hover {color: #1798e8;} QLabel[state="overriden"] {color: #ff8c1a;} QLabel[state="overriden"]:hover {color: #ffa64d;} +QLabel[state="invalid"] {color: #ad2e2e; font-weight: bold;} +QLabel[state="invalid"]:hover {color: #ad2e2e; font-weight: bold;} QWidget[input-state="modified"] { border-color: #137cbd; @@ -60,6 +62,10 @@ QWidget[input-state="overriden"] { border-color: #ff8c1a; } +QWidget[input-state="invalid"] { + border-color: #ad2e2e; +} + QPushButton { border: 1px solid #aaaaaa; border-radius: 3px; @@ -96,20 +102,18 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } -#RawJsonInput[state="invalid"] { - border-color: #ab2e46; - border-width: 2px; -} - #DictKey[state="modified"] { - border-left-color: #137cbd; + border-color: #137cbd; } #DictKey[state="overriden"] { - border-left-color: #00f; + border-color: #00f; } #DictKey[state="overriden-modified"] { - border-left-color: #0f0; + border-color: #0f0; +} +#DictKey[state="invalid"] { + border-color: #ad2e2e; } #DictLabel { @@ -136,6 +140,13 @@ QPushButton[btn-type="expand-toggle"] { border-color: #137cbd; } +#ExpandingWidget[state="child-invalid"], #ModifiableDict[state="child-invalid"], #DictWidget[state="child-invalid"] { + border-color: #ad2e2e; +} +#ExpandingWidget[state="child-invalid"]:hover, #ModifiableDict[state="child-invalid"]:hover, #DictWidget[state="child-invalid"]:hover { + border-color: #c93636; +} + #ExpandingWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"] { border-color: #e67300; } From 76777790523f77aae9a235d8567a010ce4c9f6f3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:06:41 +0200 Subject: [PATCH 233/580] added methods for getting invalid items --- .../config_setting/config_setting/widgets/inputs.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index afe805c69f..be3a1813d3 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -90,6 +90,12 @@ class ConfigObject: "{} does not have implemented `child_invalid`".format(self) ) + def get_invalid(self): + """Returns invalid items all down the hierarchy.""" + raise NotImplementedError( + "{} does not have implemented `get_invalid`".format(self) + ) + def item_value(self): """Value of an item without key.""" raise NotImplementedError( @@ -213,6 +219,12 @@ class InputObject(ConfigObject): def child_invalid(self): return self.is_invalid + def get_invalid(self): + output = [] + if self.is_invalid: + output.append(self) + return output + def reset_children_attributes(self): return From c8e2963c91b0e467d00ac02ea264442066afe91c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:31:42 +0200 Subject: [PATCH 234/580] basees won't allow save invalid values --- .../config_setting/widgets/base.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index d5f9a05aea..34405d2ad0 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -99,6 +99,30 @@ class StudioWidget(QtWidgets.QWidget): self.schema = schema def _save(self): + has_invalid = False + for item in self.input_fields: + if item.child_invalid: + has_invalid = True + + if has_invalid: + invalid_items = [] + for item in self.input_fields: + invalid_items.extend(item.get_invalid()) + msg_box = QtWidgets.QMessageBox( + QtWidgets.QMessageBox.Warning, + "Invalid input", + "There is invalid value in one of inputs." + " Please lead red color and fix them." + ) + msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok) + msg_box.exec_() + + first_invalid_item = invalid_items[0] + self.scroll_widget.ensureWidgetVisible(first_invalid_item) + if first_invalid_item.isVisible(): + first_invalid_item.setFocus(True) + return + all_values = {} for item in self.input_fields: all_values.update(item.config_value()) @@ -401,6 +425,30 @@ class ProjectWidget(QtWidgets.QWidget): self.ignore_value_changes = False def _save(self): + has_invalid = False + for item in self.input_fields: + if item.child_invalid: + has_invalid = True + + if has_invalid: + invalid_items = [] + for item in self.input_fields: + invalid_items.extend(item.get_invalid()) + msg_box = QtWidgets.QMessageBox( + QtWidgets.QMessageBox.Warning, + "Invalid input", + "There is invalid value in one of inputs." + " Please lead red color and fix them." + ) + msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok) + msg_box.exec_() + + first_invalid_item = invalid_items[0] + self.scroll_widget.ensureWidgetVisible(first_invalid_item) + if first_invalid_item.isVisible(): + first_invalid_item.setFocus(True) + return + if self.project_name is None: self._save_defaults() else: From 31227069ffe219f3fad787d974772c1711eb6995 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:45:36 +0200 Subject: [PATCH 235/580] update styles after initialization --- .../config_setting/widgets/base.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 34405d2ad0..283a5ad0a4 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -93,10 +93,10 @@ class StudioWidget(QtWidgets.QWidget): self.input_fields.clear() values = {"studio": config.studio_configurations()} - schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") - self.keys = schema.get("keys", []) - self.add_children_gui(schema, values) - self.schema = schema + self.schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") + self.keys = self.schema.get("keys", []) + self.add_children_gui(self.schema, values) + self.hierarchical_style_update() def _save(self): has_invalid = False @@ -395,10 +395,10 @@ class ProjectWidget(QtWidgets.QWidget): def reset(self): values = {"project": config.global_project_configurations()} - schema = lib.gui_schema("projects_schema", "0_project_gui_schema") - self.keys = schema.get("keys", []) - self.add_children_gui(schema, values) - self.schema = schema + self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") + self.keys = self.schema.get("keys", []) + self.add_children_gui(self.schema, values) + self.hierarchical_style_update() def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] From de1ed6d639a2dfbbf86343615f80afc302d9d89e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:48:26 +0200 Subject: [PATCH 236/580] added default values to inputs --- .../config_setting/widgets/inputs.py | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index be3a1813d3..7d25880045 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -239,6 +239,7 @@ class BooleanWidget(ConfigWidget, InputObject): self._as_widget = values is AS_WIDGET self.is_group = input_data.get("is_group", False) + self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -268,14 +269,12 @@ class BooleanWidget(ConfigWidget, InputObject): keys = list(parent_keys) keys.append(self.key) self.keys = keys - - default_value = input_data.get("default", NOT_SET) value = self.value_from_values(values) if value is not NOT_SET: self.checkbox.setChecked(value) - elif default_value is not NOT_SET: - self.checkbox.setChecked(default_value) + elif self.default_value is not NOT_SET: + self.checkbox.setChecked(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -362,6 +361,7 @@ class IntegerWidget(ConfigWidget, InputObject): self._as_widget = values is AS_WIDGET self.is_group = input_data.get("is_group", False) + self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -394,6 +394,9 @@ class IntegerWidget(ConfigWidget, InputObject): if value is not NOT_SET: self.int_input.setValue(value) + elif self.default_value is not NOT_SET: + self.int_input.setValue(self.default_value) + self.global_value = value self.start_value = self.item_value() self.override_value = NOT_SET @@ -472,6 +475,7 @@ class FloatWidget(ConfigWidget, InputObject): self._as_widget = values is AS_WIDGET self.is_group = input_data.get("is_group", False) + self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -514,6 +518,9 @@ class FloatWidget(ConfigWidget, InputObject): if value is not NOT_SET: self.float_input.setValue(value) + elif self.default_value is not NOT_SET: + self.float_input.setValue(self.default_value) + self.start_value = self.item_value() self.global_value = value self.override_value = NOT_SET @@ -590,6 +597,7 @@ class TextSingleLineWidget(ConfigWidget, InputObject): self._as_widget = values is AS_WIDGET self.is_group = input_data.get("is_group", False) + self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -622,6 +630,9 @@ class TextSingleLineWidget(ConfigWidget, InputObject): if value is not NOT_SET: self.text_input.setText(value) + elif self.default_value is not NOT_SET: + self.text_input.setText(self.default_value) + self.global_value = value self.start_value = self.item_value() self.override_value = NOT_SET @@ -700,6 +711,7 @@ class TextMultiLineWidget(ConfigWidget, InputObject): self._as_widget = values is AS_WIDGET self.is_group = input_data.get("is_group", False) + self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -732,6 +744,9 @@ class TextMultiLineWidget(ConfigWidget, InputObject): if value is not NOT_SET: self.text_input.setPlainText(value) + elif self.default_value is not NOT_SET: + self.text_input.setPlainText(self.default_value) + self.global_value = value self.start_value = self.item_value() self.override_value = NOT_SET @@ -860,6 +875,7 @@ class RawJsonWidget(ConfigWidget, InputObject): self._as_widget = values is AS_WIDGET self.is_group = input_data.get("is_group", False) + self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -895,6 +911,9 @@ class RawJsonWidget(ConfigWidget, InputObject): value = self.value_from_values(values) if value is not NOT_SET: self.text_input.set_value(value) + + elif self.default_value is not NOT_SET: + self.text_input.set_value(self.default_value) self._is_invalid = self.text_input.has_invalid_value() self.global_value = value @@ -1050,6 +1069,7 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.object_type = input_data["object_type"] + self.default_value = input_data.get("default", NOT_SET) self.key = input_data["key"] keys = list(parent_keys) @@ -1061,6 +1081,10 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): for item_value in value: self.add_row(value=item_value) + elif self.default_value is not NOT_SET: + for item_value in self.default_value: + self.add_row(value=item_value) + if self.count() == 0: self.add_row() @@ -1392,6 +1416,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.object_type = input_data["object_type"] + self.default_value = input_data.get("default", NOT_SET) self.key = input_data["key"] keys = list(parent_keys) @@ -1403,6 +1428,10 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): for item_key, item_value in value.items(): self.add_row(key=item_key, value=item_value) + elif self.default_value is not NOT_SET: + for item_key, item_value in self.default_value.items(): + self.add_row(key=item_key, value=item_value) + if self.count() == 0: self.add_row() From f6839a79530b490fc9fddb576573576f7b64732a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:48:54 +0200 Subject: [PATCH 237/580] implemented get_invalid for dictionaries --- .../config_setting/widgets/inputs.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 7d25880045..e2aa2e01a1 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1775,6 +1775,12 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): return True return False + def get_invalid(self): + output = [] + for input_field in self.input_fields: + output.extend(input_field.get_invalid()) + return output + def item_value(self): output = {} for input_field in self.input_fields: @@ -1989,6 +1995,12 @@ class DictWidget(ConfigWidget, ConfigObject): return True return False + def get_invalid(self): + output = [] + for input_field in self.input_fields: + output.extend(input_field.get_invalid()) + return output + def item_value(self): output = {} for input_field in self.input_fields: @@ -2086,6 +2098,12 @@ class DictInvisible(ConfigWidget, ConfigObject): return True return False + def get_invalid(self): + output = [] + for input_field in self.input_fields: + output.extend(input_field.get_invalid()) + return output + def item_value(self): output = {} for input_field in self.input_fields: @@ -2249,6 +2267,19 @@ class DictFormWidget(ConfigWidget, ConfigObject): return True return False + @property + def child_invalid(self): + for input_field in self.input_fields.values(): + if input_field.child_invalid: + return True + return False + + def get_invalid(self): + output = [] + for input_field in self.input_fields.values(): + output.extend(input_field.get_invalid()) + return output + def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] key = child_configuration["key"] From 2dc39e276f1961a9c58aff1d3d3c03791d73c6dd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:49:43 +0200 Subject: [PATCH 238/580] set is modified on input init --- .../config_setting/widgets/inputs.py | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e2aa2e01a1..20ccf20290 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -276,9 +276,11 @@ class BooleanWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.checkbox.setChecked(self.default_value) + self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value self.checkbox.stateChanged.connect(self._on_value_change) @@ -397,9 +399,11 @@ class IntegerWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.int_input.setValue(self.default_value) + self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value self.int_input.valueChanged.connect(self._on_value_change) @@ -521,9 +525,11 @@ class FloatWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.float_input.setValue(self.default_value) + self.override_value = NOT_SET self.start_value = self.item_value() self.global_value = value - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value self.float_input.valueChanged.connect(self._on_value_change) @@ -633,9 +639,11 @@ class TextSingleLineWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.text_input.setText(self.default_value) + self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value self.text_input.textChanged.connect(self._on_value_change) @@ -747,9 +755,11 @@ class TextMultiLineWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.text_input.setPlainText(self.default_value) + self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value self.text_input.textChanged.connect(self._on_value_change) @@ -916,9 +926,11 @@ class RawJsonWidget(ConfigWidget, InputObject): self.text_input.set_value(self.default_value) self._is_invalid = self.text_input.has_invalid_value() + self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value self.text_input.textChanged.connect(self._on_value_change) @@ -1088,9 +1100,11 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): if self.count() == 0: self.add_row() + self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value def set_value(self, value, *, global_value=False): previous_inputs = tuple(self.input_fields) @@ -1435,9 +1449,12 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): if self.count() == 0: self.add_row() + self.override_value = NOT_SET + self.global_value = value self.start_value = self.config_value() - self.override_value = NOT_SET + + self._is_modified = self.global_value != self.start_value @property def is_group(self): @@ -1555,8 +1572,11 @@ class ModifiableDict(ExpandingWidget, InputObject): self.key = input_data["key"] - self.global_value = self.item_value() self.override_value = NOT_SET + self.start_value = self.value_widget.start_value + self.global_value = self.value_widget.global_value + + self._is_modified = self.global_value != self.start_value def _on_value_change(self, item=None): if self.ignore_value_changes: From 61e11552667839bbe9b53f7ddcf8f059bd0fa6dd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:50:05 +0200 Subject: [PATCH 239/580] rawjson set's invalid bool even if values changes are ignored --- pype/tools/config_setting/config_setting/widgets/inputs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 20ccf20290..9fcbd20454 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -962,6 +962,7 @@ class RawJsonWidget(ConfigWidget, InputObject): self.update_style() def _on_value_change(self, item=None): + self._is_invalid = self.text_input.has_invalid_value() if self.ignore_value_changes: return @@ -1064,7 +1065,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def config_value(self): return self.value_input.item_value() - +# TODO Move subwidget to main widget class ListSubWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) From ad69ee3e4b9179da221b39de05c2248a39874296 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 16:59:55 +0200 Subject: [PATCH 240/580] allow empty objects in raw json --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9fcbd20454..b290927ed1 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -851,9 +851,9 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): return hint def set_value(self, value, *, global_value=False): - if not value or value is NOT_SET: + if value is NOT_SET: value = "" - if not isinstance(value, str): + elif not isinstance(value, str): try: value = json.dumps(value, indent=4) except Exception: From 24ab3fcaad29b380fa854b2ac524f085bbd3b15a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 17:00:17 +0200 Subject: [PATCH 241/580] added few default values --- .../projects_schema/1_plugins_gui_schema.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 9f40c7871b..dbbcaf2b36 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -81,7 +81,8 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled" + "label": "Enabled", + "default": true }, { "type": "text-singleline", "key": "note_with_intent_template", @@ -157,11 +158,13 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled" + "label": "Enabled", + "default": true }, { "type": "raw-json", "key": "profiles", - "label": "Profiles" + "label": "Profiles", + "default": [] } ] }, { From 81a433941f1b7adbb4281157d7d1f8f76566f6e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 17:04:11 +0200 Subject: [PATCH 242/580] modified default min/max for number inputs --- pype/tools/config_setting/config_setting/widgets/widgets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 89f6782cfd..c2de371ffc 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -5,6 +5,8 @@ class ModifiedIntSpinBox(QtWidgets.QSpinBox): def __init__(self, *args, **kwargs): super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) + self.setMinimum(-99999) + self.setMaximum(99999) def wheelEvent(self, event): if self.hasFocus(): @@ -17,6 +19,8 @@ class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): def __init__(self, *args, **kwargs): super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) + self.setMinimum(-99999) + self.setMaximum(99999) def wheelEvent(self, event): if self.hasFocus(): From a910969c02b1e3488e4432b9c02fe62d3018df39 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 17:08:44 +0200 Subject: [PATCH 243/580] default number are settable by kwargs --- .../config_setting/widgets/widgets.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index c2de371ffc..0b493d307d 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -3,10 +3,12 @@ from Qt import QtWidgets, QtCore, QtGui class ModifiedIntSpinBox(QtWidgets.QSpinBox): def __init__(self, *args, **kwargs): + min_value = kwargs.pop("min", -99999) + max_value = kwargs.pop("max", 99999) super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) - self.setMinimum(-99999) - self.setMaximum(99999) + self.setMinimum(min_value) + self.setMaximum(max_value) def wheelEvent(self, event): if self.hasFocus(): @@ -17,10 +19,14 @@ class ModifiedIntSpinBox(QtWidgets.QSpinBox): class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): def __init__(self, *args, **kwargs): + min_value = kwargs.pop("min", -99999) + max_value = kwargs.pop("max", 99999) + decimals = kwargs.pop("decimal", 2) super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) - self.setMinimum(-99999) - self.setMaximum(99999) + self.setDecimals(decimals) + self.setMinimum(min_value) + self.setMaximum(max_value) def wheelEvent(self, event): if self.hasFocus(): From 0fb411cff071d383d0219a83bdf75e99ccb8f9e0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 17:15:10 +0200 Subject: [PATCH 244/580] added modifiers for number inputs --- .../studio_schema/1_tray_items.json | 4 +++- .../config_setting/widgets/inputs.py | 16 ++++++++++++++-- .../config_setting/widgets/widgets.py | 8 ++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index e6f9a41e51..45b1bc65ce 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -69,7 +69,9 @@ { "type": "int", "key": "default_port", - "label": "Default Port" + "label": "Default Port", + "minimum": 1, + "maximum": 65535 } ] }, { diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b290927ed1..4136069d6a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -355,6 +355,7 @@ class BooleanWidget(ConfigWidget, InputObject): class IntegerWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) + input_modifiers = ("minimum", "maximum") def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -373,7 +374,12 @@ class IntegerWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.int_input = ModifiedIntSpinBox(self) + kwargs = { + modifier: input_data.get(modifier) + for modifier in self.input_modifiers + if input_data.get(modifier) + } + self.int_input = ModifiedIntSpinBox(self, **kwargs) self.setFocusProxy(self.int_input) @@ -471,6 +477,7 @@ class IntegerWidget(ConfigWidget, InputObject): class FloatWidget(ConfigWidget, InputObject): value_changed = QtCore.Signal(object) + input_modifiers = ("minimum", "maximum", "decimal") def __init__( self, input_data, values, parent_keys, parent, label_widget=None @@ -489,7 +496,12 @@ class FloatWidget(ConfigWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.float_input = ModifiedFloatSpinBox(self) + kwargs = { + modifier: input_data.get(modifier) + for modifier in self.input_modifiers + if input_data.get(modifier) + } + self.float_input = ModifiedFloatSpinBox(self, **kwargs) self.setFocusProxy(self.float_input) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 0b493d307d..b824ea8720 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -3,8 +3,8 @@ from Qt import QtWidgets, QtCore, QtGui class ModifiedIntSpinBox(QtWidgets.QSpinBox): def __init__(self, *args, **kwargs): - min_value = kwargs.pop("min", -99999) - max_value = kwargs.pop("max", 99999) + min_value = kwargs.pop("minimum", -99999) + max_value = kwargs.pop("maximum", 99999) super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setMinimum(min_value) @@ -19,8 +19,8 @@ class ModifiedIntSpinBox(QtWidgets.QSpinBox): class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): def __init__(self, *args, **kwargs): - min_value = kwargs.pop("min", -99999) - max_value = kwargs.pop("max", 99999) + min_value = kwargs.pop("minimum", -99999) + max_value = kwargs.pop("maximum", 99999) decimals = kwargs.pop("decimal", 2) super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) From 95aa493aaf5f35cf8db77ccd2f0190a081d2f6a9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 17:21:51 +0200 Subject: [PATCH 245/580] added possibility of input modifier for list and modifiable dict --- .../studio_schema/0_studio_gui_schema.json | 4 ++++ .../config_setting/widgets/inputs.py | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index 921122166b..db465fb392 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -22,6 +22,10 @@ "children": [{ "type": "dict-modifiable", "object_type": "int", + "input_modifiers": { + "minimum": 0, + "maximum": 300 + }, "is_group": true, "is_file": true, "key": "templates_mapping", diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4136069d6a..35b8719bb6 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -11,6 +11,8 @@ from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass class ConfigObject: + input_modifiers = tuple() + default_state = "" _is_overriden = False _is_modified = False @@ -1018,7 +1020,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, parent): + def __init__(self, object_type, input_modifiers, parent): self._parent = parent super(ListItem, self).__init__(parent) @@ -1029,7 +1031,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): ItemKlass = TypeToKlass.types[object_type] self.value_input = ItemKlass( - {}, + input_modifiers, AS_WIDGET, [], self, @@ -1077,6 +1079,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def config_value(self): return self.value_input.item_value() + # TODO Move subwidget to main widget class ListSubWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) @@ -1095,6 +1098,7 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) + self.input_modifiers = input_data.get("input_modifiers") or {} self.key = input_data["key"] keys = list(parent_keys) @@ -1157,7 +1161,7 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): def add_row(self, row=None, value=None): # Create new item - item_widget = ListItem(self.object_type, self) + item_widget = ListItem(self.object_type, self.input_modifiers, self) # Set/unset if new item is single item current_count = self.count() @@ -1318,7 +1322,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, parent): + def __init__(self, object_type, input_modifiers, parent): self._parent = parent super(ModifiableDictItem, self).__init__(parent) @@ -1333,7 +1337,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.key_input.setObjectName("DictKey") self.value_input = ItemKlass( - {}, + input_modifiers, AS_WIDGET, [], self, @@ -1444,6 +1448,7 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) + self.input_modifiers = input_data.get("input_modifiers") or {} self.key = input_data["key"] keys = list(parent_keys) @@ -1485,7 +1490,9 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): def add_row(self, row=None, key=None, value=None): # Create new item - item_widget = ModifiableDictItem(self.object_type, self) + item_widget = ModifiableDictItem( + self.object_type, self.input_modifiers, self + ) # Set/unset if new item is single item current_count = self.count() From 7a382f3f2073fdbe34982b50781ad22f3054bc8c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 17:22:51 +0200 Subject: [PATCH 246/580] removed global input_modifiers = tuple() --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 35b8719bb6..e5a63e635a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -11,8 +11,6 @@ from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass class ConfigObject: - input_modifiers = tuple() - default_state = "" _is_overriden = False _is_modified = False From f76331207cec10b3476b8f9dcdb5024d82e25f48 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 10:02:06 +0200 Subject: [PATCH 247/580] fixed json overrides on project change --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e5a63e635a..244d3642ae 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -965,9 +965,11 @@ class RawJsonWidget(ConfigWidget, InputObject): self.override_value = override_value if override_value is NOT_SET: self._is_overriden = False + self._was_overriden = False value = self.start_value else: self._is_overriden = True + self._was_overriden = True value = override_value self.set_value(value) @@ -981,6 +983,8 @@ class RawJsonWidget(ConfigWidget, InputObject): self._is_invalid = self.text_input.has_invalid_value() if self._is_invalid: self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value else: self._is_modified = self.item_value() != self.global_value From 0797edccfd0e65e1e0d5712d853c99c2cf5a1f8b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 10:02:32 +0200 Subject: [PATCH 248/580] overrides are loaded with metadatakey --- pype/tools/config_setting/config_setting/widgets/base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 283a5ad0a4..fd558e1ea3 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -412,12 +412,13 @@ class ProjectWidget(QtWidgets.QWidget): def _on_project_change(self): project_name = self.project_list_widget.project_name() if project_name is None: - overrides = lib.NOT_SET + _overrides = lib.NOT_SET self.is_overidable = False else: - overrides = config.project_configurations_overrides(project_name) + _overrides = config.project_configurations_overrides(project_name) self.is_overidable = True + overrides = lib.convert_overrides_to_gui_data(_overrides) self.project_name = project_name self.ignore_value_changes = True for item in self.input_fields: From de0e9f2effe964ab54bdfc53e4634178ca3f7db1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 10:02:51 +0200 Subject: [PATCH 249/580] project overrides cancel modifcation changes on save --- pype/tools/config_setting/config_setting/widgets/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index fd558e1ea3..b412db5308 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -454,6 +454,7 @@ class ProjectWidget(QtWidgets.QWidget): self._save_defaults() else: self._save_overrides() + self._on_project_change() def _save_overrides(self): _data = {} From 6ea8b1ef051831f211c1e90a1aa06f34f150dba4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 10:03:00 +0200 Subject: [PATCH 250/580] changed default for few plugins --- .../projects_schema/1_plugins_gui_schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index dbbcaf2b36..c70daab32c 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -82,7 +82,7 @@ "type": "boolean", "key": "enabled", "label": "Enabled", - "default": true + "default": false }, { "type": "text-singleline", "key": "note_with_intent_template", @@ -397,7 +397,7 @@ "type": "boolean", "key": "enabled", "label": "Enabled", - "default": false + "default": true }, { "type": "raw-json", "key": "nodes", From 78a336939e1b45a32ff8623de57bcec11d8b1b2f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 10:11:09 +0200 Subject: [PATCH 251/580] added possibility to have expanded expandable dict by default --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 244d3642ae..b2b3b3990b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1690,6 +1690,10 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): self.set_content_widget(content_widget) + expanded = input_data.get("expanded", False) + if expanded: + self.toggle_content() + self.setAttribute(QtCore.Qt.WA_StyledBackground) self.content_widget = content_widget From 1bbfae31f9f7b2b25b46b7359fa7a4fe6f7ab028 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 11:05:57 +0200 Subject: [PATCH 252/580] added update_global_values method --- .../config_setting/widgets/inputs.py | 124 ++++++++++++++---- 1 file changed, 97 insertions(+), 27 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b2b3b3990b..950fdb5bf8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -262,13 +262,22 @@ class BooleanWidget(ConfigWidget, InputObject): layout.addWidget(self.checkbox, 1) - value = NOT_SET if not self._as_widget: self.label_widget = label_widget + self.key = input_data["key"] keys = list(parent_keys) keys.append(self.key) self.keys = keys + + self.update_global_values(values) + self.override_value = NOT_SET + + self.checkbox.stateChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: self.checkbox.setChecked(value) @@ -276,14 +285,11 @@ class BooleanWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.checkbox.setChecked(self.default_value) - self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - self.checkbox.stateChanged.connect(self._on_value_change) - def set_value(self, value, *, global_value=False): # Ignore value change because if `self.isChecked()` has same # value as `value` the `_on_value_change` is not triggered @@ -389,7 +395,6 @@ class IntegerWidget(ConfigWidget, InputObject): layout.addWidget(label_widget, 0) layout.addWidget(self.int_input, 1) - value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -398,6 +403,15 @@ class IntegerWidget(ConfigWidget, InputObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + self.override_value = NOT_SET + + self.int_input.valueChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: self.int_input.setValue(value) @@ -405,14 +419,11 @@ class IntegerWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.int_input.setValue(self.default_value) - self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - self.int_input.valueChanged.connect(self._on_value_change) - def set_value(self, value, *, global_value=False): self.int_input.setValue(value) if global_value: @@ -521,7 +532,6 @@ class FloatWidget(ConfigWidget, InputObject): layout.addWidget(label_widget, 0) layout.addWidget(self.float_input, 1) - value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -530,6 +540,15 @@ class FloatWidget(ConfigWidget, InputObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + self.override_value = NOT_SET + + self.float_input.valueChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: self.float_input.setValue(value) @@ -537,14 +556,11 @@ class FloatWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.float_input.setValue(self.default_value) - self.override_value = NOT_SET - self.start_value = self.item_value() self.global_value = value + self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - self.float_input.valueChanged.connect(self._on_value_change) - def set_value(self, value, *, global_value=False): self.float_input.setValue(value) if global_value: @@ -635,7 +651,6 @@ class TextSingleLineWidget(ConfigWidget, InputObject): layout.addWidget(label_widget, 0) layout.addWidget(self.text_input, 1) - value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -644,6 +659,15 @@ class TextSingleLineWidget(ConfigWidget, InputObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + self.override_value = NOT_SET + + self.text_input.textChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: self.text_input.setText(value) @@ -651,14 +675,11 @@ class TextSingleLineWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.text_input.setText(self.default_value) - self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - self.text_input.textChanged.connect(self._on_value_change) - def set_value(self, value, *, global_value=False): self.text_input.setText(value) if global_value: @@ -751,7 +772,6 @@ class TextMultiLineWidget(ConfigWidget, InputObject): layout.addWidget(label_widget, 0) layout.addWidget(self.text_input, 1) - value = NOT_SET if not self._as_widget: self.label_widget = label_widget @@ -760,6 +780,15 @@ class TextMultiLineWidget(ConfigWidget, InputObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + self.override_value = NOT_SET + + self.text_input.textChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: self.text_input.setPlainText(value) @@ -767,14 +796,11 @@ class TextMultiLineWidget(ConfigWidget, InputObject): elif self.default_value is not NOT_SET: self.text_input.setPlainText(self.default_value) - self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - self.text_input.textChanged.connect(self._on_value_change) - def set_value(self, value, *, global_value=False): self.text_input.setPlainText(value) if global_value: @@ -921,7 +947,8 @@ class RawJsonWidget(ConfigWidget, InputObject): layout.addWidget(label_widget, 0) layout.addWidget(self.text_input, 1) - value = NOT_SET + self.override_value = NOT_SET + if not self._as_widget: self.label_widget = label_widget @@ -930,22 +957,27 @@ class RawJsonWidget(ConfigWidget, InputObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + self.text_input.textChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: self.text_input.set_value(value) elif self.default_value is not NOT_SET: self.text_input.set_value(self.default_value) + self._is_invalid = self.text_input.has_invalid_value() - self.override_value = NOT_SET self.global_value = value self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - self.text_input.textChanged.connect(self._on_value_change) - def set_value(self, value, *, global_value=False): self.text_input.set_value(value) if global_value: @@ -1107,6 +1139,13 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + self.override_value = NOT_SET + + def update_global_values(self, values): + old_inputs = tuple(self.input_fields) + value = self.value_from_values(values) if value is not NOT_SET: for item_value in value: @@ -1119,7 +1158,9 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): if self.count() == 0: self.add_row() - self.override_value = NOT_SET + for old_input in old_inputs: + self.remove_row(old_input) + self.global_value = value self.start_value = self.item_value() @@ -1266,6 +1307,9 @@ class ListWidget(ConfigWidget, InputObject): self.value_widget.value_changed.connect(self._on_value_change) + def update_global_values(self, values): + self.value_widget.update_global_values(values) + @property def start_value(self): return self.value_widget.start_value @@ -1433,6 +1477,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): return {key: value} +# TODO Move subwidget to main widget class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) @@ -1457,6 +1502,11 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): keys.append(self.key) self.keys = keys + self.update_global_values(values) + + def update_global_values(self, values): + old_inputs = tuple(self.input_fields) + value = self.value_from_values(values) if value is not NOT_SET: for item_key, item_value in value.items(): @@ -1469,7 +1519,8 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): if self.count() == 0: self.add_row() - self.override_value = NOT_SET + for old_input in old_inputs: + self.remove_row(old_input) self.global_value = value self.start_value = self.config_value() @@ -1600,6 +1651,9 @@ class ModifiableDict(ExpandingWidget, InputObject): self._is_modified = self.global_value != self.start_value + def update_global_values(self, values): + self.value_widget.update_global_values(values) + def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1723,6 +1777,10 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def update_global_values(self, values): + for item in self.input_fields: + item.update_global_values(values) + def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -1943,6 +2001,10 @@ class DictWidget(ConfigWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def update_global_values(self, values): + for item in self.input_fields: + item.update_global_values(values) + def apply_overrides(self, override_value): # Make sure this is set to False self._is_overriden = False @@ -2207,6 +2269,10 @@ class DictInvisible(ConfigWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def update_global_values(self, values): + for item in self.input_fields: + item.update_global_values(values) + def apply_overrides(self, override_value): self._is_overriden = False for item in self.input_fields: @@ -2294,6 +2360,10 @@ class DictFormWidget(ConfigWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def update_global_values(self, values): + for item in self.input_fields.values(): + item.update_global_values(values) + def _on_value_change(self, item=None): if self.ignore_value_changes: return From 66d65e85105adfc79e176d04605775d3d8a345e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 11:19:41 +0200 Subject: [PATCH 253/580] global values are updated on save --- .../config_setting/widgets/base.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index b412db5308..afcac74555 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -165,6 +165,16 @@ class StudioWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(origin_values, file_stream, indent=4) + self._update_global_values() + + def _update_global_values(self): + values = {"studio": config.studio_configurations()} + for input_field in self.input_fields: + input_field.update_global_values(values) + + for input_field in self.input_fields: + input_field.hierarchical_style_update() + def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] klass = lib.TypeToKlass.types.get(item_type) @@ -454,7 +464,6 @@ class ProjectWidget(QtWidgets.QWidget): self._save_defaults() else: self._save_overrides() - self._on_project_change() def _save_overrides(self): _data = {} @@ -481,6 +490,8 @@ class ProjectWidget(QtWidgets.QWidget): with open(overrides_json_path, "w") as file_stream: json.dump(output_data, file_stream, indent=4) + self._on_project_change() + def _save_defaults(self): output = {} for item in self.input_fields: @@ -534,3 +545,13 @@ class ProjectWidget(QtWidgets.QWidget): print("Saving data to: ", output_path) with open(output_path, "w") as file_stream: json.dump(origin_values, file_stream, indent=4) + + self._update_global_values() + + def _update_global_values(self): + values = {"project": config.global_project_configurations()} + for input_field in self.input_fields: + input_field.update_global_values(values) + + for input_field in self.input_fields: + input_field.hierarchical_style_update() From b0375abaddf98c569a22e93390b9471047909773 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 15:01:16 +0200 Subject: [PATCH 254/580] removed update_style --- .../config_setting/config_setting/widgets/inputs.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 950fdb5bf8..4df9bb2736 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -317,7 +317,6 @@ class BooleanWidget(ConfigWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -451,7 +450,6 @@ class IntegerWidget(ConfigWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -583,7 +581,6 @@ class FloatWidget(ConfigWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def clear_value(self): self.set_value(0) @@ -704,7 +701,6 @@ class TextSingleLineWidget(ConfigWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def clear_value(self): self.set_value("") @@ -823,7 +819,6 @@ class TextMultiLineWidget(ConfigWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def clear_value(self): self.set_value("") @@ -1005,7 +1000,6 @@ class RawJsonWidget(ConfigWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def _on_value_change(self, item=None): self._is_invalid = self.text_input.has_invalid_value() @@ -1348,7 +1342,6 @@ class ListWidget(ConfigWidget, InputObject): self.value_widget.apply_overrides(override_value) self._is_modified = False self._state = None - self.update_style() def update_style(self): state = self.style_state( @@ -1684,7 +1677,6 @@ class ModifiableDict(ExpandingWidget, InputObject): value = override_value self.set_value(value) - self.update_style() def update_style(self): state = self.style_state( @@ -1803,7 +1795,6 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): ) ) self._was_overriden = bool(self._is_overriden) - self.update_style() def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -2026,7 +2017,7 @@ class DictWidget(ConfigWidget, ConfigObject): or self.child_overriden ) ) - self.update_style() + self._was_overriden = bool(self._is_overriden) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -2290,7 +2281,7 @@ class DictInvisible(ConfigWidget, ConfigObject): or self.child_overriden ) ) - self.update_style() + self._was_overriden = bool(self._is_overriden) def overrides(self): if not self.is_overriden and not self.child_overriden: From 084d9a9a116bc830daf103c4abe9e218da77be10 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 15:02:16 +0200 Subject: [PATCH 255/580] implemented override_value_from_values for override values --- .../config_setting/widgets/inputs.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4df9bb2736..80cb168fda 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -126,6 +126,39 @@ class ConfigObject: value = value[key] return value + def override_value_from_values(self, values, keys=None): + """Global getter of value based on loaded values.""" + if not values or values is AS_WIDGET: + return NOT_SET + + if keys is None: + keys = self.keys + + value = values + if not keys: + return value, False + + parent_value = None + last_key = None + for key in keys: + if not isinstance(value, dict): + raise TypeError( + "Expected dictionary got {}.".format(str(type(value))) + ) + if key not in value: + return NOT_SET, False + + parent_value = value + last_key = key + value = value[key] + + if not parent_value: + return value, False + + metadata = parent_value.get(METADATA_KEY) or {} + groups = metadata.get("group") or tuple() + return value, last_key in groups + def style_state(self, is_invalid, is_overriden, is_modified): items = [] if is_invalid: From 077f5c7163a7bbeea63f8cbcec9b278a27ba1927 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 16:17:56 +0200 Subject: [PATCH 256/580] different logic for applying overrides --- .../config_setting/widgets/base.py | 2 +- .../config_setting/widgets/inputs.py | 276 ++++++------------ 2 files changed, 96 insertions(+), 182 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index afcac74555..9c1fee5b6f 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -428,7 +428,7 @@ class ProjectWidget(QtWidgets.QWidget): _overrides = config.project_configurations_overrides(project_name) self.is_overidable = True - overrides = lib.convert_overrides_to_gui_data(_overrides) + overrides = {"project": lib.convert_overrides_to_gui_data(_overrides)} self.project_name = project_name self.ignore_value_changes = True for item in self.input_fields: diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 80cb168fda..3eeea4df6a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -126,39 +126,6 @@ class ConfigObject: value = value[key] return value - def override_value_from_values(self, values, keys=None): - """Global getter of value based on loaded values.""" - if not values or values is AS_WIDGET: - return NOT_SET - - if keys is None: - keys = self.keys - - value = values - if not keys: - return value, False - - parent_value = None - last_key = None - for key in keys: - if not isinstance(value, dict): - raise TypeError( - "Expected dictionary got {}.".format(str(type(value))) - ) - if key not in value: - return NOT_SET, False - - parent_value = value - last_key = key - value = value[key] - - if not parent_value: - return value, False - - metadata = parent_value.get(METADATA_KEY) or {} - groups = metadata.get("group") or tuple() - return value, last_key in groups - def style_state(self, is_invalid, is_overriden, is_modified): items = [] if is_invalid: @@ -222,6 +189,28 @@ class InputObject(ConfigObject): self._is_modified = False self._was_overriden = False + def apply_overrides(self, parent_values): + self._is_modified = False + self._state = None + + if parent_values is NOT_SET or self.key not in parent_values: + override_value = NOT_SET + else: + override_value = parent_values[self.key] + + self.override_value = override_value + + if override_value is NOT_SET: + self._is_overriden = False + self._was_overriden = False + value = self.start_value + else: + self._is_overriden = True + self._was_overriden = True + value = override_value + + self.set_value(value) + def discard_changes(self): if ( self.is_overidable @@ -336,21 +325,6 @@ class BooleanWidget(ConfigWidget, InputObject): def clear_value(self): self.set_value(False) - def apply_overrides(self, override_value): - self._is_modified = False - self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - value = self.start_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -469,21 +443,6 @@ class IntegerWidget(ConfigWidget, InputObject): def reset_value(self): self.set_value(self.start_value) - def apply_overrides(self, override_value): - self._is_modified = False - self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - value = self.global_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -602,19 +561,6 @@ class FloatWidget(ConfigWidget, InputObject): def reset_value(self): self.set_value(self.global_value) - def apply_overrides(self, override_value): - self._is_modified = False - self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - value = self.start_value - else: - self._is_overriden = True - value = override_value - - self.set_value(value) - def clear_value(self): self.set_value(0) @@ -720,21 +666,6 @@ class TextSingleLineWidget(ConfigWidget, InputObject): def reset_value(self): self.set_value(self.start_value) - def apply_overrides(self, override_value): - self._is_modified = False - self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - value = self.start_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - def clear_value(self): self.set_value("") @@ -840,19 +771,6 @@ class TextMultiLineWidget(ConfigWidget, InputObject): def reset_value(self): self.set_value(self.start_value) - def apply_overrides(self, override_value): - self._is_modified = False - self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - value = self.start_value - else: - self._is_overriden = True - value = override_value - - self.set_value(value) - def clear_value(self): self.set_value("") @@ -1019,21 +937,6 @@ class RawJsonWidget(ConfigWidget, InputObject): def clear_value(self): self.set_value("") - def apply_overrides(self, override_value): - self._is_modified = False - self._state = None - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - value = self.start_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - def _on_value_change(self, item=None): self._is_invalid = self.text_input.has_invalid_value() if self.ignore_value_changes: @@ -1206,13 +1109,22 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): self.start_value = self.item_value() self._on_value_change() - def apply_overrides(self, override_value): + # TODO use same as InputObject + def apply_overrides(self, parent_values): + if parent_values is NOT_SET or self.key not in parent_values: + override_value = NOT_SET + else: + override_value = parent_values[self.key] + self.override_value = override_value + if override_value is NOT_SET: self._is_overriden = False + self._was_overriden = False value = self.start_value else: self._is_overriden = True + self._was_overriden = True value = override_value self.set_value(value) @@ -1372,9 +1284,9 @@ class ListWidget(ConfigWidget, InputObject): self.value_widget.clear_value() def apply_overrides(self, override_value): - self.value_widget.apply_overrides(override_value) self._is_modified = False self._state = None + self.value_widget.apply_overrides(override_value) def update_style(self): state = self.style_state( @@ -1696,21 +1608,6 @@ class ModifiableDict(ExpandingWidget, InputObject): self.update_style() - def apply_overrides(self, override_value): - self._state = None - self._is_modified = False - self.override_value = override_value - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - value = self.global_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - def update_style(self): state = self.style_state( self.is_invalid, self.is_overriden, self.is_modified @@ -1806,27 +1703,30 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): for item in self.input_fields: item.update_global_values(values) - def apply_overrides(self, override_value): + def apply_overrides(self, parent_values): # Make sure this is set to False - self._is_overriden = False self._state = None self._child_state = None + + metadata = {} + groups = tuple() + override_values = NOT_SET + if parent_values is not NOT_SET: + metadata = parent_values.get(METADATA_KEY) or metadata + groups = metadata.get("groups") or groups + override_values = parent_values.get(self.key, override_values) + + self._is_overriden = self.key in groups + for item in self.input_fields: - if override_value is NOT_SET: - child_value = NOT_SET - else: - child_value = override_value.get(item.key, NOT_SET) + item.apply_overrides(override_values) - item.apply_overrides(child_value) - - self._is_overriden = ( - self.is_group - and self.is_overidable - and ( - override_value is not NOT_SET - or self.child_overriden + if not self._is_overriden: + self._is_overriden = ( + self.is_group + and self.is_overidable + and self.child_overriden ) - ) self._was_overriden = bool(self._is_overriden) def _on_value_change(self, item=None): @@ -2029,27 +1929,30 @@ class DictWidget(ConfigWidget, ConfigObject): for item in self.input_fields: item.update_global_values(values) - def apply_overrides(self, override_value): + def apply_overrides(self, parent_values): # Make sure this is set to False - self._is_overriden = False self._state = None self._child_state = None + + metadata = {} + groups = tuple() + override_values = NOT_SET + if parent_values is not NOT_SET: + metadata = parent_values.get(METADATA_KEY) or metadata + groups = metadata.get("groups") or groups + override_values = parent_values.get(self.key, override_values) + + self._is_overriden = self.key in groups + for item in self.input_fields: - if override_value is NOT_SET: - child_value = NOT_SET - else: - child_value = override_value.get(item.key, NOT_SET) + item.apply_overrides(override_values) - item.apply_overrides(child_value) - - self._is_overriden = ( - self.is_group - and self.is_overidable - and ( - override_value is not NOT_SET - or self.child_overriden + if not self._is_overriden: + self._is_overriden = ( + self.is_group + and self.is_overidable + and self.child_overriden ) - ) self._was_overriden = bool(self._is_overriden) def _on_value_change(self, item=None): @@ -2297,23 +2200,30 @@ class DictInvisible(ConfigWidget, ConfigObject): for item in self.input_fields: item.update_global_values(values) - def apply_overrides(self, override_value): - self._is_overriden = False - for item in self.input_fields: - if override_value is NOT_SET: - child_value = NOT_SET - else: - child_value = override_value.get(item.key, NOT_SET) - item.apply_overrides(child_value) + def apply_overrides(self, parent_values): + # Make sure this is set to False + self._state = None + self._child_state = None - self._is_overriden = ( - self.is_group - and self.is_overidable - and ( - override_value is not None - or self.child_overriden + metadata = {} + groups = tuple() + override_values = NOT_SET + if parent_values is not NOT_SET: + metadata = parent_values.get(METADATA_KEY) or metadata + groups = metadata.get("groups") or groups + override_values = parent_values.get(self.key, override_values) + + self._is_overriden = self.key in groups + + for item in self.input_fields: + item.apply_overrides(override_values) + + if not self._is_overriden: + self._is_overriden = ( + self.is_group + and self.is_overidable + and self.child_overriden ) - ) self._was_overriden = bool(self._is_overriden) def overrides(self): @@ -2377,6 +2287,10 @@ class DictFormWidget(ConfigWidget, ConfigObject): return super(DictFormWidget, self).mouseReleaseEvent(event) + def apply_overrides(self, parent_values): + for item in self.input_fields.values(): + item.apply_overrides(parent_values) + def discard_changes(self): for item in self.input_fields.values(): item.discard_changes() From 618b2f4825aa87608be50ba4e5491149950a7002 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 17:21:16 +0200 Subject: [PATCH 257/580] added Timers manager to tray modules --- .../config_gui_schema/studio_schema/1_tray_items.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index 45b1bc65ce..4e0e040dfe 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -44,6 +44,10 @@ "type": "boolean", "key": "Idle Manager", "label": "Idle Manager" + }, { + "type": "boolean", + "key": "Timers Manager", + "label": "Timers Manager" }, { "type": "boolean", "key": "Rest Api", From 1d72f9d01310d5ee72c6e5a51d875f13157c09ac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 17:22:18 +0200 Subject: [PATCH 258/580] fix method name --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3eeea4df6a..e054f918cd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1036,7 +1036,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def on_remove_clicked(self): if self.is_single: - self.value_input.clear() + self.value_input.clear_value() else: self.parent().remove_row(self) From 8276c7397154f3423dd184c54aee642b7770110f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 17:22:28 +0200 Subject: [PATCH 259/580] added exclude ports to schema --- .../config_gui_schema/studio_schema/1_tray_items.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index 4e0e040dfe..849019c89e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -76,6 +76,15 @@ "label": "Default Port", "minimum": 1, "maximum": 65535 + }, { + "type": "list", + "object_type": "int", + "key": "exclude_ports", + "label": "Exclude ports", + "input_modifiers": { + "minimum": 1, + "maximum": 65535 + } } ] }, { From 85df0e3dbbb507d6eab569e6403401dca0f34484 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 17:59:24 +0200 Subject: [PATCH 260/580] item widget in list is after buttons --- .../config_setting/widgets/inputs.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e054f918cd..5d41ce836c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -993,15 +993,6 @@ class ListItem(QtWidgets.QWidget, ConfigObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - ItemKlass = TypeToKlass.types[object_type] - self.value_input = ItemKlass( - input_modifiers, - AS_WIDGET, - [], - self, - None - ) - self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") @@ -1014,13 +1005,22 @@ class ListItem(QtWidgets.QWidget, ConfigObject): self.add_btn.setProperty("btn-type", "tool-item") self.remove_btn.setProperty("btn-type", "tool-item") - layout.addWidget(self.value_input, 1) layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) self.add_btn.clicked.connect(self.on_add_clicked) self.remove_btn.clicked.connect(self.on_remove_clicked) + ItemKlass = TypeToKlass.types[object_type] + self.value_input = ItemKlass( + input_modifiers, + AS_WIDGET, + [], + self, + None + ) + layout.addWidget(self.value_input, 1) + self.value_input.value_changed.connect(self._on_value_change) self.is_single = False From 2e8abd02cb29511726b6f860511b4b31a4dc01a9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 18:00:57 +0200 Subject: [PATCH 261/580] empty list is shown as disabled first item --- .../config_setting/widgets/inputs.py | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 5d41ce836c..d197e85d1e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1023,7 +1023,9 @@ class ListItem(QtWidgets.QWidget, ConfigObject): self.value_input.value_changed.connect(self._on_value_change) - self.is_single = False + def set_as_empty(self, is_empty=True): + self.value_input.setEnabled(not is_empty) + self.remove_btn.setEnabled(not is_empty) def _on_value_change(self, item=None): self.value_changed.emit(self) @@ -1032,16 +1034,18 @@ class ListItem(QtWidgets.QWidget, ConfigObject): return self.parent().input_fields.index(self) def on_add_clicked(self): - self.parent().add_row(row=self.row() + 1) + if self.value_input.isEnabled(): + self.parent().add_row(row=self.row() + 1) + else: + self.set_as_empty(False) def on_remove_clicked(self): - if self.is_single: - self.value_input.clear_value() - else: - self.parent().remove_row(self) + self.parent().remove_row(self) def config_value(self): - return self.value_input.item_value() + if self.value_input.isEnabled(): + return self.value_input.item_value() + return NOT_SET # TODO Move subwidget to main widget @@ -1085,12 +1089,12 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): for item_value in self.default_value: self.add_row(value=item_value) - if self.count() == 0: - self.add_row() - for old_input in old_inputs: self.remove_row(old_input) + if self.count() == 0: + self.add_row(is_empty=True) + self.global_value = value self.start_value = self.item_value() @@ -1141,18 +1145,11 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): def count(self): return len(self.input_fields) - def add_row(self, row=None, value=None): + def add_row(self, row=None, value=None, is_empty=False): # Create new item item_widget = ListItem(self.object_type, self.input_modifiers, self) - - # Set/unset if new item is single item - current_count = self.count() - if current_count == 0: - item_widget.is_single = True - elif current_count == 1: - for _input_field in self.input_fields: - _input_field.is_single = False - + if is_empty: + item_widget.set_as_empty() item_widget.value_changed.connect(self._on_value_change) if row is None: @@ -1186,12 +1183,8 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): item_widget.setParent(None) item_widget.deleteLater() - current_count = self.count() - if current_count == 0: - self.add_row() - elif current_count == 1: - for _input_field in self.input_fields: - _input_field.is_single = True + if self.count() == 0: + self.add_row(is_empty=True) self._on_value_change() self.parent().updateGeometry() @@ -1199,9 +1192,9 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): def item_value(self): output = [] for item in self.input_fields: - text = item.config_value() - if text: - output.append(text) + value = item.config_value() + if value is not NOT_SET: + output.append(value) return output From ed2d4175ed22d6139f4270f7cbc78860dc22a0fd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 18:08:07 +0200 Subject: [PATCH 262/580] added color for disabled widgets --- pype/tools/config_setting/config_setting/style/style.css | 4 ++++ pype/tools/config_setting/config_setting/widgets/inputs.py | 1 + 2 files changed, 5 insertions(+) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index c575ed64c3..b39eaf0802 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -5,6 +5,10 @@ QWidget { border-radius: 0px; } +QWidget:disabled { + background-color: #4e6474; +} + QMenu { border: 1px solid #555555; background-color: #1d272f; diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d197e85d1e..08bc90766f 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1026,6 +1026,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def set_as_empty(self, is_empty=True): self.value_input.setEnabled(not is_empty) self.remove_btn.setEnabled(not is_empty) + self._on_value_change() def _on_value_change(self, item=None): self.value_changed.emit(self) From 8bca9da7902cdf3422d7f3dd35b8a132d85d309c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 18:45:25 +0200 Subject: [PATCH 263/580] removed ConfigWidget --- .../config_setting/widgets/inputs.py | 66 +++++++++++++++---- .../config_setting/widgets/widgets.py | 40 +---------- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 08bc90766f..f603514784 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2,7 +2,6 @@ import json import logging from Qt import QtWidgets, QtCore, QtGui from .widgets import ( - ConfigWidget, ExpandingWidget, ModifiedIntSpinBox, ModifiedFloatSpinBox @@ -11,6 +10,8 @@ from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass class ConfigObject: + allow_actions = True + default_state = "" _is_overriden = False _is_modified = False @@ -173,6 +174,49 @@ class ConfigObject: "Method `hierarchical_style_update` not implemented!" ) + def mouseReleaseEvent(self, event): + if self.allow_actions and event.button() == QtCore.Qt.RightButton: + menu = QtWidgets.QMenu() + + actions_mapping = {} + if self.child_modified: + action = QtWidgets.QAction("Discard changes") + actions_mapping[action] = self._discard_changes + menu.addAction(action) + + if ( + not self.any_parent_overriden() + and (self.is_overriden or self.child_overriden) + ): + # TODO better label + action = QtWidgets.QAction("Remove override") + actions_mapping[action] = self._remove_overrides + menu.addAction(action) + + if not actions_mapping: + action = QtWidgets.QAction("< No action >") + actions_mapping[action] = None + menu.addAction(action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + return + + mro = type(self).mro() + index = mro.index(self.__class__) + item = None + for idx in range(index + 1, len(mro)): + _item = mro[idx] + if hasattr(_item, "mouseReleaseEvent"): + item = _item + break + + if item: + return item.mouseReleaseEvent(self, event) + class InputObject(ConfigObject): def overrides(self): @@ -251,7 +295,7 @@ class InputObject(ConfigObject): return -class BooleanWidget(ConfigWidget, InputObject): +class BooleanWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -365,7 +409,7 @@ class BooleanWidget(ConfigWidget, InputObject): return self.checkbox.isChecked() -class IntegerWidget(ConfigWidget, InputObject): +class IntegerWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) input_modifiers = ("minimum", "maximum") @@ -476,7 +520,7 @@ class IntegerWidget(ConfigWidget, InputObject): return self.int_input.value() -class FloatWidget(ConfigWidget, InputObject): +class FloatWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) input_modifiers = ("minimum", "maximum", "decimal") @@ -597,7 +641,7 @@ class FloatWidget(ConfigWidget, InputObject): return self.float_input.value() -class TextSingleLineWidget(ConfigWidget, InputObject): +class TextSingleLineWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -702,7 +746,7 @@ class TextSingleLineWidget(ConfigWidget, InputObject): return self.text_input.text() -class TextMultiLineWidget(ConfigWidget, InputObject): +class TextMultiLineWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -859,7 +903,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): super(RawJsonInput, self).resizeEvent(event) -class RawJsonWidget(ConfigWidget, InputObject): +class RawJsonWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -1200,7 +1244,7 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): return output -class ListWidget(ConfigWidget, InputObject): +class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -1841,7 +1885,7 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): return {self.key: values}, self.is_group -class DictWidget(ConfigWidget, ConfigObject): +class DictWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__( @@ -2068,7 +2112,7 @@ class DictWidget(ConfigWidget, ConfigObject): return {self.key: values}, self.is_group -class DictInvisible(ConfigWidget, ConfigObject): +class DictInvisible(QtWidgets.QWidget, ConfigObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) allow_actions = False @@ -2244,7 +2288,7 @@ class FormLabel(QtWidgets.QLabel): # Proxy for form layout -class DictFormWidget(ConfigWidget, ConfigObject): +class DictFormWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) allow_actions = False diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index b824ea8720..e551d1e9c3 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -1,4 +1,4 @@ -from Qt import QtWidgets, QtCore, QtGui +from Qt import QtWidgets, QtCore class ModifiedIntSpinBox(QtWidgets.QSpinBox): @@ -48,43 +48,7 @@ class ClickableWidget(QtWidgets.QLabel): super(ClickableWidget, self).mouseReleaseEvent(event) -class ConfigWidget(QtWidgets.QWidget): - allow_actions = True - - def mouseReleaseEvent(self, event): - if self.allow_actions and event.button() == QtCore.Qt.RightButton: - menu = QtWidgets.QMenu() - - actions_mapping = {} - if self.child_modified: - action = QtWidgets.QAction("Discard changes") - actions_mapping[action] = self._discard_changes - menu.addAction(action) - - if ( - not self.any_parent_overriden() - and (self.is_overriden or self.child_overriden) - ): - # TODO better label - action = QtWidgets.QAction("Remove override") - actions_mapping[action] = self._remove_overrides - menu.addAction(action) - - if not actions_mapping: - action = QtWidgets.QAction("< No action >") - actions_mapping[action] = None - menu.addAction(action) - - result = menu.exec_(QtGui.QCursor.pos()) - if result: - to_run = actions_mapping[result] - if to_run: - to_run() - return - super(ConfigWidget, self).mouseReleaseEvent(event) - - -class ExpandingWidget(ConfigWidget): +class ExpandingWidget(QtWidgets.QWidget): def __init__(self, label, parent): super(ExpandingWidget, self).__init__(parent) self.setObjectName("ExpandingWidget") From e7875892e992105d0698d0f2b510914408d63537 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 18:45:47 +0200 Subject: [PATCH 264/580] added better disabled style --- pype/tools/config_setting/config_setting/style/style.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index b39eaf0802..996b73b9cd 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -5,10 +5,6 @@ QWidget { border-radius: 0px; } -QWidget:disabled { - background-color: #4e6474; -} - QMenu { border: 1px solid #555555; background-color: #1d272f; @@ -36,6 +32,10 @@ QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit, QTextEdit { background-color: #1d272f; } +QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:disabled, QTextEdit:disabled, QPushButton:disabled { + background-color: #4e6474; +} + QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { border: 1px solid #ffffff; } From a1d3616bb59d12d52c3b7c2bc97ced31d6a6c4ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 19:23:56 +0200 Subject: [PATCH 265/580] removed list subwidget --- .../config_setting/widgets/inputs.py | 200 +++++++----------- 1 file changed, 74 insertions(+), 126 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f603514784..e4a1fba096 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1093,26 +1093,49 @@ class ListItem(QtWidgets.QWidget, ConfigObject): return NOT_SET -# TODO Move subwidget to main widget -class ListSubWidget(QtWidgets.QWidget, ConfigObject): +class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) - def __init__(self, input_data, values, parent_keys, parent): + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): self._parent = parent - super(ListSubWidget, self).__init__(parent) - self.setObjectName("ListSubWidget") + super(ListWidget, self).__init__(parent) + self.setObjectName("ListWidget") - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 5, 0, 5) - layout.setSpacing(3) - self.setLayout(layout) + self._state = None + self.is_group = input_data.get("is_group", False) - self.input_fields = [] self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} + self.input_fields = [] + + inputs_widget = QtWidgets.QWidget(self) + inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + + inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout.setContentsMargins(0, 5, 0, 5) + inputs_layout.setSpacing(3) + + self.inputs_widget = inputs_widget + self.inputs_layout = inputs_layout + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget) + + self.label_widget = label_widget + + layout.addWidget(inputs_widget) + self.key = input_data["key"] keys = list(parent_keys) keys.append(self.key) @@ -1122,10 +1145,22 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): self.override_value = NOT_SET + def count(self): + return len(self.input_fields) + + def reset_value(self): + self.set_value(self.start_value) + + def clear_value(self): + self.set_value([]) + def update_global_values(self, values): old_inputs = tuple(self.input_fields) value = self.value_from_values(values) + + self.global_value = value + if value is not NOT_SET: for item_value in value: self.add_row(value=item_value) @@ -1140,7 +1175,6 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): if self.count() == 0: self.add_row(is_empty=True) - self.global_value = value self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value @@ -1158,37 +1192,16 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): self.start_value = self.item_value() self._on_value_change() - # TODO use same as InputObject - def apply_overrides(self, parent_values): - if parent_values is NOT_SET or self.key not in parent_values: - override_value = NOT_SET - else: - override_value = parent_values[self.key] - - self.override_value = override_value - - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - value = self.start_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - - def reset_value(self): - self.set_value(self.start_value) - - def clear_value(self): - self.set_value([]) - def _on_value_change(self, item=None): - self.value_changed.emit(self) + if self.ignore_value_changes: + return + self._is_modified = self.item_value() != self.global_value + if self.is_overidable: + self._is_overriden = True - def count(self): - return len(self.input_fields) + self.update_style() + + self.value_changed.emit(self) def add_row(self, row=None, value=None, is_empty=False): # Create new item @@ -1234,97 +1247,27 @@ class ListSubWidget(QtWidgets.QWidget, ConfigObject): self._on_value_change() self.parent().updateGeometry() - def item_value(self): - output = [] - for item in self.input_fields: - value = item.config_value() - if value is not NOT_SET: - output.append(value) + def apply_overrides(self, parent_values): + if parent_values is NOT_SET or self.key not in parent_values: + override_value = NOT_SET + else: + override_value = parent_values[self.key] - return output + self.override_value = override_value - -class ListWidget(QtWidgets.QWidget, InputObject): - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, values, parent_keys, parent, label_widget=None - ): - self._parent = parent - - self.is_group = input_data.get("is_group", False) - - self._state = None - - super(ListWidget, self).__init__(parent) - self.setObjectName("ListWidget") - - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) - - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget) - - self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.value_widget = ListSubWidget( - input_data, values, parent_keys, self - ) - self.value_widget.setAttribute(QtCore.Qt.WA_StyledBackground) - - layout.addWidget(self.value_widget) - self.setLayout(layout) - - self.value_widget.value_changed.connect(self._on_value_change) - - def update_global_values(self, values): - self.value_widget.update_global_values(values) - - @property - def start_value(self): - return self.value_widget.start_value - - @property - def global_value(self): - return self.value_widget.global_value - - @property - def override_value(self): - return self.value_widget.override_value - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - self._is_modified = self.item_value() != self.global_value - if self.is_overidable: + if override_value is NOT_SET: + self._is_overriden = False + self._was_overriden = False + value = self.start_value + else: self._is_overriden = True + self._was_overriden = True + value = override_value - self.update_style() - - self.value_changed.emit(self) - - def set_value(self, value, *, global_value=False): - self.value_widget.set_value(value, global_value=global_value) - if global_value: - self._on_value_change() - - def reset_value(self): - self.value_widget.reset_value() - - def clear_value(self): - self.value_widget.clear_value() - - def apply_overrides(self, override_value): self._is_modified = False self._state = None - self.value_widget.apply_overrides(override_value) + + self.set_value(value) def update_style(self): state = self.style_state( @@ -1337,7 +1280,12 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.label_widget.style().polish(self.label_widget) def item_value(self): - return self.value_widget.item_value() + output = [] + for item in self.input_fields: + value = item.config_value() + if value is not NOT_SET: + output.append(value) + return output class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): From 0f1dc4271ff5da6d1b67a6a99380edaf2745795e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 19:28:04 +0200 Subject: [PATCH 266/580] list changes cleanup --- .../config_setting/widgets/inputs.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e4a1fba096..6c33ffacc0 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1028,8 +1028,8 @@ class ListItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, input_modifiers, parent): - self._parent = parent + def __init__(self, object_type, input_modifiers, config_parent, parent): + self._parent = config_parent super(ListItem, self).__init__(parent) @@ -1076,16 +1076,16 @@ class ListItem(QtWidgets.QWidget, ConfigObject): self.value_changed.emit(self) def row(self): - return self.parent().input_fields.index(self) + return self._parent.input_fields.index(self) def on_add_clicked(self): if self.value_input.isEnabled(): - self.parent().add_row(row=self.row() + 1) + self._parent.add_row(row=self.row() + 1) else: self.set_as_empty(False) def on_remove_clicked(self): - self.parent().remove_row(self) + self._parent.remove_row(self) def config_value(self): if self.value_input.isEnabled(): @@ -1205,16 +1205,18 @@ class ListWidget(QtWidgets.QWidget, InputObject): def add_row(self, row=None, value=None, is_empty=False): # Create new item - item_widget = ListItem(self.object_type, self.input_modifiers, self) + item_widget = ListItem( + self.object_type, self.input_modifiers, self, self.inputs_widget + ) if is_empty: item_widget.set_as_empty() item_widget.value_changed.connect(self._on_value_change) if row is None: - self.layout().addWidget(item_widget) + self.inputs_layout.addWidget(item_widget) self.input_fields.append(item_widget) else: - self.layout().insertWidget(row, item_widget) + self.inputs_layout.insertWidget(row, item_widget) self.input_fields.insert(row, item_widget) previous_input = None @@ -1231,12 +1233,12 @@ class ListWidget(QtWidgets.QWidget, InputObject): item_widget.value_input.set_value(value, global_value=True) else: self._on_value_change() - self.parent().updateGeometry() + self.updateGeometry() def remove_row(self, item_widget): item_widget.value_changed.disconnect() - self.layout().removeWidget(item_widget) + self.inputs_layout.removeWidget(item_widget) self.input_fields.remove(item_widget) item_widget.setParent(None) item_widget.deleteLater() @@ -1245,7 +1247,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.add_row(is_empty=True) self._on_value_change() - self.parent().updateGeometry() + self.updateGeometry() def apply_overrides(self, parent_values): if parent_values is NOT_SET or self.key not in parent_values: From 7849c707e1a756a8e6605eb3ad367a46896af6eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 19:33:26 +0200 Subject: [PATCH 267/580] added possibility to set key as overriden --- .../config_setting/widgets/inputs.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 6c33ffacc0..208bfa6685 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -169,6 +169,14 @@ class ConfigObject: ) ) + def _set_as_overriden(self): + self.ignore_value_changes = True + self.set_as_overriden() + self.ignore_value_changes = False + + def set_as_overriden(self): + self._is_overriden = True + def hierarchical_style_update(self): raise NotImplementedError( "Method `hierarchical_style_update` not implemented!" @@ -184,6 +192,15 @@ class ConfigObject: actions_mapping[action] = self._discard_changes menu.addAction(action) + if ( + self.is_overidable + and not self.is_overriden + and not self.any_parent_is_group + ): + action = QtWidgets.QAction("Set as overriden") + actions_mapping[action] = self._set_as_overriden + menu.addAction(action) + if ( not self.any_parent_overriden() and (self.is_overriden or self.child_overriden) From 1ab9162b3b94e1d757bb62c3377263d45883504e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 19:55:50 +0200 Subject: [PATCH 268/580] is group is abstract attribute --- .../config_setting/widgets/inputs.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 208bfa6685..d8121367e3 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -13,10 +13,13 @@ class ConfigObject: allow_actions = True default_state = "" + _is_overriden = False _is_modified = False _was_overriden = False _is_invalid = False + _is_group = False + _log = None @property @@ -45,6 +48,11 @@ class ConfigObject: """Value set in is not valid.""" return self._is_invalid + @property + def is_group(self): + """Value set in is not valid.""" + return self._is_group + @property def is_overidable(self): """Should care about overrides.""" @@ -321,7 +329,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -436,7 +444,7 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -547,7 +555,7 @@ class FloatWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -667,7 +675,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -772,7 +780,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -929,7 +937,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -1122,7 +1130,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.setObjectName("ListWidget") self._state = None - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) @@ -1572,7 +1580,7 @@ class ModifiableDict(ExpandingWidget, InputObject): self.any_parent_is_group = any_parent_is_group - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self._state = None super(ModifiableDict, self).__init__(input_data["label"], parent) @@ -1656,7 +1664,7 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self._state = None self._child_state = None @@ -1870,7 +1878,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) self._state = None self._child_state = None @@ -2094,7 +2102,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): any_parent_is_group = parent.any_parent_is_group self.any_parent_is_group = any_parent_is_group - self.is_group = input_data.get("is_group", False) + self._is_group = input_data.get("is_group", False) super(DictInvisible, self).__init__(parent) self.setObjectName("DictInvisible") @@ -2270,7 +2278,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group - self.is_group = False + self._is_group = False super(DictFormWidget, self).__init__(parent) From 724fe35c84aff0cb00503d4f3fc5f88e0b0766d3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 19:56:07 +0200 Subject: [PATCH 269/580] set as overriden is abstract method --- .../config_setting/widgets/inputs.py | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d8121367e3..1261f3b91b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -183,7 +183,9 @@ class ConfigObject: self.ignore_value_changes = False def set_as_overriden(self): - self._is_overriden = True + raise NotImplementedError( + "Method `set_as_overriden` not implemented!" + ) def hierarchical_style_update(self): raise NotImplementedError( @@ -298,6 +300,9 @@ class InputObject(ConfigObject): self._is_modified = False self._is_overriden = self._was_overriden + def set_as_overriden(self): + self._is_overriden = True + @property def child_modified(self): return self.is_modified @@ -1712,6 +1717,17 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def set_as_overriden(self): + if self.is_overriden: + return + + if self.is_group: + self._is_overriden = True + return + + for item in self.input_fields: + item.set_as_overriden() + def update_global_values(self, values): for item in self.input_fields: item.update_global_values(values) @@ -1938,6 +1954,17 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def set_as_overriden(self): + if self.is_overriden: + return + + if self.is_group: + self._is_overriden = True + return + + for item in self.input_fields: + item.set_as_overriden() + def update_global_values(self, values): for item in self.input_fields: item.update_global_values(values) @@ -2209,6 +2236,17 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def set_as_overriden(self): + if self.is_overriden: + return + + if self.is_group: + self._is_overriden = True + return + + for item in self.input_fields: + item.set_as_overriden() + def update_global_values(self, values): for item in self.input_fields: item.update_global_values(values) @@ -2311,6 +2349,17 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def set_as_overriden(self): + if self.is_overriden: + return + + if self.is_group: + self._is_overriden = True + return + + for item in self.input_fields: + item.set_as_overriden() + def update_global_values(self, values): for item in self.input_fields.values(): item.update_global_values(values) From e7a451775611dfe0e14039f2db110e4404a3673d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 20:09:01 +0200 Subject: [PATCH 270/580] fixed determination of overriden keys --- .../tools/config_setting/config_setting/widgets/inputs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 1261f3b91b..0c35f7d10d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1821,7 +1821,7 @@ class DictExpandWidget(ExpandingWidget, ConfigObject): @property def child_overriden(self): for input_field in self.input_fields: - if input_field.child_overriden: + if input_field.is_overriden or input_field.child_overriden: return True return False @@ -2059,7 +2059,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): @property def child_overriden(self): for input_field in self.input_fields: - if input_field.child_overriden: + if input_field.is_overriden or input_field.child_overriden: return True return False @@ -2162,7 +2162,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): @property def child_overriden(self): for input_field in self.input_fields: - if input_field.child_overriden: + if input_field.is_overriden or input_field.child_overriden: return True return False @@ -2379,7 +2379,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): @property def child_overriden(self): for input_field in self.input_fields.values(): - if input_field.child_overriden: + if input_field.is_overriden or input_field.child_overriden: return True return False From d7f48119ed3b7966a413872882b5f3fde38cdb13 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 20:09:55 +0200 Subject: [PATCH 271/580] added testing function --- .../config_setting/config_setting/widgets/tests.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/tests.py b/pype/tools/config_setting/config_setting/widgets/tests.py index 16c97a85ef..fc53e38ad5 100644 --- a/pype/tools/config_setting/config_setting/widgets/tests.py +++ b/pype/tools/config_setting/config_setting/widgets/tests.py @@ -1,6 +1,17 @@ from Qt import QtWidgets, QtCore +def indented_print(data, indent=0): + spaces = " " * (indent * 4) + if not isinstance(data, dict): + print("{}{}".format(spaces, data)) + return + + for key, value in data.items(): + print("{}{}".format(spaces, key)) + indented_print(value, indent + 1) + + class SelectableMenu(QtWidgets.QMenu): selection_changed = QtCore.Signal() From 5986041bf0caaa37be01d6b7175adb5bf38b3949 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 20:26:22 +0200 Subject: [PATCH 272/580] get rid of subwidget of modifiable dictionary --- .../config_setting/widgets/inputs.py | 262 ++++++++---------- 1 file changed, 122 insertions(+), 140 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0c35f7d10d..91882de958 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1324,8 +1324,8 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, input_modifiers, parent): - self._parent = parent + def __init__(self, object_type, input_modifiers, config_parent, parent): + self._parent = config_parent super(ModifiableDictItem, self).__init__(parent) @@ -1413,17 +1413,17 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.key_input.style().polish(self.key_input) def row(self): - return self.parent().input_fields.index(self) + return self._parent.input_fields.index(self) def on_add_clicked(self): - self.parent().add_row(row=self.row() + 1) + self._parent.add_row(row=self.row() + 1) def on_remove_clicked(self): if self.is_single: self.value_input.clear_value() self.key_input.setText("") else: - self.parent().remove_row(self) + self._parent.remove_row(self) def config_value(self): key = self.key_input.text() @@ -1433,22 +1433,44 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): return {key: value} -# TODO Move subwidget to main widget -class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): +class ModifiableDict(ExpandingWidget, InputObject): + # Should be used only for dictionary with one datatype as value + # TODO this is actually input field (do not care if is group or not) value_changed = QtCore.Signal(object) - def __init__(self, input_data, values, parent_keys, parent): + def __init__( + self, input_data, values, parent_keys, parent, + label_widget=None + ): self._parent = parent - super(ModifiableDictSubWidget, self).__init__(parent) - self.setObjectName("ModifiableDictSubWidget") + super(ModifiableDict, self).__init__(input_data["label"], parent) + self.setObjectName("ModifiableDict") - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(5, 5, 0, 5) - layout.setSpacing(5) - self.setLayout(layout) + self._state = None self.input_fields = [] + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + self.any_parent_is_group = any_parent_is_group + + self._is_group = input_data.get("is_group", False) + + inputs_widget = QtWidgets.QWidget(self) + inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + + inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout.setContentsMargins(5, 5, 0, 5) + inputs_layout.setSpacing(5) + + self.set_content_widget(inputs_widget) + + self.inputs_widget = inputs_widget + self.inputs_layout = inputs_layout + self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} @@ -1458,12 +1480,20 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): keys.append(self.key) self.keys = keys + self.override_value = NOT_SET + self.update_global_values(values) + def count(self): + return len(self.input_fields) + def update_global_values(self, values): old_inputs = tuple(self.input_fields) value = self.value_from_values(values) + + self.global_value = value + if value is not NOT_SET: for item_key, item_value in value.items(): self.add_row(key=item_key, value=item_value) @@ -1478,137 +1508,22 @@ class ModifiableDictSubWidget(QtWidgets.QWidget, ConfigObject): for old_input in old_inputs: self.remove_row(old_input) - self.global_value = value - self.start_value = self.config_value() + self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value - @property - def is_group(self): - return self._parent.is_group + def set_value(self, value, *, global_value=False): + previous_inputs = tuple(self.input_fields) + for item_key, item_value in value.items(): + self.add_row(key=item_key, value=item_value) - @property - def any_parent_is_group(self): - return self._parent.any_parent_is_group + for input_field in previous_inputs: + self.remove_row(input_field) - def _on_value_change(self, item=None): - self.value_changed.emit(self) - - def count(self): - return len(self.input_fields) - - def add_row(self, row=None, key=None, value=None): - # Create new item - item_widget = ModifiableDictItem( - self.object_type, self.input_modifiers, self - ) - - # Set/unset if new item is single item - current_count = self.count() - if current_count == 0: - item_widget.is_single = True - elif current_count == 1: - for _input_field in self.input_fields: - _input_field.is_single = False - - item_widget.value_changed.connect(self._on_value_change) - - if row is None: - self.layout().addWidget(item_widget) - self.input_fields.append(item_widget) - else: - self.layout().insertWidget(row, item_widget) - self.input_fields.insert(row, item_widget) - - previous_input = None - for input_field in self.input_fields: - if previous_input is not None: - self.setTabOrder( - previous_input, input_field.key_input - ) - previous_input = input_field.value_input.focusProxy() - self.setTabOrder( - input_field.key_input, previous_input - ) - - # Set value if entered value is not None - # else (when add button clicked) trigger `_on_value_change` - if value is not None and key is not None: - item_widget.default_key = key - item_widget.key_input.setText(key) - item_widget.value_input.set_value(value, global_value=True) - else: + if global_value: + self.global_value = value + self.start_value = self.item_value() self._on_value_change() - self.parent().updateGeometry() - - def remove_row(self, item_widget): - item_widget.value_changed.disconnect() - - self.layout().removeWidget(item_widget) - self.input_fields.remove(item_widget) - item_widget.setParent(None) - item_widget.deleteLater() - - current_count = self.count() - if current_count == 0: - self.add_row() - elif current_count == 1: - for _input_field in self.input_fields: - _input_field.is_single = True - - self._on_value_change() - self.parent().updateGeometry() - - def config_value(self): - output = {} - for item in self.input_fields: - item_value = item.config_value() - if item_value: - output.update(item_value) - return output - - -class ModifiableDict(ExpandingWidget, InputObject): - # Should be used only for dictionary with one datatype as value - # TODO this is actually input field (do not care if is group or not) - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, values, parent_keys, parent, - label_widget=None - ): - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self.any_parent_is_group = any_parent_is_group - - self._is_group = input_data.get("is_group", False) - self._state = None - - super(ModifiableDict, self).__init__(input_data["label"], parent) - self.setObjectName("ModifiableDict") - - self.value_widget = ModifiableDictSubWidget( - input_data, values, parent_keys, self - ) - self.value_widget.setAttribute(QtCore.Qt.WA_StyledBackground) - self.value_widget.value_changed.connect(self._on_value_change) - - self.set_content_widget(self.value_widget) - - self.key = input_data["key"] - - self.override_value = NOT_SET - self.start_value = self.value_widget.start_value - self.global_value = self.value_widget.global_value - - self._is_modified = self.global_value != self.start_value - - def update_global_values(self, values): - self.value_widget.update_global_values(values) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -1647,7 +1562,74 @@ class ModifiableDict(ExpandingWidget, InputObject): self._state = state def item_value(self): - return self.value_widget.config_value() + output = {} + for item in self.input_fields: + item_value = item.config_value() + if item_value: + output.update(item_value) + return output + + def add_row(self, row=None, key=None, value=None): + # Create new item + item_widget = ModifiableDictItem( + self.object_type, self.input_modifiers, self, self.inputs_widget + ) + + # Set/unset if new item is single item + current_count = self.count() + if current_count == 0: + item_widget.is_single = True + elif current_count == 1: + for _input_field in self.input_fields: + _input_field.is_single = False + + item_widget.value_changed.connect(self._on_value_change) + + if row is None: + self.inputs_layout.addWidget(item_widget) + self.input_fields.append(item_widget) + else: + self.inputs_layout.insertWidget(row, item_widget) + self.input_fields.insert(row, item_widget) + + previous_input = None + for input_field in self.input_fields: + if previous_input is not None: + self.setTabOrder( + previous_input, input_field.key_input + ) + previous_input = input_field.value_input.focusProxy() + self.setTabOrder( + input_field.key_input, previous_input + ) + + # Set value if entered value is not None + # else (when add button clicked) trigger `_on_value_change` + if value is not None and key is not None: + item_widget.default_key = key + item_widget.key_input.setText(key) + item_widget.value_input.set_value(value, global_value=True) + else: + self._on_value_change() + self.parent().updateGeometry() + + def remove_row(self, item_widget): + item_widget.value_changed.disconnect() + + self.inputs_layout.removeWidget(item_widget) + self.input_fields.remove(item_widget) + item_widget.setParent(None) + item_widget.deleteLater() + + current_count = self.count() + if current_count == 0: + self.add_row() + elif current_count == 1: + for _input_field in self.input_fields: + _input_field.is_single = True + + self._on_value_change() + self.parent().updateGeometry() # Dictionaries From 416de13fe270b4512609c4da58a48a212881ee06 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 20:34:33 +0200 Subject: [PATCH 273/580] fixed form group for overrides --- .../config_setting/config_setting/widgets/inputs.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 91882de958..873481e352 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2331,6 +2331,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + for item in self.input_fields.values(): + item.remove_overrides() + def set_as_overriden(self): if self.is_overriden: return @@ -2350,6 +2357,8 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): if self.ignore_value_changes: return self.value_changed.emit(self) + if self.any_parent_is_group: + self.hierarchical_style_update() @property def child_modified(self): @@ -2419,7 +2428,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): values = {} groups = [] - for input_field in self.input_fields: + for input_field in self.input_fields.values(): value, is_group = input_field.overrides() if value is not NOT_SET: values.update(value) @@ -2427,7 +2436,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): groups.extend(value.keys()) if groups: values[METADATA_KEY] = {"groups": groups} - return {self.key: values}, self.is_group + return values, self.is_group TypeToKlass.types["boolean"] = BooleanWidget From 008204f7d9b3a30f77392b17da2d38aacb9a9f43 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 31 Aug 2020 20:35:14 +0200 Subject: [PATCH 274/580] added form widget to overridable configurations --- .../projects_schema/1_plugins_gui_schema.json | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index c70daab32c..bed839e6dc 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -21,40 +21,45 @@ "is_group": true, "children": [ { - "type": "boolean", - "key": "enabled", - "label": "Enabled", - "default": true - }, { - "type": "text-singleline", - "key": "deadline_department", - "label": "Deadline apartment", - "default": "" - }, { - "type": "int", - "key": "deadline_priority", - "label": "Deadline priority", - "default": 50 - }, { - "type": "text-singleline", - "key": "deadline_pool", - "label": "Deadline pool", - "default": "" - }, { - "type": "text-singleline", - "key": "deadline_pool_secondary", - "label": "Deadline pool (secondary)", - "default": "" - }, { - "type": "text-singleline", - "key": "deadline_group", - "label": "Deadline Group", - "default": "" - }, { - "type": "int", - "key": "deadline_chunk_size", - "label": "Deadline Chunk size", - "default": 10 + "type": "dict-form", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": true + }, { + "type": "text-singleline", + "key": "deadline_department", + "label": "Deadline apartment", + "default": "" + }, { + "type": "int", + "key": "deadline_priority", + "label": "Deadline priority", + "default": 50 + }, { + "type": "text-singleline", + "key": "deadline_pool", + "label": "Deadline pool", + "default": "" + }, { + "type": "text-singleline", + "key": "deadline_pool_secondary", + "label": "Deadline pool (secondary)", + "default": "" + }, { + "type": "text-singleline", + "key": "deadline_group", + "label": "Deadline Group", + "default": "" + }, { + "type": "int", + "key": "deadline_chunk_size", + "label": "Deadline Chunk size", + "default": 10 + } + ] } ] } From 2e1dbec431df446c941b297694fe695e3643443f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 09:45:51 +0200 Subject: [PATCH 275/580] added any_parent_is_group to RawJson --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 873481e352..82befa3276 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -942,6 +942,12 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + self.any_parent_is_group = any_parent_is_group + self._is_group = input_data.get("is_group", False) self.default_value = input_data.get("default", NOT_SET) From 1cafdb0aa89e0fd8c6fcb1deadd53ecb1afad0f9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 09:46:10 +0200 Subject: [PATCH 276/580] input_fields in FormWidget are in list not dict --- .../config_setting/widgets/inputs.py | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 82befa3276..8c9e4a054b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2308,7 +2308,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): super(DictFormWidget, self).__init__(parent) - self.input_fields = {} + self.input_fields = [] self.content_layout = QtWidgets.QFormLayout(self) self.keys = list(parent_keys) @@ -2327,11 +2327,11 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): super(DictFormWidget, self).mouseReleaseEvent(event) def apply_overrides(self, parent_values): - for item in self.input_fields.values(): + for item in self.input_fields: item.apply_overrides(parent_values) def discard_changes(self): - for item in self.input_fields.values(): + for item in self.input_fields: item.discard_changes() self._is_modified = self.child_modified @@ -2341,7 +2341,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self._is_overriden = False self._is_modified = False self._was_overriden = False - for item in self.input_fields.values(): + for item in self.input_fields: item.remove_overrides() def set_as_overriden(self): @@ -2356,7 +2356,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): item.set_as_overriden() def update_global_values(self, values): - for item in self.input_fields.values(): + for item in self.input_fields: item.update_global_values(values) def _on_value_change(self, item=None): @@ -2368,34 +2368,33 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): @property def child_modified(self): - for input_field in self.input_fields.values(): + for input_field in self.input_fields: if input_field.child_modified: return True return False @property def child_overriden(self): - for input_field in self.input_fields.values(): + for input_field in self.input_fields: if input_field.is_overriden or input_field.child_overriden: return True return False @property def child_invalid(self): - for input_field in self.input_fields.values(): + for input_field in self.input_fields: if input_field.child_invalid: return True return False def get_invalid(self): output = [] - for input_field in self.input_fields.values(): + for input_field in self.input_fields: output.extend(input_field.get_invalid()) return output def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] - key = child_configuration["key"] # Pop label to not be set in child label = child_configuration["label"] @@ -2410,16 +2409,16 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): item.value_changed.connect(self._on_value_change) self.content_layout.addRow(label_widget, item) - self.input_fields[key] = item + self.input_fields.append(item) return item def hierarchical_style_update(self): - for input_field in self.input_fields.values(): + for input_field in self.input_fields: input_field.hierarchical_style_update() def item_value(self): output = {} - for input_field in self.input_fields.values(): + for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts output.update(input_field.config_value()) @@ -2434,7 +2433,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): values = {} groups = [] - for input_field in self.input_fields.values(): + for input_field in self.input_fields: value, is_group = input_field.overrides() if value is not NOT_SET: values.update(value) From bfc4a7d595bd152a67a585a8c23e6fa3b629fdfd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 10:10:59 +0200 Subject: [PATCH 277/580] DictWidget can be also expandable --- .../config_setting/widgets/inputs.py | 85 +++++++++++-------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8c9e4a054b..8e66a5b1c2 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1874,50 +1874,22 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): raise TypeError("Can't use \"{}\" as widget item.".format( self.__class__.__name__ )) + + super(DictWidget, self).__init__(parent) + self.setObjectName("DictWidget") + + self._state = None + self._child_state = None + self._parent = parent any_parent_is_group = parent.is_group if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) - self._state = None - self._child_state = None - - super(DictWidget, self).__init__(parent) - self.setObjectName("DictWidget") - - body_widget = QtWidgets.QWidget(self) - - label_widget = QtWidgets.QLabel( - input_data["label"], parent=body_widget - ) - label_widget.setObjectName("DictLabel") - - content_widget = QtWidgets.QWidget(body_widget) - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 0, 3) - - body_layout = QtWidgets.QVBoxLayout(body_widget) - body_layout.setContentsMargins(0, 0, 0, 0) - body_layout.setSpacing(5) - body_layout.addWidget(label_widget) - body_layout.addWidget(content_widget) - - self.setAttribute(QtCore.Qt.WA_StyledBackground) - - main_layout = QtWidgets.QHBoxLayout(self) - main_layout.setContentsMargins(5, 5, 0, 5) - main_layout.setSpacing(0) - main_layout.addWidget(body_widget) - - self.label_widget = label_widget - self.content_widget = content_widget - self.content_layout = content_layout - self.input_fields = [] self.key = input_data["key"] @@ -1925,6 +1897,49 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): keys.append(self.key) self.keys = keys + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setSpacing(0) + + expandable = input_data.get("expandable", True) + if expandable: + main_layout.setContentsMargins(0, 0, 0, 0) + body_widget = ExpandingWidget(input_data["label"], self) + else: + main_layout.setContentsMargins(5, 5, 0, 5) + body_widget = QtWidgets.QWidget(self) + + main_layout.addWidget(body_widget) + + content_widget = QtWidgets.QWidget(body_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(3, 3, 0, 3) + + self.content_widget = content_widget + self.content_layout = content_layout + + if not expandable: + label_widget = QtWidgets.QLabel( + input_data["label"], parent=body_widget + ) + label_widget.setObjectName("DictLabel") + + body_layout = QtWidgets.QVBoxLayout(body_widget) + body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setSpacing(5) + body_layout.addWidget(label_widget) + body_layout.addWidget(content_widget) + + self.label_widget = label_widget + + else: + body_widget.set_content_widget(content_widget) + self.label_widget = body_widget.label_widget + expanded = input_data.get("expanded", False) + if expanded: + self.toggle_content() + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) From cedb8dd2d78650806058f09a5b9c8db51ebc15aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 10:11:22 +0200 Subject: [PATCH 278/580] added expandable false to current dict types --- .../projects_schema/1_plugins_gui_schema.json | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index bed839e6dc..4b7b19a74d 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -16,6 +16,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "ExtractCelactionDeadline", "label": "ExtractCelactionDeadline", "is_group": true, @@ -79,6 +80,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "IntegrateFtrackNote", "label": "IntegrateFtrackNote", "is_group": true, @@ -118,6 +120,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "IntegrateMasterVersion", "label": "IntegrateMasterVersion", "is_group": true, @@ -130,6 +133,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractJpegEXR", "label": "ExtractJpegEXR", "is_group": true, @@ -156,6 +160,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractReview", "label": "ExtractReview", "is_group": true, @@ -174,6 +179,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractBurnin", "label": "ExtractBurnin", "is_group": true, @@ -227,6 +233,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "IntegrateAssetNew", "label": "IntegrateAssetNew", "is_group": true, @@ -239,6 +246,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ProcessSubmittedJobOnFarm", "label": "ProcessSubmittedJobOnFarm", "is_group": true, @@ -278,6 +286,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "ValidateModelName", "label": "Validate Model Name", "is_group": true, @@ -299,6 +308,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ValidateAssemblyName", "label": "Validate Assembly Name", "is_group": true, @@ -311,6 +321,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ValidateShaderName", "label": "ValidateShaderName", "is_group": true, @@ -328,6 +339,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ValidateMeshHasOverlappingUVs", "label": "ValidateMeshHasOverlappingUVs", "is_group": true, @@ -360,6 +372,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "CreateWriteRender", "label": "CreateWriteRender", "is_group": true, @@ -373,6 +386,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "CreateWritePrerender", "label": "CreateWritePrerender", "is_group": true, @@ -394,6 +408,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "ExtractThumbnail", "label": "ExtractThumbnail", "is_group": true, @@ -411,6 +426,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ValidateNukeWriteKnobs", "label": "ValidateNukeWriteKnobs", "is_group": true, @@ -428,6 +444,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractReviewDataLut", "label": "ExtractReviewDataLut", "is_group": true, @@ -441,6 +458,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractReviewDataMov", "label": "ExtractReviewDataMov", "is_group": true, @@ -459,6 +477,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractSlateFrame", "label": "ExtractSlateFrame", "is_group": true, @@ -472,6 +491,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "NukeSubmitDeadline", "label": "NukeSubmitDeadline", "is_group": true, @@ -520,6 +540,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "CollectInstanceVersion", "label": "Collect Instance Version", "is_group": true, @@ -533,6 +554,7 @@ ] }, { "type": "dict", + "expandable": false, "key": "ExtractReviewCutUpVideo", "label": "Extract Review Cut Up Video", "is_group": true, @@ -567,6 +589,7 @@ "children": [ { "type": "dict", + "expandable": false, "key": "CreateShotClip", "label": "Create Shot Clip", "is_group": true, From 32ac3a77d7afd073e26b1b1fac94f6444c8754c6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 10:16:23 +0200 Subject: [PATCH 279/580] extended modified attribute --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8e66a5b1c2..4a23b93a85 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2049,7 +2049,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): @property def is_modified(self): if self.is_group: - return self.child_modified + return self._is_modified or self.child_modified return False @property From 00b5ac261a6379f529de684de040c79858416287 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 10:19:49 +0200 Subject: [PATCH 280/580] removed dict-expanding input type as is duplicated --- .../1_ftrack_projects_gui_schema.json | 9 +- .../projects_schema/1_plugins_gui_schema.json | 57 +++-- .../1_applications_gui_schema.json | 3 +- .../studio_schema/1_intents_gui_schema.json | 3 +- .../studio_schema/1_tools_gui_schema.json | 3 +- .../studio_schema/1_tray_items.json | 13 +- .../config_setting/widgets/inputs.py | 226 ------------------ 7 files changed, 58 insertions(+), 256 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json index ac696d18d0..51c05aeb3a 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json @@ -1,11 +1,13 @@ { "key": "ftrack", - "type": "dict-expanding", + "type": "dict", + "expandable": true, "label": "Ftrack", "children": [ { "key": "status_update", - "type": "dict-expanding", + "type": "dict", + "expandable": true, "label": "Status updates", "is_group": true, "is_file": true, @@ -22,7 +24,8 @@ ] }, { "key": "status_version_to_task", - "type": "dict-expanding", + "type": "dict", + "expandable": true, "label": "Version status to Task status", "is_group": true, "is_file": true, diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 4b7b19a74d..bb323c9803 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -1,15 +1,18 @@ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "plugins", "label": "Plugins", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "celaction", "label": "CelAction", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, @@ -68,12 +71,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "ftrack", "label": "Ftrack", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, @@ -108,12 +113,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "global", "label": "Global", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, @@ -189,7 +196,8 @@ "key": "enabled", "label": "Enabled" }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "options", "label": "Burnin formating options", "children": [ @@ -274,12 +282,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "maya", "label": "Maya", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, @@ -360,12 +370,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "nuke", "label": "Nuke", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "create", "label": "Create plugins", "is_file": true, @@ -401,7 +413,8 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, @@ -528,12 +541,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "nukestudio", "label": "NukeStudio", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, @@ -577,12 +592,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "resolve", "label": "DaVinci Resolve", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "create", "label": "Creator plugins", "is_file": true, @@ -617,12 +634,14 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "standalonepublisher", "label": "StandalonePublisher", "children": [ { - "type": "dict-expanding", + "type": "dict", + "expandable": true, "key": "publish", "label": "Publish plugins", "is_file": true, diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json index 2e60ed360d..bc2c9f239c 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json @@ -1,7 +1,8 @@ { "key": "applications", - "type": "dict-expanding", + "type": "dict", "label": "Applications", + "expandable": true, "is_file": true, "is_group": true, "children": [ diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json index 37d525cfb6..18f3d42ba7 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json @@ -1,7 +1,8 @@ { "key": "intent", - "type": "dict-expanding", + "type": "dict", "label": "Intent Setting", + "expandable": true, "is_group": true, "is_file": true, "children": [ diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json index 4c905a3826..bf35326d1c 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json @@ -1,7 +1,8 @@ { "key": "tools", - "type": "dict-expanding", + "type": "dict", "label": "Tools", + "expandable": true, "is_group": true, "is_file": true, "children": [ diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index 849019c89e..7cea724f29 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -1,7 +1,8 @@ { "key": "tray_modules", - "type": "dict-expanding", + "type": "dict", "label": "Modules", + "expandable": true, "is_file": true, "is_group": true, "children": [ @@ -65,10 +66,10 @@ "type": "dict-invisible", "children": [ { - "type": "dict-expanding", + "type": "dict", "key": "Rest Api", "label": "Rest Api", - "MISINGKEYCONF": {"exclude_ports": []}, + "expandable": true, "children": [ { "type": "int", @@ -88,9 +89,10 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", "key": "Timers Manager", "label": "Timers Manager", + "expandable": true, "children": [ { "type": "float", @@ -103,9 +105,10 @@ } ] }, { - "type": "dict-expanding", + "type": "dict", "key": "Clockify", "label": "Clockify", + "expandable": true, "children": [ { "type": "text-singleline", diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4a23b93a85..f0feb6fce3 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1639,231 +1639,6 @@ class ModifiableDict(ExpandingWidget, InputObject): # Dictionaries -class DictExpandWidget(ExpandingWidget, ConfigObject): - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, values, parent_keys, parent, label_widget=None - ): - if values is AS_WIDGET: - raise TypeError("Can't use \"{}\" as widget item.".format( - self.__class__.__name__ - )) - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self.any_parent_is_group = any_parent_is_group - - self._is_group = input_data.get("is_group", False) - - self._state = None - self._child_state = None - - super(DictExpandWidget, self).__init__(input_data["label"], parent) - - content_widget = QtWidgets.QWidget(self) - content_widget.setVisible(False) - - content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 0, 3) - - self.set_content_widget(content_widget) - - expanded = input_data.get("expanded", False) - if expanded: - self.toggle_content() - - self.setAttribute(QtCore.Qt.WA_StyledBackground) - - self.content_widget = content_widget - self.content_layout = content_layout - - self.input_fields = [] - - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) - - def remove_overrides(self): - self._is_overriden = False - self._is_modified = False - self._was_overriden = False - for item in self.input_fields: - item.remove_overrides() - - def discard_changes(self): - for item in self.input_fields: - item.discard_changes() - - self._is_modified = self.child_modified - self._is_overriden = self._was_overriden - - def set_as_overriden(self): - if self.is_overriden: - return - - if self.is_group: - self._is_overriden = True - return - - for item in self.input_fields: - item.set_as_overriden() - - def update_global_values(self, values): - for item in self.input_fields: - item.update_global_values(values) - - def apply_overrides(self, parent_values): - # Make sure this is set to False - self._state = None - self._child_state = None - - metadata = {} - groups = tuple() - override_values = NOT_SET - if parent_values is not NOT_SET: - metadata = parent_values.get(METADATA_KEY) or metadata - groups = metadata.get("groups") or groups - override_values = parent_values.get(self.key, override_values) - - self._is_overriden = self.key in groups - - for item in self.input_fields: - item.apply_overrides(override_values) - - if not self._is_overriden: - self._is_overriden = ( - self.is_group - and self.is_overidable - and self.child_overriden - ) - self._was_overriden = bool(self._is_overriden) - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_group: - if self.is_overidable: - self._is_overriden = True - - # TODO update items - if item is not None: - for _item in self.input_fields: - if _item is not item: - _item.update_style() - - self.value_changed.emit(self) - - self.update_style() - - def hierarchical_style_update(self): - self.update_style() - for input_field in self.input_fields: - input_field.hierarchical_style_update() - - def update_style(self, is_overriden=None): - child_modified = self.child_modified - child_state = self.style_state( - self.child_invalid, self.child_overriden, child_modified - ) - if child_state: - child_state = "child-{}".format(child_state) - - if child_state != self._child_state: - self.setProperty("state", child_state) - self.style().polish(self) - self._child_state = child_state - - state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return - - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) - - self._state = state - - @property - def is_modified(self): - if self.is_group: - return self.child_modified - return False - - @property - def child_modified(self): - for input_field in self.input_fields: - if input_field.child_modified: - return True - return False - - @property - def child_overriden(self): - for input_field in self.input_fields: - if input_field.is_overriden or input_field.child_overriden: - return True - return False - - @property - def child_invalid(self): - for input_field in self.input_fields: - if input_field.child_invalid: - return True - return False - - def get_invalid(self): - output = [] - for input_field in self.input_fields: - output.extend(input_field.get_invalid()) - return output - - def item_value(self): - output = {} - for input_field in self.input_fields: - # TODO maybe merge instead of update should be used - # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) - return output - - def add_children_gui(self, child_configuration, values): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - - item = klass( - child_configuration, values, self.keys, self - ) - item.value_changed.connect(self._on_value_change) - self.content_layout.addWidget(item) - - self.input_fields.append(item) - return item - - def overrides(self): - if not self.is_overriden and not self.child_overriden: - return NOT_SET, False - - values = {} - groups = [] - for input_field in self.input_fields: - value, is_group = input_field.overrides() - if value is not NOT_SET: - values.update(value) - if is_group: - groups.extend(value.keys()) - if groups: - values[METADATA_KEY] = {"groups": groups} - return {self.key: values}, self.is_group - - class DictWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) @@ -2467,7 +2242,6 @@ TypeToKlass.types["int"] = IntegerWidget TypeToKlass.types["float"] = FloatWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["dict"] = DictWidget -TypeToKlass.types["dict-expanding"] = DictExpandWidget TypeToKlass.types["dict-form"] = DictFormWidget TypeToKlass.types["dict-invisible"] = DictInvisible TypeToKlass.types["list"] = ListWidget From 8f4a7138e5104cb6b89e03678ad321e121df5b12 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:26:44 +0200 Subject: [PATCH 281/580] form widget has update_style method --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f0feb6fce3..dd1af3eb9d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2127,6 +2127,10 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def update_style(self): + for item in self.input_fields: + item.update_style() + def remove_overrides(self): self._is_overriden = False self._is_modified = False From c954fafeb0e4a9fbaafe2c416cd7971a1dd1ac6c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:29:10 +0200 Subject: [PATCH 282/580] trigger hierarchical_style_update instead of triggering update_style for each item --- pype/tools/config_setting/config_setting/widgets/inputs.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index dd1af3eb9d..9896fda4e1 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1986,12 +1986,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): if self.is_group: if self.is_overidable: self._is_overriden = True - # TODO update items - if item is not None: - is_overriden = self.is_overriden - for _item in self.input_fields: - if _item is not item: - _item.update_style(is_overriden) + self.hierarchical_style_update() self.value_changed.emit(self) From 5393b79d987c81bd51f4e3c3d8c4348b4546b062 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:31:24 +0200 Subject: [PATCH 283/580] label widget in dictionary widget is wrapped with QWidget --- .../config_setting/widgets/inputs.py | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9896fda4e1..f6fc0310aa 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1692,26 +1692,33 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.content_widget = content_widget self.content_layout = content_layout - if not expandable: - label_widget = QtWidgets.QLabel( - input_data["label"], parent=body_widget - ) - label_widget.setObjectName("DictLabel") - - body_layout = QtWidgets.QVBoxLayout(body_widget) - body_layout.setContentsMargins(0, 0, 0, 0) - body_layout.setSpacing(5) - body_layout.addWidget(label_widget) - body_layout.addWidget(content_widget) - - self.label_widget = label_widget - - else: + if expandable: body_widget.set_content_widget(content_widget) self.label_widget = body_widget.label_widget expanded = input_data.get("expanded", False) if expanded: - self.toggle_content() + body_widget.toggle_content() + + else: + top_widget = QtWidgets.QWidget(body_widget) + top_layout = QtWidgets.QHBoxLayout(top_widget) + top_layout.setContentsMargins(0, 0, 0, 0) + top_layout.setSpacing(5) + + label_widget = QtWidgets.QLabel( + input_data["label"], parent=top_widget + ) + label_widget.setObjectName("DictLabel") + + top_layout.addWidget(label_widget) + + body_layout = QtWidgets.QVBoxLayout(body_widget) + body_layout.setContentsMargins(0, 0, 0, 0) + body_layout.setSpacing(5) + body_layout.addWidget(top_widget) + body_layout.addWidget(content_widget) + + self.label_widget = label_widget self.setAttribute(QtCore.Qt.WA_StyledBackground) From f994d56464fa2f0fe6e104d385a22e5c266554e8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:35:58 +0200 Subject: [PATCH 284/580] it is possible to add checkbox next to label instead of child input --- .../config_setting/widgets/inputs.py | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f6fc0310aa..56ce22bdaf 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1722,6 +1722,31 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.setAttribute(QtCore.Qt.WA_StyledBackground) + checkbox_widget = None + checkbox_key = input_data.get("checkbox_key") + if checkbox_key: + checkbox_input_data = { + "key": checkbox_key, + "label": "test" + } + if expandable: + checkbox_widget = BooleanWidget( + checkbox_input_data, values, self.keys, self, + label_widget=self.label_widget, + # parent_widget=body_widget.top_part + ) + body_widget.top_part.layout().addWidget(checkbox_widget) + else: + checkbox_widget = BooleanWidget( + checkbox_input_data, values, self.keys, self, + label_widget=self.label_widget, + # parent_widget=top_widget + ) + top_layout.addWidget(checkbox_widget) + + self.input_fields.append(checkbox_widget) + checkbox_widget.value_changed.connect(self._on_value_change) + for child_data in input_data.get("children", []): self.add_children_gui(child_data, values) @@ -2129,10 +2154,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified self._is_overriden = self._was_overriden - def update_style(self): - for item in self.input_fields: - item.update_style() - def remove_overrides(self): self._is_overriden = False self._is_modified = False From 354b5b26f4c81bde9185c247364d87847ca0d51b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:44:51 +0200 Subject: [PATCH 285/580] added validation for checkbox_key --- .../config_setting/config_setting/widgets/lib.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index fe4e514aaf..ac18f09669 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -219,20 +219,24 @@ def validate_is_group_is_unique_in_hierarchy( def validate_keys_are_unique(schema_data, keys=None): + children = schema_data.get("children") + if not children: + return + is_top = keys is None if keys is None: keys = [schema_data["key"]] else: keys.append(schema_data["key"]) - children = schema_data.get("children") - if not children: - return - child_queue = Queue() for child in children: child_queue.put(child) + checkbox_key = schema_data.get("checkbox_key") + if checkbox_key: + child_queue.put({"key": checkbox_key}) + child_inputs = [] while not child_queue.empty(): child = child_queue.get() From 2960dcb1e0808b7623369bd49602fc4e93d467c3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:45:09 +0200 Subject: [PATCH 286/580] expandable widget has ability to hide toolbox button --- .../config_setting/config_setting/widgets/widgets.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index e551d1e9c3..d90242600e 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -53,6 +53,8 @@ class ExpandingWidget(QtWidgets.QWidget): super(ExpandingWidget, self).__init__(parent) self.setObjectName("ExpandingWidget") + self.toolbox_hidden = False + top_part = ClickableWidget(parent=self) button_size = QtCore.QSize(5, 5) @@ -82,6 +84,12 @@ class ExpandingWidget(QtWidgets.QWidget): self.top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) + def hide_toolbox(self): + self.button_toggle.setArrowType(QtCore.Qt.NoArrow) + self.toolbox_hidden = True + self.content_widget.setVisible(False) + self.parent().updateGeometry() + def set_content_widget(self, content_widget): main_layout = QtWidgets.QVBoxLayout(self) main_layout.setContentsMargins(9, 9, 0, 9) @@ -98,6 +106,8 @@ class ExpandingWidget(QtWidgets.QWidget): self.toggle_content(not self.button_toggle.isChecked()) def toggle_content(self, *args): + if self.toolbox_hidden: + return if len(args) > 0: checked = args[0] else: From 977855566b51f484890955c1e520eaee1f9a1d15 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:45:34 +0200 Subject: [PATCH 287/580] checkbox creation is same --- .../config_setting/widgets/inputs.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 56ce22bdaf..477fdc9292 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1726,22 +1726,15 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): checkbox_key = input_data.get("checkbox_key") if checkbox_key: checkbox_input_data = { - "key": checkbox_key, - "label": "test" + "key": checkbox_key } + checkbox_widget = BooleanWidget( + checkbox_input_data, values, self.keys, self, + label_widget=self.label_widget + ) if expandable: - checkbox_widget = BooleanWidget( - checkbox_input_data, values, self.keys, self, - label_widget=self.label_widget, - # parent_widget=body_widget.top_part - ) body_widget.top_part.layout().addWidget(checkbox_widget) else: - checkbox_widget = BooleanWidget( - checkbox_input_data, values, self.keys, self, - label_widget=self.label_widget, - # parent_widget=top_widget - ) top_layout.addWidget(checkbox_widget) self.input_fields.append(checkbox_widget) From 7b679f5e79239565875b490c7d89208ed4d2e7f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:45:56 +0200 Subject: [PATCH 288/580] trigger hierarchical_style_update instead of individual update_style on items --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 477fdc9292..3c5c246c43 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1806,11 +1806,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): if self.is_overidable: self._is_overriden = True - # TODO update items - if item is not None: - for _item in self.input_fields: - if _item is not item: - _item.update_style() + self.hierarchical_style_update() self.value_changed.emit(self) From 3800fc91dc3e9b796ff95e60a4f232b6c017a13d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 11:46:19 +0200 Subject: [PATCH 289/580] hide content and arrow if only checkbox key is set in dict widget --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3c5c246c43..64d2cbb761 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1740,7 +1740,11 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.input_fields.append(checkbox_widget) checkbox_widget.value_changed.connect(self._on_value_change) - for child_data in input_data.get("children", []): + children_data = input_data.get("children", []) + if expandable and checkbox_widget and not children_data: + body_widget.hide_toolbox() + + for child_data in children_data: self.add_children_gui(child_data, values) def remove_overrides(self): From 5e3599b8d08272923bac24f5f1bf623c50563249 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 12:33:57 +0200 Subject: [PATCH 290/580] expandign widget can set custom context margins --- pype/tools/config_setting/config_setting/widgets/widgets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index d90242600e..ba6a3c6629 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -90,9 +90,11 @@ class ExpandingWidget(QtWidgets.QWidget): self.content_widget.setVisible(False) self.parent().updateGeometry() - def set_content_widget(self, content_widget): + def set_content_widget(self, content_widget, margins=None): main_layout = QtWidgets.QVBoxLayout(self) - main_layout.setContentsMargins(9, 9, 0, 9) + if margins is None: + margins = (9, 9, 0, 9) + main_layout.setContentsMargins(*margins) content_widget.setVisible(False) From bbea0da42c57fe6c488e7e5f25e617068d995c4c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 12:34:21 +0200 Subject: [PATCH 291/580] ExpandingWidget style is not used anymore --- .../config_setting/config_setting/style/style.css | 12 ++++++------ .../config_setting/config_setting/widgets/widgets.py | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 996b73b9cd..937259ba7b 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -124,7 +124,7 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } -#ExpandingWidget, #ModifiableDict, #DictWidget { +#ModifiableDict, #DictWidget { border-style: solid; border-color: #455c6e; border-left-width: 3px; @@ -132,22 +132,22 @@ QPushButton[btn-type="expand-toggle"] { border-right-width: 0px; border-top-width: 0px; } -#ExpandingWidget:hover, #ModifiableDict:hover, #DictWidget:hover { +#ModifiableDict:hover, #DictWidget:hover { border-color: #62839d; } -#ExpandingWidget[state="child-modified"], #ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { +#ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { border-color: #106aa2; } -#ExpandingWidget[state="child-modified"]:hover, #ModifiableDict[state="child-modified"]:hover, #DictWidget[state="child-modified"]:hover { +#ModifiableDict[state="child-modified"]:hover, #DictWidget[state="child-modified"]:hover { border-color: #137cbd; } -#ExpandingWidget[state="child-invalid"], #ModifiableDict[state="child-invalid"], #DictWidget[state="child-invalid"] { +#ModifiableDict[state="child-invalid"], #DictWidget[state="child-invalid"] { border-color: #ad2e2e; } -#ExpandingWidget[state="child-invalid"]:hover, #ModifiableDict[state="child-invalid"]:hover, #DictWidget[state="child-invalid"]:hover { +#ModifiableDict[state="child-invalid"]:hover, #DictWidget[state="child-invalid"]:hover { border-color: #c93636; } diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index ba6a3c6629..c0045e37fd 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -51,7 +51,6 @@ class ClickableWidget(QtWidgets.QLabel): class ExpandingWidget(QtWidgets.QWidget): def __init__(self, label, parent): super(ExpandingWidget, self).__init__(parent) - self.setObjectName("ExpandingWidget") self.toolbox_hidden = False From 9bd6f5961c315a17148383164ab8b23fdddd84c5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 12:34:46 +0200 Subject: [PATCH 292/580] expanding widget can hide arrow and keep context showed --- pype/tools/config_setting/config_setting/widgets/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index c0045e37fd..db41fda1f6 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -83,10 +83,10 @@ class ExpandingWidget(QtWidgets.QWidget): self.top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) - def hide_toolbox(self): + def hide_toolbox(self, hide_content=False): self.button_toggle.setArrowType(QtCore.Qt.NoArrow) self.toolbox_hidden = True - self.content_widget.setVisible(False) + self.content_widget.setVisible(not hide_content) self.parent().updateGeometry() def set_content_widget(self, content_widget, margins=None): From 5c806ca77e7254896a5c43616bdde20f693def77 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 12:35:15 +0200 Subject: [PATCH 293/580] content margins are same for both cases --- pype/tools/config_setting/config_setting/widgets/inputs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 64d2cbb761..2fb83566b0 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1673,14 +1673,13 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.keys = keys main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(5, 5, 0, 5) main_layout.setSpacing(0) expandable = input_data.get("expandable", True) if expandable: - main_layout.setContentsMargins(0, 0, 0, 0) body_widget = ExpandingWidget(input_data["label"], self) else: - main_layout.setContentsMargins(5, 5, 0, 5) body_widget = QtWidgets.QWidget(self) main_layout.addWidget(body_widget) From fd58aeb7fdd5a68018c171fae3c44e20ae396c74 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 12:35:42 +0200 Subject: [PATCH 294/580] as body widget is always used expanding widget in dict widget --- .../config_setting/widgets/inputs.py | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 2fb83566b0..3737d8c858 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1676,11 +1676,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): main_layout.setContentsMargins(5, 5, 0, 5) main_layout.setSpacing(0) - expandable = input_data.get("expandable", True) - if expandable: - body_widget = ExpandingWidget(input_data["label"], self) - else: - body_widget = QtWidgets.QWidget(self) + body_widget = ExpandingWidget(input_data["label"], self) main_layout.addWidget(body_widget) @@ -1691,33 +1687,16 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.content_widget = content_widget self.content_layout = content_layout + body_widget.set_content_widget(content_widget, (4, 4, 0, 4)) + self.label_widget = body_widget.label_widget + + expandable = input_data.get("expandable", True) if expandable: - body_widget.set_content_widget(content_widget) - self.label_widget = body_widget.label_widget expanded = input_data.get("expanded", False) if expanded: body_widget.toggle_content() - else: - top_widget = QtWidgets.QWidget(body_widget) - top_layout = QtWidgets.QHBoxLayout(top_widget) - top_layout.setContentsMargins(0, 0, 0, 0) - top_layout.setSpacing(5) - - label_widget = QtWidgets.QLabel( - input_data["label"], parent=top_widget - ) - label_widget.setObjectName("DictLabel") - - top_layout.addWidget(label_widget) - - body_layout = QtWidgets.QVBoxLayout(body_widget) - body_layout.setContentsMargins(0, 0, 0, 0) - body_layout.setSpacing(5) - body_layout.addWidget(top_widget) - body_layout.addWidget(content_widget) - - self.label_widget = label_widget + body_widget.hide_toolbox(hide_content=False) self.setAttribute(QtCore.Qt.WA_StyledBackground) @@ -1741,7 +1720,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): children_data = input_data.get("children", []) if expandable and checkbox_widget and not children_data: - body_widget.hide_toolbox() + body_widget.hide_toolbox(hide_content=True) for child_data in children_data: self.add_children_gui(child_data, values) From 01ae1ef294226fce524b6045d660400dcb8f5de1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 12:55:26 +0200 Subject: [PATCH 295/580] checkbox key requires to have widget specification in children --- .../config_setting/widgets/inputs.py | 59 ++++++++++--------- .../config_setting/widgets/lib.py | 4 -- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3737d8c858..cf1e7b017e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1684,47 +1684,33 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(3, 3, 0, 3) + body_widget.set_content_widget(content_widget, (4, 4, 0, 4)) + + self.body_widget = body_widget self.content_widget = content_widget self.content_layout = content_layout - body_widget.set_content_widget(content_widget, (4, 4, 0, 4)) self.label_widget = body_widget.label_widget + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + self.checkbox_widget = None + self.checkbox_key = input_data.get("checkbox_key") + + for child_data in input_data.get("children", []): + self.add_children_gui(child_data, values) + expandable = input_data.get("expandable", True) - if expandable: + if len(self.input_fields) == 1 and self.checkbox_widget: + body_widget.hide_toolbox(hide_content=True) + + elif expandable: expanded = input_data.get("expanded", False) if expanded: body_widget.toggle_content() else: body_widget.hide_toolbox(hide_content=False) - self.setAttribute(QtCore.Qt.WA_StyledBackground) - - checkbox_widget = None - checkbox_key = input_data.get("checkbox_key") - if checkbox_key: - checkbox_input_data = { - "key": checkbox_key - } - checkbox_widget = BooleanWidget( - checkbox_input_data, values, self.keys, self, - label_widget=self.label_widget - ) - if expandable: - body_widget.top_part.layout().addWidget(checkbox_widget) - else: - top_layout.addWidget(checkbox_widget) - - self.input_fields.append(checkbox_widget) - checkbox_widget.value_changed.connect(self._on_value_change) - - children_data = input_data.get("children", []) - if expandable and checkbox_widget and not children_data: - body_widget.hide_toolbox(hide_content=True) - - for child_data in children_data: - self.add_children_gui(child_data, values) - def remove_overrides(self): self._is_overriden = False self._is_modified = False @@ -1868,6 +1854,10 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): def add_children_gui(self, child_configuration, values): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) + if self.checkbox_key and not self.checkbox_widget: + key = child_configuration.get("key") + if key == self.checkbox_key: + return self._add_checkbox_child(child_configuration, values) item = klass( child_configuration, values, self.keys, self @@ -1878,6 +1868,17 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.input_fields.append(item) return item + def _add_checkbox_child(self, child_configuration, values): + item = BooleanWidget( + child_configuration, values, self.keys, self, self.label_widget + ) + item.value_changed.connect(self._on_value_change) + + self.body_widget.top_part.layout().addWidget(item) + self.checkbox_widget = item + self.input_fields.append(item) + return item + def overrides(self): if not self.is_overriden and not self.child_overriden: return NOT_SET, False diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index ac18f09669..c416f7a5b0 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -233,10 +233,6 @@ def validate_keys_are_unique(schema_data, keys=None): for child in children: child_queue.put(child) - checkbox_key = schema_data.get("checkbox_key") - if checkbox_key: - child_queue.put({"key": checkbox_key}) - child_inputs = [] while not child_queue.empty(): child = child_queue.get() From aae3fbf971afbcf96956aea5903badbee10e7a79 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 13:01:03 +0200 Subject: [PATCH 296/580] modified few schemas to match new dict checkbox key --- .../projects_schema/1_plugins_gui_schema.json | 69 ++++++++++++------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index bb323c9803..19d5127a95 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -19,20 +19,21 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ExtractCelactionDeadline", "label": "ExtractCelactionDeadline", "is_group": true, "children": [ { + "type": "boolean", + "key": "enabled", + "label": "Enabled", + "default": true + }, { "type": "dict-form", "children": [ { - "type": "boolean", - "key": "enabled", - "label": "Enabled", - "default": true - }, { "type": "text-singleline", "key": "deadline_department", "label": "Deadline apartment", @@ -85,7 +86,8 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "IntegrateFtrackNote", "label": "IntegrateFtrackNote", "is_group": true, @@ -127,7 +129,8 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "IntegrateMasterVersion", "label": "IntegrateMasterVersion", "is_group": true, @@ -140,7 +143,8 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ExtractJpegEXR", "label": "ExtractJpegEXR", "is_group": true, @@ -167,9 +171,10 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ExtractReview", "label": "ExtractReview", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -186,9 +191,10 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ExtractBurnin", "label": "ExtractBurnin", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -241,7 +247,7 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "IntegrateAssetNew", "label": "IntegrateAssetNew", "is_group": true, @@ -254,9 +260,10 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ProcessSubmittedJobOnFarm", "label": "ProcessSubmittedJobOnFarm", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -296,9 +303,10 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, "key": "ValidateModelName", "label": "Validate Model Name", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -318,9 +326,10 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ValidateAssemblyName", "label": "Validate Assembly Name", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -331,9 +340,10 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ValidateShaderName", "label": "ValidateShaderName", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -349,9 +359,10 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ValidateMeshHasOverlappingUVs", "label": "ValidateMeshHasOverlappingUVs", + "checkbox_key": "enabled", "is_group": true, "children": [ { @@ -421,7 +432,8 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ExtractThumbnail", "label": "ExtractThumbnail", "is_group": true, @@ -439,7 +451,8 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ValidateNukeWriteKnobs", "label": "ValidateNukeWriteKnobs", "is_group": true, @@ -457,7 +470,8 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ExtractReviewDataLut", "label": "ExtractReviewDataLut", "is_group": true, @@ -471,7 +485,8 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ExtractReviewDataMov", "label": "ExtractReviewDataMov", "is_group": true, @@ -490,7 +505,7 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "ExtractSlateFrame", "label": "ExtractSlateFrame", "is_group": true, @@ -504,7 +519,7 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, "key": "NukeSubmitDeadline", "label": "NukeSubmitDeadline", "is_group": true, @@ -555,7 +570,8 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "CollectInstanceVersion", "label": "Collect Instance Version", "is_group": true, @@ -569,7 +585,8 @@ ] }, { "type": "dict", - "expandable": false, + "expandable": true, + "checkbox_key": "enabled", "key": "ExtractReviewCutUpVideo", "label": "Extract Review Cut Up Video", "is_group": true, @@ -606,7 +623,7 @@ "children": [ { "type": "dict", - "expandable": false, + "expandable": true, "key": "CreateShotClip", "label": "Create Shot Clip", "is_group": true, From ce6e64e5734dcde2a7c0f0b5282f7e1f9532c2e9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 14:45:09 +0200 Subject: [PATCH 297/580] adde is_nullable to inputs --- .../config_setting/widgets/inputs.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index cf1e7b017e..f1eee2b33b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -19,6 +19,7 @@ class ConfigObject: _was_overriden = False _is_invalid = False _is_group = False + _is_nullable = False _log = None @@ -53,6 +54,10 @@ class ConfigObject: """Value set in is not valid.""" return self._is_group + @property + def is_nullable(self): + return self._is_nullable + @property def is_overidable(self): """Should care about overrides.""" @@ -335,6 +340,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self._as_widget = values is AS_WIDGET self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -450,6 +456,7 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): self._as_widget = values is AS_WIDGET self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -561,6 +568,7 @@ class FloatWidget(QtWidgets.QWidget, InputObject): self._as_widget = values is AS_WIDGET self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -681,6 +689,7 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): self._as_widget = values is AS_WIDGET self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -786,6 +795,7 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputObject): self._as_widget = values is AS_WIDGET self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -949,6 +959,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) self._state = None @@ -1142,6 +1153,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self._state = None self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) @@ -1464,6 +1476,7 @@ class ModifiableDict(ExpandingWidget, InputObject): self.any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) inputs_widget = QtWidgets.QWidget(self) inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) @@ -1664,6 +1677,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) self.input_fields = [] From a57fbd8f407cc115bb64674173116440378a9fe6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 1 Sep 2020 15:02:53 +0200 Subject: [PATCH 298/580] feat(nuke): adding image loader --- pype/plugins/nuke/load/load_image.py | 233 ++++++++++++++++++++++++ pype/plugins/nuke/load/load_sequence.py | 18 +- 2 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 pype/plugins/nuke/load/load_image.py diff --git a/pype/plugins/nuke/load/load_image.py b/pype/plugins/nuke/load/load_image.py new file mode 100644 index 0000000000..377d52aa14 --- /dev/null +++ b/pype/plugins/nuke/load/load_image.py @@ -0,0 +1,233 @@ +import re +import nuke + +from avalon.vendor import qargparse +from avalon import api, io + +from pype.hosts.nuke import presets + + +class LoadImage(api.Loader): + """Load still image into Nuke""" + + families = [ + "render2d", "source", "plate", + "render", "prerender", "review", + "image" + ] + representations = ["exr", "dpx", "jpg", "jpeg", "png", "psd"] + + label = "Load Image" + order = -10 + icon = "image" + color = "white" + + options = [ + qargparse.Integer( + "frame_number", + label="Frame Number", + default=int(nuke.root()["first_frame"].getValue()), + min=1, + max=999999, + help="What frame is reading from?" + ) + ] + + def load(self, context, name, namespace, options): + from avalon.nuke import ( + containerise, + viewer_update_and_undo_stop + ) + self.log.info("__ options: `{}`".format(options)) + frame_number = options.get("frame_number", 1) + + version = context['version'] + version_data = version.get("data", {}) + repr_id = context["representation"]["_id"] + + self.log.info("version_data: {}\n".format(version_data)) + self.log.debug( + "Representation id `{}` ".format(repr_id)) + + last = first = int(frame_number) + + # Fallback to asset name when namespace is None + if namespace is None: + namespace = context['asset']['name'] + + file = self.fname + + if not file: + repr_id = context["representation"]["_id"] + self.log.warning( + "Representation id `{}` is failing to load".format(repr_id)) + return + + file = file.replace("\\", "/") + + repr_cont = context["representation"]["context"] + frame = repr_cont.get("frame") + if frame: + padding = len(frame) + file = file.replace( + frame, + format(frame_number, "0{}".format(padding))) + + read_name = "Read_{0}_{1}_{2}".format( + repr_cont["asset"], + repr_cont["subset"], + repr_cont["representation"]) + + # Create the Loader with the filename path set + with viewer_update_and_undo_stop(): + r = nuke.createNode( + "Read", + "name {}".format(read_name)) + r["file"].setValue(file) + + # Set colorspace defined in version data + colorspace = context["version"]["data"].get("colorspace") + if colorspace: + r["colorspace"].setValue(str(colorspace)) + + # load nuke presets for Read's colorspace + read_clrs_presets = presets.get_colorspace_preset().get( + "nuke", {}).get("read", {}) + + # check if any colorspace presets for read is mathing + preset_clrsp = next((read_clrs_presets[k] + for k in read_clrs_presets + if bool(re.search(k, file))), + None) + if preset_clrsp is not None: + r["colorspace"].setValue(str(preset_clrsp)) + + r["origfirst"].setValue(first) + r["first"].setValue(first) + r["origlast"].setValue(last) + r["last"].setValue(last) + + # add additional metadata from the version to imprint Avalon knob + add_keys = ["source", "colorspace", "author", "fps", "version"] + + data_imprint = { + "frameStart": first, + "frameEnd": last + } + for k in add_keys: + if k == 'version': + data_imprint.update({k: context["version"]['name']}) + else: + data_imprint.update( + {k: context["version"]['data'].get(k, str(None))}) + + data_imprint.update({"objectName": read_name}) + + r["tile_color"].setValue(int("0x4ecd25ff", 16)) + + return containerise(r, + name=name, + namespace=namespace, + context=context, + loader=self.__class__.__name__, + data=data_imprint) + + def switch(self, container, representation): + self.update(container, representation) + + def update(self, container, representation): + """Update the Loader's path + + Nuke automatically tries to reset some variables when changing + the loader's path to a new file. These automatic changes are to its + inputs: + + """ + + from avalon.nuke import ( + update_container + ) + + node = nuke.toNode(container["objectName"]) + frame_number = node["first"].value() + + assert node.Class() == "Read", "Must be Read" + + repr_cont = representation["context"] + + file = api.get_representation_path(representation) + + if not file: + repr_id = representation["_id"] + self.log.warning( + "Representation id `{}` is failing to load".format(repr_id)) + return + + file = file.replace("\\", "/") + + frame = repr_cont.get("frame") + if frame: + padding = len(frame) + file = file.replace( + frame, + format(frame_number, "0{}".format(padding))) + + # Get start frame from version data + version = io.find_one({ + "type": "version", + "_id": representation["parent"] + }) + + # get all versions in list + versions = io.find({ + "type": "version", + "parent": version["parent"] + }).distinct('name') + + max_version = max(versions) + + version_data = version.get("data", {}) + + last = first = int(frame_number) + + # Set the global in to the start frame of the sequence + node["origfirst"].setValue(first) + node["first"].setValue(first) + node["origlast"].setValue(last) + node["last"].setValue(last) + + updated_dict = {} + updated_dict.update({ + "representation": str(representation["_id"]), + "frameStart": str(first), + "frameEnd": str(last), + "version": str(version.get("name")), + "colorspace": version_data.get("colorspace"), + "source": version_data.get("source"), + "fps": str(version_data.get("fps")), + "author": version_data.get("author"), + "outputDir": version_data.get("outputDir"), + }) + + # change color of node + if version.get("name") not in [max_version]: + node["tile_color"].setValue(int("0xd84f20ff", 16)) + else: + node["tile_color"].setValue(int("0x4ecd25ff", 16)) + + # Update the imprinted representation + update_container( + node, + updated_dict + ) + self.log.info("udated to version: {}".format(version.get("name"))) + + def remove(self, container): + + from avalon.nuke import viewer_update_and_undo_stop + + node = nuke.toNode(container['objectName']) + assert node.Class() == "Read", "Must be Read" + + with viewer_update_and_undo_stop(): + nuke.delete(node) diff --git a/pype/plugins/nuke/load/load_sequence.py b/pype/plugins/nuke/load/load_sequence.py index 601e28c7c1..c5ce288540 100644 --- a/pype/plugins/nuke/load/load_sequence.py +++ b/pype/plugins/nuke/load/load_sequence.py @@ -120,12 +120,12 @@ class LoadSequence(api.Loader): if "#" not in file: frame = repr_cont.get("frame") padding = len(frame) - file = file.replace(frame, "#"*padding) + file = file.replace(frame, "#" * padding) read_name = "Read_{0}_{1}_{2}".format( - repr_cont["asset"], - repr_cont["subset"], - repr_cont["representation"]) + repr_cont["asset"], + repr_cont["subset"], + repr_cont["representation"]) # Create the Loader with the filename path set with viewer_update_and_undo_stop(): @@ -250,7 +250,7 @@ class LoadSequence(api.Loader): if "#" not in file: frame = repr_cont.get("frame") padding = len(frame) - file = file.replace(frame, "#"*padding) + file = file.replace(frame, "#" * padding) # Get start frame from version data version = io.find_one({ @@ -276,10 +276,10 @@ class LoadSequence(api.Loader): last = version_data.get("frameEnd") if first is None: - self.log.warning("Missing start frame for updated version" - "assuming starts at frame 0 for: " - "{} ({})".format( - node['name'].value(), representation)) + self.log.warning( + "Missing start frame for updated version" + "assuming starts at frame 0 for: " + "{} ({})".format(node['name'].value(), representation)) first = 0 first -= self.handle_start From dabe68f28cd1c391a2b4930af40d60b801bc78e2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 16:50:00 +0200 Subject: [PATCH 299/580] initial commit for anatomy widget --- .../projects_schema/0_project_gui_schema.json | 4 ++ .../config_setting/widgets/__init__.py | 4 +- .../config_setting/widgets/anatomy_inputs.py | 63 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json index 10641d5eda..91bacf2e5a 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json @@ -3,6 +3,10 @@ "type": "dict-invisible", "children": [ { + "type": "anatomy", + "key": "anatomy", + "is_file": true + }, { "type": "schema", "children": [ "1_plugins_gui_schema" diff --git a/pype/tools/config_setting/config_setting/widgets/__init__.py b/pype/tools/config_setting/config_setting/widgets/__init__.py index 0682f00324..034692898c 100644 --- a/pype/tools/config_setting/config_setting/widgets/__init__.py +++ b/pype/tools/config_setting/config_setting/widgets/__init__.py @@ -1,8 +1,10 @@ from .window import MainWidget # TODO properly register inputs to TypeToKlass class from . import inputs +from . import anatomy_inputs __all__ = [ "MainWidget", - "inputs" + "inputs", + "anatomy_inputs" ] diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py new file mode 100644 index 0000000000..addd0d6666 --- /dev/null +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -0,0 +1,63 @@ +import json +import logging +from Qt import QtWidgets, QtCore, QtGui +from .widgets import ( + ExpandingWidget, + ModifiedIntSpinBox, + ModifiedFloatSpinBox +) +from .inputs import ConfigObject, InputObject +from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass + + +class AnatomyWidget(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + self._as_widget = values is AS_WIDGET + + self._is_group = True + self._state = None + + self.key = "anatomy" + self.start_value = None + + super(AnatomyWidget, self).__init__(parent) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + label = QtWidgets.QLabel("Test") + layout.addWidget(label) + + self.override_value = NOT_SET + + def update_global_values(self, values): + print("* update_global_values") + + def set_value(self, value, *, global_value=False): + print("* set_value") + + def clear_value(self): + print("* clear_value") + + def _on_value_change(self, item=None): + print("* _on_value_change") + + def update_style(self): + print("* update_style") + + def item_value(self): + print("* item_value") + + +class TemplatesWidget: + pass + + + + +TypeToKlass.types["anatomy"] = AnatomyWidget From 13ee08a4ac73fdf4b5e000224da2bbb715b4cc12 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 17:55:24 +0200 Subject: [PATCH 300/580] initial commit of path input --- .../config_setting/widgets/inputs.py | 283 ++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f1eee2b33b..1416bbebda 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2247,8 +2247,291 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): return values, self.is_group +class PathInput(QtWidgets.QLineEdit): + def clear_end_path(self): + value = self.text().strip() + print("clearing") + if value.endswith("/"): + while value and value[-1] == "/": + value = value[:-1] + self.setText(value) + + def keyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_Backslash: + event.accept() + new_event = QtGui.QKeyEvent( + event.type(), + QtCore.Qt.Key_Slash, + event.modifiers(), + "/", + event.isAutoRepeat(), + event.count() + ) + QtWidgets.QApplication.sendEvent(self, new_event) + return + super(PathInput, self).keyPressEvent(event) + + def focusOutEvent(self, event): + super(PathInput, self).focusOutEvent(event) + self.clear_end_path() + + +class PathWidgetInput(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + self._parent = parent + self._as_widget = values is AS_WIDGET + + self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) + self.default_value = input_data.get("default", NOT_SET) + + self._state = None + + super(PathWidgetInput, self).__init__(parent) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + self.path_input = PathInput(self) + + self.setFocusProxy(self.path_input) + + if not self._as_widget and not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + layout.addWidget(self.path_input, 1) + + if not self._as_widget: + self.label_widget = label_widget + + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + self.update_global_values(values) + + self.override_value = NOT_SET + + self.path_input.textChanged.connect(self._on_value_change) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: + value = self.value_from_values(values) + if value is not NOT_SET: + self.path_input.setText(value) + + elif self.default_value is not NOT_SET: + self.path_input.setText(self.default_value) + + self.global_value = value + self.start_value = self.item_value() + + self._is_modified = self.global_value != self.start_value + + def set_value(self, value, *, global_value=False): + self.path_input.setText(value) + if global_value: + self.start_value = self.item_value() + self.global_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.start_value) + + def clear_value(self): + self.set_value("") + + def focusOutEvent(self, event): + super(PathInput, self).focusOutEvent(event) + value = self.item_value().strip() + if value.endswith("/"): + while value and value[-1] == "/": + value = value[:-1] + self.set_value(value) + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + self._is_modified = self.item_value() != self.global_value + if self.is_overidable: + self._is_overriden = True + + self.update_style() + + self.value_changed.emit(self) + + def update_style(self): + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return + + if self._as_widget: + property_name = "input-state" + widget = self.path_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) + + def item_value(self): + return self.path_input.text() + + +class PathWidget(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + + platforms = ("windows", "darwin", "linux") + platform_labels_mapping = { + "windows": "Windows", + "darwin": "MacOS", + "linux": "Linux" + } + platform_separators = { + "windows": ";", + "darwin": ":", + "linux": ":" + } + + def __init__( + self, input_data, values, parent_keys, parent, label_widget=None + ): + super(PathWidget, self).__init__(parent) + + self._parent = parent + self._as_widget = values is AS_WIDGET + + self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) + + self.default_value = input_data.get("default", NOT_SET) + self.multi_platform = input_data.get("multi_platform", NOT_SET) + self.multi_path = input_data.get("multi_path", NOT_SET) + + self.override_value = NOT_SET + + self._state = None + + self.input_fields = [] + + if not self._as_widget: + self.key = input_data["key"] + keys = list(parent_keys) + keys.append(self.key) + self.keys = keys + + if not self.multi_platform and not self.multi_path: + layout = QtWidgets.QVBoxLayout(self) + else: + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + if not self._as_widget and not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + + self.label_widget = label_widget + + self.content_widget = QtWidgets.QWidget(self) + self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) + + layout.addWidget(self.content_widget) + + self.create_gui() + + self.update_global_values(values) + + def create_gui(self): + if self.multi_platform and self.multi_path: + pass + elif self.multi_platform: + pass + elif self.multi_path: + pass + else: + text_input = QtWidgets.QLineEdit(self.content_widget) + self.setFocusProxy(text_input) + self.content_layout.addWidget(text_input, 1) + self.input_fields.append(text_input) + + def update_global_values(self, values): + value = NOT_SET + if not self._as_widget: + value = self.value_from_values(values) + if value is not NOT_SET: + self.text_input.setText(value) + + elif self.default_value is not NOT_SET: + self.text_input.setText(self.default_value) + + self.global_value = value + self.start_value = self.item_value() + + self._is_modified = self.global_value != self.start_value + + def set_value(self, value, *, global_value=False): + self.text_input.setText(value) + if global_value: + self.start_value = self.item_value() + self.global_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.start_value) + + def clear_value(self): + self.set_value("") + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + self._is_modified = self.item_value() != self.global_value + if self.is_overidable: + self._is_overriden = True + + self.update_style() + + self.value_changed.emit(self) + + def update_style(self): + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return + + if self._as_widget: + property_name = "input-state" + widget = self.text_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) + + def item_value(self): + return self.text_input.text() + + TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["text-singleline"] = TextSingleLineWidget +TypeToKlass.types["path-input"] = PathWidgetInput TypeToKlass.types["text-multiline"] = TextMultiLineWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["int"] = IntegerWidget From cd6c83913fd3af359875c38d17bc1ee93bfc95ae Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 2 Sep 2020 08:56:29 +0100 Subject: [PATCH 301/580] Nuke: skip thumbnail creation on farm submission. The thumbnail is being created when publishing from the baked colourspace movie. --- pype/plugins/global/publish/extract_jpeg.py | 5 +++++ pype/plugins/nuke/publish/extract_thumbnail.py | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_jpeg.py b/pype/plugins/global/publish/extract_jpeg.py index 89a4bbd664..d23ce4360f 100644 --- a/pype/plugins/global/publish/extract_jpeg.py +++ b/pype/plugins/global/publish/extract_jpeg.py @@ -81,6 +81,11 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin): jpeg_items.append("-i {}".format(full_input_path)) # output arguments from presets jpeg_items.extend(ffmpeg_args.get("output") or []) + + # If its a movie file, we just want one frame. + if repre["ext"] == "mov": + jpeg_items.append("-vframes 1") + # output file jpeg_items.append(full_output_path) diff --git a/pype/plugins/nuke/publish/extract_thumbnail.py b/pype/plugins/nuke/publish/extract_thumbnail.py index a3ef09bc9f..a53cb4d146 100644 --- a/pype/plugins/nuke/publish/extract_thumbnail.py +++ b/pype/plugins/nuke/publish/extract_thumbnail.py @@ -15,10 +15,12 @@ class ExtractThumbnail(pype.api.Extractor): order = pyblish.api.ExtractorOrder + 0.01 label = "Extract Thumbnail" - families = ["review", "render.farm"] + families = ["review"] hosts = ["nuke"] def process(self, instance): + if "render.farm" in instance.data["families"]: + return with anlib.maintained_selection(): self.log.debug("instance: {}".format(instance)) From 5b74678220750d0da52c9f290bcbc1299fc7106e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 10:50:27 +0200 Subject: [PATCH 302/580] PathWidgetInput cleanup --- .../config_setting/widgets/inputs.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 1416bbebda..24d0259baf 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2250,13 +2250,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): class PathInput(QtWidgets.QLineEdit): def clear_end_path(self): value = self.text().strip() - print("clearing") if value.endswith("/"): while value and value[-1] == "/": value = value[:-1] self.setText(value) def keyPressEvent(self, event): + # Always change backslash `\` for forwardslash `/` if event.key() == QtCore.Qt.Key_Backslash: event.accept() new_event = QtGui.QKeyEvent( @@ -2276,7 +2276,7 @@ class PathInput(QtWidgets.QLineEdit): self.clear_end_path() -class PathWidgetInput(QtWidgets.QWidget, InputObject): +class PathInputWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( @@ -2291,7 +2291,7 @@ class PathWidgetInput(QtWidgets.QWidget, InputObject): self._state = None - super(PathWidgetInput, self).__init__(parent) + super(PathInputWidget, self).__init__(parent) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -2350,12 +2350,8 @@ class PathWidgetInput(QtWidgets.QWidget, InputObject): self.set_value("") def focusOutEvent(self, event): + self.path_input.clear_end_path() super(PathInput, self).focusOutEvent(event) - value = self.item_value().strip() - if value.endswith("/"): - while value and value[-1] == "/": - value = value[:-1] - self.set_value(value) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -2531,7 +2527,7 @@ class PathWidget(QtWidgets.QWidget, InputObject): TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["text-singleline"] = TextSingleLineWidget -TypeToKlass.types["path-input"] = PathWidgetInput +TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["text-multiline"] = TextMultiLineWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["int"] = IntegerWidget From bf4205f23d8f4467376696a3b2b0263c75b69665 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 11:08:03 +0200 Subject: [PATCH 303/580] path widget is partially completed --- .../config_setting/widgets/inputs.py | 107 ++++++++++++------ 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 24d0259baf..63db5cb2e2 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2413,8 +2413,8 @@ class PathWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self.multi_platform = input_data.get("multi_platform", NOT_SET) - self.multi_path = input_data.get("multi_path", NOT_SET) + self.multiplatform = input_data.get("multiplatform", False) + self.multipath = input_data.get("multipath", False) self.override_value = NOT_SET @@ -2428,10 +2428,10 @@ class PathWidget(QtWidgets.QWidget, InputObject): keys.append(self.key) self.keys = keys - if not self.multi_platform and not self.multi_path: - layout = QtWidgets.QVBoxLayout(self) - else: + if not self.multiplatform and not self.multipath: layout = QtWidgets.QHBoxLayout(self) + else: + layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -2441,30 +2441,69 @@ class PathWidget(QtWidgets.QWidget, InputObject): layout.addWidget(label_widget, 0) self.label_widget = label_widget + layout.addWidget(label_widget) self.content_widget = QtWidgets.QWidget(self) self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) + self.content_layout.setSpacing(0) + self.content_layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.content_widget) - self.create_gui() + self.create_gui(values) self.update_global_values(values) - def create_gui(self): - if self.multi_platform and self.multi_path: - pass - elif self.multi_platform: - pass - elif self.multi_path: - pass - else: - text_input = QtWidgets.QLineEdit(self.content_widget) - self.setFocusProxy(text_input) - self.content_layout.addWidget(text_input, 1) - self.input_fields.append(text_input) + def create_gui(self, values): + if not self.multiplatform and not self.multipath: + input_data = {"key": self.key} + path_input = PathInputWidget( + input_data, values, self.keys, self, self.label_widget + ) + self.setFocusProxy(path_input) + self.content_layout.addWidget(path_input) + self.input_fields.append(path_input) + path_input.value_changed.connect(self._on_value_change) + return + + input_data_for_list = { + "object_type": "path-input" + } + if not self.multiplatform: + input_data_for_list["key"] = self.key + input_widget = ListWidget( + input_data_for_list, values, self.keys, self, self.label_widget + ) + self.setFocusProxy(input_widget) + self.content_layout.addWidget(input_widget) + self.input_fields.append(input_widget) + input_widget.value_changed.connect(self._on_value_change) + return + + proxy_widget = QtWidgets.QWidget(self.content_widget) + proxy_layout = QtWidgets.QFormLayout(proxy_widget) + for platform_key in self.platforms: + platform_label = self.platform_labels_mapping[platform_key] + label_widget = QtWidgets.QLabel(platform_label, proxy_widget) + if self.multipath: + input_data_for_list["key"] = platform_key + input_widget = ListWidget( + input_data_for_list, values, self.keys, self, label_widget + ) + else: + input_data = {"key": platform_key} + input_widget = PathInputWidget( + input_data, values, self.keys, self, label_widget + ) + proxy_layout.addRow(label_widget, input_widget) + self.input_fields.append(input_widget) + input_widget.value_changed.connect(self._on_value_change) + + self.setFocusProxy(self.input_fields[0]) + self.content_layout.addWidget(proxy_widget) def update_global_values(self, values): + print(self.__class__.__name__, "* TODO implement `update_global_values`") value = NOT_SET if not self._as_widget: value = self.value_from_values(values) @@ -2480,6 +2519,7 @@ class PathWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value def set_value(self, value, *, global_value=False): + print(self.__class__.__name__, "* TODO implement `set_value`") self.text_input.setText(value) if global_value: self.start_value = self.item_value() @@ -2487,12 +2527,15 @@ class PathWidget(QtWidgets.QWidget, InputObject): self._on_value_change() def reset_value(self): + print(self.__class__.__name__, "* TODO implement `reset_value`") self.set_value(self.start_value) def clear_value(self): + print(self.__class__.__name__, "* TODO implement `clear_value`") self.set_value("") def _on_value_change(self, item=None): + print(self.__class__.__name__, "* TODO implement `_on_value_change`") if self.ignore_value_changes: return @@ -2505,29 +2548,25 @@ class PathWidget(QtWidgets.QWidget, InputObject): self.value_changed.emit(self) def update_style(self): - state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return - - if self._as_widget: - property_name = "input-state" - widget = self.text_input - else: - property_name = "state" - widget = self.label_widget - - widget.setProperty(property_name, state) - widget.style().polish(widget) + print(self.__class__.__name__, "* TODO implement `update_style`") def item_value(self): - return self.text_input.text() + if not self.multiplatform and not self.multipath: + return self.input_fields[0].item_value() + + if not self.multiplatform: + return self.input_fields[0].item_value() + + output = {} + for input_field in self.input_fields: + output.update(input_field.config_value()) + return output TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["text-singleline"] = TextSingleLineWidget TypeToKlass.types["path-input"] = PathInputWidget +TypeToKlass.types["path-widget"] = PathWidget TypeToKlass.types["text-multiline"] = TextMultiLineWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["int"] = IntegerWidget From a8b4daa4646e66c326dd1c9926800cdc6a853c2e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 11:09:13 +0200 Subject: [PATCH 304/580] PathInput moved to widgets --- .../config_setting/widgets/inputs.py | 32 ++----------------- .../config_setting/widgets/widgets.py | 31 +++++++++++++++++- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 63db5cb2e2..812d005153 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -4,7 +4,8 @@ from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ExpandingWidget, ModifiedIntSpinBox, - ModifiedFloatSpinBox + ModifiedFloatSpinBox, + PathInput ) from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass @@ -2247,35 +2248,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): return values, self.is_group -class PathInput(QtWidgets.QLineEdit): - def clear_end_path(self): - value = self.text().strip() - if value.endswith("/"): - while value and value[-1] == "/": - value = value[:-1] - self.setText(value) - - def keyPressEvent(self, event): - # Always change backslash `\` for forwardslash `/` - if event.key() == QtCore.Qt.Key_Backslash: - event.accept() - new_event = QtGui.QKeyEvent( - event.type(), - QtCore.Qt.Key_Slash, - event.modifiers(), - "/", - event.isAutoRepeat(), - event.count() - ) - QtWidgets.QApplication.sendEvent(self, new_event) - return - super(PathInput, self).keyPressEvent(event) - - def focusOutEvent(self, event): - super(PathInput, self).focusOutEvent(event) - self.clear_end_path() - - class PathInputWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index db41fda1f6..8e0dda42fd 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -1,4 +1,4 @@ -from Qt import QtWidgets, QtCore +from Qt import QtWidgets, QtCore, QtGui class ModifiedIntSpinBox(QtWidgets.QSpinBox): @@ -35,6 +35,35 @@ class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): event.ignore() +class PathInput(QtWidgets.QLineEdit): + def clear_end_path(self): + value = self.text().strip() + if value.endswith("/"): + while value and value[-1] == "/": + value = value[:-1] + self.setText(value) + + def keyPressEvent(self, event): + # Always change backslash `\` for forwardslash `/` + if event.key() == QtCore.Qt.Key_Backslash: + event.accept() + new_event = QtGui.QKeyEvent( + event.type(), + QtCore.Qt.Key_Slash, + event.modifiers(), + "/", + event.isAutoRepeat(), + event.count() + ) + QtWidgets.QApplication.sendEvent(self, new_event) + return + super(PathInput, self).keyPressEvent(event) + + def focusOutEvent(self, event): + super(PathInput, self).focusOutEvent(event) + self.clear_end_path() + + class ClickableWidget(QtWidgets.QLabel): clicked = QtCore.Signal() From 78c88a9429cfb0c7b6de22da6b332c1a97aae383 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 11:16:49 +0200 Subject: [PATCH 305/580] fixed ListItem right click --- .../tools/config_setting/config_setting/widgets/inputs.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 812d005153..dbc220d89a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1140,6 +1140,14 @@ class ListItem(QtWidgets.QWidget, ConfigObject): return self.value_input.item_value() return NOT_SET + @property + def child_modified(self): + return self.value_input.child_modified + + @property + def child_overriden(self): + return self.value_input.child_overriden + class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) From 22ec0a03b9116ce42e31c0d0ea71f4f05840d68e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 11:39:59 +0200 Subject: [PATCH 306/580] integer and lfoat widget merged into one number widget --- .../config_setting/widgets/widgets.py | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 8e0dda42fd..d5b0f088de 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -1,28 +1,12 @@ from Qt import QtWidgets, QtCore, QtGui -class ModifiedIntSpinBox(QtWidgets.QSpinBox): +class NumberSpinBox(QtWidgets.QDoubleSpinBox): def __init__(self, *args, **kwargs): min_value = kwargs.pop("minimum", -99999) max_value = kwargs.pop("maximum", 99999) - super(ModifiedIntSpinBox, self).__init__(*args, **kwargs) - self.setFocusPolicy(QtCore.Qt.StrongFocus) - self.setMinimum(min_value) - self.setMaximum(max_value) - - def wheelEvent(self, event): - if self.hasFocus(): - super(ModifiedIntSpinBox, self).wheelEvent(event) - else: - event.ignore() - - -class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): - def __init__(self, *args, **kwargs): - min_value = kwargs.pop("minimum", -99999) - max_value = kwargs.pop("maximum", 99999) - decimals = kwargs.pop("decimal", 2) - super(ModifiedFloatSpinBox, self).__init__(*args, **kwargs) + decimals = kwargs.pop("decimal", 0) + super(NumberSpinBox, self).__init__(*args, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setDecimals(decimals) self.setMinimum(min_value) @@ -30,7 +14,7 @@ class ModifiedFloatSpinBox(QtWidgets.QDoubleSpinBox): def wheelEvent(self, event): if self.hasFocus(): - super(ModifiedFloatSpinBox, self).wheelEvent(event) + super(NumberSpinBox, self).wheelEvent(event) else: event.ignore() From d0a5d2800650ac5a1165dfa5abf40faf1e72a081 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 11:40:52 +0200 Subject: [PATCH 307/580] integer and float input widgets also reduced to one input field with changeable "decimal" attribute --- .../projects_schema/1_plugins_gui_schema.json | 22 +-- .../studio_schema/0_studio_gui_schema.json | 2 +- .../studio_schema/1_tray_items.json | 10 +- .../config_setting/widgets/inputs.py | 154 ++---------------- 4 files changed, 33 insertions(+), 155 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 19d5127a95..e43518989a 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -39,7 +39,7 @@ "label": "Deadline apartment", "default": "" }, { - "type": "int", + "type": "number", "key": "deadline_priority", "label": "Deadline priority", "default": 50 @@ -59,7 +59,7 @@ "label": "Deadline Group", "default": "" }, { - "type": "int", + "type": "number", "key": "deadline_chunk_size", "label": "Deadline Chunk size", "default": 10 @@ -208,32 +208,32 @@ "label": "Burnin formating options", "children": [ { - "type": "int", + "type": "number", "key": "font_size", "label": "Font size", "default": 42 }, { - "type": "int", + "type": "number", "key": "opacity", "label": "Font opacity", "default": 1 }, { - "type": "int", + "type": "number", "key": "bg_opacity", "label": "Background opacity", "default": 1 }, { - "type": "int", + "type": "number", "key": "x_offset", "label": "X Offset", "default": 5 }, { - "type": "int", + "type": "number", "key": "y_offset", "label": "Y Offset", "default": 5 }, { - "type": "int", + "type": "number", "key": "bg_padding", "label": "Padding aroung text", "default": 5 @@ -525,7 +525,7 @@ "is_group": true, "children": [ { - "type": "int", + "type": "number", "key": "deadline_priority", "label": "deadline_priority", "default": 50 @@ -540,7 +540,7 @@ "label": "deadline_pool_secondary", "default": "" }, { - "type": "int", + "type": "number", "key": "deadline_chunk_size", "label": "deadline_chunk_size", "default": 1 @@ -639,7 +639,7 @@ "label": "Folder", "default": "takes" }, { - "type": "int", + "type": "number", "key": "steps", "label": "Steps", "default": 20 diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index db465fb392..bde340250e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -21,7 +21,7 @@ "key": "muster", "children": [{ "type": "dict-modifiable", - "object_type": "int", + "object_type": "number", "input_modifiers": { "minimum": 0, "maximum": 300 diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index 7cea724f29..610430b25e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -72,14 +72,14 @@ "expandable": true, "children": [ { - "type": "int", + "type": "number", "key": "default_port", "label": "Default Port", "minimum": 1, "maximum": 65535 }, { "type": "list", - "object_type": "int", + "object_type": "number", "key": "exclude_ports", "label": "Exclude ports", "input_modifiers": { @@ -95,11 +95,13 @@ "expandable": true, "children": [ { - "type": "float", + "type": "number", + "decimal": 2, "key": "full_time", "label": "Max idle time" }, { - "type": "float", + "type": "number", + "decimal": 2, "key": "message_time", "label": "When dialog will show" } diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index dbc220d89a..3e86b864b4 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -3,8 +3,7 @@ import logging from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ExpandingWidget, - ModifiedIntSpinBox, - ModifiedFloatSpinBox, + NumberSpinBox, PathInput ) from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass @@ -446,13 +445,15 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): return self.checkbox.isChecked() -class IntegerWidget(QtWidgets.QWidget, InputObject): +class NumberWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) - input_modifiers = ("minimum", "maximum") + input_modifiers = ("minimum", "maximum", "decimal") def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + super(NumberWidget, self).__init__(parent) + self._parent = parent self._as_widget = values is AS_WIDGET @@ -462,8 +463,6 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): self._state = None - super(IntegerWidget, self).__init__(parent) - layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -473,15 +472,15 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): for modifier in self.input_modifiers if input_data.get(modifier) } - self.int_input = ModifiedIntSpinBox(self, **kwargs) + self.input_field = NumberSpinBox(self, **kwargs) - self.setFocusProxy(self.int_input) + self.setFocusProxy(self.input_field) if not self._as_widget and not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) - layout.addWidget(self.int_input, 1) + layout.addWidget(self.input_field, 1) if not self._as_widget: self.label_widget = label_widget @@ -495,17 +494,17 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): self.override_value = NOT_SET - self.int_input.valueChanged.connect(self._on_value_change) + self.input_field.valueChanged.connect(self._on_value_change) def update_global_values(self, values): value = NOT_SET if not self._as_widget: value = self.value_from_values(values) if value is not NOT_SET: - self.int_input.setValue(value) + self.input_field.setValue(value) elif self.default_value is not NOT_SET: - self.int_input.setValue(self.default_value) + self.input_field.setValue(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -513,7 +512,7 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value def set_value(self, value, *, global_value=False): - self.int_input.setValue(value) + self.input_field.setValue(value) if global_value: self.start_value = self.item_value() self.global_value = self.item_value() @@ -546,7 +545,7 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): if self._as_widget: property_name = "input-state" - widget = self.int_input + widget = self.input_field else: property_name = "state" widget = self.label_widget @@ -555,129 +554,7 @@ class IntegerWidget(QtWidgets.QWidget, InputObject): widget.style().polish(widget) def item_value(self): - return self.int_input.value() - - -class FloatWidget(QtWidgets.QWidget, InputObject): - value_changed = QtCore.Signal(object) - input_modifiers = ("minimum", "maximum", "decimal") - - def __init__( - self, input_data, values, parent_keys, parent, label_widget=None - ): - self._parent = parent - self._as_widget = values is AS_WIDGET - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) - - self._state = None - - super(FloatWidget, self).__init__(parent) - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - kwargs = { - modifier: input_data.get(modifier) - for modifier in self.input_modifiers - if input_data.get(modifier) - } - self.float_input = ModifiedFloatSpinBox(self, **kwargs) - - self.setFocusProxy(self.float_input) - - decimals = input_data.get("decimals", 5) - maximum = input_data.get("maximum") - minimum = input_data.get("minimum") - - self.float_input.setDecimals(decimals) - if maximum is not None: - self.float_input.setMaximum(float(maximum)) - if minimum is not None: - self.float_input.setMinimum(float(minimum)) - - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - layout.addWidget(self.float_input, 1) - - if not self._as_widget: - self.label_widget = label_widget - - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) - - self.override_value = NOT_SET - - self.float_input.valueChanged.connect(self._on_value_change) - - def update_global_values(self, values): - value = NOT_SET - if not self._as_widget: - value = self.value_from_values(values) - if value is not NOT_SET: - self.float_input.setValue(value) - - elif self.default_value is not NOT_SET: - self.float_input.setValue(self.default_value) - - self.global_value = value - self.start_value = self.item_value() - - self._is_modified = self.global_value != self.start_value - - def set_value(self, value, *, global_value=False): - self.float_input.setValue(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() - - def reset_value(self): - self.set_value(self.global_value) - - def clear_value(self): - self.set_value(0) - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - self._is_modified = self.item_value() != self.global_value - if self.is_overidable: - self._is_overriden = True - - self.update_style() - - self.value_changed.emit(self) - - def update_style(self): - state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return - - if self._as_widget: - property_name = "input-state" - widget = self.float_input - else: - property_name = "state" - widget = self.label_widget - - widget.setProperty(property_name, state) - widget.style().polish(widget) - - def item_value(self): - return self.float_input.value() + return self.input_field.value() class TextSingleLineWidget(QtWidgets.QWidget, InputObject): @@ -2549,8 +2426,7 @@ TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["path-widget"] = PathWidget TypeToKlass.types["text-multiline"] = TextMultiLineWidget TypeToKlass.types["raw-json"] = RawJsonWidget -TypeToKlass.types["int"] = IntegerWidget -TypeToKlass.types["float"] = FloatWidget +TypeToKlass.types["number"] = NumberWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-form"] = DictFormWidget From d4a3a2ec17ed9fa87f8ddea823451d413432c513 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 11:56:06 +0200 Subject: [PATCH 308/580] changed order in boolean input --- .../config_setting/widgets/inputs.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3e86b864b4..0d2ff628ce 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -351,22 +351,20 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.checkbox = QtWidgets.QCheckBox(self) - - self.setFocusProxy(self.checkbox) - - self.checkbox.setAttribute(QtCore.Qt.WA_StyledBackground) - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) - layout.addWidget(label_widget, 0) - - layout.addWidget(self.checkbox, 1) - if not self._as_widget: + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + layout.addWidget(label_widget, 0) self.label_widget = label_widget + self.checkbox = QtWidgets.QCheckBox(self) + self.checkbox.setAttribute(QtCore.Qt.WA_StyledBackground) + layout.addWidget(self.checkbox, 1) + self.setFocusProxy(self.checkbox) + + if not self._as_widget: self.key = input_data["key"] keys = list(parent_keys) keys.append(self.key) From e79b051b59330027e1080cf648f10dfa55766d21 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 12:43:24 +0200 Subject: [PATCH 309/580] cleanup anatomy input imports --- .../config_setting/widgets/anatomy_inputs.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index addd0d6666..feae91ba99 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,13 +1,6 @@ -import json -import logging -from Qt import QtWidgets, QtCore, QtGui -from .widgets import ( - ExpandingWidget, - ModifiedIntSpinBox, - ModifiedFloatSpinBox -) -from .inputs import ConfigObject, InputObject -from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass +from Qt import QtWidgets, QtCore +from .inputs import InputObject +from .lib import NOT_SET, AS_WIDGET, TypeToKlass class AnatomyWidget(QtWidgets.QWidget, InputObject): From 0ceb697c21be236711e179dcd15f90d8cea522a9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 12:45:52 +0200 Subject: [PATCH 310/580] changed way how global values a propagated to inputs --- .../config_setting/widgets/base.py | 8 +- .../config_setting/widgets/inputs.py | 361 ++++++++---------- 2 files changed, 164 insertions(+), 205 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 9c1fee5b6f..cd459aa674 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -92,10 +92,10 @@ class StudioWidget(QtWidgets.QWidget): widget.deleteLater() self.input_fields.clear() - values = {"studio": config.studio_configurations()} self.schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") self.keys = self.schema.get("keys", []) - self.add_children_gui(self.schema, values) + self.add_children_gui(self.schema, lib.NOT_SET) + self._update_global_values() self.hierarchical_style_update() def _save(self): @@ -404,10 +404,10 @@ class ProjectWidget(QtWidgets.QWidget): input_field.hierarchical_style_update() def reset(self): - values = {"project": config.global_project_configurations()} self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = self.schema.get("keys", []) - self.add_children_gui(self.schema, values) + self.add_children_gui(self.schema, lib.NOT_SET) + self._update_global_values() self.hierarchical_style_update() def add_children_gui(self, child_configuration, values): diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 0d2ff628ce..5f5747fd71 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -120,26 +120,6 @@ class ConfigObject: """Output for saving changes or overrides.""" return {self.key: self.item_value()} - def value_from_values(self, values, keys=None): - """Global getter of value based on loaded values.""" - if not values or values is AS_WIDGET: - return NOT_SET - - if keys is None: - keys = self.keys - - value = values - for key in keys: - if not isinstance(value, dict): - raise TypeError( - "Expected dictionary got {}.".format(str(type(value))) - ) - - if key not in value: - return NOT_SET - value = value[key] - return value - def style_state(self, is_invalid, is_overriden, is_modified): items = [] if is_invalid: @@ -336,22 +316,26 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + super(BooleanWidget, self).__init__(parent) + self._parent = parent self._as_widget = values is AS_WIDGET + self._state = None self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self._state = None - - super(BooleanWidget, self).__init__(parent) + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) if not self._as_widget: + self.key = input_data["key"] if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) @@ -364,21 +348,14 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): layout.addWidget(self.checkbox, 1) self.setFocusProxy(self.checkbox) - if not self._as_widget: - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) - self.override_value = NOT_SET - self.checkbox.stateChanged.connect(self._on_value_change) - def update_global_values(self, values): + def update_global_values(self, parent_values): value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.checkbox.setChecked(value) @@ -454,12 +431,15 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._as_widget = values is AS_WIDGET + self._state = None self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self._state = None + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -474,30 +454,24 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.input_field) - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - layout.addWidget(self.input_field, 1) - if not self._as_widget: + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) - - self.override_value = NOT_SET + layout.addWidget(self.input_field, 1) self.input_field.valueChanged.connect(self._on_value_change) - def update_global_values(self, values): + def update_global_values(self, parent_values): value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.input_field.setValue(value) @@ -561,16 +535,19 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + super(TextSingleLineWidget, self).__init__(parent) + self._parent = parent self._as_widget = values is AS_WIDGET + self._state = None self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self._state = None - - super(TextSingleLineWidget, self).__init__(parent) + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -580,30 +557,24 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.text_input) - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - layout.addWidget(self.text_input, 1) - if not self._as_widget: + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) - - self.override_value = NOT_SET + layout.addWidget(self.text_input, 1) self.text_input.textChanged.connect(self._on_value_change) - def update_global_values(self, values): + def update_global_values(self, parent_values): value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.text_input.setText(value) @@ -667,16 +638,19 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + super(TextMultiLineWidget, self).__init__(parent) + self._parent = parent self._as_widget = values is AS_WIDGET + self._state = None self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self._state = None - - super(TextMultiLineWidget, self).__init__(parent) + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -686,30 +660,23 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.text_input) - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - layout.addWidget(self.text_input, 1) - if not self._as_widget: - self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) - - self.override_value = NOT_SET + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + layout.addWidget(self.text_input, 1) self.text_input.textChanged.connect(self._on_value_change) - def update_global_values(self, values): + def update_global_values(self, parent_values): value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.text_input.setPlainText(value) @@ -825,8 +792,11 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + super(RawJsonWidget, self).__init__(parent) + self._parent = parent self._as_widget = values is AS_WIDGET + self._state = None any_parent_is_group = parent.is_group if not any_parent_is_group: @@ -838,9 +808,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self._state = None - - super(RawJsonWidget, self).__init__(parent) + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -854,30 +824,23 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.text_input) - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - layout.addWidget(self.text_input, 1) - - self.override_value = NOT_SET - if not self._as_widget: - self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + layout.addWidget(self.text_input, 1) self.text_input.textChanged.connect(self._on_value_change) - def update_global_values(self, values): + def update_global_values(self, parent_values): value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.text_input.set_value(value) @@ -1030,12 +993,12 @@ class ListWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): - self._parent = parent - super(ListWidget, self).__init__(parent) self.setObjectName("ListWidget") + self._parent = parent self._state = None + self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) @@ -1043,18 +1006,14 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET + + self.key = input_data["key"] + self.input_fields = [] - inputs_widget = QtWidgets.QWidget(self) - inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) - - inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) - inputs_layout.setContentsMargins(0, 5, 0, 5) - inputs_layout.setSpacing(3) - - self.inputs_widget = inputs_widget - self.inputs_layout = inputs_layout - layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) @@ -1063,19 +1022,18 @@ class ListWidget(QtWidgets.QWidget, InputObject): label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget) - self.label_widget = label_widget + inputs_widget = QtWidgets.QWidget(self) + inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) layout.addWidget(inputs_widget) - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys + inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout.setContentsMargins(0, 5, 0, 5) + inputs_layout.setSpacing(3) - self.update_global_values(values) - - self.override_value = NOT_SET + self.inputs_widget = inputs_widget + self.inputs_layout = inputs_layout def count(self): return len(self.input_fields) @@ -1086,10 +1044,12 @@ class ListWidget(QtWidgets.QWidget, InputObject): def clear_value(self): self.set_value([]) - def update_global_values(self, values): + def update_global_values(self, parent_values): old_inputs = tuple(self.input_fields) - value = self.value_from_values(values) + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) self.global_value = value @@ -1227,10 +1187,10 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__(self, object_type, input_modifiers, config_parent, parent): - self._parent = config_parent - super(ModifiableDictItem, self).__init__(parent) + self._parent = config_parent + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) @@ -1344,13 +1304,18 @@ class ModifiableDict(ExpandingWidget, InputObject): self, input_data, values, parent_keys, parent, label_widget=None ): - self._parent = parent - super(ModifiableDict, self).__init__(input_data["label"], parent) self.setObjectName("ModifiableDict") + self._parent = parent self._state = None + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET + + self.key = input_data["key"] + self.input_fields = [] any_parent_is_group = parent.is_group @@ -1378,22 +1343,15 @@ class ModifiableDict(ExpandingWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.override_value = NOT_SET - - self.update_global_values(values) - def count(self): return len(self.input_fields) - def update_global_values(self, values): + def update_global_values(self, parent_values): old_inputs = tuple(self.input_fields) - value = self.value_from_values(values) + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) self.global_value = value @@ -1566,9 +1524,6 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(5, 5, 0, 5) @@ -1596,7 +1551,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.checkbox_key = input_data.get("checkbox_key") for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) + self.add_children_gui(child_data) expandable = input_data.get("expandable", True) if len(self.input_fields) == 1 and self.checkbox_widget: @@ -1634,9 +1589,13 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() - def update_global_values(self, values): + def update_global_values(self, parent_values): + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + for item in self.input_fields: - item.update_global_values(values) + item.update_global_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -1749,16 +1708,16 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): output.update(input_field.config_value()) return output - def add_children_gui(self, child_configuration, values): + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) if self.checkbox_key and not self.checkbox_widget: key = child_configuration.get("key") if key == self.checkbox_key: - return self._add_checkbox_child(child_configuration, values) + return self._add_checkbox_child(child_configuration) item = klass( - child_configuration, values, self.keys, self + child_configuration, NOT_SET, self.keys, self ) item.value_changed.connect(self._on_value_change) self.content_layout.addWidget(item) @@ -1766,9 +1725,9 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.input_fields.append(item) return item - def _add_checkbox_child(self, child_configuration, values): + def _add_checkbox_child(self, child_configuration): item = BooleanWidget( - child_configuration, values, self.keys, self, self.label_widget + child_configuration, NOT_SET, self.keys, self, self.label_widget ) item.value_changed.connect(self._on_value_change) @@ -1823,11 +1782,9 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.key = input_data["key"] - self.keys = list(parent_keys) - self.keys.append(self.key) for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) + self.add_children_gui(child_data) def update_style(self, *args, **kwargs): return @@ -1867,12 +1824,12 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): output.update(input_field.config_value()) return output - def add_children_gui(self, child_configuration, values): + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) item = klass( - child_configuration, values, self.keys, self + child_configuration, NOT_SET, self.keys, self ) self.layout().addWidget(item) @@ -1922,9 +1879,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() - def update_global_values(self, values): + def update_global_values(self, parent_values): + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + for item in self.input_fields: - item.update_global_values(values) + item.update_global_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -2001,7 +1962,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self.keys = list(parent_keys) for child_data in input_data.get("children", []): - self.add_children_gui(child_data, values) + self.add_children_gui(child_data) def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.RightButton: @@ -2042,9 +2003,9 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() - def update_global_values(self, values): + def update_global_values(self, value): for item in self.input_fields: - item.update_global_values(values) + item.update_global_values(value) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -2080,7 +2041,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): output.extend(input_field.get_invalid()) return output - def add_children_gui(self, child_configuration, values): + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] # Pop label to not be set in child label = child_configuration["label"] @@ -2090,7 +2051,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): label_widget = FormLabel(label, self) item = klass( - child_configuration, values, self.keys, self, label_widget + child_configuration, NOT_SET, self.keys, self, label_widget ) label_widget.item = item @@ -2137,16 +2098,19 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, values, parent_keys, parent, label_widget=None ): + super(PathInputWidget, self).__init__(parent) + self._parent = parent self._as_widget = values is AS_WIDGET + self._state = None self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self._state = None - - super(PathInputWidget, self).__init__(parent) + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -2156,30 +2120,23 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.path_input) - if not self._as_widget and not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - layout.addWidget(self.path_input, 1) - if not self._as_widget: - self.label_widget = label_widget - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - - self.update_global_values(values) - - self.override_value = NOT_SET + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + layout.addWidget(self.path_input, 1) self.path_input.textChanged.connect(self._on_value_change) - def update_global_values(self, values): + def update_global_values(self, parent_values): value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.path_input.setText(value) @@ -2305,15 +2262,13 @@ class PathWidget(QtWidgets.QWidget, InputObject): layout.addWidget(self.content_widget) - self.create_gui(values) + self.create_gui() - self.update_global_values(values) - - def create_gui(self, values): + def create_gui(self): if not self.multiplatform and not self.multipath: input_data = {"key": self.key} path_input = PathInputWidget( - input_data, values, self.keys, self, self.label_widget + input_data, NOT_SET, self.keys, self, self.label_widget ) self.setFocusProxy(path_input) self.content_layout.addWidget(path_input) @@ -2327,7 +2282,7 @@ class PathWidget(QtWidgets.QWidget, InputObject): if not self.multiplatform: input_data_for_list["key"] = self.key input_widget = ListWidget( - input_data_for_list, values, self.keys, self, self.label_widget + input_data_for_list, NOT_SET, self.keys, self, self.label_widget ) self.setFocusProxy(input_widget) self.content_layout.addWidget(input_widget) @@ -2343,12 +2298,12 @@ class PathWidget(QtWidgets.QWidget, InputObject): if self.multipath: input_data_for_list["key"] = platform_key input_widget = ListWidget( - input_data_for_list, values, self.keys, self, label_widget + input_data_for_list, NOT_SET, self.keys, self, label_widget ) else: input_data = {"key": platform_key} input_widget = PathInputWidget( - input_data, values, self.keys, self, label_widget + input_data, NOT_SET, self.keys, self, label_widget ) proxy_layout.addRow(label_widget, input_widget) self.input_fields.append(input_widget) @@ -2357,11 +2312,15 @@ class PathWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.input_fields[0]) self.content_layout.addWidget(proxy_widget) - def update_global_values(self, values): - print(self.__class__.__name__, "* TODO implement `update_global_values`") + def update_global_values(self, parent_values): + print( + self.__class__.__name__, "* TODO implement `update_global_values`" + ) value = NOT_SET if not self._as_widget: - value = self.value_from_values(values) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + if value is not NOT_SET: self.text_input.setText(value) From 370705a10a286770c1eb67994da67d2495762496 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 13:07:13 +0200 Subject: [PATCH 311/580] removed AS_WIDGET constant and reduced input args --- .../config_setting/widgets/anatomy_inputs.py | 6 +- .../config_setting/widgets/base.py | 16 +- .../config_setting/widgets/inputs.py | 193 ++++++++---------- .../config_setting/widgets/lib.py | 1 - 4 files changed, 95 insertions(+), 121 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index feae91ba99..7c9ac0d8f4 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,16 +1,16 @@ from Qt import QtWidgets, QtCore from .inputs import InputObject -from .lib import NOT_SET, AS_WIDGET, TypeToKlass +from .lib import NOT_SET, TypeToKlass class AnatomyWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._is_group = True self._state = None diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index cd459aa674..f057f5a0f6 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -94,7 +94,7 @@ class StudioWidget(QtWidgets.QWidget): self.schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") self.keys = self.schema.get("keys", []) - self.add_children_gui(self.schema, lib.NOT_SET) + self.add_children_gui(self.schema) self._update_global_values() self.hierarchical_style_update() @@ -175,12 +175,10 @@ class StudioWidget(QtWidgets.QWidget): for input_field in self.input_fields: input_field.hierarchical_style_update() - def add_children_gui(self, child_configuration, values): + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = lib.TypeToKlass.types.get(item_type) - item = klass( - child_configuration, values, self.keys, self - ) + item = klass(child_configuration, self) self.input_fields.append(item) self.content_layout.addWidget(item) @@ -406,16 +404,14 @@ class ProjectWidget(QtWidgets.QWidget): def reset(self): self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = self.schema.get("keys", []) - self.add_children_gui(self.schema, lib.NOT_SET) + self.add_children_gui(self.schema) self._update_global_values() self.hierarchical_style_update() - def add_children_gui(self, child_configuration, values): + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = lib.TypeToKlass.types.get(item_type) - item = klass( - child_configuration, values, self.keys, self - ) + item = klass(child_configuration, self) self.input_fields.append(item) self.content_layout.addWidget(item) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 5f5747fd71..336a8ef93e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -6,7 +6,7 @@ from .widgets import ( NumberSpinBox, PathInput ) -from .lib import NOT_SET, AS_WIDGET, METADATA_KEY, TypeToKlass +from .lib import NOT_SET, METADATA_KEY, TypeToKlass class ConfigObject: @@ -314,12 +314,12 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(BooleanWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._state = None self._is_group = input_data.get("is_group", False) @@ -334,7 +334,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self._as_widget: + if not as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] @@ -425,12 +425,12 @@ class NumberWidget(QtWidgets.QWidget, InputObject): input_modifiers = ("minimum", "maximum", "decimal") def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(NumberWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._state = None self._is_group = input_data.get("is_group", False) @@ -533,12 +533,12 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(TextSingleLineWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._state = None self._is_group = input_data.get("is_group", False) @@ -636,12 +636,12 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(TextMultiLineWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._state = None self._is_group = input_data.get("is_group", False) @@ -790,12 +790,12 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(RawJsonWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._state = None any_parent_is_group = parent.is_group @@ -944,10 +944,9 @@ class ListItem(QtWidgets.QWidget, ConfigObject): ItemKlass = TypeToKlass.types[object_type] self.value_input = ItemKlass( input_modifiers, - AS_WIDGET, - [], self, - None + as_widget=True, + label_widget=None ) layout.addWidget(self.value_input, 1) @@ -991,7 +990,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(ListWidget, self).__init__(parent) self.setObjectName("ListWidget") @@ -1202,10 +1201,9 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.value_input = ItemKlass( input_modifiers, - AS_WIDGET, - [], self, - None + as_widget=True, + label_widget=None ) self.add_btn = QtWidgets.QPushButton("+") self.remove_btn = QtWidgets.QPushButton("-") @@ -1301,8 +1299,7 @@ class ModifiableDict(ExpandingWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, - label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(ModifiableDict, self).__init__(input_data["label"], parent) self.setObjectName("ModifiableDict") @@ -1498,9 +1495,9 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): - if values is AS_WIDGET: + if as_widget: raise TypeError("Can't use \"{}\" as widget item.".format( self.__class__.__name__ )) @@ -1564,6 +1561,32 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): else: body_widget.hide_toolbox(hide_content=False) + def add_children_gui(self, child_configuration): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + if self.checkbox_key and not self.checkbox_widget: + key = child_configuration.get("key") + if key == self.checkbox_key: + return self._add_checkbox_child(child_configuration) + + item = klass(child_configuration, self) + item.value_changed.connect(self._on_value_change) + self.content_layout.addWidget(item) + + self.input_fields.append(item) + return item + + def _add_checkbox_child(self, child_configuration): + item = BooleanWidget( + child_configuration, self, label_widget=self.label_widget + ) + item.value_changed.connect(self._on_value_change) + + self.body_widget.top_part.layout().addWidget(item) + self.checkbox_widget = item + self.input_fields.append(item) + return item + def remove_overrides(self): self._is_overriden = False self._is_modified = False @@ -1708,34 +1731,6 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): output.update(input_field.config_value()) return output - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - if self.checkbox_key and not self.checkbox_widget: - key = child_configuration.get("key") - if key == self.checkbox_key: - return self._add_checkbox_child(child_configuration) - - item = klass( - child_configuration, NOT_SET, self.keys, self - ) - item.value_changed.connect(self._on_value_change) - self.content_layout.addWidget(item) - - self.input_fields.append(item) - return item - - def _add_checkbox_child(self, child_configuration): - item = BooleanWidget( - child_configuration, NOT_SET, self.keys, self, self.label_widget - ) - item.value_changed.connect(self._on_value_change) - - self.body_widget.top_part.layout().addWidget(item) - self.checkbox_widget = item - self.input_fields.append(item) - return item - def overrides(self): if not self.is_overriden and not self.child_overriden: return NOT_SET, False @@ -1759,7 +1754,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): allow_actions = False def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): self._parent = parent @@ -1786,6 +1781,18 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): for child_data in input_data.get("children", []): self.add_children_gui(child_data) + def add_children_gui(self, child_configuration): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + item = klass(child_configuration, self) + self.layout().addWidget(item) + + item.value_changed.connect(self._on_value_change) + + self.input_fields.append(item) + return item + def update_style(self, *args, **kwargs): return @@ -1824,20 +1831,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): output.update(input_field.config_value()) return output - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - - item = klass( - child_configuration, NOT_SET, self.keys, self - ) - self.layout().addWidget(item) - - item.value_changed.connect(self._on_value_change) - - self.input_fields.append(item) - return item - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1942,7 +1935,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): allow_actions = False def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): self._parent = parent @@ -1959,11 +1952,26 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.content_layout = QtWidgets.QFormLayout(self) - self.keys = list(parent_keys) - for child_data in input_data.get("children", []): self.add_children_gui(child_data) + def add_children_gui(self, child_configuration): + item_type = child_configuration["type"] + # Pop label to not be set in child + label = child_configuration["label"] + + klass = TypeToKlass.types.get(item_type) + + label_widget = FormLabel(label, self) + + item = klass(child_configuration, self, label_widget=label_widget) + label_widget.item = item + + item.value_changed.connect(self._on_value_change) + self.content_layout.addRow(label_widget, item) + self.input_fields.append(item) + return item + def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.RightButton: position = self.mapFromGlobal(QtGui.QCursor().pos()) @@ -2041,25 +2049,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): output.extend(input_field.get_invalid()) return output - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - # Pop label to not be set in child - label = child_configuration["label"] - - klass = TypeToKlass.types.get(item_type) - - label_widget = FormLabel(label, self) - - item = klass( - child_configuration, NOT_SET, self.keys, self, label_widget - ) - label_widget.item = item - - item.value_changed.connect(self._on_value_change) - self.content_layout.addRow(label_widget, item) - self.input_fields.append(item) - return item - def hierarchical_style_update(self): for input_field in self.input_fields: input_field.hierarchical_style_update() @@ -2096,12 +2085,12 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(PathInputWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET + self._as_widget = as_widget self._state = None self._is_group = input_data.get("is_group", False) @@ -2214,12 +2203,11 @@ class PathWidget(QtWidgets.QWidget, InputObject): } def __init__( - self, input_data, values, parent_keys, parent, label_widget=None + self, input_data, parent, as_widget=False, label_widget=None ): super(PathWidget, self).__init__(parent) self._parent = parent - self._as_widget = values is AS_WIDGET self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) @@ -2234,12 +2222,6 @@ class PathWidget(QtWidgets.QWidget, InputObject): self.input_fields = [] - if not self._as_widget: - self.key = input_data["key"] - keys = list(parent_keys) - keys.append(self.key) - self.keys = keys - if not self.multiplatform and not self.multipath: layout = QtWidgets.QHBoxLayout(self) else: @@ -2247,13 +2229,12 @@ class PathWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self._as_widget and not label_widget: + self.key = input_data["key"] + if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) - self.label_widget = label_widget - layout.addWidget(label_widget) self.content_widget = QtWidgets.QWidget(self) self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) @@ -2267,9 +2248,7 @@ class PathWidget(QtWidgets.QWidget, InputObject): def create_gui(self): if not self.multiplatform and not self.multipath: input_data = {"key": self.key} - path_input = PathInputWidget( - input_data, NOT_SET, self.keys, self, self.label_widget - ) + path_input = PathInputWidget(input_data, self, self.label_widget) self.setFocusProxy(path_input) self.content_layout.addWidget(path_input) self.input_fields.append(path_input) @@ -2282,7 +2261,7 @@ class PathWidget(QtWidgets.QWidget, InputObject): if not self.multiplatform: input_data_for_list["key"] = self.key input_widget = ListWidget( - input_data_for_list, NOT_SET, self.keys, self, self.label_widget + input_data_for_list, self, self.label_widget ) self.setFocusProxy(input_widget) self.content_layout.addWidget(input_widget) @@ -2298,12 +2277,12 @@ class PathWidget(QtWidgets.QWidget, InputObject): if self.multipath: input_data_for_list["key"] = platform_key input_widget = ListWidget( - input_data_for_list, NOT_SET, self.keys, self, label_widget + input_data_for_list, self, label_widget ) else: input_data = {"key": platform_key} input_widget = PathInputWidget( - input_data, NOT_SET, self.keys, self, label_widget + input_data, self, label_widget ) proxy_layout.addRow(label_widget, input_widget) self.input_fields.append(input_widget) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index c416f7a5b0..4669004b53 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -12,7 +12,6 @@ class TypeToKlass: NOT_SET = type("NOT_SET", (), {}) -AS_WIDGET = type("AS_WIDGET", (), {}) METADATA_KEY = type("METADATA_KEY", (), {}) OVERRIDE_VERSION = 1 From 9c34ee32abd971a80ff4c4fb44f26d23d96bda65 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 16:37:03 +0200 Subject: [PATCH 312/580] few updates and fixes for path input --- .../config_setting/widgets/inputs.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 336a8ef93e..53054b27a6 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2105,10 +2105,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.path_input = PathInput(self) - - self.setFocusProxy(self.path_input) - if not self._as_widget: self.key = input_data["key"] if not label_widget: @@ -2116,6 +2112,9 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) self.label_widget = label_widget + + self.path_input = PathInput(self) + self.setFocusProxy(self.path_input) layout.addWidget(self.path_input, 1) self.path_input.textChanged.connect(self._on_value_change) @@ -2217,6 +2216,8 @@ class PathWidget(QtWidgets.QWidget, InputObject): self.multipath = input_data.get("multipath", False) self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET self._state = None @@ -2248,7 +2249,9 @@ class PathWidget(QtWidgets.QWidget, InputObject): def create_gui(self): if not self.multiplatform and not self.multipath: input_data = {"key": self.key} - path_input = PathInputWidget(input_data, self, self.label_widget) + path_input = PathInputWidget( + input_data, self, label_widget=self.label_widget + ) self.setFocusProxy(path_input) self.content_layout.addWidget(path_input) self.input_fields.append(path_input) @@ -2261,7 +2264,7 @@ class PathWidget(QtWidgets.QWidget, InputObject): if not self.multiplatform: input_data_for_list["key"] = self.key input_widget = ListWidget( - input_data_for_list, self, self.label_widget + input_data_for_list, self, label_widget=self.label_widget ) self.setFocusProxy(input_widget) self.content_layout.addWidget(input_widget) @@ -2277,12 +2280,12 @@ class PathWidget(QtWidgets.QWidget, InputObject): if self.multipath: input_data_for_list["key"] = platform_key input_widget = ListWidget( - input_data_for_list, self, label_widget + input_data_for_list, self, label_widget=label_widget ) else: input_data = {"key": platform_key} input_widget = PathInputWidget( - input_data, self, label_widget + input_data, self, label_widget=label_widget ) proxy_layout.addRow(label_widget, input_widget) self.input_fields.append(input_widget) From e3a62eae3fd2cd17fa186eb1982f56017c7a24be Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 16:37:15 +0200 Subject: [PATCH 313/580] path widget can update global values --- .../config_setting/widgets/inputs.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 53054b27a6..23068ce236 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2295,19 +2295,16 @@ class PathWidget(QtWidgets.QWidget, InputObject): self.content_layout.addWidget(proxy_widget) def update_global_values(self, parent_values): - print( - self.__class__.__name__, "* TODO implement `update_global_values`" - ) value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if value is not NOT_SET: - self.text_input.setText(value) + if not self.multiplatform: + self.input_fields[0].update_global_values(parent_values) - elif self.default_value is not NOT_SET: - self.text_input.setText(self.default_value) + elif self.multiplatform: + for input_field in self.input_fields: + input_field.update_global_values(value) self.global_value = value self.start_value = self.item_value() From 4c0f0a6bddcd688f255d6475db8e196be50d559d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 16:45:18 +0200 Subject: [PATCH 314/580] reorganization --- .../config_setting/widgets/inputs.py | 572 +++++++++--------- 1 file changed, 289 insertions(+), 283 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 23068ce236..ac08a9ae4f 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -734,6 +734,111 @@ class TextMultiLineWidget(QtWidgets.QWidget, InputObject): return self.text_input.toPlainText() +class PathInputWidget(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, parent, as_widget=False, label_widget=None + ): + super(PathInputWidget, self).__init__(parent) + + self._parent = parent + self._as_widget = as_widget + self._state = None + + self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) + self.default_value = input_data.get("default", NOT_SET) + + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + if not self._as_widget: + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + + self.path_input = PathInput(self) + self.setFocusProxy(self.path_input) + layout.addWidget(self.path_input, 1) + + self.path_input.textChanged.connect(self._on_value_change) + + def update_global_values(self, parent_values): + value = NOT_SET + if not self._as_widget: + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + if value is not NOT_SET: + self.path_input.setText(value) + + elif self.default_value is not NOT_SET: + self.path_input.setText(self.default_value) + + self.global_value = value + self.start_value = self.item_value() + + self._is_modified = self.global_value != self.start_value + + def set_value(self, value, *, global_value=False): + self.path_input.setText(value) + if global_value: + self.start_value = self.item_value() + self.global_value = self.item_value() + self._on_value_change() + + def reset_value(self): + self.set_value(self.start_value) + + def clear_value(self): + self.set_value("") + + def focusOutEvent(self, event): + self.path_input.clear_end_path() + super(PathInput, self).focusOutEvent(event) + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + self._is_modified = self.item_value() != self.global_value + if self.is_overidable: + self._is_overriden = True + + self.update_style() + + self.value_changed.emit(self) + + def update_style(self): + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return + + if self._as_widget: + property_name = "input-state" + widget = self.path_input + else: + property_name = "state" + widget = self.label_widget + + widget.setProperty(property_name, state) + widget.style().polish(widget) + + def item_value(self): + return self.path_input.text() + + class RawJsonInput(QtWidgets.QPlainTextEdit): tab_length = 4 @@ -1923,13 +2028,189 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): return {self.key: values}, self.is_group +class PathWidget(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + + platforms = ("windows", "darwin", "linux") + platform_labels_mapping = { + "windows": "Windows", + "darwin": "MacOS", + "linux": "Linux" + } + platform_separators = { + "windows": ";", + "darwin": ":", + "linux": ":" + } + + def __init__( + self, input_data, parent, as_widget=False, label_widget=None + ): + super(PathWidget, self).__init__(parent) + + self._parent = parent + + self._is_group = input_data.get("is_group", False) + self._is_nullable = input_data.get("is_nullable", False) + + self.default_value = input_data.get("default", NOT_SET) + self.multiplatform = input_data.get("multiplatform", False) + self.multipath = input_data.get("multipath", False) + + self.override_value = NOT_SET + self.global_value = NOT_SET + self.start_value = NOT_SET + + self._state = None + + self.input_fields = [] + + if not self.multiplatform and not self.multipath: + layout = QtWidgets.QHBoxLayout(self) + else: + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + + self.content_widget = QtWidgets.QWidget(self) + self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) + self.content_layout.setSpacing(0) + self.content_layout.setContentsMargins(0, 0, 0, 0) + + layout.addWidget(self.content_widget) + + self.create_gui() + + def create_gui(self): + if not self.multiplatform and not self.multipath: + input_data = {"key": self.key} + path_input = PathInputWidget( + input_data, self, label_widget=self.label_widget + ) + self.setFocusProxy(path_input) + self.content_layout.addWidget(path_input) + self.input_fields.append(path_input) + path_input.value_changed.connect(self._on_value_change) + return + + input_data_for_list = { + "object_type": "path-input" + } + if not self.multiplatform: + input_data_for_list["key"] = self.key + input_widget = ListWidget( + input_data_for_list, self, label_widget=self.label_widget + ) + self.setFocusProxy(input_widget) + self.content_layout.addWidget(input_widget) + self.input_fields.append(input_widget) + input_widget.value_changed.connect(self._on_value_change) + return + + proxy_widget = QtWidgets.QWidget(self.content_widget) + proxy_layout = QtWidgets.QFormLayout(proxy_widget) + for platform_key in self.platforms: + platform_label = self.platform_labels_mapping[platform_key] + label_widget = QtWidgets.QLabel(platform_label, proxy_widget) + if self.multipath: + input_data_for_list["key"] = platform_key + input_widget = ListWidget( + input_data_for_list, self, label_widget=label_widget + ) + else: + input_data = {"key": platform_key} + input_widget = PathInputWidget( + input_data, self, label_widget=label_widget + ) + proxy_layout.addRow(label_widget, input_widget) + self.input_fields.append(input_widget) + input_widget.value_changed.connect(self._on_value_change) + + self.setFocusProxy(self.input_fields[0]) + self.content_layout.addWidget(proxy_widget) + + def update_global_values(self, parent_values): + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + if not self.multiplatform: + self.input_fields[0].update_global_values(parent_values) + + elif self.multiplatform: + for input_field in self.input_fields: + input_field.update_global_values(value) + + self.global_value = value + self.start_value = self.item_value() + + self._is_modified = self.global_value != self.start_value + + def set_value(self, value, *, global_value=False): + if not self.multiplatform: + self.input_fields[0].set_value(value, global_value=global_value) + + else: + for input_field in self.input_fields: + _value = value[input_field.key] + input_field.set_value(_value) + + if global_value: + self.global_value = value + self.start_value = self.item_value() + self._on_value_change() + + def reset_value(self): + for input_field in self.input_fields: + input_field.reset_value() + + def clear_value(self): + for input_field in self.input_fields: + input_field.clear_value() + + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + self._is_modified = self.item_value() != self.global_value + if self.is_overidable: + self._is_overriden = True + + self.update_style() + + self.value_changed.emit(self) + + def update_style(self): + for input_field in self.input_fields: + input_field.update_style() + + def item_value(self): + if not self.multiplatform and not self.multipath: + return self.input_fields[0].item_value() + + if not self.multiplatform: + return self.input_fields[0].item_value() + + output = {} + for input_field in self.input_fields: + output.update(input_field.config_value()) + return output + + +# Proxy for form layout class FormLabel(QtWidgets.QLabel): def __init__(self, *args, **kwargs): super(FormLabel, self).__init__(*args, **kwargs) self.item = None -# Proxy for form layout class DictFormWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) allow_actions = False @@ -2081,290 +2362,15 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): return values, self.is_group -class PathInputWidget(QtWidgets.QWidget, InputObject): - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, parent, as_widget=False, label_widget=None - ): - super(PathInputWidget, self).__init__(parent) - - self._parent = parent - self._as_widget = as_widget - self._state = None - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) - - self.override_value = NOT_SET - self.global_value = NOT_SET - self.start_value = NOT_SET - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - self.label_widget = label_widget - - self.path_input = PathInput(self) - self.setFocusProxy(self.path_input) - layout.addWidget(self.path_input, 1) - - self.path_input.textChanged.connect(self._on_value_change) - - def update_global_values(self, parent_values): - value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.path_input.setText(value) - - elif self.default_value is not NOT_SET: - self.path_input.setText(self.default_value) - - self.global_value = value - self.start_value = self.item_value() - - self._is_modified = self.global_value != self.start_value - - def set_value(self, value, *, global_value=False): - self.path_input.setText(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() - - def reset_value(self): - self.set_value(self.start_value) - - def clear_value(self): - self.set_value("") - - def focusOutEvent(self, event): - self.path_input.clear_end_path() - super(PathInput, self).focusOutEvent(event) - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - self._is_modified = self.item_value() != self.global_value - if self.is_overidable: - self._is_overriden = True - - self.update_style() - - self.value_changed.emit(self) - - def update_style(self): - state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return - - if self._as_widget: - property_name = "input-state" - widget = self.path_input - else: - property_name = "state" - widget = self.label_widget - - widget.setProperty(property_name, state) - widget.style().polish(widget) - - def item_value(self): - return self.path_input.text() - - -class PathWidget(QtWidgets.QWidget, InputObject): - value_changed = QtCore.Signal(object) - - platforms = ("windows", "darwin", "linux") - platform_labels_mapping = { - "windows": "Windows", - "darwin": "MacOS", - "linux": "Linux" - } - platform_separators = { - "windows": ";", - "darwin": ":", - "linux": ":" - } - - def __init__( - self, input_data, parent, as_widget=False, label_widget=None - ): - super(PathWidget, self).__init__(parent) - - self._parent = parent - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - - self.default_value = input_data.get("default", NOT_SET) - self.multiplatform = input_data.get("multiplatform", False) - self.multipath = input_data.get("multipath", False) - - self.override_value = NOT_SET - self.global_value = NOT_SET - self.start_value = NOT_SET - - self._state = None - - self.input_fields = [] - - if not self.multiplatform and not self.multipath: - layout = QtWidgets.QHBoxLayout(self) - else: - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - self.label_widget = label_widget - - self.content_widget = QtWidgets.QWidget(self) - self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) - self.content_layout.setSpacing(0) - self.content_layout.setContentsMargins(0, 0, 0, 0) - - layout.addWidget(self.content_widget) - - self.create_gui() - - def create_gui(self): - if not self.multiplatform and not self.multipath: - input_data = {"key": self.key} - path_input = PathInputWidget( - input_data, self, label_widget=self.label_widget - ) - self.setFocusProxy(path_input) - self.content_layout.addWidget(path_input) - self.input_fields.append(path_input) - path_input.value_changed.connect(self._on_value_change) - return - - input_data_for_list = { - "object_type": "path-input" - } - if not self.multiplatform: - input_data_for_list["key"] = self.key - input_widget = ListWidget( - input_data_for_list, self, label_widget=self.label_widget - ) - self.setFocusProxy(input_widget) - self.content_layout.addWidget(input_widget) - self.input_fields.append(input_widget) - input_widget.value_changed.connect(self._on_value_change) - return - - proxy_widget = QtWidgets.QWidget(self.content_widget) - proxy_layout = QtWidgets.QFormLayout(proxy_widget) - for platform_key in self.platforms: - platform_label = self.platform_labels_mapping[platform_key] - label_widget = QtWidgets.QLabel(platform_label, proxy_widget) - if self.multipath: - input_data_for_list["key"] = platform_key - input_widget = ListWidget( - input_data_for_list, self, label_widget=label_widget - ) - else: - input_data = {"key": platform_key} - input_widget = PathInputWidget( - input_data, self, label_widget=label_widget - ) - proxy_layout.addRow(label_widget, input_widget) - self.input_fields.append(input_widget) - input_widget.value_changed.connect(self._on_value_change) - - self.setFocusProxy(self.input_fields[0]) - self.content_layout.addWidget(proxy_widget) - - def update_global_values(self, parent_values): - value = NOT_SET - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if not self.multiplatform: - self.input_fields[0].update_global_values(parent_values) - - elif self.multiplatform: - for input_field in self.input_fields: - input_field.update_global_values(value) - - self.global_value = value - self.start_value = self.item_value() - - self._is_modified = self.global_value != self.start_value - - def set_value(self, value, *, global_value=False): - print(self.__class__.__name__, "* TODO implement `set_value`") - self.text_input.setText(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() - - def reset_value(self): - print(self.__class__.__name__, "* TODO implement `reset_value`") - self.set_value(self.start_value) - - def clear_value(self): - print(self.__class__.__name__, "* TODO implement `clear_value`") - self.set_value("") - - def _on_value_change(self, item=None): - print(self.__class__.__name__, "* TODO implement `_on_value_change`") - if self.ignore_value_changes: - return - - self._is_modified = self.item_value() != self.global_value - if self.is_overidable: - self._is_overriden = True - - self.update_style() - - self.value_changed.emit(self) - - def update_style(self): - print(self.__class__.__name__, "* TODO implement `update_style`") - - def item_value(self): - if not self.multiplatform and not self.multipath: - return self.input_fields[0].item_value() - - if not self.multiplatform: - return self.input_fields[0].item_value() - - output = {} - for input_field in self.input_fields: - output.update(input_field.config_value()) - return output - - TypeToKlass.types["boolean"] = BooleanWidget -TypeToKlass.types["text-singleline"] = TextSingleLineWidget -TypeToKlass.types["path-input"] = PathInputWidget -TypeToKlass.types["path-widget"] = PathWidget -TypeToKlass.types["text-multiline"] = TextMultiLineWidget -TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["number"] = NumberWidget +TypeToKlass.types["text-singleline"] = TextSingleLineWidget +TypeToKlass.types["text-multiline"] = TextMultiLineWidget +TypeToKlass.types["path-input"] = PathInputWidget +TypeToKlass.types["raw-json"] = RawJsonWidget +TypeToKlass.types["list"] = ListWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["dict"] = DictWidget -TypeToKlass.types["dict-form"] = DictFormWidget TypeToKlass.types["dict-invisible"] = DictInvisible -TypeToKlass.types["list"] = ListWidget +TypeToKlass.types["path-widget"] = PathWidget +TypeToKlass.types["dict-form"] = DictFormWidget From b183564954bd29735a85630ef2246fec0f1f3282 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 16:52:13 +0200 Subject: [PATCH 315/580] text input has one input widget with settable attribute "multiline" --- .../1_ftrack_projects_gui_schema.json | 6 +- .../projects_schema/1_plugins_gui_schema.json | 42 +++--- .../studio_schema/1_intents_gui_schema.json | 4 +- .../studio_schema/1_tray_items.json | 2 +- .../config_setting/widgets/inputs.py | 128 +++--------------- 5 files changed, 45 insertions(+), 137 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json index 51c05aeb3a..6608463100 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json @@ -14,11 +14,11 @@ "children": [ { "key": "Ready", - "type": "text-singleline", + "type": "text", "label": "Ready" }, { "key": "Ready2", - "type": "text-singleline", + "type": "text", "label": "Ready2" } ] @@ -32,7 +32,7 @@ "children": [ { "key": "in progress", - "type": "text-singleline", + "type": "text", "label": "In Progress" } ] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index e43518989a..98fbfb206d 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -34,7 +34,7 @@ "type": "dict-form", "children": [ { - "type": "text-singleline", + "type": "text", "key": "deadline_department", "label": "Deadline apartment", "default": "" @@ -44,17 +44,17 @@ "label": "Deadline priority", "default": 50 }, { - "type": "text-singleline", + "type": "text", "key": "deadline_pool", "label": "Deadline pool", "default": "" }, { - "type": "text-singleline", + "type": "text", "key": "deadline_pool_secondary", "label": "Deadline pool (secondary)", "default": "" }, { - "type": "text-singleline", + "type": "text", "key": "deadline_group", "label": "Deadline Group", "default": "" @@ -98,13 +98,13 @@ "label": "Enabled", "default": false }, { - "type": "text-singleline", + "type": "text", "key": "note_with_intent_template", "label": "Note with intent template", "default": "{intent}: {comment}" }, { "type": "list", - "object_type": "text-singleline", + "object_type": "text", "key": "note_labels", "label": "Note labels", "default": [] @@ -155,13 +155,13 @@ "children": [ { "type": "list", - "object_type": "text-singleline", + "object_type": "text", "key": "input", "label": "FFmpeg input arguments", "default": [] }, { "type": "list", - "object_type": "text-singleline", + "object_type": "text", "key": "output", "label": "FFmpeg output arguments", "default": [] @@ -271,15 +271,15 @@ "key": "enabled", "label": "Enabled" }, { - "type": "text-singleline", + "type": "text", "key": "deadline_department", "label": "Deadline department" }, { - "type": "text-singleline", + "type": "text", "key": "deadline_pool", "label": "Deadline Pool" }, { - "type": "text-singleline", + "type": "text", "key": "deadline_group", "label": "Deadline Group" } @@ -314,11 +314,11 @@ "key": "enabled", "label": "Enabled" }, { - "type": "text-singleline", + "type": "text", "key": "material_file", "label": "Material File" }, { - "type": "text-singleline", + "type": "text", "key": "regex", "label": "Validation regex", "default": "(.*)_(\\d)*_(?P.*)_(GEO)" @@ -351,7 +351,7 @@ "key": "enabled", "label": "Enabled" }, { - "type": "text-singleline", + "type": "text", "key": "regex", "label": "Validation regex", "default": "(?P.*)_(.*)_SHD" @@ -401,7 +401,7 @@ "is_group": true, "children": [ { - "type": "text-singleline", + "type": "text", "key": "fpath_template", "label": "Path template", "default": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" @@ -415,7 +415,7 @@ "is_group": true, "children": [ { - "type": "text-singleline", + "type": "text", "key": "fpath_template", "label": "Path template", "default": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" @@ -530,12 +530,12 @@ "label": "deadline_priority", "default": 50 }, { - "type": "text-singleline", + "type": "text", "key": "deadline_pool", "label": "deadline_pool", "default": "" }, { - "type": "text-singleline", + "type": "text", "key": "deadline_pool_secondary", "label": "deadline_pool_secondary", "default": "" @@ -598,7 +598,7 @@ "default": true }, { "type": "list", - "object_type": "text-singleline", + "object_type": "text", "key": "tags_addition", "label": "Tags addition", "default": [] @@ -629,12 +629,12 @@ "is_group": true, "children": [ { - "type": "text-singleline", + "type": "text", "key": "clipName", "label": "Clip name template", "default": "{track}{sequence}{shot}" }, { - "type": "text-singleline", + "type": "text", "key": "folder", "label": "Folder", "default": "takes" diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json index 18f3d42ba7..a4b5e16fa1 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json @@ -8,11 +8,11 @@ "children": [ { "type": "dict-modifiable", - "object_type": "text-singleline", + "object_type": "text", "key": "items", "label": "Intent Key/Label" }, { - "type": "text-singleline", + "type": "text", "key": "default", "label": "Default intent" } diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json index 610430b25e..13ab0293de 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json @@ -113,7 +113,7 @@ "expandable": true, "children": [ { - "type": "text-singleline", + "type": "text", "key": "workspace_name", "label": "Workspace name" } diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ac08a9ae4f..ce14e575cf 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -529,13 +529,13 @@ class NumberWidget(QtWidgets.QWidget, InputObject): return self.input_field.value() -class TextSingleLineWidget(QtWidgets.QWidget, InputObject): +class TextWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( self, input_data, parent, as_widget=False, label_widget=None ): - super(TextSingleLineWidget, self).__init__(parent) + super(TextWidget, self).__init__(parent) self._parent = parent self._as_widget = as_widget @@ -545,6 +545,8 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) + self.multiline = input_data.get("multiline", False) + self.override_value = NOT_SET self.global_value = NOT_SET self.start_value = NOT_SET @@ -553,7 +555,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.text_input = QtWidgets.QLineEdit(self) + if self.multiline: + self.text_input = QtWidgets.QPlainTextEdit(self) + else: + self.text_input = QtWidgets.QLineEdit(self) self.setFocusProxy(self.text_input) @@ -576,10 +581,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): value = parent_values.get(self.key, NOT_SET) if value is not NOT_SET: - self.text_input.setText(value) + self.set_value(value) elif self.default_value is not NOT_SET: - self.text_input.setText(self.default_value) + self.set_value(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -587,7 +592,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value def set_value(self, value, *, global_value=False): - self.text_input.setText(value) + if self.multiline: + self.text_input.setPlainText(value) + else: + self.text_input.setText(value) if global_value: self.start_value = self.item_value() self.global_value = self.item_value() @@ -629,109 +637,10 @@ class TextSingleLineWidget(QtWidgets.QWidget, InputObject): widget.style().polish(widget) def item_value(self): - return self.text_input.text() - - -class TextMultiLineWidget(QtWidgets.QWidget, InputObject): - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, parent, as_widget=False, label_widget=None - ): - super(TextMultiLineWidget, self).__init__(parent) - - self._parent = parent - self._as_widget = as_widget - self._state = None - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) - - self.override_value = NOT_SET - self.global_value = NOT_SET - self.start_value = NOT_SET - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - - self.text_input = QtWidgets.QPlainTextEdit(self) - - self.setFocusProxy(self.text_input) - - if not self._as_widget: - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - self.label_widget = label_widget - layout.addWidget(self.text_input, 1) - - self.text_input.textChanged.connect(self._on_value_change) - - def update_global_values(self, parent_values): - value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.text_input.setPlainText(value) - - elif self.default_value is not NOT_SET: - self.text_input.setPlainText(self.default_value) - - self.global_value = value - self.start_value = self.item_value() - - self._is_modified = self.global_value != self.start_value - - def set_value(self, value, *, global_value=False): - self.text_input.setPlainText(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() - - def reset_value(self): - self.set_value(self.start_value) - - def clear_value(self): - self.set_value("") - - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - self._is_modified = self.item_value() != self.global_value - if self.is_overidable: - self._is_overriden = True - - self.update_style() - - self.value_changed.emit(self) - - def update_style(self): - state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return - - if self._as_widget: - property_name = "input-state" - widget = self.text_input + if self.multiline: + return self.text_input.toPlainText() else: - property_name = "state" - widget = self.label_widget - - widget.setProperty(property_name, state) - widget.style().polish(widget) - - def item_value(self): - return self.text_input.toPlainText() + return self.text_input.text() class PathInputWidget(QtWidgets.QWidget, InputObject): @@ -2364,8 +2273,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["number"] = NumberWidget -TypeToKlass.types["text-singleline"] = TextSingleLineWidget -TypeToKlass.types["text-multiline"] = TextMultiLineWidget +TypeToKlass.types["text"] = TextWidget TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget From 5cba39b998bbb563ebbeb59cac415b87f9498ce0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 17:16:08 +0200 Subject: [PATCH 316/580] path widget works right with overrides --- .../config_setting/widgets/inputs.py | 125 ++++++++++++++++-- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ce14e575cf..09e4629a45 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1937,7 +1937,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): return {self.key: values}, self.is_group -class PathWidget(QtWidgets.QWidget, InputObject): +class PathWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) platforms = ("windows", "darwin", "linux") @@ -1958,8 +1958,19 @@ class PathWidget(QtWidgets.QWidget, InputObject): super(PathWidget, self).__init__(parent) self._parent = parent + self._state = None + self._child_state = None - self._is_group = input_data.get("is_group", False) + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + self.any_parent_is_group = any_parent_is_group + + # This is partial input and dictionary input + if not any_parent_is_group: + self._is_group = True + else: + self._is_group = False self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) @@ -1970,8 +1981,6 @@ class PathWidget(QtWidgets.QWidget, InputObject): self.global_value = NOT_SET self.start_value = NOT_SET - self._state = None - self.input_fields = [] if not self.multiplatform and not self.multipath: @@ -2062,6 +2071,30 @@ class PathWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value + def apply_overrides(self, parent_values): + # Make sure this is set to False + self._state = None + self._child_state = None + self._is_modified = False + override_values = NOT_SET + if parent_values is not NOT_SET: + override_values = parent_values.get(self.key, override_values) + + self._is_overriden = override_values is not NOT_SET + if not self.multiplatform: + self.input_fields[0].apply_overrides(parent_values) + else: + for item in self.input_fields: + item.apply_overrides(override_values) + + if not self._is_overriden: + self._is_overriden = ( + self.is_group + and self.is_overidable + and self.child_overriden + ) + self._was_overriden = bool(self._is_overriden) + def set_value(self, value, *, global_value=False): if not self.multiplatform: self.input_fields[0].set_value(value, global_value=global_value) @@ -2089,16 +2122,79 @@ class PathWidget(QtWidgets.QWidget, InputObject): return self._is_modified = self.item_value() != self.global_value - if self.is_overidable: - self._is_overriden = True - - self.update_style() + if self.is_group: + if self.is_overidable: + self._is_overriden = True + self.hierarchical_style_update() self.value_changed.emit(self) - def update_style(self): + self.update_style() + + def update_style(self, is_overriden=None): + child_modified = self.child_modified + child_invalid = self.child_invalid + child_state = self.style_state( + child_invalid, self.child_overriden, child_modified + ) + if child_state: + child_state = "child-{}".format(child_state) + + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state + + state = self.style_state( + child_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + self._state = state + + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + for item in self.input_fields: + item.remove_overrides() + + def discard_changes(self): for input_field in self.input_fields: - input_field.update_style() + input_field.discard_changes() + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + + @property + def child_modified(self): + for input_field in self.input_fields: + if input_field.child_modified: + return True + return False + + @property + def child_overriden(self): + for input_field in self.input_fields: + if input_field.child_overriden: + return True + return False + + @property + def child_invalid(self): + for input_field in self.input_fields: + if input_field.child_invalid: + return True + return False + + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + self.update_style() def item_value(self): if not self.multiplatform and not self.multipath: @@ -2112,6 +2208,15 @@ class PathWidget(QtWidgets.QWidget, InputObject): output.update(input_field.config_value()) return output + def overrides(self): + if not self.is_overriden and not self.child_overriden: + return NOT_SET, False + + value = self.item_value() + if not self.multiplatform: + value = {self.key: value} + return value, self.is_group + # Proxy for form layout class FormLabel(QtWidgets.QLabel): From cbf1519645ff0e200af6e464314a8dbe276fea14 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 19:10:43 +0200 Subject: [PATCH 317/580] first introducing enhancement of anatomy widget --- .../config_setting/widgets/anatomy_inputs.py | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 7c9ac0d8f4..d07f69e7ca 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -5,28 +5,59 @@ from .lib import NOT_SET, TypeToKlass class AnatomyWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) + template_keys = ( + "project[name]", + "project[code]", + "asset", + "task", + "subset", + "family", + "version", + "ext", + "representation" + ) + default_exmaple_data = { + "project": { + "name": "ProjectPype", + "code": "pp", + }, + "asset": "sq01sh0010", + "task": "compositing", + "subset": "renderMain", + "family": "render", + "version": 1, + "ext": ".png", + "representation": "png" + } def __init__( self, input_data, parent, as_widget=False, label_widget=None ): + super(AnatomyWidget, self).__init__(parent) + self._parent = parent self._as_widget = as_widget self._is_group = True - self._state = None self.key = "anatomy" - self.start_value = None - super(AnatomyWidget, self).__init__(parent) + self.override_value = NOT_SET + self.start_value = NOT_SET + self.global_value = NOT_SET + + self.root_keys = None + self.root_widget = RootsWidget(self) + self.templates_widget = TemplatesWidget(self) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - label = QtWidgets.QLabel("Test") - layout.addWidget(label) - self.override_value = NOT_SET + label = QtWidgets.QLabel("Anatomy", self) + layout.addWidget(label) + layout.addWidget(self.root_widget) + layout.addWidget(self.templates_widget) def update_global_values(self, values): print("* update_global_values") @@ -47,10 +78,37 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): print("* item_value") -class TemplatesWidget: - pass +class RootsWidget(QtWidgets.QWidget): + multiroot_changed = QtCore.QSignal() + + def __init__(self, parent=None): + super(RootsWidget, self).__init__(parent) + + self.root_keys = None + + layout = QtWidgets.QHBoxLayout(self) + multiroot_checkbox = QtWidgets.QCheckBox(self) + layout.addWidget(multiroot_checkbox) + + self.multiroot_checkbox = multiroot_checkbox + multiroot_checkbox.stateChanged.connect(self._on_multiroot_checkbox) + + def _on_multiroot_checkbox(self): + self.set_multiroot(self.multiroot_checkbox.isChecked()) + + def set_multiroot(self, is_multiroot=None): + if is_multiroot is None: + is_multiroot = not self.multiroot_checkbox.isChecked() + + if is_multiroot != self.multiroot_checkbox.isChecked(): + self.multiroot_checkbox.setChecked(is_multiroot) + + self.multiroot_changed.emit() +class TemplatesWidget(QtWidgets.QWidget): + def __init__(self, parent=None): + super(TemplatesWidget, self).__init__(parent) TypeToKlass.types["anatomy"] = AnatomyWidget From 059152188d191240791e9b53f862bb17c452e7d8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 19:25:34 +0200 Subject: [PATCH 318/580] fix numer value when decimals are set to 0 --- .../tools/config_setting/config_setting/widgets/widgets.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index d5b0f088de..35b515d641 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -18,6 +18,13 @@ class NumberSpinBox(QtWidgets.QDoubleSpinBox): else: event.ignore() + def value(self): + output = super(NumberSpinBox, self).value() + print(self.decimals()) + if self.decimals() == 0: + output = int(output) + return output + class PathInput(QtWidgets.QLineEdit): def clear_end_path(self): From 043aec3fef57a430bbed0cd9bede58f466758518 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 2 Sep 2020 19:25:47 +0200 Subject: [PATCH 319/580] fix class name in anatomy --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index d07f69e7ca..46b69aaffe 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -79,7 +79,7 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): class RootsWidget(QtWidgets.QWidget): - multiroot_changed = QtCore.QSignal() + multiroot_changed = QtCore.Signal() def __init__(self, parent=None): super(RootsWidget, self).__init__(parent) From a88fcfe9fa3de9e2b52478b70f1ddb0b8a72f7c2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:19:57 +0200 Subject: [PATCH 320/580] removed debug print --- pype/tools/config_setting/config_setting/widgets/widgets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 35b515d641..e9ba1b798c 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -20,7 +20,6 @@ class NumberSpinBox(QtWidgets.QDoubleSpinBox): def value(self): output = super(NumberSpinBox, self).value() - print(self.decimals()) if self.decimals() == 0: output = int(output) return output From bccaec878ff084bafe8c04cb604b34f2d377f08b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:46:11 +0200 Subject: [PATCH 321/580] PathWidget can be as widget --- .../config_setting/widgets/inputs.py | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 09e4629a45..c0c0ba3406 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1960,6 +1960,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self._parent = parent self._state = None self._child_state = None + self._as_widget = as_widget any_parent_is_group = parent.is_group if not any_parent_is_group: @@ -1967,7 +1968,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group # This is partial input and dictionary input - if not any_parent_is_group: + if not any_parent_is_group and not as_widget: self._is_group = True else: self._is_group = False @@ -1990,12 +1991,14 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.key = input_data["key"] - if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) - self.label_widget = label_widget + if not as_widget: + self.key = input_data["key"] + if not label_widget: + label = input_data["label"] + label_widget = QtWidgets.QLabel(label) + label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget self.content_widget = QtWidgets.QWidget(self) self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) @@ -2056,15 +2059,16 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): def update_global_values(self, parent_values): value = NOT_SET - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if not self._as_widget: + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if not self.multiplatform: - self.input_fields[0].update_global_values(parent_values) + if not self.multiplatform: + self.input_fields[0].update_global_values(parent_values) - elif self.multiplatform: - for input_field in self.input_fields: - input_field.update_global_values(value) + elif self.multiplatform: + for input_field in self.input_fields: + input_field.update_global_values(value) self.global_value = value self.start_value = self.item_value() From e515895cf38e1c4f73a740dfa4f3c49ff8c80efe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:46:40 +0200 Subject: [PATCH 322/580] roots widget has multiroot and singleroot widget --- .../config_setting/widgets/anatomy_inputs.py | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 46b69aaffe..3148b8f32d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,5 +1,5 @@ from Qt import QtWidgets, QtCore -from .inputs import InputObject +from .inputs import ConfigObject, InputObject, ModifiableDict, PathWidget from .lib import NOT_SET, TypeToKlass @@ -50,7 +50,7 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): self.root_widget = RootsWidget(self) self.templates_widget = TemplatesWidget(self) - layout = QtWidgets.QHBoxLayout(self) + layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -61,6 +61,8 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): def update_global_values(self, values): print("* update_global_values") + self.root_widget.update_global_values(values) + self.templates_widget.update_global_values(values) def set_value(self, value, *, global_value=False): print("* set_value") @@ -78,21 +80,59 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): print("* item_value") -class RootsWidget(QtWidgets.QWidget): +class RootsWidget(QtWidgets.QWidget, ConfigObject): multiroot_changed = QtCore.Signal() - def __init__(self, parent=None): + def __init__(self, parent): super(RootsWidget, self).__init__(parent) + self._parent = parent + self._is_group = True self.root_keys = None - layout = QtWidgets.QHBoxLayout(self) - multiroot_checkbox = QtWidgets.QCheckBox(self) - layout.addWidget(multiroot_checkbox) + checkbox_widget = QtWidgets.QWidget(self) + + multiroot_label = QtWidgets.QLabel( + "Use multiple roots", checkbox_widget + ) + multiroot_checkbox = QtWidgets.QCheckBox(checkbox_widget) + + checkbox_layout = QtWidgets.QHBoxLayout(checkbox_widget) + checkbox_layout.addWidget(multiroot_label, 0) + checkbox_layout.addWidget(multiroot_checkbox, 1) + + path_widget_data = { + "key": "roots", + "multiplatform": True, + "label": "Roots" + } + singleroot_widget = PathWidget(path_widget_data, self) + multiroot_data = { + "key": "roots", + "label": "Roots", + "object_type": "path-widget", + "input_modifiers": { + "multiplatform": True + } + } + multiroot_widget = ModifiableDict(multiroot_data, self) + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.addWidget(checkbox_widget) + main_layout.addWidget(singleroot_widget) + main_layout.addWidget(multiroot_widget) self.multiroot_checkbox = multiroot_checkbox + self.singleroot_widget = singleroot_widget + self.multiroot_widget = multiroot_widget + multiroot_checkbox.stateChanged.connect(self._on_multiroot_checkbox) + def update_global_values(self, values): + print(values) + self.singleroot_widget.update_global_values(NOT_SET) + self.multiroot_widget.update_global_values(NOT_SET) + def _on_multiroot_checkbox(self): self.set_multiroot(self.multiroot_checkbox.isChecked()) @@ -110,5 +150,8 @@ class TemplatesWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(TemplatesWidget, self).__init__(parent) + def update_global_values(self, values): + pass + TypeToKlass.types["anatomy"] = AnatomyWidget From f147579ad943baf56c4da157aea2b8cada39fbf0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:56:00 +0200 Subject: [PATCH 323/580] pass global values to subwidgets --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 3148b8f32d..a0c94fb846 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -129,9 +129,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): multiroot_checkbox.stateChanged.connect(self._on_multiroot_checkbox) def update_global_values(self, values): - print(values) - self.singleroot_widget.update_global_values(NOT_SET) - self.multiroot_widget.update_global_values(NOT_SET) + self.singleroot_widget.update_global_values(values) + self.multiroot_widget.update_global_values(values) def _on_multiroot_checkbox(self): self.set_multiroot(self.multiroot_checkbox.isChecked()) From 462c350c0bdc25dff4700780a3d289f0c12f2e80 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:57:05 +0200 Subject: [PATCH 324/580] modifiable dict has buttons at first place --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c0c0ba3406..36bb8c9902 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1228,10 +1228,10 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.add_btn.setProperty("btn-type", "tool-item") self.remove_btn.setProperty("btn-type", "tool-item") - layout.addWidget(self.key_input, 0) - layout.addWidget(self.value_input, 1) layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) + layout.addWidget(self.key_input, 0) + layout.addWidget(self.value_input, 1) self.setFocusProxy(self.value_input) From 93a0905b6f8be0f4607a8169a0c2ddf717a40d6d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 12:11:58 +0200 Subject: [PATCH 325/580] ModifiedDictionary Item looks same as ListItem --- .../config_setting/widgets/inputs.py | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 36bb8c9902..441bc6c9a5 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1263,6 +1263,21 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def is_group(self): return self._parent.is_group + def on_add_clicked(self): + if self.value_input.isEnabled(): + self._parent.add_row(row=self.row() + 1) + else: + self.set_as_empty(False) + + def on_remove_clicked(self): + self._parent.remove_row(self) + + def set_as_empty(self, is_empty=True): + self.key_input.setEnabled(not is_empty) + self.value_input.setEnabled(not is_empty) + self.remove_btn.setEnabled(not is_empty) + self._on_value_change() + @property def any_parent_is_group(self): return self._parent.any_parent_is_group @@ -1289,16 +1304,6 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def row(self): return self._parent.input_fields.index(self) - def on_add_clicked(self): - self._parent.add_row(row=self.row() + 1) - - def on_remove_clicked(self): - if self.is_single: - self.value_input.clear_value() - self.key_input.setText("") - else: - self._parent.remove_row(self) - def config_value(self): key = self.key_input.text() value = self.value_input.item_value() @@ -1374,12 +1379,12 @@ class ModifiableDict(ExpandingWidget, InputObject): for item_key, item_value in self.default_value.items(): self.add_row(key=item_key, value=item_value) - if self.count() == 0: - self.add_row() - for old_input in old_inputs: self.remove_row(old_input) + if self.count() == 0: + self.add_row(is_empty=True) + self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value @@ -1441,19 +1446,13 @@ class ModifiableDict(ExpandingWidget, InputObject): output.update(item_value) return output - def add_row(self, row=None, key=None, value=None): + def add_row(self, row=None, key=None, value=None, is_empty=False): # Create new item item_widget = ModifiableDictItem( self.object_type, self.input_modifiers, self, self.inputs_widget ) - - # Set/unset if new item is single item - current_count = self.count() - if current_count == 0: - item_widget.is_single = True - elif current_count == 1: - for _input_field in self.input_fields: - _input_field.is_single = False + if is_empty: + item_widget.set_as_empty() item_widget.value_changed.connect(self._on_value_change) @@ -1493,12 +1492,8 @@ class ModifiableDict(ExpandingWidget, InputObject): item_widget.setParent(None) item_widget.deleteLater() - current_count = self.count() - if current_count == 0: - self.add_row() - elif current_count == 1: - for _input_field in self.input_fields: - _input_field.is_single = True + if self.count() == 0: + self.add_row(is_empty=True) self._on_value_change() self.parent().updateGeometry() From 787d8516cbaa288b3c8c14c83c0f2fd53cfa52da Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 13:21:11 +0200 Subject: [PATCH 326/580] hide inputs based on checkbox --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index a0c94fb846..943b8b0973 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -128,6 +128,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): multiroot_checkbox.stateChanged.connect(self._on_multiroot_checkbox) + self._on_multiroot_checkbox() + def update_global_values(self, values): self.singleroot_widget.update_global_values(values) self.multiroot_widget.update_global_values(values) @@ -142,6 +144,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot != self.multiroot_checkbox.isChecked(): self.multiroot_checkbox.setChecked(is_multiroot) + self.singleroot_widget.setVisible(not is_multiroot) + self.multiroot_widget.setVisible(is_multiroot) + self.multiroot_changed.emit() From f505f3099ac79d9bdde4fd9c952576eb5672afc0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 13:53:00 +0200 Subject: [PATCH 327/580] modifiable dict is not based on expanding widget but using it inside --- .../config_setting/widgets/inputs.py | 56 ++++++++++++------- .../config_setting/widgets/widgets.py | 2 +- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 441bc6c9a5..394a0f69ca 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1312,7 +1312,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): return {key: value} -class ModifiableDict(ExpandingWidget, InputObject): +class ModifiableDict(QtWidgets.QWidget, InputObject): # Should be used only for dictionary with one datatype as value # TODO this is actually input field (do not care if is group or not) value_changed = QtCore.Signal(object) @@ -1320,7 +1320,7 @@ class ModifiableDict(ExpandingWidget, InputObject): def __init__( self, input_data, parent, as_widget=False, label_widget=None ): - super(ModifiableDict, self).__init__(input_data["label"], parent) + super(ModifiableDict, self).__init__(parent) self.setObjectName("ModifiableDict") self._parent = parent @@ -1330,10 +1330,6 @@ class ModifiableDict(ExpandingWidget, InputObject): self.global_value = NOT_SET self.start_value = NOT_SET - self.key = input_data["key"] - - self.input_fields = [] - any_parent_is_group = parent.is_group if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group @@ -1343,17 +1339,39 @@ class ModifiableDict(ExpandingWidget, InputObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) - inputs_widget = QtWidgets.QWidget(self) - inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + self.input_fields = [] - inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) - inputs_layout.setContentsMargins(5, 5, 0, 5) - inputs_layout.setSpacing(5) + self.key = input_data["key"] - self.set_content_widget(inputs_widget) + main_layout = QtWidgets.QHBoxLayout(self) + main_layout.setContentsMargins(5, 5, 0, 5) + main_layout.setSpacing(0) - self.inputs_widget = inputs_widget - self.inputs_layout = inputs_layout + body_widget = ExpandingWidget(input_data["label"], self) + + main_layout.addWidget(body_widget) + + content_widget = QtWidgets.QWidget(self) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(3, 3, 0, 3) + + body_widget.set_content_widget(content_widget) + + self.body_widget = body_widget + self.content_widget = content_widget + self.content_layout = content_layout + + self.label_widget = body_widget.label_widget + + self.setAttribute(QtCore.Qt.WA_StyledBackground) + + expandable = input_data.get("expandable", True) + if not expandable: + body_widget.hide_toolbox(hide_content=False) + else: + expanded = input_data.get("expanded", False) + if expanded: + body_widget.toggle_content() self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) @@ -1449,7 +1467,7 @@ class ModifiableDict(ExpandingWidget, InputObject): def add_row(self, row=None, key=None, value=None, is_empty=False): # Create new item item_widget = ModifiableDictItem( - self.object_type, self.input_modifiers, self, self.inputs_widget + self.object_type, self.input_modifiers, self, self.content_widget ) if is_empty: item_widget.set_as_empty() @@ -1457,10 +1475,10 @@ class ModifiableDict(ExpandingWidget, InputObject): item_widget.value_changed.connect(self._on_value_change) if row is None: - self.inputs_layout.addWidget(item_widget) + self.content_layout.addWidget(item_widget) self.input_fields.append(item_widget) else: - self.inputs_layout.insertWidget(row, item_widget) + self.content_layout.insertWidget(row, item_widget) self.input_fields.insert(row, item_widget) previous_input = None @@ -1487,7 +1505,7 @@ class ModifiableDict(ExpandingWidget, InputObject): def remove_row(self, item_widget): item_widget.value_changed.disconnect() - self.inputs_layout.removeWidget(item_widget) + self.content_layout.removeWidget(item_widget) self.input_fields.remove(item_widget) item_widget.setParent(None) item_widget.deleteLater() @@ -1543,7 +1561,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(3, 3, 0, 3) - body_widget.set_content_widget(content_widget, (4, 4, 0, 4)) + body_widget.set_content_widget(content_widget) self.body_widget = body_widget self.content_widget = content_widget diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index e9ba1b798c..fbbc3f26df 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -111,7 +111,7 @@ class ExpandingWidget(QtWidgets.QWidget): def set_content_widget(self, content_widget, margins=None): main_layout = QtWidgets.QVBoxLayout(self) if margins is None: - margins = (9, 9, 0, 9) + margins = (4, 4, 0, 4) main_layout.setContentsMargins(*margins) content_widget.setVisible(False) From 88e2a794d4d79eb6c4a57d922c7b6e1614e7e7e6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 16:23:46 +0200 Subject: [PATCH 328/580] added abstract class for objects --- .../config_setting/widgets/inputs.py | 76 +------- .../config_setting/widgets/widgets.py | 180 ++++++++++++++++++ 2 files changed, 185 insertions(+), 71 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 394a0f69ca..379b255359 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2,6 +2,7 @@ import json import logging from Qt import QtWidgets, QtCore, QtGui from .widgets import ( + AbstractConfigObject, ExpandingWidget, NumberSpinBox, PathInput @@ -9,7 +10,7 @@ from .widgets import ( from .lib import NOT_SET, METADATA_KEY, TypeToKlass -class ConfigObject: +class ConfigObject(AbstractConfigObject): allow_actions = True default_state = "" @@ -72,10 +73,6 @@ class ConfigObject: @property def ignore_value_changes(self): """Most of attribute changes are ignored on value change when True.""" - if not hasattr(self, "_parent"): - raise NotImplementedError( - "Object {} does not have `_parent` attribute".format(self) - ) return self._parent.ignore_value_changes @ignore_value_changes.setter @@ -83,44 +80,12 @@ class ConfigObject: """Setter for global parent item to apply changes for all inputs.""" self._parent.ignore_value_changes = value - @property - def child_modified(self): - """Any children item is modified.""" - raise NotImplementedError( - "{} does not have implemented `child_modified`".format(self) - ) - - @property - def child_overriden(self): - """Any children item is overriden.""" - raise NotImplementedError( - "{} does not have implemented `child_overriden`".format(self) - ) - - @property - def child_invalid(self): - """Any children item does not have valid value.""" - raise NotImplementedError( - "{} does not have implemented `child_invalid`".format(self) - ) - - def get_invalid(self): - """Returns invalid items all down the hierarchy.""" - raise NotImplementedError( - "{} does not have implemented `get_invalid`".format(self) - ) - - def item_value(self): - """Value of an item without key.""" - raise NotImplementedError( - "Method `item_value` not implemented!" - ) - def config_value(self): """Output for saving changes or overrides.""" return {self.key: self.item_value()} - def style_state(self, is_invalid, is_overriden, is_modified): + @classmethod + def style_state(cls, is_invalid, is_overriden, is_modified): items = [] if is_invalid: items.append("invalid") @@ -129,54 +94,23 @@ class ConfigObject: items.append("overriden") if is_modified: items.append("modified") - return "-".join(items) or self.default_state - - def add_children_gui(self, child_configuration, values): - raise NotImplementedError( - "{} Method `add_children_gui` is not implemented!.".format( - repr(self) - ) - ) + return "-".join(items) or cls.default_state def _discard_changes(self): self.ignore_value_changes = True self.discard_changes() self.ignore_value_changes = False - def discard_changes(self): - raise NotImplementedError( - "{} Method `discard_changes` not implemented!".format( - repr(self) - ) - ) - def _remove_overrides(self): self.ignore_value_changes = True self.remove_overrides() self.ignore_value_changes = False - def remove_overrides(self): - raise NotImplementedError( - "{} Method `remove_overrides` not implemented!".format( - repr(self) - ) - ) - def _set_as_overriden(self): self.ignore_value_changes = True self.set_as_overriden() self.ignore_value_changes = False - def set_as_overriden(self): - raise NotImplementedError( - "Method `set_as_overriden` not implemented!" - ) - - def hierarchical_style_update(self): - raise NotImplementedError( - "Method `hierarchical_style_update` not implemented!" - ) - def mouseReleaseEvent(self, event): if self.allow_actions and event.button() == QtCore.Qt.RightButton: menu = QtWidgets.QMenu() diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index fbbc3f26df..42ca49d600 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -180,3 +180,183 @@ class UnsavedChangesDialog(QtWidgets.QDialog): def on_discard_pressed(self): self.done(2) + + +class AbstractConfigObject: + abstract_attributes = ("_parent", ) + + def __getattr__(self, name): + if name in self.abstract_attributes: + raise NotImplementedError( + "Attribute `{}` is not implemented. {}".format(name, self) + ) + return super(AbstractConfigObject, self).__getattribute__(name) + + @property + def log(self): + raise NotImplementedError( + "{} does not have implemented `log`".format(self) + ) + + @property + def is_modified(self): + """Has object any changes that require saving.""" + raise NotImplementedError( + "{} does not have implemented `is_modified`".format(self) + ) + + @property + def is_overriden(self): + """Is object overriden so should be saved to overrides.""" + raise NotImplementedError( + "{} does not have implemented `is_overriden`".format(self) + ) + + @property + def was_overriden(self): + """Initial state after applying overrides.""" + raise NotImplementedError( + "{} does not have implemented `was_overriden`".format(self) + ) + + @property + def is_invalid(self): + """Value set in is not valid.""" + raise NotImplementedError( + "{} does not have implemented `is_invalid`".format(self) + ) + + @property + def is_group(self): + """Value set in is not valid.""" + raise NotImplementedError( + "{} does not have implemented `is_group`".format(self) + ) + + @property + def is_nullable(self): + raise NotImplementedError( + "{} does not have implemented `is_nullable`".format(self) + ) + + @property + def is_overidable(self): + """Should care about overrides.""" + raise NotImplementedError( + "{} does not have implemented `is_overidable`".format(self) + ) + + def any_parent_overriden(self): + """Any of parent object up to top hiearchy is overriden.""" + raise NotImplementedError( + "{} does not have implemented `any_parent_overriden`".format(self) + ) + + @property + def ignore_value_changes(self): + """Most of attribute changes are ignored on value change when True.""" + raise NotImplementedError( + "{} does not have implemented `ignore_value_changes`".format(self) + ) + + @ignore_value_changes.setter + def ignore_value_changes(self, value): + """Setter for global parent item to apply changes for all inputs.""" + raise NotImplementedError(( + "{} does not have implemented setter method `ignore_value_changes`" + ).format(self)) + + @property + def child_modified(self): + """Any children item is modified.""" + raise NotImplementedError( + "{} does not have implemented `child_modified`".format(self) + ) + + @property + def child_overriden(self): + """Any children item is overriden.""" + raise NotImplementedError( + "{} does not have implemented `child_overriden`".format(self) + ) + + @property + def child_invalid(self): + """Any children item does not have valid value.""" + raise NotImplementedError( + "{} does not have implemented `child_invalid`".format(self) + ) + + def get_invalid(self): + """Returns invalid items all down the hierarchy.""" + raise NotImplementedError( + "{} does not have implemented `get_invalid`".format(self) + ) + + def item_value(self): + """Value of an item without key.""" + raise NotImplementedError( + "Method `item_value` not implemented!" + ) + + def config_value(self): + """Output for saving changes or overrides.""" + return {self.key: self.item_value()} + + @classmethod + def style_state(cls, is_invalid, is_overriden, is_modified): + items = [] + if is_invalid: + items.append("invalid") + else: + if is_overriden: + items.append("overriden") + if is_modified: + items.append("modified") + return "-".join(items) or cls.default_state + + def add_children_gui(self, child_configuration, values): + raise NotImplementedError( + "{} Method `add_children_gui` is not implemented!.".format( + repr(self) + ) + ) + + def _discard_changes(self): + self.ignore_value_changes = True + self.discard_changes() + self.ignore_value_changes = False + + def discard_changes(self): + raise NotImplementedError( + "{} Method `discard_changes` not implemented!".format( + repr(self) + ) + ) + + def _remove_overrides(self): + self.ignore_value_changes = True + self.remove_overrides() + self.ignore_value_changes = False + + def remove_overrides(self): + raise NotImplementedError( + "{} Method `remove_overrides` not implemented!".format( + repr(self) + ) + ) + + def _set_as_overriden(self): + self.ignore_value_changes = True + self.set_as_overriden() + self.ignore_value_changes = False + + def set_as_overriden(self): + raise NotImplementedError( + "Method `set_as_overriden` not implemented!" + ) + + def hierarchical_style_update(self): + raise NotImplementedError( + "Method `hierarchical_style_update` not implemented!" + ) From 3ef141c8cadcd77caba894517764ff9730750716 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 16:24:08 +0200 Subject: [PATCH 329/580] Anatmy widget updated style changes --- .../config_setting/style/style.css | 21 +-- .../config_setting/widgets/anatomy_inputs.py | 172 ++++++++++++++++-- 2 files changed, 167 insertions(+), 26 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 937259ba7b..638bf1c6fb 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -123,8 +123,7 @@ QPushButton[btn-type="expand-toggle"] { #DictLabel { font-weight: bold; } - -#ModifiableDict, #DictWidget { +#ModifiableDict, #DictWidget, #AnatomyWidget { border-style: solid; border-color: #455c6e; border-left-width: 3px; @@ -132,36 +131,36 @@ QPushButton[btn-type="expand-toggle"] { border-right-width: 0px; border-top-width: 0px; } -#ModifiableDict:hover, #DictWidget:hover { +#ModifiableDict:hover, #DictWidget:hover, #AnatomyWidget:hover { border-color: #62839d; } -#ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"] { +#ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"], #AnatomyWidget[state="child-modified"] { border-color: #106aa2; } -#ModifiableDict[state="child-modified"]:hover, #DictWidget[state="child-modified"]:hover { +#ModifiableDict[state="child-modified"]:hover, #DictWidget[state="child-modified"]:hover, #AnatomyWidget[state="child-modified"]:hover { border-color: #137cbd; } -#ModifiableDict[state="child-invalid"], #DictWidget[state="child-invalid"] { +#ModifiableDict[state="child-invalid"], #DictWidget[state="child-invalid"], #AnatomyWidget[state="child-invalid"] { border-color: #ad2e2e; } -#ModifiableDict[state="child-invalid"]:hover, #DictWidget[state="child-invalid"]:hover { +#ModifiableDict[state="child-invalid"]:hover, #DictWidget[state="child-invalid"]:hover, #AnatomyWidget[state="child-invalid"]:hover { border-color: #c93636; } -#ExpandingWidget[state="child-overriden"], #ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"] { +#ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"], #AnatomyWidget[state="child-overriden"] { border-color: #e67300; } -#ExpandingWidget[state="child-overriden"]:hover, #ModifiableDict[state="child-overriden"]:hover, #DictWidget[state="child-overriden"]:hover { +#ModifiableDict[state="child-overriden"]:hover, #DictWidget[state="child-overriden"]:hover, #AnatomyWidget[state="child-overriden"]:hover { border-color: #ff8c1a; } -#ExpandingWidget[state="child-overriden-modified"], #ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"] { +#ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"], #AnatomyWidget[state="child-modified"] { border-color: #106aa2; } -#ExpandingWidget[state="child-overriden-modified"]:hover, #ModifiableDict[state="child-overriden-modified"]:hover, #DictWidget[state="child-overriden-modified"]:hover { +#ModifiableDict[state="child-overriden-modified"]:hover, #DictWidget[state="child-overriden-modified"]:hover, #AnatomyWidget[state="child-modified"]:hover { border-color: #137cbd; } diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 943b8b0973..11d94319e6 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,9 +1,10 @@ from Qt import QtWidgets, QtCore -from .inputs import ConfigObject, InputObject, ModifiableDict, PathWidget +from .widgets import ExpandingWidget +from .inputs import ConfigObject, ModifiableDict, PathWidget from .lib import NOT_SET, TypeToKlass -class AnatomyWidget(QtWidgets.QWidget, InputObject): +class AnatomyWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) template_keys = ( "project[name]", @@ -33,10 +34,16 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): def __init__( self, input_data, parent, as_widget=False, label_widget=None ): + if as_widget: + raise TypeError( + "`AnatomyWidget` does not allow to be used as widget." + ) super(AnatomyWidget, self).__init__(parent) - + self.setObjectName("AnatomyWidget") self._parent = parent - self._as_widget = as_widget + + self._child_state = None + self._state = None self._is_group = True @@ -50,14 +57,26 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): self.root_widget = RootsWidget(self) self.templates_widget = TemplatesWidget(self) - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) + self.setAttribute(QtCore.Qt.WA_StyledBackground) - label = QtWidgets.QLabel("Anatomy", self) - layout.addWidget(label) - layout.addWidget(self.root_widget) - layout.addWidget(self.templates_widget) + body_widget = ExpandingWidget("Anatomy", self) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(5, 5, 0, 5) + layout.setSpacing(0) + layout.addWidget(body_widget) + + content_widget = QtWidgets.QWidget(body_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setSpacing(5) + + content_layout.addWidget(self.root_widget) + content_layout.addWidget(self.templates_widget) + + body_widget.set_content_widget(content_widget) + + self.label_widget = body_widget.label_widget def update_global_values(self, values): print("* update_global_values") @@ -73,8 +92,63 @@ class AnatomyWidget(QtWidgets.QWidget, InputObject): def _on_value_change(self, item=None): print("* _on_value_change") - def update_style(self): + def update_style(self, is_overriden=None): print("* update_style") + child_modified = self.child_modified + child_invalid = self.child_invalid + child_state = self.style_state( + child_invalid, self.child_overriden, child_modified + ) + if child_state: + child_state = "child-{}".format(child_state) + + if child_state != self._child_state: + self.setProperty("state", child_state) + self.style().polish(self) + self._child_state = child_state + + state = self.style_state( + child_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + self._state = state + + def hierarchical_style_update(self): + self.root_widget.hierarchical_style_update() + self.templates_widget.hierarchical_style_update() + self.update_style() + + @property + def is_modified(self): + return self._is_modified or self.child_modified + + @property + def child_modified(self): + return ( + self.root_widget.child_modified + or self.templates_widget.child_modified + ) + + @property + def child_overriden(self): + return ( + self.root_widget.is_overriden + or self.root_widget.child_overriden + or self.templates_widget.is_overriden + or self.templates_widget.child_overriden + ) + + @property + def child_invalid(self): + return ( + self.root_widget.child_invalid + or self.templates_widget.child_invalid + ) def item_value(self): print("* item_value") @@ -85,6 +159,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def __init__(self, parent): super(RootsWidget, self).__init__(parent) + self.setObjectName("RootsWidget") self._parent = parent self._is_group = True @@ -111,6 +186,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): "key": "roots", "label": "Roots", "object_type": "path-widget", + "expandable": False, "input_modifiers": { "multiplatform": True } @@ -130,18 +206,26 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._on_multiroot_checkbox() + @property + def is_multiroot(self): + return self.multiroot_checkbox.isChecked() + def update_global_values(self, values): self.singleroot_widget.update_global_values(values) self.multiroot_widget.update_global_values(values) + def hierarchical_style_update(self): + self.singleroot_widget.hierarchical_style_update() + self.multiroot_widget.hierarchical_style_update() + def _on_multiroot_checkbox(self): - self.set_multiroot(self.multiroot_checkbox.isChecked()) + self.set_multiroot(self.is_multiroot) def set_multiroot(self, is_multiroot=None): if is_multiroot is None: - is_multiroot = not self.multiroot_checkbox.isChecked() + is_multiroot = not self.is_multiroot - if is_multiroot != self.multiroot_checkbox.isChecked(): + if is_multiroot != self.is_multiroot: self.multiroot_checkbox.setChecked(is_multiroot) self.singleroot_widget.setVisible(not is_multiroot) @@ -149,6 +233,41 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.multiroot_changed.emit() + @property + def is_modified(self): + return self._is_modified or self.child_modified + + @property + def is_overriden(self): + return self._is_overriden + + @property + def child_modified(self): + if self.is_multiroot: + return self.multiroot_widget.child_modified + else: + return self.singleroot_widget.child_modified + + @property + def child_overriden(self): + if self.is_multiroot: + return ( + self.multiroot_widget.is_overriden + or self.multiroot_widget.child_overriden + ) + else: + return ( + self.singleroot_widget.is_overriden + or self.singleroot_widget.child_overriden + ) + + @property + def child_invalid(self): + if self.is_multiroot: + return self.multiroot_widget.child_invalid + else: + return self.singleroot_widget.child_invalid + class TemplatesWidget(QtWidgets.QWidget): def __init__(self, parent=None): @@ -157,5 +276,28 @@ class TemplatesWidget(QtWidgets.QWidget): def update_global_values(self, values): pass + def hierarchical_style_update(self): + pass + + @property + def is_modified(self): + return False + + @property + def is_overriden(self): + return False + + @property + def child_modified(self): + return False + + @property + def child_overriden(self): + return False + + @property + def child_invalid(self): + return False + TypeToKlass.types["anatomy"] = AnatomyWidget From 821a9c2dacae9952830ad7412b717a7885e766eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 18:07:11 +0200 Subject: [PATCH 330/580] fixed maya icon --- pype/resources/app_icons/maya.png | Bin 41557 -> 122413 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pype/resources/app_icons/maya.png b/pype/resources/app_icons/maya.png index e84a6a3742f325769d6cf619045d17107d925f3c..95c605f50d6d4459a2c1028922a44affe0d11161 100644 GIT binary patch literal 122413 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 z
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 literal 41557 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 From 3271346b129f5b5027aec3d5343f771bbbe30a10 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 10:29:22 +0200 Subject: [PATCH 331/580] make sure saving won't crash if current files are not valid --- .../config_setting/config_setting/widgets/base.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index f057f5a0f6..066c00c96d 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -144,11 +144,14 @@ class StudioWidget(QtWidgets.QWidget): subpath = "/".join(key_sequence) + ".json" origin_values = current_configurations for key in key_sequence: - if key not in origin_values: + if not origin_values or key not in origin_values: origin_values = {} break origin_values = origin_values[key] + if not origin_values: + origin_values = {} + new_values = all_values for key in key_sequence: new_values = new_values[key] @@ -518,11 +521,14 @@ class ProjectWidget(QtWidgets.QWidget): subpath = "/".join(key_sequence) + ".json" origin_values = current_configurations for key in key_sequence: - if key not in origin_values: + if not origin_values or key not in origin_values: origin_values = {} break origin_values = origin_values[key] + if not origin_values: + origin_values = {} + new_values = all_values for key in key_sequence: new_values = new_values[key] From e87288998db354bae408af01fae131219f69a6d0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 10:30:03 +0200 Subject: [PATCH 332/580] pathwidget does not care about label if is used as widget --- .../config_setting/widgets/inputs.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 379b255359..f925e6e163 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2096,16 +2096,17 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.style().polish(self) self._child_state = child_state - state = self.style_state( - child_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return + if not self._as_widget: + state = self.style_state( + child_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) - self._state = state + self._state = state def remove_overrides(self): self._is_overriden = False From 3831af2a26d008f9c01ccd7b851b554adeb50e6d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 10:30:22 +0200 Subject: [PATCH 333/580] roots can collect data --- .../config_setting/widgets/anatomy_inputs.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 11d94319e6..c0a64a8d7d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -151,7 +151,12 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): ) def item_value(self): - print("* item_value") + output = {} + output.update(self.root_widget.config_value()) + return output + + def config_value(self): + return {self.key: self.item_value()} class RootsWidget(QtWidgets.QWidget, ConfigObject): @@ -162,11 +167,11 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.setObjectName("RootsWidget") self._parent = parent self._is_group = True + self.key = "roots" self.root_keys = None checkbox_widget = QtWidgets.QWidget(self) - multiroot_label = QtWidgets.QLabel( "Use multiple roots", checkbox_widget ) @@ -268,6 +273,15 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: return self.singleroot_widget.child_invalid + def item_value(self): + if self.is_multiroot: + return self.multiroot_widget.item_value() + else: + return self.singleroot_widget.item_value() + + def config_value(self): + return {self.key: self.item_value()} + class TemplatesWidget(QtWidgets.QWidget): def __init__(self, parent=None): From 69dbfd2faf101facbe611c57eec4d8f925d8d248 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 10:41:14 +0200 Subject: [PATCH 334/580] updating global values for roots should work --- .../config_setting/widgets/anatomy_inputs.py | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index c0a64a8d7d..e4f7a6383a 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -78,10 +78,14 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget - def update_global_values(self, values): - print("* update_global_values") - self.root_widget.update_global_values(values) - self.templates_widget.update_global_values(values) + def update_global_values(self, parent_values): + if isinstance(parent_values, dict): + value = parent_values.get(self.key, NOT_SET) + else: + value = NOT_SET + + self.root_widget.update_global_values(value) + self.templates_widget.update_global_values(value) def set_value(self, value, *, global_value=False): print("* set_value") @@ -215,9 +219,25 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def is_multiroot(self): return self.multiroot_checkbox.isChecked() - def update_global_values(self, values): - self.singleroot_widget.update_global_values(values) - self.multiroot_widget.update_global_values(values) + def update_global_values(self, parent_values): + if isinstance(parent_values, dict): + value = parent_values.get(self.key, NOT_SET) + else: + value = NOT_SET + + is_multiroot = False + if isinstance(value, dict): + for _value in value.values(): + if isinstance(_value, dict): + is_multiroot = True + break + + self.set_multiroot(is_multiroot) + + if is_multiroot: + self.multiroot_widget.update_global_values(parent_values) + else: + self.singleroot_widget.update_global_values(parent_values) def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() From 7efc99b5ef87dbc9bc2b80fbeed3acb9f4970d63 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 10:44:56 +0200 Subject: [PATCH 335/580] add first row to list and modifiable dictionary by default --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f925e6e163..ae0ece42bd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -982,6 +982,8 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.inputs_widget = inputs_widget self.inputs_layout = inputs_layout + self.add_row(is_empty=True) + def count(self): return len(self.input_fields) @@ -1311,6 +1313,8 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} + self.add_row(is_empty=True) + def count(self): return len(self.input_fields) From 18812a64e093619422e33834696a786862f9cb25 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 12:49:25 +0200 Subject: [PATCH 336/580] NOT_SET is False when used in condition --- pype/tools/config_setting/config_setting/widgets/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index 4669004b53..0d70885de7 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -11,7 +11,7 @@ class TypeToKlass: types = {} -NOT_SET = type("NOT_SET", (), {}) +NOT_SET = type("NOT_SET", (), {"__bool__": lambda obj: False})() METADATA_KEY = type("METADATA_KEY", (), {}) OVERRIDE_VERSION = 1 From 1d0f00dced4b4001ef0d53d84fba66e4c98e1c25 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 13:01:02 +0200 Subject: [PATCH 337/580] modifiable dict and its item has right hiearrchical update methods --- .../config_setting/config_setting/widgets/inputs.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ae0ece42bd..eeb6cf64cd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1228,6 +1228,10 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def is_modified(self): return self.is_value_modified() or self.is_key_modified() + def hierarchical_style_update(self): + self.value_input.hierarchical_style_update() + self.update_style() + def update_style(self): if self.is_key_modified(): state = "modified" @@ -1374,6 +1378,11 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.update_style() + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + self.update_style() + def update_style(self): state = self.style_state( self.is_invalid, self.is_overriden, self.is_modified From e215f2e1407ed14919892d9fb72532b2324b09f4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 13:02:51 +0200 Subject: [PATCH 338/580] inputs' set_value method does not accept global_value as kwarg --- .../config_setting/widgets/inputs.py | 59 ++++--------------- 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index eeb6cf64cd..57785a1bce 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -301,16 +301,11 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): # Ignore value change because if `self.isChecked()` has same # value as `value` the `_on_value_change` is not triggered self.checkbox.setChecked(value) - if global_value: - self.global_value = self.item_value() - - self._on_value_change() - def clear_value(self): self.set_value(False) @@ -417,12 +412,8 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): self.input_field.setValue(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() def clear_value(self): self.set_value(0) @@ -525,15 +516,11 @@ class TextWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): if self.multiline: self.text_input.setPlainText(value) else: self.text_input.setText(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() def reset_value(self): self.set_value(self.start_value) @@ -632,12 +619,8 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): self.path_input.setText(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() def reset_value(self): self.set_value(self.start_value) @@ -709,7 +692,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): return hint - def set_value(self, value, *, global_value=False): + def set_value(self, value): if value is NOT_SET: value = "" elif not isinstance(value, str): @@ -802,12 +785,8 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): self.text_input.set_value(value) - if global_value: - self.start_value = self.item_value() - self.global_value = self.item_value() - self._on_value_change() def reset_value(self): self.set_value(self.start_value) @@ -1020,7 +999,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): previous_inputs = tuple(self.input_fields) for item_value in value: self.add_row(value=item_value) @@ -1028,11 +1007,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): for input_field in previous_inputs: self.remove_row(input_field) - if global_value: - self.global_value = value - self.start_value = self.item_value() - self._on_value_change() - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1349,7 +1323,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._is_modified = self.global_value != self.start_value - def set_value(self, value, *, global_value=False): + def set_value(self, value): previous_inputs = tuple(self.input_fields) for item_key, item_value in value.items(): self.add_row(key=item_key, value=item_value) @@ -1357,11 +1331,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): for input_field in previous_inputs: self.remove_row(input_field) - if global_value: - self.global_value = value - self.start_value = self.item_value() - self._on_value_change() - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1444,7 +1413,8 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if value is not None and key is not None: item_widget.default_key = key item_widget.key_input.setText(key) - item_widget.value_input.set_value(value, global_value=True) + item_widget.value_input.update_global_values(value) + self.hierarchical_style_update() else: self._on_value_change() self.parent().updateGeometry() @@ -2059,20 +2029,15 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): ) self._was_overriden = bool(self._is_overriden) - def set_value(self, value, *, global_value=False): + def set_value(self, value): if not self.multiplatform: - self.input_fields[0].set_value(value, global_value=global_value) + self.input_fields[0].set_value(value) else: for input_field in self.input_fields: _value = value[input_field.key] input_field.set_value(_value) - if global_value: - self.global_value = value - self.start_value = self.item_value() - self._on_value_change() - def reset_value(self): for input_field in self.input_fields: input_field.reset_value() From 87085481551cefa94c9ddf7775ab6238deeb34b4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 13:03:48 +0200 Subject: [PATCH 339/580] update_global_value can accept values for inputs used as widgets --- .../config_setting/widgets/inputs.py | 102 ++++++++++-------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 57785a1bce..ea6cd121bd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -286,15 +286,16 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): def update_global_values(self, parent_values): value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if value is not NOT_SET: - self.checkbox.setChecked(value) + if value is not NOT_SET: + self.set_value(value) - elif self.default_value is not NOT_SET: - self.checkbox.setChecked(self.default_value) + elif self.default_value is not NOT_SET: + self.set_value(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -397,15 +398,17 @@ class NumberWidget(QtWidgets.QWidget, InputObject): def update_global_values(self, parent_values): value = NOT_SET - if not self._as_widget: + if self._as_widget: + value = parent_values + else: if parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) - if value is not NOT_SET: - self.input_field.setValue(value) + if value is not NOT_SET: + self.set_value(value) - elif self.default_value is not NOT_SET: - self.input_field.setValue(self.default_value) + elif self.default_value is not NOT_SET: + self.set_value(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -501,15 +504,16 @@ class TextWidget(QtWidgets.QWidget, InputObject): def update_global_values(self, parent_values): value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if value is not NOT_SET: - self.set_value(value) + if value is not NOT_SET: + self.set_value(value) - elif self.default_value is not NOT_SET: - self.set_value(self.default_value) + elif self.default_value is not NOT_SET: + self.set_value(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -604,15 +608,16 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): def update_global_values(self, parent_values): value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if value is not NOT_SET: - self.path_input.setText(value) + if value is not NOT_SET: + self.set_value(value) - elif self.default_value is not NOT_SET: - self.path_input.setText(self.default_value) + elif self.default_value is not NOT_SET: + self.set_value(self.default_value) self.global_value = value self.start_value = self.item_value() @@ -768,21 +773,21 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def update_global_values(self, parent_values): value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if value is not NOT_SET: - self.text_input.set_value(value) + if value is not NOT_SET: + self.set_value(value) - elif self.default_value is not NOT_SET: - self.text_input.set_value(self.default_value) - - self._is_invalid = self.text_input.has_invalid_value() + elif self.default_value is not NOT_SET: + self.set_value(self.default_value) self.global_value = value self.start_value = self.item_value() + self._is_invalid = self.text_input.has_invalid_value() self._is_modified = self.global_value != self.start_value def set_value(self, value): @@ -924,6 +929,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self._parent = parent self._state = None + self._as_widget = as_widget self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) @@ -976,7 +982,9 @@ class ListWidget(QtWidgets.QWidget, InputObject): old_inputs = tuple(self.input_fields) value = NOT_SET - if parent_values is not NOT_SET: + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) self.global_value = value @@ -1300,7 +1308,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): old_inputs = tuple(self.input_fields) value = NOT_SET - if parent_values is not NOT_SET: + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) self.global_value = value @@ -1989,20 +1999,20 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): def update_global_values(self, parent_values): value = NOT_SET - if not self._as_widget: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - if not self.multiplatform: - self.input_fields[0].update_global_values(parent_values) + if not self.multiplatform: + self.input_fields[0].update_global_values(parent_values) - elif self.multiplatform: - for input_field in self.input_fields: - input_field.update_global_values(value) + elif self.multiplatform: + for input_field in self.input_fields: + input_field.update_global_values(value) self.global_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value def apply_overrides(self, parent_values): From df2ecaa6696fb55b286b158783cf18435dad9cf8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 13:05:03 +0200 Subject: [PATCH 340/580] styles are updated in right way for as_widget inputs --- .../config_setting/config_setting/widgets/inputs.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ea6cd121bd..d2f7f6cae6 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1053,7 +1053,8 @@ class ListWidget(QtWidgets.QWidget, InputObject): # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` if value is not None: - item_widget.value_input.set_value(value, global_value=True) + item_widget.value_input.update_global_values(value) + self.hierarchical_style_update() else: self._on_value_change() self.updateGeometry() @@ -1247,6 +1248,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._parent = parent self._state = None + self._as_widget = as_widget self.override_value = NOT_SET self.global_value = NOT_SET @@ -1615,9 +1617,9 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.update_style() def hierarchical_style_update(self): - self.update_style() for input_field in self.input_fields: input_field.hierarchical_style_update() + self.update_style() def update_style(self, is_overriden=None): child_modified = self.child_modified @@ -1797,9 +1799,9 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): self.value_changed.emit(self) def hierarchical_style_update(self): - self.update_style() for input_field in self.input_fields: input_field.hierarchical_style_update() + self.update_style() def remove_overrides(self): self._is_overriden = False @@ -1886,6 +1888,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): "darwin": "MacOS", "linux": "Linux" } + # TODO be able to save and load with separators platform_separators = { "windows": ";", "darwin": ":", From 575ea828759f22b23ca59213b95b4dc75ae7ba45 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 13:56:32 +0200 Subject: [PATCH 341/580] discard changes and remove overrides works for roots widget --- .../config_setting/widgets/anatomy_inputs.py | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index e4f7a6383a..efbcd437ad 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -41,14 +41,13 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): super(AnatomyWidget, self).__init__(parent) self.setObjectName("AnatomyWidget") self._parent = parent + self.key = "anatomy" self._child_state = None self._state = None self._is_group = True - self.key = "anatomy" - self.override_value = NOT_SET self.start_value = NOT_SET self.global_value = NOT_SET @@ -88,7 +87,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.update_global_values(value) def set_value(self, value, *, global_value=False): - print("* set_value") + raise TypeError("AnatomyWidget does not allow to use `set_value`") def clear_value(self): print("* clear_value") @@ -97,7 +96,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): print("* _on_value_change") def update_style(self, is_overriden=None): - print("* update_style") child_modified = self.child_modified child_invalid = self.child_invalid child_state = self.style_state( @@ -154,6 +152,21 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): or self.templates_widget.child_invalid ) + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + + self.root_widget.remove_overrides() + self.templates_widget.remove_overrides() + + def discard_changes(self): + self.root_widget.discard_changes() + self.templates_widget.discard_changes() + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + def item_value(self): output = {} output.update(self.root_widget.config_value()) @@ -175,6 +188,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.root_keys = None + self.was_multiroot = NOT_SET + checkbox_widget = QtWidgets.QWidget(self) multiroot_label = QtWidgets.QLabel( "Use multiple roots", checkbox_widget @@ -220,6 +235,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): return self.multiroot_checkbox.isChecked() def update_global_values(self, parent_values): + self._is_modified = False if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) else: @@ -232,12 +248,15 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): is_multiroot = True break + self.was_multiroot = is_multiroot self.set_multiroot(is_multiroot) if is_multiroot: + self.singleroot_widget.update_global_values(NOT_SET) self.multiroot_widget.update_global_values(parent_values) else: self.singleroot_widget.update_global_values(parent_values) + self.multiroot_widget.update_global_values(NOT_SET) def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() @@ -293,6 +312,21 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: return self.singleroot_widget.child_invalid + def remove_overrides(self): + self._is_overriden = False + self._is_modified = False + self._was_overriden = False + + self.singleroot_widget.remove_overrides() + self.multiroot_widget.remove_overrides() + + def discard_changes(self): + self.singleroot_widget.discard_changes() + self.multiroot_widget.discard_changes() + + self._is_modified = self.child_modified + self._is_overriden = self._was_overriden + def item_value(self): if self.is_multiroot: return self.multiroot_widget.item_value() @@ -333,5 +367,11 @@ class TemplatesWidget(QtWidgets.QWidget): def child_invalid(self): return False + def remove_overrides(self): + pass + + def discard_changes(self): + pass + TypeToKlass.types["anatomy"] = AnatomyWidget From d6c3d95478f49bb815fce1a3c91df9ee96ee6065 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 14:40:18 +0200 Subject: [PATCH 342/580] added few missing methods to roots widget --- .../config_setting/widgets/anatomy_inputs.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index efbcd437ad..4fb01a468e 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -258,6 +258,33 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.singleroot_widget.update_global_values(parent_values) self.multiroot_widget.update_global_values(NOT_SET) + def apply_overrides(self, parent_values): + # Make sure this is set to False + self._is_modified = False + self._state = None + self._child_state = None + + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, value) + + is_multiroot = False + if isinstance(value, dict): + for _value in value.values(): + if isinstance(_value, dict): + is_multiroot = True + break + + self._is_overriden = value is not NOT_SET + self._was_overriden = bool(self._is_overriden) + + if is_multiroot: + self.singleroot_widget.apply_overrides(NOT_SET) + self.multiroot_widget.apply_overrides(value) + else: + self.singleroot_widget.apply_overrides(value) + self.multiroot_widget.apply_overrides(NOT_SET) + def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() self.multiroot_widget.hierarchical_style_update() @@ -265,6 +292,17 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def _on_multiroot_checkbox(self): self.set_multiroot(self.is_multiroot) + def _on_value_change(self, item=None): + if self.is_group and self.is_overidable: + self._is_overriden = True + + self._is_modified = ( + self.was_multiroot != self.is_multiroot + or self.child_modified + ) + + self.value_changed.emit(self) + def set_multiroot(self, is_multiroot=None): if is_multiroot is None: is_multiroot = not self.is_multiroot @@ -337,6 +375,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): return {self.key: self.item_value()} +# TODO implement class TemplatesWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(TemplatesWidget, self).__init__(parent) @@ -344,6 +383,9 @@ class TemplatesWidget(QtWidgets.QWidget): def update_global_values(self, values): pass + def apply_overrides(self, parent_values): + pass + def hierarchical_style_update(self): pass From 2a34a77d168e49f815adebe80937ca1d40078cdb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 14:40:56 +0200 Subject: [PATCH 343/580] more value changes reaction implemented --- .../config_setting/widgets/anatomy_inputs.py | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 4fb01a468e..6b174ca575 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -77,6 +77,9 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget + self.root_widget.multiroot_changed.connect(self._on_multiroot_change) + self.root_widget.value_changed.connect(self._on_value_change) + def update_global_values(self, parent_values): if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) @@ -86,14 +89,41 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.update_global_values(value) self.templates_widget.update_global_values(value) + def apply_overrides(self, parent_values): + # Make sure this is set to False + self._state = None + self._child_state = None + + value = NOT_SET + if parent_values is not NOT_SET: + value = parent_values.get(self.key, value) + + self._is_overriden = value is not NOT_SET + + self.root_widget.apply_overrides(value) + self.templates_widget.apply_overrides(value) + + self._was_overriden = bool(self._is_overriden) + def set_value(self, value, *, global_value=False): raise TypeError("AnatomyWidget does not allow to use `set_value`") def clear_value(self): - print("* clear_value") + raise TypeError("AnatomyWidget does not allow to use `clear_value`") + + def _on_multiroot_change(self): + self.update_style() def _on_value_change(self, item=None): - print("* _on_value_change") + if self.ignore_value_changes: + return + + if self.is_overidable: + self._is_overriden = True + + self.hierarchical_style_update() + + self.value_changed.emit(self) def update_style(self, is_overriden=None): child_modified = self.child_modified @@ -154,7 +184,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False - self._is_modified = False self._was_overriden = False self.root_widget.remove_overrides() @@ -164,9 +193,13 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.discard_changes() self.templates_widget.discard_changes() - self._is_modified = self.child_modified self._is_overriden = self._was_overriden + def overrides(self): + if self.is_overriden: + return self.config_value(), True + return {self.key: {}}, True + def item_value(self): output = {} output.update(self.root_widget.config_value()) @@ -178,6 +211,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): class RootsWidget(QtWidgets.QWidget, ConfigObject): multiroot_changed = QtCore.Signal() + value_changed = QtCore.Signal(object) def __init__(self, parent): super(RootsWidget, self).__init__(parent) @@ -227,6 +261,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.multiroot_widget = multiroot_widget multiroot_checkbox.stateChanged.connect(self._on_multiroot_checkbox) + singleroot_widget.value_changed.connect(self._on_value_change) + multiroot_widget.value_changed.connect(self._on_value_change) self._on_multiroot_checkbox() From d570f287100fb325e8f10ae9c59be93cfab077d4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 15:05:35 +0200 Subject: [PATCH 344/580] _was_overriden is not changed on remove overrides to keep information about change --- .../config_setting/widgets/anatomy_inputs.py | 12 ++++-------- .../config_setting/config_setting/widgets/inputs.py | 5 ----- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 6b174ca575..331921ea68 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -98,14 +98,10 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): if parent_values is not NOT_SET: value = parent_values.get(self.key, value) - self._is_overriden = value is not NOT_SET - self.root_widget.apply_overrides(value) self.templates_widget.apply_overrides(value) - self._was_overriden = bool(self._is_overriden) - - def set_value(self, value, *, global_value=False): + def set_value(self, value): raise TypeError("AnatomyWidget does not allow to use `set_value`") def clear_value(self): @@ -184,7 +180,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False - self._was_overriden = False self.root_widget.remove_overrides() self.templates_widget.remove_overrides() @@ -271,7 +266,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): return self.multiroot_checkbox.isChecked() def update_global_values(self, parent_values): - self._is_modified = False + self._state = None + self._child_state = None + if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) else: @@ -296,7 +293,6 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def apply_overrides(self, parent_values): # Make sure this is set to False - self._is_modified = False self._state = None self._child_state = None diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d2f7f6cae6..81dad86c25 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -177,7 +177,6 @@ class InputObject(ConfigObject): self.set_value(self.start_value) self._is_overriden = False self._is_modified = False - self._was_overriden = False def apply_overrides(self, parent_values): self._is_modified = False @@ -1546,7 +1545,6 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - self._was_overriden = False for item in self.input_fields: item.remove_overrides() @@ -1806,7 +1804,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - self._was_overriden = False for item in self.input_fields: item.remove_overrides() @@ -2102,7 +2099,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - self._was_overriden = False for item in self.input_fields: item.remove_overrides() @@ -2234,7 +2230,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - self._was_overriden = False for item in self.input_fields: item.remove_overrides() From 38325b8d7f106296273a4b1ac28212cd33d1ec16 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 15:06:24 +0200 Subject: [PATCH 345/580] AnatomyWidget is not group --- .../config_setting/widgets/anatomy_inputs.py | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 331921ea68..96ad0c786b 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -46,13 +46,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self._child_state = None self._state = None - self._is_group = True - - self.override_value = NOT_SET - self.start_value = NOT_SET - self.global_value = NOT_SET - - self.root_keys = None self.root_widget = RootsWidget(self) self.templates_widget = TemplatesWidget(self) @@ -80,7 +73,13 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.multiroot_changed.connect(self._on_multiroot_change) self.root_widget.value_changed.connect(self._on_value_change) + def any_parent_is_group(self): + return False + def update_global_values(self, parent_values): + self._state = None + self._child_state = None + if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) else: @@ -135,17 +134,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.style().polish(self) self._child_state = child_state - state = self.style_state( - child_invalid, self.is_overriden, self.is_modified - ) - if self._state == state: - return - - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) - - self._state = state - def hierarchical_style_update(self): self.root_widget.hierarchical_style_update() self.templates_widget.hierarchical_style_update() @@ -310,6 +298,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._is_overriden = value is not NOT_SET self._was_overriden = bool(self._is_overriden) + self.was_multiroot = is_multiroot + self.set_multiroot(is_multiroot) + if is_multiroot: self.singleroot_widget.apply_overrides(NOT_SET) self.multiroot_widget.apply_overrides(value) From 7c48e2544243e832cde214f837fcc67934706af4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 16:08:18 +0200 Subject: [PATCH 346/580] apply override pass right values --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 96ad0c786b..229dff0bd9 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -303,9 +303,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot: self.singleroot_widget.apply_overrides(NOT_SET) - self.multiroot_widget.apply_overrides(value) + self.multiroot_widget.apply_overrides(parent_values) else: - self.singleroot_widget.apply_overrides(value) + self.singleroot_widget.apply_overrides(parent_values) self.multiroot_widget.apply_overrides(NOT_SET) def hierarchical_style_update(self): From bd6d5999c82ec2f7059707825ceff8787dc0e30e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 16:09:11 +0200 Subject: [PATCH 347/580] is_modified is set right on overrides --- .../config_setting/widgets/inputs.py | 82 +++++++++++++------ 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 81dad86c25..93ce5603aa 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -313,17 +313,15 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): if self.ignore_value_changes: return - _value = self.item_value() - is_modified = None if self.is_overidable: self._is_overriden = True - if self.override_value is not None: - is_modified = _value != self.override_value - if is_modified is None: - is_modified = _value != self.global_value - - self._is_modified = is_modified + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.global_value self.update_style() @@ -427,10 +425,16 @@ class NumberWidget(QtWidgets.QWidget, InputObject): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.global_value + self.update_style() self.value_changed.emit(self) @@ -535,10 +539,16 @@ class TextWidget(QtWidgets.QWidget, InputObject): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.global_value + self.update_style() self.value_changed.emit(self) @@ -640,10 +650,16 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.global_value if self.is_overidable: self._is_overriden = True + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.global_value + self.update_style() self.value_changed.emit(self) @@ -803,7 +819,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): if self.ignore_value_changes: return - self._is_invalid = self.text_input.has_invalid_value() + if self.is_overidable: + self._is_overriden = True + if self._is_invalid: self._is_modified = True elif self._is_overriden: @@ -811,9 +829,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): else: self._is_modified = self.item_value() != self.global_value - if self.is_overidable: - self._is_overriden = True - self.update_style() self.value_changed.emit(self) @@ -1017,10 +1032,17 @@ class ListWidget(QtWidgets.QWidget, InputObject): def _on_value_change(self, item=None): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.global_value + if self.is_overidable: self._is_overriden = True + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.global_value + self.update_style() self.value_changed.emit(self) @@ -1349,15 +1371,17 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if self.is_overidable: self._is_overriden = True - if self.is_overriden: + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: self._is_modified = self.item_value() != self.global_value - self.value_changed.emit(self) - self.update_style() + self.value_changed.emit(self) + def hierarchical_style_update(self): for input_field in self.input_fields: input_field.hierarchical_style_update() @@ -2019,7 +2043,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): # Make sure this is set to False self._state = None self._child_state = None - self._is_modified = False override_values = NOT_SET if parent_values is not NOT_SET: override_values = parent_values.get(self.key, override_values) @@ -2037,6 +2060,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): and self.is_overidable and self.child_overriden ) + self._is_modified = False self._was_overriden = bool(self._is_overriden) def set_value(self, value): @@ -2060,16 +2084,20 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): if self.ignore_value_changes: return - self._is_modified = self.item_value() != self.global_value - if self.is_group: - if self.is_overidable: - self._is_overriden = True - self.hierarchical_style_update() + if self.is_overidable: + self._is_overriden = True + + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + else: + self._is_modified = self.item_value() != self.global_value + + self.hierarchical_style_update() self.value_changed.emit(self) - self.update_style() - def update_style(self, is_overriden=None): child_modified = self.child_modified child_invalid = self.child_invalid From 0f0dd751e8e088ea286ee9e708a1252ff1e57bad Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 16:10:16 +0200 Subject: [PATCH 348/580] is_multiroot deduction is better --- .../config_setting/widgets/anatomy_inputs.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 229dff0bd9..fb95f17785 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -288,12 +288,15 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if parent_values is not NOT_SET: value = parent_values.get(self.key, value) - is_multiroot = False - if isinstance(value, dict): - for _value in value.values(): - if isinstance(_value, dict): - is_multiroot = True - break + if value is NOT_SET: + is_multiroot = self.global_is_multiroot + else: + is_multiroot = False + if isinstance(value, dict): + for _value in value.values(): + if isinstance(_value, dict): + is_multiroot = True + break self._is_overriden = value is not NOT_SET self._was_overriden = bool(self._is_overriden) From 0e95344bfc5f321348c8f3c30a6bd1ca59f933ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 16:11:01 +0200 Subject: [PATCH 349/580] _on_value_changed ignore changes of not current roots widget --- .../config_setting/widgets/anatomy_inputs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index fb95f17785..aaea588ab2 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -205,6 +205,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.root_keys = None + self.global_is_multiroot = False self.was_multiroot = NOT_SET checkbox_widget = QtWidgets.QWidget(self) @@ -219,6 +220,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): path_widget_data = { "key": "roots", + "multipath": False, "multiplatform": True, "label": "Roots" } @@ -269,6 +271,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): is_multiroot = True break + self.global_is_multiroot = is_multiroot self.was_multiroot = is_multiroot self.set_multiroot(is_multiroot) @@ -283,6 +286,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): # Make sure this is set to False self._state = None self._child_state = None + self._is_modified = False value = NOT_SET if parent_values is not NOT_SET: @@ -319,6 +323,12 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(self.is_multiroot) def _on_value_change(self, item=None): + if ( + (self.is_multiroot and item != self.multiroot_widget) + or (not self.is_multiroot and item != self.singleroot_widget) + ): + return + if self.is_group and self.is_overidable: self._is_overriden = True From 2d77236f4c05fd466ee28dc1eb17063ce22cd70b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 16:17:52 +0200 Subject: [PATCH 350/580] skip was removed on removind overrides action --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index aaea588ab2..f3fc1bfd1a 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -153,9 +153,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): @property def child_overriden(self): return ( - self.root_widget.is_overriden - or self.root_widget.child_overriden - or self.templates_widget.is_overriden + self.root_widget.child_overriden or self.templates_widget.child_overriden ) @@ -389,7 +387,6 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - self._was_overriden = False self.singleroot_widget.remove_overrides() self.multiroot_widget.remove_overrides() From b9db80e1bb7051642fa35e85100199360551623e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 4 Sep 2020 16:21:50 +0200 Subject: [PATCH 351/580] discard changes and remove overrides set multiroot widgets right way --- .../config_setting/widgets/anatomy_inputs.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index f3fc1bfd1a..8e7bb4bb8a 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -388,10 +388,18 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._is_overriden = False self._is_modified = False + self.set_multiroot(self.global_is_multiroot) + self.singleroot_widget.remove_overrides() self.multiroot_widget.remove_overrides() def discard_changes(self): + is_overriden = bool(self._is_overriden) + if is_overriden: + self.set_multiroot(self.was_multiroot) + else: + self.set_multiroot(self.global_is_multiroot) + self.singleroot_widget.discard_changes() self.multiroot_widget.discard_changes() From 89e96b6cfeb04d9b1808653f07bea81aaceade00 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 09:21:00 +0200 Subject: [PATCH 352/580] modifiable widget can be used as widget --- .../config_setting/widgets/inputs.py | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 93ce5603aa..10dd9913b8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1292,32 +1292,33 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): main_layout.setContentsMargins(5, 5, 0, 5) main_layout.setSpacing(0) - body_widget = ExpandingWidget(input_data["label"], self) - - main_layout.addWidget(body_widget) - content_widget = QtWidgets.QWidget(self) content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(3, 3, 0, 3) - body_widget.set_content_widget(content_widget) + if as_widget: + main_layout.addWidget(content_widget) + else: + body_widget = ExpandingWidget(input_data["label"], self) + main_layout.addWidget(body_widget) + body_widget.set_content_widget(content_widget) + + self.body_widget = body_widget + self.label_widget = body_widget.label_widget + + expandable = input_data.get("expandable", True) + if not expandable: + body_widget.hide_toolbox(hide_content=False) + else: + expanded = input_data.get("expanded", False) + if expanded: + body_widget.toggle_content() - self.body_widget = body_widget self.content_widget = content_widget self.content_layout = content_layout - self.label_widget = body_widget.label_widget - self.setAttribute(QtCore.Qt.WA_StyledBackground) - expandable = input_data.get("expandable", True) - if not expandable: - body_widget.hide_toolbox(hide_content=False) - else: - expanded = input_data.get("expanded", False) - if expanded: - body_widget.toggle_content() - self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} @@ -1402,8 +1403,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.setProperty("state", child_state) self.style().polish(self) - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + if not self._as_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) self._state = state @@ -2044,7 +2046,9 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self._state = None self._child_state = None override_values = NOT_SET - if parent_values is not NOT_SET: + if self._as_widget: + override_values = parent_values + elif parent_values is not NOT_SET: override_values = parent_values.get(self.key, override_values) self._is_overriden = override_values is not NOT_SET From 0ca9cf309c9e39a4b82d1efb28f66f370bc47bc1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 09:21:17 +0200 Subject: [PATCH 353/580] widgets in roots are used as widgets --- .../config_setting/widgets/anatomy_inputs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 8e7bb4bb8a..c6c06a42ae 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -222,7 +222,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): "multiplatform": True, "label": "Roots" } - singleroot_widget = PathWidget(path_widget_data, self) + singleroot_widget = PathWidget(path_widget_data, self, as_widget=True) multiroot_data = { "key": "roots", "label": "Roots", @@ -232,7 +232,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): "multiplatform": True } } - multiroot_widget = ModifiableDict(multiroot_data, self) + multiroot_widget = ModifiableDict(multiroot_data, self, as_widget=True) main_layout = QtWidgets.QVBoxLayout(self) main_layout.addWidget(checkbox_widget) @@ -275,9 +275,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot: self.singleroot_widget.update_global_values(NOT_SET) - self.multiroot_widget.update_global_values(parent_values) + self.multiroot_widget.update_global_values(value) else: - self.singleroot_widget.update_global_values(parent_values) + self.singleroot_widget.update_global_values(value) self.multiroot_widget.update_global_values(NOT_SET) def apply_overrides(self, parent_values): @@ -308,9 +308,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot: self.singleroot_widget.apply_overrides(NOT_SET) - self.multiroot_widget.apply_overrides(parent_values) + self.multiroot_widget.apply_overrides(value) else: - self.singleroot_widget.apply_overrides(parent_values) + self.singleroot_widget.apply_overrides(value) self.multiroot_widget.apply_overrides(NOT_SET) def hierarchical_style_update(self): From ed6c1609dca1b0167af3f6b2e89307da94637cb1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 10:57:54 +0200 Subject: [PATCH 354/580] fixed discard changes --- .../config_setting/widgets/inputs.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 10dd9913b8..a9ca88c171 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -201,10 +201,11 @@ class InputObject(ConfigObject): self.set_value(value) def discard_changes(self): + self._is_overriden = self._was_overriden if ( self.is_overidable + and self._was_overriden and self.override_value is not NOT_SET - and self._was_overriden is True ): self.set_value(self.override_value) else: @@ -1575,11 +1576,13 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): item.remove_overrides() def discard_changes(self): + self._is_overriden = self._was_overriden + self._is_modified = False + for item in self.input_fields: item.discard_changes() self._is_modified = self.child_modified - self._is_overriden = self._was_overriden def set_as_overriden(self): if self.is_overriden: @@ -1834,11 +1837,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): item.remove_overrides() def discard_changes(self): + self._is_modified = False + self._is_overriden = self._was_overriden + for item in self.input_fields: item.discard_changes() self._is_modified = self.child_modified - self._is_overriden = self._was_overriden def set_as_overriden(self): if self.is_overriden: @@ -2135,11 +2140,13 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): item.remove_overrides() def discard_changes(self): + self._is_modified = False + self._is_overriden = self._was_overriden + for input_field in self.input_fields: input_field.discard_changes() self._is_modified = self.child_modified - self._is_overriden = self._was_overriden @property def child_modified(self): @@ -2253,11 +2260,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): item.apply_overrides(parent_values) def discard_changes(self): + self._is_modified = False + self._is_overriden = self._was_overriden + for item in self.input_fields: item.discard_changes() self._is_modified = self.child_modified - self._is_overriden = self._was_overriden def remove_overrides(self): self._is_overriden = False From 93658f8a3ea7a8f2226fa7b48c765f0db800c227 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 11:02:55 +0200 Subject: [PATCH 355/580] added representation of object to not implemented exception --- pype/tools/config_setting/config_setting/widgets/widgets.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 42ca49d600..e547b8181a 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -353,10 +353,12 @@ class AbstractConfigObject: def set_as_overriden(self): raise NotImplementedError( - "Method `set_as_overriden` not implemented!" + "{} Method `set_as_overriden` not implemented!".format(repr(self)) ) def hierarchical_style_update(self): raise NotImplementedError( - "Method `hierarchical_style_update` not implemented!" + "{} Method `hierarchical_style_update` not implemented!".format( + repr(self) + ) ) From 208075acfaf87bdb460a423edbc5984928bbe7a3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:12:36 +0200 Subject: [PATCH 356/580] list and dict items skip right mouse release --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index a9ca88c171..b5e0b2c5b6 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -932,6 +932,9 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def child_overriden(self): return self.value_input.child_overriden + def mouseReleaseEvent(self, event): + return QtWidgets.QWidget.mouseReleaseEvent(self, event) + class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) @@ -1256,6 +1259,9 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): return {} return {key: value} + def mouseReleaseEvent(self, event): + return QtWidgets.QWidget.mouseReleaseEvent(self, event) + class ModifiableDict(QtWidgets.QWidget, InputObject): # Should be used only for dictionary with one datatype as value From 78c68beb3fd2babcf9f20dd5ae9f101c7377995d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:13:55 +0200 Subject: [PATCH 357/580] removed signal multiroot_changed --- .../config_setting/widgets/anatomy_inputs.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index c6c06a42ae..0b825b90e6 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -70,7 +70,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget - self.root_widget.multiroot_changed.connect(self._on_multiroot_change) self.root_widget.value_changed.connect(self._on_value_change) def any_parent_is_group(self): @@ -106,9 +105,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): def clear_value(self): raise TypeError("AnatomyWidget does not allow to use `clear_value`") - def _on_multiroot_change(self): - self.update_style() - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -191,7 +187,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): class RootsWidget(QtWidgets.QWidget, ConfigObject): - multiroot_changed = QtCore.Signal() value_changed = QtCore.Signal(object) def __init__(self, parent): @@ -347,7 +342,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.singleroot_widget.setVisible(not is_multiroot) self.multiroot_widget.setVisible(is_multiroot) - self.multiroot_changed.emit() + self._on_value_change() @property def is_modified(self): From 8ec6d0cba5d8793cf2fe2086b696db7bf6c5944c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:14:22 +0200 Subject: [PATCH 358/580] removed label from root widgets --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 0b825b90e6..e4c555138a 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -214,13 +214,11 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): path_widget_data = { "key": "roots", "multipath": False, - "multiplatform": True, - "label": "Roots" + "multiplatform": True } singleroot_widget = PathWidget(path_widget_data, self, as_widget=True) multiroot_data = { "key": "roots", - "label": "Roots", "object_type": "path-widget", "expandable": False, "input_modifiers": { From 04d8e6d2420139f3bbb43adb4cf082d16e836694 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:20:08 +0200 Subject: [PATCH 359/580] any_parent_is_group is real attribute not function --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index e4c555138a..2f1f59c31d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -46,6 +46,8 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self._child_state = None self._state = None + self.any_parent_is_group = False + self.root_widget = RootsWidget(self) self.templates_widget = TemplatesWidget(self) @@ -72,9 +74,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.value_changed.connect(self._on_value_change) - def any_parent_is_group(self): - return False - def update_global_values(self, parent_values): self._state = None self._child_state = None From d0b05421f722397c76e8060ffb0c898742e8a489 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:21:00 +0200 Subject: [PATCH 360/580] roots widget is expandable --- .../config_setting/widgets/anatomy_inputs.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 2f1f59c31d..6a7906d46e 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -226,11 +226,21 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): } multiroot_widget = ModifiableDict(multiroot_data, self, as_widget=True) - main_layout = QtWidgets.QVBoxLayout(self) - main_layout.addWidget(checkbox_widget) - main_layout.addWidget(singleroot_widget) - main_layout.addWidget(multiroot_widget) + body_widget = ExpandingWidget("Roots", self) + content_widget = QtWidgets.QWidget(body_widget) + contnet_layout = QtWidgets.QVBoxLayout(content_widget) + contnet_layout.addWidget(checkbox_widget) + contnet_layout.addWidget(singleroot_widget) + contnet_layout.addWidget(multiroot_widget) + + body_widget.set_content_widget(content_widget) + self.label_widget = body_widget.label_widget + + main_layout = QtWidgets.QVBoxLayout(self) + main_layout.addWidget(body_widget) + + self.multiroot_label = multiroot_label self.multiroot_checkbox = multiroot_checkbox self.singleroot_widget = singleroot_widget self.multiroot_widget = multiroot_widget From 4e0afbd300b48b0bfcdfd465b92f9e84fa4761e0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:21:22 +0200 Subject: [PATCH 361/580] added mutliroot state for multiroot checkbox label --- .../config_setting/widgets/anatomy_inputs.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 6a7906d46e..81a7357c4d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -192,10 +192,13 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): super(RootsWidget, self).__init__(parent) self.setObjectName("RootsWidget") self._parent = parent - self._is_group = True self.key = "roots" - self.root_keys = None + self._state = None + self._multiroot_state = None + + self._is_group = True + self.any_parent_is_group = False self.global_is_multiroot = False self.was_multiroot = NOT_SET @@ -257,7 +260,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def update_global_values(self, parent_values): self._state = None - self._child_state = None + self._multiroot_state = None if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) @@ -285,7 +288,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def apply_overrides(self, parent_values): # Make sure this is set to False self._state = None - self._child_state = None + self._multiroot_state = None self._is_modified = False value = NOT_SET From 41d92b03afb3e89610562493058ab99de73c426f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:22:48 +0200 Subject: [PATCH 362/580] roots value change can ignore changes and do what should if item is not defined --- .../config_setting/widgets/anatomy_inputs.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 81a7357c4d..c34418be87 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -326,7 +326,12 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(self.is_multiroot) def _on_value_change(self, item=None): - if ( + if self.ignore_value_changes: + return + + if item is None: + pass + elif ( (self.is_multiroot and item != self.multiroot_widget) or (not self.is_multiroot and item != self.singleroot_widget) ): From 2d778ae37a43074f06be89be5e2bdbfb6770b94d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:24:01 +0200 Subject: [PATCH 363/580] discard changes sets right multiroot on discard changes --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index c34418be87..5817d67274 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -404,8 +404,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.multiroot_widget.remove_overrides() def discard_changes(self): - is_overriden = bool(self._is_overriden) - if is_overriden: + self._is_overriden = self._was_overriden + self._is_modified = False + if self._is_overriden: self.set_multiroot(self.was_multiroot) else: self.set_multiroot(self.global_is_multiroot) @@ -414,7 +415,6 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.multiroot_widget.discard_changes() self._is_modified = self.child_modified - self._is_overriden = self._was_overriden def item_value(self): if self.is_multiroot: From d35c2b62ff3edcd7a2ad0660fefc6dfdc697746c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:24:13 +0200 Subject: [PATCH 364/580] roots widget has update style --- .../config_setting/widgets/anatomy_inputs.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 5817d67274..df5be5108d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -321,6 +321,37 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() self.multiroot_widget.hierarchical_style_update() + self.update_style() + + def update_style(self): + multiroot_state = self.style_state( + False, + self.is_overriden, + self.was_multiroot and not self.is_multiroot + ) + if multiroot_state != self._multiroot_state: + self.multiroot_label.setProperty("state", multiroot_state) + self.multiroot_label.style().polish(self.multiroot_label) + self._multiroot_state = multiroot_state + + state = self.style_state( + self.is_invalid, self.is_overriden, self.is_modified + ) + if self._state == state: + return + + if state: + child_state = "child-{}".format(state) + else: + child_state = "" + + self.setProperty("state", child_state) + self.style().polish(self) + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + self._state = state def _on_multiroot_checkbox(self): self.set_multiroot(self.is_multiroot) From 9c1e18cc103959b29788f15784136d1ff7b32bd4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 12:24:30 +0200 Subject: [PATCH 365/580] multiroot widget apply parent values --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index df5be5108d..85f562eb8b 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -313,7 +313,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot: self.singleroot_widget.apply_overrides(NOT_SET) - self.multiroot_widget.apply_overrides(value) + self.multiroot_widget.apply_overrides(parent_values) else: self.singleroot_widget.apply_overrides(value) self.multiroot_widget.apply_overrides(NOT_SET) From ec80578304e9f61affee1f63b4ff7b80ebe295e8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 14:15:02 +0200 Subject: [PATCH 366/580] anatomy widget does not care about is overriden --- .../config_setting/widgets/anatomy_inputs.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 85f562eb8b..e918c97bf8 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -108,9 +108,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): if self.ignore_value_changes: return - if self.is_overidable: - self._is_overriden = True - self.hierarchical_style_update() self.value_changed.emit(self) @@ -160,8 +157,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): ) def remove_overrides(self): - self._is_overriden = False - self.root_widget.remove_overrides() self.templates_widget.remove_overrides() @@ -169,8 +164,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.discard_changes() self.templates_widget.discard_changes() - self._is_overriden = self._was_overriden - def overrides(self): if self.is_overriden: return self.config_value(), True @@ -305,9 +298,6 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): is_multiroot = True break - self._is_overriden = value is not NOT_SET - self._was_overriden = bool(self._is_overriden) - self.was_multiroot = is_multiroot self.set_multiroot(is_multiroot) From 964241286bc0d7ec4b884413268ddfcd7750a7b5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 14:16:01 +0200 Subject: [PATCH 367/580] roots widget cares about is overriden and fixed multiroot state --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index e918c97bf8..a1a0879dc2 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -302,12 +302,16 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(is_multiroot) if is_multiroot: + self._is_overriden = parent_values is not NOT_SET self.singleroot_widget.apply_overrides(NOT_SET) self.multiroot_widget.apply_overrides(parent_values) else: + self._is_overriden = value is not NOT_SET self.singleroot_widget.apply_overrides(value) self.multiroot_widget.apply_overrides(NOT_SET) + self._was_overriden = bool(self._is_overriden) + def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() self.multiroot_widget.hierarchical_style_update() @@ -317,7 +321,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): multiroot_state = self.style_state( False, self.is_overriden, - self.was_multiroot and not self.is_multiroot + self.was_multiroot != self.is_multiroot ) if multiroot_state != self._multiroot_state: self.multiroot_label.setProperty("state", multiroot_state) From 5f6687cd9687bcdba276d686ab8823cd8e800075 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:11:57 +0200 Subject: [PATCH 368/580] inputs can have different parent widget than input parent --- .../config_setting/widgets/inputs.py | 83 +++++++++++++------ 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b5e0b2c5b6..ea40b6d25e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -248,9 +248,12 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(BooleanWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(BooleanWidget, self).__init__(parent_widget) self._parent = parent self._as_widget = as_widget @@ -353,9 +356,12 @@ class NumberWidget(QtWidgets.QWidget, InputObject): input_modifiers = ("minimum", "maximum", "decimal") def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(NumberWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(NumberWidget, self).__init__(parent_widget) self._parent = parent self._as_widget = as_widget @@ -465,9 +471,12 @@ class TextWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(TextWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(TextWidget, self).__init__(parent_widget) self._parent = parent self._as_widget = as_widget @@ -582,9 +591,12 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(PathInputWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(PathInputWidget, self).__init__(parent_widget) self._parent = parent self._as_widget = as_widget @@ -742,9 +754,12 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(RawJsonWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(RawJsonWidget, self).__init__(parent_widget) self._parent = parent self._as_widget = as_widget @@ -940,9 +955,12 @@ class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(ListWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(ListWidget, self).__init__(parent_widget) self.setObjectName("ListWidget") self._parent = parent @@ -1269,9 +1287,12 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(ModifiableDict, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(ModifiableDict, self).__init__(parent_widget) self.setObjectName("ModifiableDict") self._parent = parent @@ -1483,14 +1504,17 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): if as_widget: raise TypeError("Can't use \"{}\" as widget item.".format( self.__class__.__name__ )) - super(DictWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(DictWidget, self).__init__(parent_widget) self.setObjectName("DictWidget") self._state = None @@ -1743,8 +1767,14 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): allow_actions = False def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): + if parent_widget is None: + parent_widget = parent + super(DictInvisible, self).__init__(parent_widget) + self.setObjectName("DictInvisible") + self._parent = parent any_parent_is_group = parent.is_group @@ -1754,9 +1784,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) - super(DictInvisible, self).__init__(parent) - self.setObjectName("DictInvisible") - self.setAttribute(QtCore.Qt.WA_StyledBackground) layout = QtWidgets.QVBoxLayout(self) @@ -1930,9 +1957,12 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): } def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): - super(PathWidget, self).__init__(parent) + if parent_widget is None: + parent_widget = parent + super(PathWidget, self).__init__(parent_widget) self._parent = parent self._state = None @@ -2214,8 +2244,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): allow_actions = False def __init__( - self, input_data, parent, as_widget=False, label_widget=None + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None ): + if parent_widget is None: + parent_widget = parent + super(DictFormWidget, self).__init__(parent_widget) + self._parent = parent any_parent_is_group = parent.is_group @@ -2226,8 +2261,6 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self._is_group = False - super(DictFormWidget, self).__init__(parent) - self.input_fields = [] self.content_layout = QtWidgets.QFormLayout(self) From 4b63222ac76bcbd6805168125905cb56a98cc276 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:20:15 +0200 Subject: [PATCH 369/580] fixed name of content layour in roots --- .../config_setting/widgets/anatomy_inputs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index a1a0879dc2..eec6bf2a13 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -225,10 +225,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): body_widget = ExpandingWidget("Roots", self) content_widget = QtWidgets.QWidget(body_widget) - contnet_layout = QtWidgets.QVBoxLayout(content_widget) - contnet_layout.addWidget(checkbox_widget) - contnet_layout.addWidget(singleroot_widget) - contnet_layout.addWidget(multiroot_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.addWidget(checkbox_widget) + content_layout.addWidget(singleroot_widget) + content_layout.addWidget(multiroot_widget) body_widget.set_content_widget(content_widget) self.label_widget = body_widget.label_widget From f8d925f7121a2ebc211cd89e9c666acf3af03261 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:20:32 +0200 Subject: [PATCH 370/580] templates widget has something in --- .../config_setting/widgets/anatomy_inputs.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index eec6bf2a13..a3d3e74e48 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -456,6 +456,20 @@ class TemplatesWidget(QtWidgets.QWidget): def __init__(self, parent=None): super(TemplatesWidget, self).__init__(parent) + body_widget = ExpandingWidget("Templates", self) + content_widget = QtWidgets.QWidget(body_widget) + body_widget.set_content_widget(content_widget) + content_layout = QtWidgets.QVBoxLayout(content_widget) + + label = QtWidgets.QLabel("Nothing yet", content_widget) + content_layout.addWidget(label) + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + layout.addWidget(body_widget) + def update_global_values(self, values): pass From 35482ef9737d254ec62ca951ec5320a0b996765a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:21:08 +0200 Subject: [PATCH 371/580] item_value o dictionary return all keys event if are empty --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ea40b6d25e..3b40775718 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1440,9 +1440,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def item_value(self): output = {} for item in self.input_fields: - item_value = item.config_value() - if item_value: - output.update(item_value) + output.update(item.config_value()) return output def add_row(self, row=None, key=None, value=None, is_empty=False): From a4424f6f5099c624ab2bb91941877c346ed01888 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:28:37 +0200 Subject: [PATCH 372/580] dictionary item has key_vlaue instead of _key --- .../tools/config_setting/config_setting/widgets/inputs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3b40775718..ad01ea2ad9 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1206,16 +1206,16 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.value_input.value_changed.connect(self._on_value_change) # TODO This doesn't make sence! - self.default_key = self._key() self.global_value = self.value_input.item_value() + self.origin_key = self.key_value() self.override_key = NOT_SET self.override_value = NOT_SET + def key_value(self): + return self.key_input.text() self.is_single = False - def _key(self): - return self.key_input.text() def _on_value_change(self, item=None): self.update_style() @@ -1245,7 +1245,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): return self._parent.any_parent_is_group def is_key_modified(self): - return self._key() != self.default_key + return self.key_value() != self.origin_key def is_value_modified(self): return self.value_input.is_modified From 147f3f29d99f91e0786fff2549e1f7ee16b6f2be Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:29:31 +0200 Subject: [PATCH 373/580] removed unnecessary attributes --- .../config_setting/config_setting/widgets/inputs.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ad01ea2ad9..9f45a2211c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1166,6 +1166,9 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self._parent = config_parent + self.is_single = False + self.is_key_duplicated = False + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) @@ -1205,16 +1208,11 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.key_input.textChanged.connect(self._on_value_change) self.value_input.value_changed.connect(self._on_value_change) - # TODO This doesn't make sence! - self.global_value = self.value_input.item_value() self.origin_key = self.key_value() - self.override_key = NOT_SET - self.override_value = NOT_SET def key_value(self): return self.key_input.text() - self.is_single = False def _on_value_change(self, item=None): @@ -1273,8 +1271,6 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def config_value(self): key = self.key_input.text() value = self.value_input.item_value() - if not key: - return {} return {key: value} def mouseReleaseEvent(self, event): From a7d6eabe325daed58109f4b325adf737fa2b239f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:29:46 +0200 Subject: [PATCH 374/580] dict item has set_values --- .../config_setting/config_setting/widgets/inputs.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9f45a2211c..21ee1fc6e8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1219,6 +1219,11 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.update_style() self.value_changed.emit(self) + def set_values(self, key, value): + self.origin_key = key + self.key_input.setText(key) + self.value_input.update_global_values(value) + @property def is_group(self): return self._parent.is_group @@ -1470,9 +1475,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` if value is not None and key is not None: - item_widget.default_key = key - item_widget.key_input.setText(key) - item_widget.value_input.update_global_values(value) + item_widget.set_values(key, value) self.hierarchical_style_update() else: self._on_value_change() From 51b4bc4e7dfb24cc7eaf7ae4bdd3ea2b4efa7b03 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:30:02 +0200 Subject: [PATCH 375/580] basic logic of key is valid in dict item --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 21ee1fc6e8..476fc0c69f 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1213,7 +1213,13 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def key_value(self): return self.key_input.text() + def is_key_valid(self): + if self.key_value() == "": + return False + if self.is_key_duplicated: + return False + return True def _on_value_change(self, item=None): self.update_style() From 0a4379557cb9a01195cc298fccc6b21c37bfd6d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:36:53 +0200 Subject: [PATCH 376/580] added duplication invalidation for dictionary item --- .../config_setting/widgets/inputs.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 476fc0c69f..1f21f35d6b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1,5 +1,6 @@ import json import logging +import collections from Qt import QtWidgets, QtCore, QtGui from .widgets import ( AbstractConfigObject, @@ -1268,7 +1269,9 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.update_style() def update_style(self): - if self.is_key_modified(): + if not self.is_key_valid(): + state = "invalid" + elif self.is_key_modified(): state = "modified" else: state = "" @@ -1401,6 +1404,23 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.remove_row(input_field) def _on_value_change(self, item=None): + fields_by_keys = collections.defaultdict(list) + for input_field in self.input_fields: + key = input_field.key_value() + fields_by_keys[key].append(input_field) + + any_invalid = False + for fields in fields_by_keys.values(): + if len(fields) == 1: + field = fields[0] + if field.is_key_duplicated: + field.is_key_duplicated = False + field.update_style() + else: + for field in fields: + field.is_key_duplicated = True + field.update_style() + if self.ignore_value_changes: return From ce7e11e12c95aef286ee6029059edcd29a6f7dc2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:37:30 +0200 Subject: [PATCH 377/580] removed unused variable --- pype/tools/config_setting/config_setting/widgets/inputs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 1f21f35d6b..4a2d955ae4 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1409,7 +1409,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): key = input_field.key_value() fields_by_keys[key].append(input_field) - any_invalid = False for fields in fields_by_keys.values(): if len(fields) == 1: field = fields[0] From 0053379aa37aa617a9cf52bffd4b5a3bc5e244f6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 18:43:30 +0200 Subject: [PATCH 378/580] modifiable dict is validated in right way --- .../config_setting/widgets/inputs.py | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4a2d955ae4..2d23085854 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1214,13 +1214,13 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def key_value(self): return self.key_input.text() - def is_key_valid(self): + def is_key_invalid(self): if self.key_value() == "": - return False + return True if self.is_key_duplicated: - return False - return True + return True + return False def _on_value_change(self, item=None): self.update_style() @@ -1268,8 +1268,12 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.value_input.hierarchical_style_update() self.update_style() + @property + def is_invalid(self): + return self.is_key_invalid() or self.value_input.is_invalid + def update_style(self): - if not self.is_key_valid(): + if self.is_key_invalid(): state = "invalid" elif self.is_key_modified(): state = "modified" @@ -1426,7 +1430,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if self.is_overidable: self._is_overriden = True - if self._is_invalid: + if self.is_invalid: self._is_modified = True elif self._is_overriden: self._is_modified = self.item_value() != self.override_value @@ -1520,6 +1524,17 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._on_value_change() self.parent().updateGeometry() + @property + def is_invalid(self): + return self._is_invalid or self.child_invalid + + @property + def child_invalid(self): + for input_field in self.input_fields: + if input_field.is_invalid: + return True + return False + # Dictionaries class DictWidget(QtWidgets.QWidget, ConfigObject): From 4d109fb4e2aca4457f245b9edcf226c365e5a3a8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 19:08:06 +0200 Subject: [PATCH 379/580] roots widget at right place --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index a3d3e74e48..9e69d7234e 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -234,6 +234,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget main_layout = QtWidgets.QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) main_layout.addWidget(body_widget) self.multiroot_label = multiroot_label From 5350e7a50592a53a2d9b6462647372629060f2cb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 7 Sep 2020 19:22:15 +0200 Subject: [PATCH 380/580] clickable widget does not override init --- pype/tools/config_setting/config_setting/widgets/widgets.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index e547b8181a..dff966fa36 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -57,10 +57,6 @@ class PathInput(QtWidgets.QLineEdit): class ClickableWidget(QtWidgets.QLabel): clicked = QtCore.Signal() - def __init__(self, *args, **kwargs): - super(ClickableWidget, self).__init__(*args, **kwargs) - self.setObjectName("ExpandLabel") - def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self.clicked.emit() From 8ef37d3dfa565c22f776cea73e257f0000d07e64 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:46:07 +0200 Subject: [PATCH 381/580] defined child offset for nested hierarchy --- pype/tools/config_setting/config_setting/widgets/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index 0d70885de7..08b0dfc3c4 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -14,6 +14,7 @@ class TypeToKlass: NOT_SET = type("NOT_SET", (), {"__bool__": lambda obj: False})() METADATA_KEY = type("METADATA_KEY", (), {}) OVERRIDE_VERSION = 1 +CHILD_OFFSET = 15 def convert_gui_data_to_overrides(data, first=True): From de9e7811e40f64093ee92435d93beb2b95b7509b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:46:22 +0200 Subject: [PATCH 382/580] clickable widget is not qlabel but qwidget --- pype/tools/config_setting/config_setting/widgets/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index dff966fa36..a2e3e058b0 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -54,7 +54,7 @@ class PathInput(QtWidgets.QLineEdit): self.clear_end_path() -class ClickableWidget(QtWidgets.QLabel): +class ClickableWidget(QtWidgets.QWidget): clicked = QtCore.Signal() def mouseReleaseEvent(self, event): From 4829bbc473963187963392749634851d8283eab6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:46:48 +0200 Subject: [PATCH 383/580] expandable widget has one more widget for showing the left side line --- .../config_setting/widgets/widgets.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index a2e3e058b0..19d9ad9d25 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -82,40 +82,41 @@ class ExpandingWidget(QtWidgets.QWidget): label_widget = QtWidgets.QLabel(label, parent=top_part) label_widget.setObjectName("DictLabel") - layout = QtWidgets.QHBoxLayout(top_part) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(button_toggle) - layout.addWidget(label_widget) - top_part.setLayout(layout) + side_line_widget = QtWidgets.QWidget(top_part) + side_line_widget.setObjectName("SideLineWidget") + side_line_layout = QtWidgets.QHBoxLayout(side_line_widget) + side_line_layout.setContentsMargins(5, 10, 0, 10) + side_line_layout.addWidget(button_toggle) + side_line_layout.addWidget(label_widget) + + top_part_layout = QtWidgets.QHBoxLayout(top_part) + top_part_layout.setContentsMargins(0, 0, 0, 0) + top_part_layout.addWidget(side_line_widget) self.setAttribute(QtCore.Qt.WA_StyledBackground) self.top_part = top_part + self.side_line_widget = side_line_widget self.button_toggle = button_toggle self.label_widget = label_widget self.top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) + self.main_layout = QtWidgets.QVBoxLayout(self) + self.main_layout.setContentsMargins(0, 0, 0, 0) + self.main_layout.setSpacing(0) + self.main_layout.addWidget(self.top_part) + def hide_toolbox(self, hide_content=False): self.button_toggle.setArrowType(QtCore.Qt.NoArrow) self.toolbox_hidden = True self.content_widget.setVisible(not hide_content) self.parent().updateGeometry() - def set_content_widget(self, content_widget, margins=None): - main_layout = QtWidgets.QVBoxLayout(self) - if margins is None: - margins = (4, 4, 0, 4) - main_layout.setContentsMargins(*margins) - + def set_content_widget(self, content_widget): content_widget.setVisible(False) - - main_layout.addWidget(self.top_part) - main_layout.addWidget(content_widget) - self.setLayout(main_layout) - + self.main_layout.addWidget(content_widget) self.content_widget = content_widget def _top_part_clicked(self): From 58272c472bc1921127d13339c9d96de2ed220c26 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:47:37 +0200 Subject: [PATCH 384/580] modifications to match new expandable widget content properties --- .../config_setting/widgets/inputs.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 2d23085854..4347b1336d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -8,7 +8,7 @@ from .widgets import ( NumberSpinBox, PathInput ) -from .lib import NOT_SET, METADATA_KEY, TypeToKlass +from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET class ConfigObject(AbstractConfigObject): @@ -1331,12 +1331,12 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.key = input_data["key"] main_layout = QtWidgets.QHBoxLayout(self) - main_layout.setContentsMargins(5, 5, 0, 5) + main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) content_widget = QtWidgets.QWidget(self) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 0, 3) + content_layout.setContentsMargins(CHILD_OFFSET, 3, 0, 3) if as_widget: main_layout.addWidget(content_widget) @@ -1572,7 +1572,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.key = input_data["key"] main_layout = QtWidgets.QHBoxLayout(self) - main_layout.setContentsMargins(5, 5, 0, 5) + main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) body_widget = ExpandingWidget(input_data["label"], self) @@ -1581,7 +1581,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): content_widget = QtWidgets.QWidget(body_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(3, 3, 0, 3) + content_layout.setContentsMargins(CHILD_OFFSET, 3, 0, 3) body_widget.set_content_widget(content_widget) @@ -1725,8 +1725,10 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): child_state = "child-{}".format(child_state) if child_state != self._child_state: - self.setProperty("state", child_state) - self.style().polish(self) + self.body_widget.side_line_widget.setProperty("state", child_state) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) self._child_state = child_state state = self.style_state( @@ -2300,6 +2302,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): self.input_fields = [] self.content_layout = QtWidgets.QFormLayout(self) + self.content_layout.setContentsMargins(0, 0, 0, 0) for child_data in input_data.get("children", []): self.add_children_gui(child_data) From 3a566b306f1857d86a02dff264862434bc9491eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:47:51 +0200 Subject: [PATCH 385/580] only SideLineWidget has changing border colors --- .../config_setting/style/style.css | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 638bf1c6fb..9051130344 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -123,7 +123,7 @@ QPushButton[btn-type="expand-toggle"] { #DictLabel { font-weight: bold; } -#ModifiableDict, #DictWidget, #AnatomyWidget { +#SideLineWidget { border-style: solid; border-color: #455c6e; border-left-width: 3px; @@ -131,36 +131,36 @@ QPushButton[btn-type="expand-toggle"] { border-right-width: 0px; border-top-width: 0px; } -#ModifiableDict:hover, #DictWidget:hover, #AnatomyWidget:hover { +#SideLineWidget:hover { border-color: #62839d; } -#ModifiableDict[state="child-modified"], #DictWidget[state="child-modified"], #AnatomyWidget[state="child-modified"] { +#SideLineWidget[state="child-modified"]{ border-color: #106aa2; } -#ModifiableDict[state="child-modified"]:hover, #DictWidget[state="child-modified"]:hover, #AnatomyWidget[state="child-modified"]:hover { +#SideLineWidget[state="child-modified"]:hover{ border-color: #137cbd; } -#ModifiableDict[state="child-invalid"], #DictWidget[state="child-invalid"], #AnatomyWidget[state="child-invalid"] { +#SideLineWidget[state="child-invalid"]{ border-color: #ad2e2e; } -#ModifiableDict[state="child-invalid"]:hover, #DictWidget[state="child-invalid"]:hover, #AnatomyWidget[state="child-invalid"]:hover { +#SideLineWidget[state="child-invalid"]:hover{ border-color: #c93636; } -#ModifiableDict[state="child-overriden"], #DictWidget[state="child-overriden"], #AnatomyWidget[state="child-overriden"] { +#SideLineWidget[state="child-overriden"]{ border-color: #e67300; } -#ModifiableDict[state="child-overriden"]:hover, #DictWidget[state="child-overriden"]:hover, #AnatomyWidget[state="child-overriden"]:hover { +#SideLineWidget[state="child-overriden"]:hover { border-color: #ff8c1a; } -#ModifiableDict[state="child-overriden-modified"], #DictWidget[state="child-overriden-modified"], #AnatomyWidget[state="child-modified"] { +#SideLineWidget[state="child-overriden-modified"] { border-color: #106aa2; } -#ModifiableDict[state="child-overriden-modified"]:hover, #DictWidget[state="child-overriden-modified"]:hover, #AnatomyWidget[state="child-modified"]:hover { +#SideLineWidget[state="child-overriden-modified"]:hover { border-color: #137cbd; } From bafc82364df22bc9ab8e684232d1adfacb6b5849 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:54:44 +0200 Subject: [PATCH 386/580] top part of expandable widget is not used elsewhere --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 +- pype/tools/config_setting/config_setting/widgets/widgets.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4347b1336d..a66f121b3d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1631,7 +1631,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): ) item.value_changed.connect(self._on_value_change) - self.body_widget.top_part.layout().addWidget(item) + self.body_widget.side_line_layout.addWidget(item) self.checkbox_widget = item self.input_fields.append(item) return item diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 19d9ad9d25..8291f56e13 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -95,18 +95,18 @@ class ExpandingWidget(QtWidgets.QWidget): self.setAttribute(QtCore.Qt.WA_StyledBackground) - self.top_part = top_part self.side_line_widget = side_line_widget + self.side_line_layout = side_line_layout self.button_toggle = button_toggle self.label_widget = label_widget - self.top_part.clicked.connect(self._top_part_clicked) + top_part.clicked.connect(self._top_part_clicked) self.button_toggle.clicked.connect(self.toggle_content) self.main_layout = QtWidgets.QVBoxLayout(self) self.main_layout.setContentsMargins(0, 0, 0, 0) self.main_layout.setSpacing(0) - self.main_layout.addWidget(self.top_part) + self.main_layout.addWidget(top_part) def hide_toolbox(self, hide_content=False): self.button_toggle.setArrowType(QtCore.Qt.NoArrow) From e453b1c816084b957244cc5576e932d48aee6e6e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 10:54:57 +0200 Subject: [PATCH 387/580] add bg color to dict parts --- pype/tools/config_setting/config_setting/style/style.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 9051130344..3c8cc59182 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -123,7 +123,9 @@ QPushButton[btn-type="expand-toggle"] { #DictLabel { font-weight: bold; } + #SideLineWidget { + background-color: #31424e; border-style: solid; border-color: #455c6e; border-left-width: 3px; @@ -131,11 +133,11 @@ QPushButton[btn-type="expand-toggle"] { border-right-width: 0px; border-top-width: 0px; } + #SideLineWidget:hover { border-color: #62839d; } - #SideLineWidget[state="child-modified"]{ border-color: #106aa2; } From 1bc174be101002859051445b6013f5415137cdf0 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 8 Sep 2020 09:58:25 +0100 Subject: [PATCH 388/580] Fix comment tag collection and integration. --- .../publish/integrate_hierarchy_ftrack.py | 21 +++++++++++++++++++ .../publish/collect_hierarchy_context.py | 3 +-- .../nukestudio/publish/collect_shots.py | 5 +++-- .../publish/collect_tag_comments.py | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index cc569ce2d1..c4d8f2f705 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -167,6 +167,27 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.session.rollback() six.reraise(tp, value, tb) + # Create notes. + user = self.session.query( + "User where username is \"{}\"".format(self.session.api_user) + ).first() + if user: + for comment in entity_data.get("comments", []): + entity.create_note(comment, user) + else: + self.log.warning( + "Was not able to query current User {}".format( + self.session.api_user + ) + ) + try: + self.session.commit() + except Exception: + tp, value, tb = sys.exc_info() + self.session.rollback() + six.reraise(tp, value, tb) + + # Import children. if 'childs' in entity_data: self.import_to_ftrack( entity_data['childs'], entity) diff --git a/pype/plugins/nukestudio/publish/collect_hierarchy_context.py b/pype/plugins/nukestudio/publish/collect_hierarchy_context.py index a41e987bdb..930efd618e 100644 --- a/pype/plugins/nukestudio/publish/collect_hierarchy_context.py +++ b/pype/plugins/nukestudio/publish/collect_hierarchy_context.py @@ -273,8 +273,6 @@ class CollectHierarchyContext(pyblish.api.ContextPlugin): instance.data["clipOut"] - instance.data["clipIn"]) - - self.log.debug( "__ instance.data[parents]: {}".format( instance.data["parents"] @@ -319,6 +317,7 @@ class CollectHierarchyContext(pyblish.api.ContextPlugin): }) in_info['tasks'] = instance.data['tasks'] + in_info["comments"] = instance.data.get("comments", []) parents = instance.data.get('parents', []) self.log.debug("__ in_info: {}".format(in_info)) diff --git a/pype/plugins/nukestudio/publish/collect_shots.py b/pype/plugins/nukestudio/publish/collect_shots.py index 455e25bf82..7055167143 100644 --- a/pype/plugins/nukestudio/publish/collect_shots.py +++ b/pype/plugins/nukestudio/publish/collect_shots.py @@ -40,11 +40,12 @@ class CollectShots(api.InstancePlugin): data["name"] = data["subset"] + "_" + data["asset"] data["label"] = ( - "{} - {} - tasks:{} - assetbuilds:{}".format( + "{} - {} - tasks: {} - assetbuilds: {} - comments: {}".format( data["asset"], data["subset"], data["tasks"], - [x["name"] for x in data.get("assetbuilds", [])] + [x["name"] for x in data.get("assetbuilds", [])], + len(data.get("comments", [])) ) ) diff --git a/pype/plugins/nukestudio/publish/collect_tag_comments.py b/pype/plugins/nukestudio/publish/collect_tag_comments.py index 1ec98e3d3b..e14e53d439 100644 --- a/pype/plugins/nukestudio/publish/collect_tag_comments.py +++ b/pype/plugins/nukestudio/publish/collect_tag_comments.py @@ -17,7 +17,7 @@ class CollectClipTagComments(api.InstancePlugin): for tag in instance.data["tags"]: if tag["name"].lower() == "comment": instance.data["comments"].append( - tag.metadata().dict()["tag.note"] + tag["metadata"]["tag.note"] ) # Find tags on the source clip. From 19dd51fb98d53f19e010d13681fc140981604241 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 11:48:56 +0200 Subject: [PATCH 389/580] set checkbox spacing --- pype/tools/config_setting/config_setting/style/style.css | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 3c8cc59182..079d2f697e 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -19,12 +19,11 @@ QMenu::item:selected { border-left-color: #61839e; background-color: #222d37; } - -QCheckBox::indicator { -} -QCheckBox::indicator:focus { - color: #ff0000; +QCheckBox { + spacing: 0px; } +QCheckBox::indicator {} +QCheckBox::indicator:focus {} QLineEdit, QSpinBox, QDoubleSpinBox, QPlainTextEdit, QTextEdit { border: 1px solid #aaaaaa; From 842aeaf6de0d2d75d80b3af06a08190ea706bb28 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 11:53:22 +0200 Subject: [PATCH 390/580] expanding widget has more widgets --- .../config_setting/widgets/widgets.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 8291f56e13..31c7df4704 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -95,6 +95,10 @@ class ExpandingWidget(QtWidgets.QWidget): self.setAttribute(QtCore.Qt.WA_StyledBackground) + self.top_part_ending = None + self.after_label_layout = None + self.end_of_layout = None + self.side_line_widget = side_line_widget self.side_line_layout = side_line_layout self.button_toggle = button_toggle @@ -137,6 +141,47 @@ class ExpandingWidget(QtWidgets.QWidget): self.content_widget.setVisible(checked) self.parent().updateGeometry() + def add_widget_after_label(self, widget): + self._add_side_widget_subwidgets() + self.after_label_layout.addWidget(widget) + + def _add_side_widget_subwidgets(self): + if self.top_part_ending is not None: + return + + top_part_ending = QtWidgets.QWidget(self.side_line_widget) + top_part_ending.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + top_part_ending_layout = QtWidgets.QHBoxLayout(top_part_ending) + top_part_ending_layout.setContentsMargins(0, 0, 0, 0) + top_part_ending_layout.setSpacing(0) + top_part_ending_layout.setAlignment(QtCore.Qt.AlignVCenter) + + after_label_widget = QtWidgets.QWidget(top_part_ending) + spacer_item = QtWidgets.QWidget(top_part_ending) + end_of_widget = QtWidgets.QWidget(top_part_ending) + + self.after_label_layout = QtWidgets.QVBoxLayout(after_label_widget) + self.after_label_layout.setContentsMargins(0, 0, 0, 0) + + self.end_of_layout = QtWidgets.QVBoxLayout(end_of_widget) + self.end_of_layout.setContentsMargins(0, 0, 0, 0) + + spacer_layout = QtWidgets.QVBoxLayout(spacer_item) + spacer_layout.setContentsMargins(0, 0, 0, 0) + + top_part_ending_layout.addWidget(after_label_widget, 0) + top_part_ending_layout.addWidget(spacer_item, 1) + top_part_ending_layout.addWidget(end_of_widget, 0) + + top_part_ending.setAttribute(QtCore.Qt.WA_TranslucentBackground) + after_label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + spacer_item.setAttribute(QtCore.Qt.WA_TranslucentBackground) + end_of_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + self.top_part_ending = top_part_ending + self.side_line_layout.addWidget(top_part_ending) + def resizeEvent(self, event): super(ExpandingWidget, self).resizeEvent(event) self.content_widget.updateGeometry() From 47da6e688449b5c68eeaa179da618ba38cc2526c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 11:54:13 +0200 Subject: [PATCH 391/580] dict widget use different way of adding checkbox to top --- pype/tools/config_setting/config_setting/widgets/inputs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index a66f121b3d..f188471df8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -282,7 +282,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.label_widget = label_widget self.checkbox = QtWidgets.QCheckBox(self) - self.checkbox.setAttribute(QtCore.Qt.WA_StyledBackground) layout.addWidget(self.checkbox, 1) self.setFocusProxy(self.checkbox) @@ -1631,7 +1630,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): ) item.value_changed.connect(self._on_value_change) - self.body_widget.side_line_layout.addWidget(item) + self.body_widget.add_widget_after_label(item) self.checkbox_widget = item self.input_fields.append(item) return item From 37f901ad0979ad0875fc65f68e2bc406d74ec8d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 11:57:17 +0200 Subject: [PATCH 392/580] dict widget has right margins --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f188471df8..bed0e60339 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1580,7 +1580,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): content_widget = QtWidgets.QWidget(body_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(CHILD_OFFSET, 3, 0, 3) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) body_widget.set_content_widget(content_widget) From 03470eb75d9e46f62a35a443218ef3281fc7632b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 12:28:51 +0200 Subject: [PATCH 393/580] changed styled background to transparent in most of cases --- .../config_setting/config_setting/widgets/inputs.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index bed0e60339..f175cb159a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -277,7 +277,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(label_widget, 0) self.label_widget = label_widget @@ -993,7 +993,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.label_widget = label_widget inputs_widget = QtWidgets.QWidget(self) - inputs_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + inputs_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(inputs_widget) inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) @@ -1358,7 +1358,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.content_widget = content_widget self.content_layout = content_layout - self.setAttribute(QtCore.Qt.WA_StyledBackground) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.object_type = input_data["object_type"] self.default_value = input_data.get("default", NOT_SET) @@ -1590,7 +1590,6 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget - self.setAttribute(QtCore.Qt.WA_StyledBackground) self.checkbox_widget = None self.checkbox_key = input_data.get("checkbox_key") @@ -1822,7 +1821,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): self.any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) - self.setAttribute(QtCore.Qt.WA_StyledBackground) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -2041,7 +2040,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - label_widget.setAttribute(QtCore.Qt.WA_StyledBackground) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(label_widget, 0) self.label_widget = label_widget From 7794f5a20dcbd593d5b28551ef39e264f976ea4c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 12:29:08 +0200 Subject: [PATCH 394/580] chceckbox widget has spacer at the end --- pype/tools/config_setting/config_setting/widgets/inputs.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f175cb159a..6fb1f553bd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -282,7 +282,12 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.label_widget = label_widget self.checkbox = QtWidgets.QCheckBox(self) - layout.addWidget(self.checkbox, 1) + spacer = QtWidgets.QWidget(self) + layout.addWidget(self.checkbox, 0) + layout.addWidget(spacer, 1) + + spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.setFocusProxy(self.checkbox) self.checkbox.stateChanged.connect(self._on_value_change) From f21c9426aaa4bdf6cc14f687694b5e402f1773bf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 12:29:25 +0200 Subject: [PATCH 395/580] expanding widget is transparent too --- pype/tools/config_setting/config_setting/widgets/widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 31c7df4704..a76f4f6f35 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -93,7 +93,7 @@ class ExpandingWidget(QtWidgets.QWidget): top_part_layout.setContentsMargins(0, 0, 0, 0) top_part_layout.addWidget(side_line_widget) - self.setAttribute(QtCore.Qt.WA_StyledBackground) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.top_part_ending = None self.after_label_layout = None From 5224572d23284f5a7bc26c45e19a6ed852318673 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 12:30:23 +0200 Subject: [PATCH 396/580] content widget has darker and darker background --- pype/tools/config_setting/config_setting/style/style.css | 4 ++++ pype/tools/config_setting/config_setting/widgets/inputs.py | 1 + 2 files changed, 5 insertions(+) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 079d2f697e..f238246063 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -123,6 +123,10 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } +#ContentWidget { + background-color: rgba(19, 26, 32, 20%); +} + #SideLineWidget { background-color: #31424e; border-style: solid; diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 6fb1f553bd..221d02ca65 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1584,6 +1584,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): main_layout.addWidget(body_widget) content_widget = QtWidgets.QWidget(body_widget) + content_widget.setObjectName("ContentWidget") content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) From 53bbafcb244d9aa9647723486bbe365bfeaa2750 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 13:55:51 +0200 Subject: [PATCH 397/580] ContentWidget is transparent by default --- pype/tools/config_setting/config_setting/style/style.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index f238246063..af61655a36 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -124,6 +124,9 @@ QPushButton[btn-type="expand-toggle"] { } #ContentWidget { + background-color: transparent; +} +#ContentWidget[content_state="hightlighted"] { background-color: rgba(19, 26, 32, 20%); } From 1dabf20d363d7f6331c933a9525e6571d61ebd89 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 13:56:15 +0200 Subject: [PATCH 398/580] dict widget can have set if should highlight background --- .../config_setting/config_setting/widgets/inputs.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 221d02ca65..bd046e32dd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1571,6 +1571,11 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) + if input_data.get("highlight_content", False): + content_state = "hightlighted" + else: + content_state = "" + self.input_fields = [] self.key = input_data["key"] @@ -1585,6 +1590,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): content_widget = QtWidgets.QWidget(body_widget) content_widget.setObjectName("ContentWidget") + content_widget.setProperty("content_state", content_state) content_layout = QtWidgets.QVBoxLayout(content_widget) content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) @@ -1596,7 +1602,6 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget - self.checkbox_widget = None self.checkbox_key = input_data.get("checkbox_key") @@ -2311,6 +2316,8 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): for child_data in input_data.get("children", []): self.add_children_gui(child_data) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] # Pop label to not be set in child From 6efbecff8f49eab23d5a6d5ee84271519320290b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 13:59:54 +0200 Subject: [PATCH 399/580] added bottom margin to content when should highligh content --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index bd046e32dd..908fe8e070 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1573,8 +1573,10 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): if input_data.get("highlight_content", False): content_state = "hightlighted" + bottom_margin = 5 else: content_state = "" + bottom_margin = 0 self.input_fields = [] @@ -1592,7 +1594,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): content_widget.setObjectName("ContentWidget") content_widget.setProperty("content_state", content_state) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, bottom_margin) body_widget.set_content_widget(content_widget) From 967e312df0861751347e3b0b2d2ad2ab4ca20941 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:11:48 +0200 Subject: [PATCH 400/580] AnatomyWIdget is using expanding widget --- .../config_setting/widgets/anatomy_inputs.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 9e69d7234e..befd928463 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,7 +1,7 @@ from Qt import QtWidgets, QtCore from .widgets import ExpandingWidget from .inputs import ConfigObject, ModifiableDict, PathWidget -from .lib import NOT_SET, TypeToKlass +from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET class AnatomyWidget(QtWidgets.QWidget, ConfigObject): @@ -56,13 +56,13 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): body_widget = ExpandingWidget("Anatomy", self) layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(5, 5, 0, 5) + layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(body_widget) content_widget = QtWidgets.QWidget(body_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - content_layout.setContentsMargins(0, 0, 0, 0) + content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0) content_layout.setSpacing(5) content_layout.addWidget(self.root_widget) @@ -206,12 +206,18 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): checkbox_layout.addWidget(multiroot_label, 0) checkbox_layout.addWidget(multiroot_checkbox, 1) + body_widget = ExpandingWidget("Roots", self) + content_widget = QtWidgets.QWidget(body_widget) + path_widget_data = { "key": "roots", "multipath": False, "multiplatform": True } - singleroot_widget = PathWidget(path_widget_data, self, as_widget=True) + singleroot_widget = PathWidget( + path_widget_data, self, + as_widget=True, parent_widget=content_widget + ) multiroot_data = { "key": "roots", "object_type": "path-widget", @@ -220,12 +226,13 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): "multiplatform": True } } - multiroot_widget = ModifiableDict(multiroot_data, self, as_widget=True) + multiroot_widget = ModifiableDict( + multiroot_data, self, + as_widget=True, parent_widget=content_widget + ) - body_widget = ExpandingWidget("Roots", self) - - content_widget = QtWidgets.QWidget(body_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(0, 0, 0, 0) content_layout.addWidget(checkbox_widget) content_layout.addWidget(singleroot_widget) content_layout.addWidget(multiroot_widget) From 4e03a7c6a55a8884b2ed62b64bcadfa11d017a65 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:12:10 +0200 Subject: [PATCH 401/580] lowered bg color increasing --- pype/tools/config_setting/config_setting/style/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index af61655a36..fe3bba366a 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -127,7 +127,7 @@ QPushButton[btn-type="expand-toggle"] { background-color: transparent; } #ContentWidget[content_state="hightlighted"] { - background-color: rgba(19, 26, 32, 20%); + background-color: rgba(19, 26, 32, 15%); } #SideLineWidget { From 99899a35ea7caca510f883de70ef9452d02b2299 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:18:40 +0200 Subject: [PATCH 402/580] fix style updates in list --- .../config_setting/config_setting/widgets/inputs.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 908fe8e070..18a6ef690b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -952,6 +952,9 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def child_overriden(self): return self.value_input.child_overriden + def hierarchical_style_update(self): + self.value_input.hierarchical_style_update() + def mouseReleaseEvent(self, event): return QtWidgets.QWidget.mouseReleaseEvent(self, event) @@ -1047,6 +1050,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.start_value = self.item_value() self._is_modified = self.global_value != self.start_value + self.hierarchical_style_update() def set_value(self, value): previous_inputs = tuple(self.input_fields) @@ -1102,7 +1106,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): # else (when add button clicked) trigger `_on_value_change` if value is not None: item_widget.value_input.update_global_values(value) - self.hierarchical_style_update() else: self._on_value_change() self.updateGeometry() @@ -1143,6 +1146,11 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.set_value(value) + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + self.update_style() + def update_style(self): state = self.style_state( self.is_invalid, self.is_overriden, self.is_modified From 6c37ede07cb9a12a99f4282cc566d43632ebca47 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:40:08 +0200 Subject: [PATCH 403/580] fix raw json in-validation --- pype/tools/config_setting/config_setting/widgets/inputs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 18a6ef690b..a08ad88015 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -820,10 +820,11 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): elif self.default_value is not NOT_SET: self.set_value(self.default_value) + self._is_invalid = self.text_input.has_invalid_value() + self.global_value = value self.start_value = self.item_value() - self._is_invalid = self.text_input.has_invalid_value() self._is_modified = self.global_value != self.start_value def set_value(self, value): From 1ceb51a26b3659b95cb517f1a971eb99d6de07ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:43:17 +0200 Subject: [PATCH 404/580] added simple implementation of Templates --- .../config_setting/widgets/anatomy_inputs.py | 56 +++++++++++++------ 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index befd928463..7705efd91c 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,6 +1,6 @@ from Qt import QtWidgets, QtCore from .widgets import ExpandingWidget -from .inputs import ConfigObject, ModifiableDict, PathWidget +from .inputs import ConfigObject, ModifiableDict, PathWidget, RawJsonWidget from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET @@ -172,6 +172,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): def item_value(self): output = {} output.update(self.root_widget.config_value()) + output.update(self.templates_widget.config_value()) return output def config_value(self): @@ -459,18 +460,30 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): return {self.key: self.item_value()} -# TODO implement -class TemplatesWidget(QtWidgets.QWidget): - def __init__(self, parent=None): +class TemplatesWidget(QtWidgets.QWidget, ConfigObject): + def __init__(self, parent): super(TemplatesWidget, self).__init__(parent) + self._parent = parent + + self._is_group = True + self.any_parent_is_group = False + self.key = "templates" + body_widget = ExpandingWidget("Templates", self) content_widget = QtWidgets.QWidget(body_widget) body_widget.set_content_widget(content_widget) content_layout = QtWidgets.QVBoxLayout(content_widget) - label = QtWidgets.QLabel("Nothing yet", content_widget) - content_layout.addWidget(label) + template_input_data = { + "key": self.key + } + self.label_widget = body_widget.label_widget + self.value_input = RawJsonWidget( + template_input_data, self, + label_widget=self.label_widget + ) + content_layout.addWidget(self.value_input) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -479,39 +492,50 @@ class TemplatesWidget(QtWidgets.QWidget): layout.addWidget(body_widget) def update_global_values(self, values): - pass + self.value_input.update_global_values(values) def apply_overrides(self, parent_values): - pass + self.value_input.apply_overrides(parent_values) def hierarchical_style_update(self): - pass + self.value_input.hierarchical_style_update() @property def is_modified(self): - return False + return self.value_input.is_modified @property def is_overriden(self): - return False + return self._is_overriden @property def child_modified(self): - return False + return self.value_input.child_modified @property def child_overriden(self): - return False + return self.value_input.child_overriden @property def child_invalid(self): - return False + return self.value_input.child_invalid def remove_overrides(self): - pass + print("* `remove_overrides` NOT IMPLEMENTED") def discard_changes(self): - pass + print("* `discard_changes` NOT IMPLEMENTED") + + def overrides(self): + if not self.is_overriden: + return NOT_SET, False + return self.config_value(), True + + def item_value(self): + return self.value_input.item_value() + + def config_value(self): + return self.value_input.config_value() TypeToKlass.types["anatomy"] = AnatomyWidget From 80ef4bf876ccf60d0b7c1093991321d002a1d6ef Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:49:13 +0200 Subject: [PATCH 405/580] implemented set_as_overriden for path widget --- pype/tools/config_setting/config_setting/widgets/inputs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index a08ad88015..155bcbb74d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2243,6 +2243,9 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified + def set_as_overriden(self): + self._is_overriden = True + @property def child_modified(self): for input_field in self.input_fields: From d7e2b07fcc38bbdf025a9d5db529a6bb0c5011d6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 14:57:53 +0200 Subject: [PATCH 406/580] few minor changes about attribute values in anatomy iwdgets --- .../config_setting/widgets/anatomy_inputs.py | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 7705efd91c..688b4bf715 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -131,10 +131,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.hierarchical_style_update() self.update_style() - @property - def is_modified(self): - return self._is_modified or self.child_modified - @property def child_modified(self): return ( @@ -363,9 +359,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if self.ignore_value_changes: return - if item is None: - pass - elif ( + if item is not None and ( (self.is_multiroot and item != self.multiroot_widget) or (not self.is_multiroot and item != self.singleroot_widget) ): @@ -393,14 +387,6 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._on_value_change() - @property - def is_modified(self): - return self._is_modified or self.child_modified - - @property - def is_overriden(self): - return self._is_overriden - @property def child_modified(self): if self.is_multiroot: @@ -450,6 +436,11 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified + def set_as_overriden(self): + self._is_overriden = self._was_overriden + self.singleroot_widget.set_as_overriden() + self.multiroot_widget.set_as_overriden() + def item_value(self): if self.is_multiroot: return self.multiroot_widget.item_value() @@ -521,13 +512,16 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): return self.value_input.child_invalid def remove_overrides(self): - print("* `remove_overrides` NOT IMPLEMENTED") + self.value_input.remove_overrides() def discard_changes(self): - print("* `discard_changes` NOT IMPLEMENTED") + self.value_input.discard_changes() + + def set_as_overriden(self): + self.value_input.set_as_overriden() def overrides(self): - if not self.is_overriden: + if not self.child_overriden: return NOT_SET, False return self.config_value(), True From 427a6109b7ad5d1b7591b60a50e9ba6d6df78dd3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 15:09:42 +0200 Subject: [PATCH 407/580] removed all io_nonsingleton files from pype --- .../adobe_communicator/lib/io_nonsingleton.py | 460 ------------------ pype/modules/ftrack/lib/io_nonsingleton.py | 460 ------------------ 2 files changed, 920 deletions(-) delete mode 100644 pype/modules/adobe_communicator/lib/io_nonsingleton.py delete mode 100644 pype/modules/ftrack/lib/io_nonsingleton.py diff --git a/pype/modules/adobe_communicator/lib/io_nonsingleton.py b/pype/modules/adobe_communicator/lib/io_nonsingleton.py deleted file mode 100644 index da37c657c6..0000000000 --- a/pype/modules/adobe_communicator/lib/io_nonsingleton.py +++ /dev/null @@ -1,460 +0,0 @@ -""" -Wrapper around interactions with the database - -Copy of io module in avalon-core. - - In this case not working as singleton with api.Session! -""" - -import os -import time -import errno -import shutil -import logging -import tempfile -import functools -import contextlib - -from avalon import schema -from avalon.vendor import requests -from avalon.io import extract_port_from_url - -# Third-party dependencies -import pymongo - - -def auto_reconnect(func): - """Handling auto reconnect in 3 retry times""" - @functools.wraps(func) - def decorated(*args, **kwargs): - object = args[0] - for retry in range(3): - try: - return func(*args, **kwargs) - except pymongo.errors.AutoReconnect: - object.log.error("Reconnecting..") - time.sleep(0.1) - else: - raise - - return decorated - - -class DbConnector(object): - - log = logging.getLogger(__name__) - - def __init__(self): - self.Session = {} - self._mongo_client = None - self._sentry_client = None - self._sentry_logging_handler = None - self._database = None - self._is_installed = False - - def __getitem__(self, key): - # gives direct access to collection withou setting `active_table` - return self._database[key] - - def __getattribute__(self, attr): - # not all methods of PyMongo database are implemented with this it is - # possible to use them too - try: - return super(DbConnector, self).__getattribute__(attr) - except AttributeError: - cur_proj = self.Session["AVALON_PROJECT"] - return self._database[cur_proj].__getattribute__(attr) - - def install(self): - """Establish a persistent connection to the database""" - if self._is_installed: - return - - logging.basicConfig() - self.Session.update(self._from_environment()) - - timeout = int(self.Session["AVALON_TIMEOUT"]) - mongo_url = self.Session["AVALON_MONGO"] - kwargs = { - "host": mongo_url, - "serverSelectionTimeoutMS": timeout - } - - port = extract_port_from_url(mongo_url) - if port is not None: - kwargs["port"] = int(port) - - self._mongo_client = pymongo.MongoClient(**kwargs) - - for retry in range(3): - try: - t1 = time.time() - self._mongo_client.server_info() - - except Exception: - self.log.error("Retrying..") - time.sleep(1) - timeout *= 1.5 - - else: - break - - else: - raise IOError( - "ERROR: Couldn't connect to %s in " - "less than %.3f ms" % (self.Session["AVALON_MONGO"], timeout)) - - self.log.info("Connected to %s, delay %.3f s" % ( - self.Session["AVALON_MONGO"], time.time() - t1)) - - self._install_sentry() - - self._database = self._mongo_client[self.Session["AVALON_DB"]] - self._is_installed = True - - def _install_sentry(self): - if "AVALON_SENTRY" not in self.Session: - return - - try: - from raven import Client - from raven.handlers.logging import SentryHandler - from raven.conf import setup_logging - except ImportError: - # Note: There was a Sentry address in this Session - return self.log.warning("Sentry disabled, raven not installed") - - client = Client(self.Session["AVALON_SENTRY"]) - - # Transmit log messages to Sentry - handler = SentryHandler(client) - handler.setLevel(logging.WARNING) - - setup_logging(handler) - - self._sentry_client = client - self._sentry_logging_handler = handler - self.log.info( - "Connected to Sentry @ %s" % self.Session["AVALON_SENTRY"] - ) - - def _from_environment(self): - Session = { - item[0]: os.getenv(item[0], item[1]) - for item in ( - # Root directory of projects on disk - ("AVALON_PROJECTS", None), - - # Name of current Project - ("AVALON_PROJECT", ""), - - # Name of current Asset - ("AVALON_ASSET", ""), - - # Name of current silo - ("AVALON_SILO", ""), - - # Name of current task - ("AVALON_TASK", None), - - # Name of current app - ("AVALON_APP", None), - - # Path to working directory - ("AVALON_WORKDIR", None), - - # Name of current Config - # TODO(marcus): Establish a suitable default config - ("AVALON_CONFIG", "no_config"), - - # Name of Avalon in graphical user interfaces - # Use this to customise the visual appearance of Avalon - # to better integrate with your surrounding pipeline - ("AVALON_LABEL", "Avalon"), - - # Used during any connections to the outside world - ("AVALON_TIMEOUT", "1000"), - - # Address to Asset Database - ("AVALON_MONGO", "mongodb://localhost:27017"), - - # Name of database used in MongoDB - ("AVALON_DB", "avalon"), - - # Address to Sentry - ("AVALON_SENTRY", None), - - # Address to Deadline Web Service - # E.g. http://192.167.0.1:8082 - ("AVALON_DEADLINE", None), - - # Enable features not necessarily stable. The user's own risk - ("AVALON_EARLY_ADOPTER", None), - - # Address of central asset repository, contains - # the following interface: - # /upload - # /download - # /manager (optional) - ("AVALON_LOCATION", "http://127.0.0.1"), - - # Boolean of whether to upload published material - # to central asset repository - ("AVALON_UPLOAD", None), - - # Generic username and password - ("AVALON_USERNAME", "avalon"), - ("AVALON_PASSWORD", "secret"), - - # Unique identifier for instances in working files - ("AVALON_INSTANCE_ID", "avalon.instance"), - ("AVALON_CONTAINER_ID", "avalon.container"), - - # Enable debugging - ("AVALON_DEBUG", None), - - ) if os.getenv(item[0], item[1]) is not None - } - - Session["schema"] = "avalon-core:session-2.0" - try: - schema.validate(Session) - except schema.ValidationError as e: - # TODO(marcus): Make this mandatory - self.log.warning(e) - - return Session - - def uninstall(self): - """Close any connection to the database""" - try: - self._mongo_client.close() - except AttributeError: - pass - - self._mongo_client = None - self._database = None - self._is_installed = False - - def active_project(self): - """Return the name of the active project""" - return self.Session["AVALON_PROJECT"] - - def activate_project(self, project_name): - self.Session["AVALON_PROJECT"] = project_name - - def projects(self): - """List available projects - - Returns: - list of project documents - - """ - - collection_names = self.collections() - for project in collection_names: - if project in ("system.indexes",): - continue - - # Each collection will have exactly one project document - document = self.find_project(project) - - if document is not None: - yield document - - def locate(self, path): - """Traverse a hierarchy from top-to-bottom - - Example: - representation = locate(["hulk", "Bruce", "modelDefault", 1, "ma"]) - - Returns: - representation (ObjectId) - - """ - - components = zip( - ("project", "asset", "subset", "version", "representation"), - path - ) - - parent = None - for type_, name in components: - latest = (type_ == "version") and name in (None, -1) - - try: - if latest: - parent = self.find_one( - filter={ - "type": type_, - "parent": parent - }, - projection={"_id": 1}, - sort=[("name", -1)] - )["_id"] - else: - parent = self.find_one( - filter={ - "type": type_, - "name": name, - "parent": parent - }, - projection={"_id": 1}, - )["_id"] - - except TypeError: - return None - - return parent - - @auto_reconnect - def collections(self): - return self._database.collection_names() - - @auto_reconnect - def find_project(self, project): - return self._database[project].find_one({"type": "project"}) - - @auto_reconnect - def insert_one(self, item): - assert isinstance(item, dict), "item must be of type " - schema.validate(item) - return self._database[self.Session["AVALON_PROJECT"]].insert_one(item) - - @auto_reconnect - def insert_many(self, items, ordered=True): - # check if all items are valid - assert isinstance(items, list), "`items` must be of type " - for item in items: - assert isinstance(item, dict), "`item` must be of type " - schema.validate(item) - - return self._database[self.Session["AVALON_PROJECT"]].insert_many( - items, - ordered=ordered) - - @auto_reconnect - def find(self, filter, projection=None, sort=None): - return self._database[self.Session["AVALON_PROJECT"]].find( - filter=filter, - projection=projection, - sort=sort - ) - - @auto_reconnect - def find_one(self, filter, projection=None, sort=None): - assert isinstance(filter, dict), "filter must be " - - return self._database[self.Session["AVALON_PROJECT"]].find_one( - filter=filter, - projection=projection, - sort=sort - ) - - @auto_reconnect - def save(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].save( - *args, **kwargs) - - @auto_reconnect - def replace_one(self, filter, replacement): - return self._database[self.Session["AVALON_PROJECT"]].replace_one( - filter, replacement) - - @auto_reconnect - def update_many(self, filter, update): - return self._database[self.Session["AVALON_PROJECT"]].update_many( - filter, update) - - @auto_reconnect - def distinct(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].distinct( - *args, **kwargs) - - @auto_reconnect - def drop(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].drop( - *args, **kwargs) - - @auto_reconnect - def delete_many(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].delete_many( - *args, **kwargs) - - def parenthood(self, document): - assert document is not None, "This is a bug" - - parents = list() - - while document.get("parent") is not None: - document = self.find_one({"_id": document["parent"]}) - - if document is None: - break - - if document.get("type") == "master_version": - _document = self.find_one({"_id": document["version_id"]}) - document["data"] = _document["data"] - - parents.append(document) - - return parents - - @contextlib.contextmanager - def tempdir(self): - tempdir = tempfile.mkdtemp() - try: - yield tempdir - finally: - shutil.rmtree(tempdir) - - def download(self, src, dst): - """Download `src` to `dst` - - Arguments: - src (str): URL to source file - dst (str): Absolute path to destination file - - Yields tuple (progress, error): - progress (int): Between 0-100 - error (Exception): Any exception raised when first making connection - - """ - - try: - response = requests.get( - src, - stream=True, - auth=requests.auth.HTTPBasicAuth( - self.Session["AVALON_USERNAME"], - self.Session["AVALON_PASSWORD"] - ) - ) - except requests.ConnectionError as e: - yield None, e - return - - with self.tempdir() as dirname: - tmp = os.path.join(dirname, os.path.basename(src)) - - with open(tmp, "wb") as f: - total_length = response.headers.get("content-length") - - if total_length is None: # no content length header - f.write(response.content) - else: - downloaded = 0 - total_length = int(total_length) - for data in response.iter_content(chunk_size=4096): - downloaded += len(data) - f.write(data) - - yield int(100.0 * downloaded / total_length), None - - try: - os.makedirs(os.path.dirname(dst)) - except OSError as e: - # An already existing destination directory is fine. - if e.errno != errno.EEXIST: - raise - - shutil.copy(tmp, dst) diff --git a/pype/modules/ftrack/lib/io_nonsingleton.py b/pype/modules/ftrack/lib/io_nonsingleton.py deleted file mode 100644 index da37c657c6..0000000000 --- a/pype/modules/ftrack/lib/io_nonsingleton.py +++ /dev/null @@ -1,460 +0,0 @@ -""" -Wrapper around interactions with the database - -Copy of io module in avalon-core. - - In this case not working as singleton with api.Session! -""" - -import os -import time -import errno -import shutil -import logging -import tempfile -import functools -import contextlib - -from avalon import schema -from avalon.vendor import requests -from avalon.io import extract_port_from_url - -# Third-party dependencies -import pymongo - - -def auto_reconnect(func): - """Handling auto reconnect in 3 retry times""" - @functools.wraps(func) - def decorated(*args, **kwargs): - object = args[0] - for retry in range(3): - try: - return func(*args, **kwargs) - except pymongo.errors.AutoReconnect: - object.log.error("Reconnecting..") - time.sleep(0.1) - else: - raise - - return decorated - - -class DbConnector(object): - - log = logging.getLogger(__name__) - - def __init__(self): - self.Session = {} - self._mongo_client = None - self._sentry_client = None - self._sentry_logging_handler = None - self._database = None - self._is_installed = False - - def __getitem__(self, key): - # gives direct access to collection withou setting `active_table` - return self._database[key] - - def __getattribute__(self, attr): - # not all methods of PyMongo database are implemented with this it is - # possible to use them too - try: - return super(DbConnector, self).__getattribute__(attr) - except AttributeError: - cur_proj = self.Session["AVALON_PROJECT"] - return self._database[cur_proj].__getattribute__(attr) - - def install(self): - """Establish a persistent connection to the database""" - if self._is_installed: - return - - logging.basicConfig() - self.Session.update(self._from_environment()) - - timeout = int(self.Session["AVALON_TIMEOUT"]) - mongo_url = self.Session["AVALON_MONGO"] - kwargs = { - "host": mongo_url, - "serverSelectionTimeoutMS": timeout - } - - port = extract_port_from_url(mongo_url) - if port is not None: - kwargs["port"] = int(port) - - self._mongo_client = pymongo.MongoClient(**kwargs) - - for retry in range(3): - try: - t1 = time.time() - self._mongo_client.server_info() - - except Exception: - self.log.error("Retrying..") - time.sleep(1) - timeout *= 1.5 - - else: - break - - else: - raise IOError( - "ERROR: Couldn't connect to %s in " - "less than %.3f ms" % (self.Session["AVALON_MONGO"], timeout)) - - self.log.info("Connected to %s, delay %.3f s" % ( - self.Session["AVALON_MONGO"], time.time() - t1)) - - self._install_sentry() - - self._database = self._mongo_client[self.Session["AVALON_DB"]] - self._is_installed = True - - def _install_sentry(self): - if "AVALON_SENTRY" not in self.Session: - return - - try: - from raven import Client - from raven.handlers.logging import SentryHandler - from raven.conf import setup_logging - except ImportError: - # Note: There was a Sentry address in this Session - return self.log.warning("Sentry disabled, raven not installed") - - client = Client(self.Session["AVALON_SENTRY"]) - - # Transmit log messages to Sentry - handler = SentryHandler(client) - handler.setLevel(logging.WARNING) - - setup_logging(handler) - - self._sentry_client = client - self._sentry_logging_handler = handler - self.log.info( - "Connected to Sentry @ %s" % self.Session["AVALON_SENTRY"] - ) - - def _from_environment(self): - Session = { - item[0]: os.getenv(item[0], item[1]) - for item in ( - # Root directory of projects on disk - ("AVALON_PROJECTS", None), - - # Name of current Project - ("AVALON_PROJECT", ""), - - # Name of current Asset - ("AVALON_ASSET", ""), - - # Name of current silo - ("AVALON_SILO", ""), - - # Name of current task - ("AVALON_TASK", None), - - # Name of current app - ("AVALON_APP", None), - - # Path to working directory - ("AVALON_WORKDIR", None), - - # Name of current Config - # TODO(marcus): Establish a suitable default config - ("AVALON_CONFIG", "no_config"), - - # Name of Avalon in graphical user interfaces - # Use this to customise the visual appearance of Avalon - # to better integrate with your surrounding pipeline - ("AVALON_LABEL", "Avalon"), - - # Used during any connections to the outside world - ("AVALON_TIMEOUT", "1000"), - - # Address to Asset Database - ("AVALON_MONGO", "mongodb://localhost:27017"), - - # Name of database used in MongoDB - ("AVALON_DB", "avalon"), - - # Address to Sentry - ("AVALON_SENTRY", None), - - # Address to Deadline Web Service - # E.g. http://192.167.0.1:8082 - ("AVALON_DEADLINE", None), - - # Enable features not necessarily stable. The user's own risk - ("AVALON_EARLY_ADOPTER", None), - - # Address of central asset repository, contains - # the following interface: - # /upload - # /download - # /manager (optional) - ("AVALON_LOCATION", "http://127.0.0.1"), - - # Boolean of whether to upload published material - # to central asset repository - ("AVALON_UPLOAD", None), - - # Generic username and password - ("AVALON_USERNAME", "avalon"), - ("AVALON_PASSWORD", "secret"), - - # Unique identifier for instances in working files - ("AVALON_INSTANCE_ID", "avalon.instance"), - ("AVALON_CONTAINER_ID", "avalon.container"), - - # Enable debugging - ("AVALON_DEBUG", None), - - ) if os.getenv(item[0], item[1]) is not None - } - - Session["schema"] = "avalon-core:session-2.0" - try: - schema.validate(Session) - except schema.ValidationError as e: - # TODO(marcus): Make this mandatory - self.log.warning(e) - - return Session - - def uninstall(self): - """Close any connection to the database""" - try: - self._mongo_client.close() - except AttributeError: - pass - - self._mongo_client = None - self._database = None - self._is_installed = False - - def active_project(self): - """Return the name of the active project""" - return self.Session["AVALON_PROJECT"] - - def activate_project(self, project_name): - self.Session["AVALON_PROJECT"] = project_name - - def projects(self): - """List available projects - - Returns: - list of project documents - - """ - - collection_names = self.collections() - for project in collection_names: - if project in ("system.indexes",): - continue - - # Each collection will have exactly one project document - document = self.find_project(project) - - if document is not None: - yield document - - def locate(self, path): - """Traverse a hierarchy from top-to-bottom - - Example: - representation = locate(["hulk", "Bruce", "modelDefault", 1, "ma"]) - - Returns: - representation (ObjectId) - - """ - - components = zip( - ("project", "asset", "subset", "version", "representation"), - path - ) - - parent = None - for type_, name in components: - latest = (type_ == "version") and name in (None, -1) - - try: - if latest: - parent = self.find_one( - filter={ - "type": type_, - "parent": parent - }, - projection={"_id": 1}, - sort=[("name", -1)] - )["_id"] - else: - parent = self.find_one( - filter={ - "type": type_, - "name": name, - "parent": parent - }, - projection={"_id": 1}, - )["_id"] - - except TypeError: - return None - - return parent - - @auto_reconnect - def collections(self): - return self._database.collection_names() - - @auto_reconnect - def find_project(self, project): - return self._database[project].find_one({"type": "project"}) - - @auto_reconnect - def insert_one(self, item): - assert isinstance(item, dict), "item must be of type " - schema.validate(item) - return self._database[self.Session["AVALON_PROJECT"]].insert_one(item) - - @auto_reconnect - def insert_many(self, items, ordered=True): - # check if all items are valid - assert isinstance(items, list), "`items` must be of type " - for item in items: - assert isinstance(item, dict), "`item` must be of type " - schema.validate(item) - - return self._database[self.Session["AVALON_PROJECT"]].insert_many( - items, - ordered=ordered) - - @auto_reconnect - def find(self, filter, projection=None, sort=None): - return self._database[self.Session["AVALON_PROJECT"]].find( - filter=filter, - projection=projection, - sort=sort - ) - - @auto_reconnect - def find_one(self, filter, projection=None, sort=None): - assert isinstance(filter, dict), "filter must be " - - return self._database[self.Session["AVALON_PROJECT"]].find_one( - filter=filter, - projection=projection, - sort=sort - ) - - @auto_reconnect - def save(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].save( - *args, **kwargs) - - @auto_reconnect - def replace_one(self, filter, replacement): - return self._database[self.Session["AVALON_PROJECT"]].replace_one( - filter, replacement) - - @auto_reconnect - def update_many(self, filter, update): - return self._database[self.Session["AVALON_PROJECT"]].update_many( - filter, update) - - @auto_reconnect - def distinct(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].distinct( - *args, **kwargs) - - @auto_reconnect - def drop(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].drop( - *args, **kwargs) - - @auto_reconnect - def delete_many(self, *args, **kwargs): - return self._database[self.Session["AVALON_PROJECT"]].delete_many( - *args, **kwargs) - - def parenthood(self, document): - assert document is not None, "This is a bug" - - parents = list() - - while document.get("parent") is not None: - document = self.find_one({"_id": document["parent"]}) - - if document is None: - break - - if document.get("type") == "master_version": - _document = self.find_one({"_id": document["version_id"]}) - document["data"] = _document["data"] - - parents.append(document) - - return parents - - @contextlib.contextmanager - def tempdir(self): - tempdir = tempfile.mkdtemp() - try: - yield tempdir - finally: - shutil.rmtree(tempdir) - - def download(self, src, dst): - """Download `src` to `dst` - - Arguments: - src (str): URL to source file - dst (str): Absolute path to destination file - - Yields tuple (progress, error): - progress (int): Between 0-100 - error (Exception): Any exception raised when first making connection - - """ - - try: - response = requests.get( - src, - stream=True, - auth=requests.auth.HTTPBasicAuth( - self.Session["AVALON_USERNAME"], - self.Session["AVALON_PASSWORD"] - ) - ) - except requests.ConnectionError as e: - yield None, e - return - - with self.tempdir() as dirname: - tmp = os.path.join(dirname, os.path.basename(src)) - - with open(tmp, "wb") as f: - total_length = response.headers.get("content-length") - - if total_length is None: # no content length header - f.write(response.content) - else: - downloaded = 0 - total_length = int(total_length) - for data in response.iter_content(chunk_size=4096): - downloaded += len(data) - f.write(data) - - yield int(100.0 * downloaded / total_length), None - - try: - os.makedirs(os.path.dirname(dst)) - except OSError as e: - # An already existing destination directory is fine. - if e.errno != errno.EEXIST: - raise - - shutil.copy(tmp, dst) From c68423279c0c1b7dd5a9af4be3d3f42b5d0561da Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 15:10:34 +0200 Subject: [PATCH 408/580] everywhere where io_nonsingleton was used is used AvalonmongoDB now --- pype/modules/adobe_communicator/lib/__init__.py | 2 -- pype/modules/adobe_communicator/lib/rest_api.py | 4 ++-- pype/modules/avalon_apps/rest_api.py | 4 ++-- pype/modules/ftrack/actions/action_delete_asset.py | 4 ++-- pype/modules/ftrack/actions/action_delete_old_versions.py | 4 ++-- pype/modules/ftrack/actions/action_delivery.py | 4 ++-- .../ftrack/actions/action_store_thumbnails_to_avalon.py | 4 ++-- pype/modules/ftrack/events/event_sync_to_avalon.py | 4 ++-- pype/modules/ftrack/events/event_user_assigment.py | 4 ++-- pype/modules/ftrack/lib/avalon_sync.py | 4 ++-- pype/tools/launcher/window.py | 4 ++-- pype/tools/standalonepublish/app.py | 4 ++-- 12 files changed, 22 insertions(+), 24 deletions(-) diff --git a/pype/modules/adobe_communicator/lib/__init__.py b/pype/modules/adobe_communicator/lib/__init__.py index 23aee81275..f918e49a60 100644 --- a/pype/modules/adobe_communicator/lib/__init__.py +++ b/pype/modules/adobe_communicator/lib/__init__.py @@ -1,8 +1,6 @@ -from .io_nonsingleton import DbConnector from .rest_api import AdobeRestApi, PUBLISH_PATHS __all__ = [ "PUBLISH_PATHS", - "DbConnector", "AdobeRestApi" ] diff --git a/pype/modules/adobe_communicator/lib/rest_api.py b/pype/modules/adobe_communicator/lib/rest_api.py index 86739e4d80..35094d10dc 100644 --- a/pype/modules/adobe_communicator/lib/rest_api.py +++ b/pype/modules/adobe_communicator/lib/rest_api.py @@ -2,7 +2,7 @@ import os import sys import copy from pype.modules.rest_api import RestApi, route, abort, CallbackResult -from .io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB from pype.api import config, execute, Logger log = Logger().get_logger("AdobeCommunicator") @@ -14,7 +14,7 @@ PUBLISH_PATHS = [] class AdobeRestApi(RestApi): - dbcon = DbConnector() + dbcon = AvalonMongoDB() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/pype/modules/avalon_apps/rest_api.py b/pype/modules/avalon_apps/rest_api.py index 1cb9e544a7..2408e56bbc 100644 --- a/pype/modules/avalon_apps/rest_api.py +++ b/pype/modules/avalon_apps/rest_api.py @@ -4,14 +4,14 @@ import json import bson import bson.json_util from pype.modules.rest_api import RestApi, abort, CallbackResult -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB class AvalonRestApi(RestApi): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.dbcon = DbConnector() + self.dbcon = AvalonMongoDB() self.dbcon.install() @RestApi.route("/projects/", url_prefix="/avalon", methods="GET") diff --git a/pype/modules/ftrack/actions/action_delete_asset.py b/pype/modules/ftrack/actions/action_delete_asset.py index 27394770e1..7d2dac3320 100644 --- a/pype/modules/ftrack/actions/action_delete_asset.py +++ b/pype/modules/ftrack/actions/action_delete_asset.py @@ -5,7 +5,7 @@ from queue import Queue from bson.objectid import ObjectId from pype.modules.ftrack.lib import BaseAction, statics_icon -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB class DeleteAssetSubset(BaseAction): @@ -21,7 +21,7 @@ class DeleteAssetSubset(BaseAction): #: roles that are allowed to register this action role_list = ["Pypeclub", "Administrator", "Project Manager"] #: Db connection - dbcon = DbConnector() + dbcon = AvalonMongoDB() splitter = {"type": "label", "value": "---"} action_data_by_id = {} diff --git a/pype/modules/ftrack/actions/action_delete_old_versions.py b/pype/modules/ftrack/actions/action_delete_old_versions.py index 6a4c5a0cae..b55f091fdc 100644 --- a/pype/modules/ftrack/actions/action_delete_old_versions.py +++ b/pype/modules/ftrack/actions/action_delete_old_versions.py @@ -6,7 +6,7 @@ import clique from pymongo import UpdateOne from pype.modules.ftrack.lib import BaseAction, statics_icon -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB from pype.api import Anatomy import avalon.pipeline @@ -24,7 +24,7 @@ class DeleteOldVersions(BaseAction): role_list = ["Pypeclub", "Project Manager", "Administrator"] icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg") - dbcon = DbConnector() + dbcon = AvalonMongoDB() inteface_title = "Choose your preferences" splitter_item = {"type": "label", "value": "---"} diff --git a/pype/modules/ftrack/actions/action_delivery.py b/pype/modules/ftrack/actions/action_delivery.py index cf80fd77ff..8812ce9bc7 100644 --- a/pype/modules/ftrack/actions/action_delivery.py +++ b/pype/modules/ftrack/actions/action_delivery.py @@ -13,7 +13,7 @@ from avalon.vendor import filelink from pype.api import Anatomy, config from pype.modules.ftrack.lib import BaseAction, statics_icon from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_ID_KEY -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB class Delivery(BaseAction): @@ -24,7 +24,7 @@ class Delivery(BaseAction): role_list = ["Pypeclub", "Administrator", "Project manager"] icon = statics_icon("ftrack", "action_icons", "Delivery.svg") - db_con = DbConnector() + db_con = AvalonMongoDB() def discover(self, session, entities, event): for entity in entities: diff --git a/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py b/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py index 94ca503233..36f7175768 100644 --- a/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py +++ b/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py @@ -6,7 +6,7 @@ import json from bson.objectid import ObjectId from pype.modules.ftrack.lib import BaseAction, statics_icon from pype.api import Anatomy -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_ID_KEY @@ -25,7 +25,7 @@ class StoreThumbnailsToAvalon(BaseAction): icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg") thumbnail_key = "AVALON_THUMBNAIL_ROOT" - db_con = DbConnector() + db_con = AvalonMongoDB() def discover(self, session, entities, event): for entity in entities: diff --git a/pype/modules/ftrack/events/event_sync_to_avalon.py b/pype/modules/ftrack/events/event_sync_to_avalon.py index efcb74a608..314871f5b3 100644 --- a/pype/modules/ftrack/events/event_sync_to_avalon.py +++ b/pype/modules/ftrack/events/event_sync_to_avalon.py @@ -19,12 +19,12 @@ from pype.modules.ftrack.lib.avalon_sync import ( import ftrack_api from pype.modules.ftrack import BaseEvent -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB class SyncToAvalonEvent(BaseEvent): - dbcon = DbConnector() + dbcon = AvalonMongoDB() interest_entTypes = ["show", "task"] ignore_ent_types = ["Milestone"] diff --git a/pype/modules/ftrack/events/event_user_assigment.py b/pype/modules/ftrack/events/event_user_assigment.py index d1b3439c8f..19a67b745f 100644 --- a/pype/modules/ftrack/events/event_user_assigment.py +++ b/pype/modules/ftrack/events/event_user_assigment.py @@ -4,7 +4,7 @@ import subprocess from pype.modules.ftrack import BaseEvent from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_ID_KEY -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB from bson.objectid import ObjectId @@ -37,7 +37,7 @@ class UserAssigmentEvent(BaseEvent): 3) path to publish files of task user was (de)assigned to """ - db_con = DbConnector() + db_con = AvalonMongoDB() def error(self, *err): for e in err: diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 4bab1676d4..65a59452da 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -5,7 +5,7 @@ import json import collections import copy -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB import avalon import avalon.api @@ -240,7 +240,7 @@ def get_hierarchical_attributes(session, entity, attr_names, attr_defaults={}): class SyncEntitiesFactory: - dbcon = DbConnector() + dbcon = AvalonMongoDB() project_query = ( "select full_name, name, custom_attributes" diff --git a/pype/tools/launcher/window.py b/pype/tools/launcher/window.py index 13b4abee6e..7c680a927b 100644 --- a/pype/tools/launcher/window.py +++ b/pype/tools/launcher/window.py @@ -4,7 +4,7 @@ import logging from Qt import QtWidgets, QtCore, QtGui from avalon import style -from pype.modules.ftrack.lib.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB from pype.api import resources from avalon.tools import lib as tools_lib @@ -251,7 +251,7 @@ class LauncherWindow(QtWidgets.QDialog): self.log = logging.getLogger( ".".join([__name__, self.__class__.__name__]) ) - self.dbcon = DbConnector() + self.dbcon = AvalonMongoDB() self.setWindowTitle("Launcher") self.setFocusPolicy(QtCore.Qt.StrongFocus) diff --git a/pype/tools/standalonepublish/app.py b/pype/tools/standalonepublish/app.py index d139366a1c..feba46987f 100644 --- a/pype/tools/standalonepublish/app.py +++ b/pype/tools/standalonepublish/app.py @@ -1,7 +1,7 @@ from bson.objectid import ObjectId from Qt import QtWidgets, QtCore from widgets import AssetWidget, FamilyWidget, ComponentsWidget, ShadowWidget -from avalon.tools.libraryloader.io_nonsingleton import DbConnector +from avalon.api import AvalonMongoDB class Window(QtWidgets.QDialog): @@ -10,7 +10,7 @@ class Window(QtWidgets.QDialog): :param parent: Main widget that cares about all GUIs :type parent: QtWidgets.QMainWindow """ - _db = DbConnector() + _db = AvalonMongoDB() _jobs = {} valid_family = False valid_components = False From 019ed41e23ac3b9de57e865cf8645219fdb5a5f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 16:08:54 +0200 Subject: [PATCH 409/580] overrides for anatomy are saving data --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 688b4bf715..b0aed18e01 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -161,9 +161,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.discard_changes() def overrides(self): - if self.is_overriden: - return self.config_value(), True - return {self.key: {}}, True + return self.config_value(), True def item_value(self): output = {} From 73dfecbf1a9f0518e0bd15fb7cfbbe27cced0e45 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 8 Sep 2020 17:53:32 +0200 Subject: [PATCH 410/580] fix tile order for Draft Tile Assembler --- .../maya/publish/submit_maya_deadline.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pype/plugins/maya/publish/submit_maya_deadline.py b/pype/plugins/maya/publish/submit_maya_deadline.py index 747d2727b7..e4048592a7 100644 --- a/pype/plugins/maya/publish/submit_maya_deadline.py +++ b/pype/plugins/maya/publish/submit_maya_deadline.py @@ -25,6 +25,7 @@ import re import hashlib from datetime import datetime import itertools +from collections import OrderedDict import clique import requests @@ -67,7 +68,7 @@ payload_skeleton = { def _format_tiles( filename, index, tiles_x, tiles_y, - width, height, prefix, origin="blc"): + width, height, prefix): """Generate tile entries for Deadline tile job. Returns two dictionaries - one that can be directly used in Deadline @@ -113,12 +114,14 @@ def _format_tiles( """ tile = 0 out = {"JobInfo": {}, "PluginInfo": {}} - cfg = {} + cfg = OrderedDict() w_space = width / tiles_x h_space = height / tiles_y + cfg["TilesCropped"] = "False" + for tile_x in range(1, tiles_x + 1): - for tile_y in range(1, tiles_y + 1): + for tile_y in reversed(range(1, tiles_y + 1)): tile_prefix = "_tile_{}x{}_{}x{}_".format( tile_x, tile_y, tiles_x, @@ -143,14 +146,13 @@ def _format_tiles( cfg["Tile{}".format(tile)] = new_filename cfg["Tile{}Tile".format(tile)] = new_filename + cfg["Tile{}FileName".format(tile)] = new_filename cfg["Tile{}X".format(tile)] = (tile_x - 1) * w_space - if origin == "blc": - cfg["Tile{}Y".format(tile)] = (tile_y - 1) * h_space - else: - cfg["Tile{}Y".format(tile)] = int(height) - ((tile_y - 1) * h_space) # noqa: E501 - cfg["Tile{}Width".format(tile)] = tile_x * w_space - cfg["Tile{}Height".format(tile)] = tile_y * h_space + cfg["Tile{}Y".format(tile)] = int(height) - (tile_y * h_space) + + cfg["Tile{}Width".format(tile)] = w_space + cfg["Tile{}Height".format(tile)] = h_space tile += 1 return out, cfg @@ -538,7 +540,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): "AuxFiles": [], "JobInfo": { "BatchName": payload["JobInfo"]["BatchName"], - "Frames": 0, + "Frames": 1, "Name": "{} - Tile Assembly Job".format( payload["JobInfo"]["Name"]), "OutputDirectory0": @@ -590,7 +592,7 @@ class MayaSubmitDeadline(pyblish.api.InstancePlugin): payload["JobInfo"]["Name"], frame, instance.data.get("tilesX") * instance.data.get("tilesY") # noqa: E501 - ) + ) self.log.info( "... preparing job {}".format( new_payload["JobInfo"]["Name"])) From 504ae4a1b3f054c1fb8327be89675eede5c56978 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 18:22:13 +0200 Subject: [PATCH 411/580] moved setting attributes on apply overrides --- .../config_setting/widgets/anatomy_inputs.py | 4 ++-- .../config_setting/config_setting/widgets/inputs.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index b0aed18e01..6d4417a6aa 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -306,15 +306,15 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot: self._is_overriden = parent_values is not NOT_SET + self._was_overriden = bool(self._is_overriden) self.singleroot_widget.apply_overrides(NOT_SET) self.multiroot_widget.apply_overrides(parent_values) else: self._is_overriden = value is not NOT_SET + self._was_overriden = bool(self._is_overriden) self.singleroot_widget.apply_overrides(value) self.multiroot_widget.apply_overrides(NOT_SET) - self._was_overriden = bool(self._is_overriden) - def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() self.multiroot_widget.hierarchical_style_update() diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 155bcbb74d..b094e4cf67 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -16,6 +16,7 @@ class ConfigObject(AbstractConfigObject): default_state = "" + _as_widget = False _is_overriden = False _is_modified = False _was_overriden = False @@ -44,6 +45,8 @@ class ConfigObject(AbstractConfigObject): @property def was_overriden(self): """Initial state after applying overrides.""" + if self._as_widget: + return self._parent.was_overriden return self._was_overriden @property @@ -673,7 +676,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): if self._is_invalid: self._is_modified = True - elif self._is_overriden: + elif self.is_overriden: self._is_modified = self.item_value() != self.override_value else: self._is_modified = self.item_value() != self.global_value @@ -1126,6 +1129,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.updateGeometry() def apply_overrides(self, parent_values): + self._is_modified = False if parent_values is NOT_SET or self.key not in parent_values: override_value = NOT_SET else: @@ -2142,7 +2146,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.global_value != self.start_value def apply_overrides(self, parent_values): - # Make sure this is set to False + self._is_modified = False self._state = None self._child_state = None override_values = NOT_SET @@ -2152,6 +2156,8 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): override_values = parent_values.get(self.key, override_values) self._is_overriden = override_values is not NOT_SET + self._was_overriden = bool(self._is_overriden) + if not self.multiplatform: self.input_fields[0].apply_overrides(parent_values) else: From d22371d0f53436385af97bb63892eb7c307030ab Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 18:22:36 +0200 Subject: [PATCH 412/580] modifiable dict sets overrides instead of setting values --- .../config_setting/widgets/inputs.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b094e4cf67..f975567a6a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1243,11 +1243,16 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.update_style() self.value_changed.emit(self) - def set_values(self, key, value): + def update_global_values(self, key, value): self.origin_key = key self.key_input.setText(key) self.value_input.update_global_values(value) + def apply_overrides(self, key, value): + self.origin_key = key + self.key_input.setText(key) + self.value_input.apply_overrides(value) + @property def is_group(self): return self._parent.is_group @@ -1521,7 +1526,10 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` if value is not None and key is not None: - item_widget.set_values(key, value) + if self._is_overriden: + item_widget.apply_overrides(key, value) + else: + item_widget.update_global_values(key, value) self.hierarchical_style_update() else: self._on_value_change() @@ -2161,8 +2169,8 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): if not self.multiplatform: self.input_fields[0].apply_overrides(parent_values) else: - for item in self.input_fields: - item.apply_overrides(override_values) + for input_field in self.input_fields: + input_field.apply_overrides(override_values) if not self._is_overriden: self._is_overriden = ( From b03687ea055ff30b39b7c9003c888f28acf0c449 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 18:38:52 +0200 Subject: [PATCH 413/580] anatomy widgets propagate child modifications down the hierarchy --- .../config_setting/widgets/anatomy_inputs.py | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 6d4417a6aa..e59de3980f 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -70,6 +70,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): body_widget.set_content_widget(content_widget) + self.body_widget = body_widget self.label_widget = body_widget.label_widget self.root_widget.value_changed.connect(self._on_value_change) @@ -122,8 +123,10 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): child_state = "child-{}".format(child_state) if child_state != self._child_state: - self.setProperty("state", child_state) - self.style().polish(self) + self.body_widget.side_line_widget.setProperty("state", child_state) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) self._child_state = child_state def hierarchical_style_update(self): @@ -239,6 +242,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): main_layout.setContentsMargins(0, 0, 0, 0) main_layout.addWidget(body_widget) + self.body_widget = body_widget self.multiroot_label = multiroot_label self.multiroot_checkbox = multiroot_checkbox self.singleroot_widget = singleroot_widget @@ -342,8 +346,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: child_state = "" - self.setProperty("state", child_state) - self.style().polish(self) + self.body_widget.side_line_widget.setProperty("state", child_state) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) self.label_widget.setProperty("state", state) self.label_widget.style().polish(self.label_widget) @@ -455,6 +461,8 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): self._parent = parent + self._state = None + self._is_group = True self.any_parent_is_group = False self.key = "templates" @@ -467,6 +475,7 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): template_input_data = { "key": self.key } + self.body_widget = body_widget self.label_widget = body_widget.label_widget self.value_input = RawJsonWidget( template_input_data, self, @@ -481,13 +490,38 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): layout.addWidget(body_widget) def update_global_values(self, values): + self._state = None self.value_input.update_global_values(values) def apply_overrides(self, parent_values): + self._state = None self.value_input.apply_overrides(parent_values) def hierarchical_style_update(self): self.value_input.hierarchical_style_update() + self.update_style() + + def update_style(self): + state = self.style_state( + self.child_invalid, self.child_overriden, self.child_modified + ) + if self._state == state: + return + + if state: + child_state = "child-{}".format(state) + else: + child_state = "" + print(child_state) + self.body_widget.side_line_widget.setProperty("state", child_state) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) + + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + self._state = state @property def is_modified(self): From ace606efe6e4bac12e0a2c25060ae6f781335ec3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 09:51:25 +0200 Subject: [PATCH 414/580] renamed studio to system window --- pype/tools/config_setting/config_setting/widgets/base.py | 4 ++-- pype/tools/config_setting/config_setting/widgets/window.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 066c00c96d..d39b5789d9 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -7,14 +7,14 @@ from . import lib from avalon import io -class StudioWidget(QtWidgets.QWidget): +class SystemWidget(QtWidgets.QWidget): is_overidable = False _is_overriden = False _is_group = False _any_parent_is_group = False def __init__(self, parent=None): - super(StudioWidget, self).__init__(parent) + super(SystemWidget, self).__init__(parent) self._ignore_value_changes = False diff --git a/pype/tools/config_setting/config_setting/widgets/window.py b/pype/tools/config_setting/config_setting/widgets/window.py index af23e68f77..7ad46b1a06 100644 --- a/pype/tools/config_setting/config_setting/widgets/window.py +++ b/pype/tools/config_setting/config_setting/widgets/window.py @@ -1,5 +1,5 @@ from Qt import QtWidgets -from .base import StudioWidget, ProjectWidget +from .base import SystemWidget, ProjectWidget class MainWidget(QtWidgets.QWidget): @@ -13,9 +13,9 @@ class MainWidget(QtWidgets.QWidget): header_tab_widget = QtWidgets.QTabWidget(parent=self) - studio_widget = StudioWidget() + studio_widget = SystemWidget() project_widget = ProjectWidget() - header_tab_widget.addTab(studio_widget, "Studio") + header_tab_widget.addTab(studio_widget, "System") header_tab_widget.addTab(project_widget, "Project") layout = QtWidgets.QVBoxLayout(self) From 28931dba6b17aff9a634e06e6b351b9b7b6c9781 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:00:42 +0200 Subject: [PATCH 415/580] removed configs from config tool --- .../project_presets/ftrack/ftrack_config.json | 11 - .../project_presets/global/creator.json | 8 - .../global/slates/example_HD.json | 212 ------------------ .../config/project_presets/maya/capture.json | 108 --------- .../project_presets/plugins/config.json | 1 - .../plugins/ftrack/publish.json | 6 - .../plugins/global/create.json | 1 - .../plugins/global/filter.json | 1 - .../project_presets/plugins/global/load.json | 1 - .../plugins/global/publish.json | 73 ------ .../project_presets/plugins/maya/create.json | 1 - .../project_presets/plugins/maya/filter.json | 9 - .../project_presets/plugins/maya/load.json | 18 -- .../project_presets/plugins/maya/publish.json | 17 -- .../plugins/maya/workfile_build.json | 54 ----- .../project_presets/plugins/nuke/create.json | 8 - .../project_presets/plugins/nuke/load.json | 1 - .../project_presets/plugins/nuke/publish.json | 48 ---- .../plugins/nuke/workfile_build.json | 11 - .../plugins/nukestudio/filter.json | 10 - .../plugins/nukestudio/publish.json | 8 - .../plugins/standalonepublisher/publish.json | 17 -- .../project_presets/plugins/test/create.json | 8 - .../project_presets/plugins/test/publish.json | 10 - .../premiere/asset_default.json | 5 - .../project_presets/premiere/rules_tasks.json | 21 -- .../project_presets/unreal/project_setup.json | 4 - 27 files changed, 672 deletions(-) delete mode 100644 pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json delete mode 100644 pype/tools/config_setting/config/project_presets/global/creator.json delete mode 100644 pype/tools/config_setting/config/project_presets/global/slates/example_HD.json delete mode 100644 pype/tools/config_setting/config/project_presets/maya/capture.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/config.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/create.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/filter.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/load.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/global/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/create.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/filter.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/load.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/create.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/load.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/test/create.json delete mode 100644 pype/tools/config_setting/config/project_presets/plugins/test/publish.json delete mode 100644 pype/tools/config_setting/config/project_presets/premiere/asset_default.json delete mode 100644 pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json delete mode 100644 pype/tools/config_setting/config/project_presets/unreal/project_setup.json diff --git a/pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json b/pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json deleted file mode 100644 index c9dbde4596..0000000000 --- a/pype/tools/config_setting/config/project_presets/ftrack/ftrack_config.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "status_update": { - "_ignore_": ["in progress", "ommited", "on hold"], - "Ready": ["not ready"], - "In Progress" : ["_any_"] - }, - "status_version_to_task": { - "in progress": "in progress", - "approved": "approved" - } -} diff --git a/pype/tools/config_setting/config/project_presets/global/creator.json b/pype/tools/config_setting/config/project_presets/global/creator.json deleted file mode 100644 index d14e779f01..0000000000 --- a/pype/tools/config_setting/config/project_presets/global/creator.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Model": ["model"], - "Render Globals": ["light", "render"], - "Layout": ["layout"], - "Set Dress": ["setdress"], - "Look": ["look"], - "Rig": ["rigging"] -} diff --git a/pype/tools/config_setting/config/project_presets/global/slates/example_HD.json b/pype/tools/config_setting/config/project_presets/global/slates/example_HD.json deleted file mode 100644 index b06391fb63..0000000000 --- a/pype/tools/config_setting/config/project_presets/global/slates/example_HD.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "width": 1920, - "height": 1080, - "destination_path": "{destination_path}", - "style": { - "*": { - "font-family": "arial", - "font-color": "#ffffff", - "font-bold": false, - "font-italic": false, - "bg-color": "#0077ff", - "alignment-horizontal": "left", - "alignment-vertical": "top" - }, - "layer": { - "padding": 0, - "margin": 0 - }, - "rectangle": { - "padding": 0, - "margin": 0, - "bg-color": "#E9324B", - "fill": true - }, - "main_frame": { - "padding": 0, - "margin": 0, - "bg-color": "#252525" - }, - "table": { - "padding": 0, - "margin": 0, - "bg-color": "transparent" - }, - "table-item": { - "padding": 5, - "padding-bottom": 10, - "margin": 0, - "bg-color": "#212121", - "bg-alter-color": "#272727", - "font-color": "#dcdcdc", - "font-bold": false, - "font-italic": false, - "alignment-horizontal": "left", - "alignment-vertical": "top", - "word-wrap": false, - "ellide": true, - "max-lines": 1 - }, - "table-item-col[0]": { - "font-size": 20, - "font-color": "#898989", - "font-bold": true, - "ellide": false, - "word-wrap": true, - "max-lines": null - }, - "table-item-col[1]": { - "font-size": 40, - "padding-left": 10 - }, - "#colorbar": { - "bg-color": "#9932CC" - } - }, - "items": [{ - "type": "layer", - "direction": 1, - "name": "MainLayer", - "style": { - "#MainLayer": { - "width": 1094, - "height": 1000, - "margin": 25, - "padding": 0 - }, - "#LeftSide": { - "margin-right": 25 - } - }, - "items": [{ - "type": "layer", - "name": "LeftSide", - "items": [{ - "type": "layer", - "direction": 1, - "style": { - "table-item": { - "bg-color": "transparent", - "padding-bottom": 20 - }, - "table-item-col[0]": { - "font-size": 20, - "font-color": "#898989", - "alignment-horizontal": "right" - }, - "table-item-col[1]": { - "alignment-horizontal": "left", - "font-bold": true, - "font-size": 40 - } - }, - "items": [{ - "type": "table", - "values": [ - ["Show:", "{project[name]}"] - ], - "style": { - "table-item-field[0:0]": { - "width": 150 - }, - "table-item-field[0:1]": { - "width": 580 - } - } - }, { - "type": "table", - "values": [ - ["Submitting For:", "{intent}"] - ], - "style": { - "table-item-field[0:0]": { - "width": 160 - }, - "table-item-field[0:1]": { - "width": 218, - "alignment-horizontal": "right" - } - } - }] - }, { - "type": "rectangle", - "style": { - "bg-color": "#bc1015", - "width": 1108, - "height": 5, - "fill": true - } - }, { - "type": "table", - "use_alternate_color": true, - "values": [ - ["Version name:", "{version_name}"], - ["Date:", "{date}"], - ["Shot Types:", "{shot_type}"], - ["Submission Note:", "{submission_note}"] - ], - "style": { - "table-item": { - "padding-bottom": 20 - }, - "table-item-field[0:1]": { - "font-bold": true - }, - "table-item-field[3:0]": { - "word-wrap": true, - "ellide": true, - "max-lines": 4 - }, - "table-item-col[0]": { - "alignment-horizontal": "right", - "width": 150 - }, - "table-item-col[1]": { - "alignment-horizontal": "left", - "width": 958 - } - } - }] - }, { - "type": "layer", - "name": "RightSide", - "items": [{ - "type": "placeholder", - "name": "thumbnail", - "path": "{thumbnail_path}", - "style": { - "width": 730, - "height": 412 - } - }, { - "type": "placeholder", - "name": "colorbar", - "path": "{color_bar_path}", - "return_data": true, - "style": { - "width": 730, - "height": 55 - } - }, { - "type": "table", - "use_alternate_color": true, - "values": [ - ["Vendor:", "{vendor}"], - ["Shot Name:", "{shot_name}"], - ["Frames:", "{frame_start} - {frame_end} ({duration})"] - ], - "style": { - "table-item-col[0]": { - "alignment-horizontal": "left", - "width": 200 - }, - "table-item-col[1]": { - "alignment-horizontal": "right", - "width": 530, - "font-size": 30 - } - } - }] - }] - }] -} diff --git a/pype/tools/config_setting/config/project_presets/maya/capture.json b/pype/tools/config_setting/config/project_presets/maya/capture.json deleted file mode 100644 index b6c4893034..0000000000 --- a/pype/tools/config_setting/config/project_presets/maya/capture.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "Codec": { - "compression": "jpg", - "format": "image", - "quality": 95 - }, - "Display Options": { - "background": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 - ], - "backgroundBottom": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 - ], - "backgroundTop": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 - ], - "override_display": true - }, - "Generic": { - "isolate_view": true, - "off_screen": true - }, - "IO": { - "name": "", - "open_finished": false, - "raw_frame_numbers": false, - "recent_playblasts": [], - "save_file": false - }, - "PanZoom": { - "pan_zoom": true - }, - "Renderer": { - "rendererName": "vp2Renderer" - }, - "Resolution": { - "height": 1080, - "mode": "Custom", - "percent": 1.0, - "width": 1920 - }, - "Time Range": { - "end_frame": 25, - "frame": "", - "start_frame": 0, - "time": "Time Slider" - }, - "Viewport Options": { - "cameras": false, - "clipGhosts": false, - "controlVertices": false, - "deformers": false, - "dimensions": false, - "displayLights": 0, - "dynamicConstraints": false, - "dynamics": false, - "fluids": false, - "follicles": false, - "gpuCacheDisplayFilter": false, - "greasePencils": false, - "grid": false, - "hairSystems": false, - "handles": false, - "high_quality": true, - "hud": false, - "hulls": false, - "ikHandles": false, - "imagePlane": false, - "joints": false, - "lights": false, - "locators": false, - "manipulators": false, - "motionTrails": false, - "nCloths": false, - "nParticles": false, - "nRigids": false, - "nurbsCurves": false, - "nurbsSurfaces": false, - "override_viewport_options": true, - "particleInstancers": false, - "pivots": false, - "planes": false, - "pluginShapes": false, - "polymeshes": true, - "shadows": false, - "strokes": false, - "subdivSurfaces": false, - "textures": false, - "twoSidedLighting": true - }, - "Camera Options": { - "displayGateMask": false, - "displayResolution": false, - "displayFilmGate": false, - "displayFieldChart": false, - "displaySafeAction": false, - "displaySafeTitle": false, - "displayFilmPivot": false, - "displayFilmOrigin": false, - "overscan": 1.0 - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/config.json b/pype/tools/config_setting/config/project_presets/plugins/config.json deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/config.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json b/pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json deleted file mode 100644 index d0469ae4f7..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/ftrack/publish.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "IntegrateFtrackNote": { - "note_with_intent_template": "{intent}: {comment}", - "note_labels": [] - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/create.json b/pype/tools/config_setting/config/project_presets/plugins/global/create.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/global/create.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/filter.json b/pype/tools/config_setting/config/project_presets/plugins/global/filter.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/global/filter.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/load.json b/pype/tools/config_setting/config/project_presets/plugins/global/load.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/global/load.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/global/publish.json b/pype/tools/config_setting/config/project_presets/plugins/global/publish.json deleted file mode 100644 index 6e51e00497..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/global/publish.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "IntegrateMasterVersion": { - "enabled": false - }, - "ExtractReview": { - "__documentation__": "http://pype.club/docs/admin_presets_plugins", - "profiles": [ - { - "families": [], - "hosts": [], - "outputs": { - "h264": { - "filter": { - "families": ["render", "review", "ftrack"] - }, - "ext": "mp4", - "ffmpeg_args": { - "input": [ - "-gamma 2.2" - ], - "video_filters": [], - "audio_filters": [], - "output": [ - "-pix_fmt yuv420p", - "-crf 18", - "-intra" - ] - }, - "tags": ["burnin", "ftrackreview"] - } - } - } - ] - }, - "ExtractBurnin": { - "options": { - "opacity": 1, - "x_offset": 5, - "y_offset": 5, - "bg_padding": 5, - "bg_opacity": 0.5, - "font_size": 42 - }, - "fields": { - - }, - "profiles": [ - { - "burnins": { - "burnin": { - "TOP_LEFT": "{yy}-{mm}-{dd}", - "TOP_RIGHT": "{anatomy[version]}", - "TOP_CENTERED": "", - "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", - "BOTTOM_CENTERED": "{asset}", - "BOTTOM_LEFT": "{username}" - } - } - } - ] - }, - "IntegrateAssetNew": { - "template_name_profiles": { - "publish": { - "families": [], - "tasks": [] - }, - "render": { - "families": ["review", "render", "prerender"] - } - } - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/create.json b/pype/tools/config_setting/config/project_presets/plugins/maya/create.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/maya/create.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/filter.json b/pype/tools/config_setting/config/project_presets/plugins/maya/filter.json deleted file mode 100644 index 83d6f05f31..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/maya/filter.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Preset n1": { - "ValidateNoAnimation": false, - "ValidateShapeDefaultNames": false - }, - "Preset n2": { - "ValidateNoAnimation": false - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/load.json b/pype/tools/config_setting/config/project_presets/plugins/maya/load.json deleted file mode 100644 index 260fbb35ee..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/maya/load.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "colors": { - "model": [0.821, 0.518, 0.117], - "rig": [0.144, 0.443, 0.463], - "pointcache": [0.368, 0.821, 0.117], - "animation": [0.368, 0.821, 0.117], - "ass": [1.0, 0.332, 0.312], - "camera": [0.447, 0.312, 1.0], - "fbx": [1.0, 0.931, 0.312], - "mayaAscii": [0.312, 1.0, 0.747], - "setdress": [0.312, 1.0, 0.747], - "layout": [0.312, 1.0, 0.747], - "vdbcache": [0.312, 1.0, 0.428], - "vrayproxy": [0.258, 0.95, 0.541], - "yeticache": [0.2, 0.8, 0.3], - "yetiRig": [0, 0.8, 0.5] - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/publish.json b/pype/tools/config_setting/config/project_presets/plugins/maya/publish.json deleted file mode 100644 index 2e2b3164f3..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/maya/publish.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ValidateModelName": { - "enabled": false, - "material_file": "/path/to/shader_name_definition.txt", - "regex": "(.*)_(\\d)*_(?P.*)_(GEO)" - }, - "ValidateAssemblyName": { - "enabled": false - }, - "ValidateShaderName": { - "enabled": false, - "regex": "(?P.*)_(.*)_SHD" - }, - "ValidateMeshHasOverlappingUVs": { - "enabled": false - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json b/pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json deleted file mode 100644 index 2872b783cb..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/maya/workfile_build.json +++ /dev/null @@ -1,54 +0,0 @@ -[{ - "tasks": ["lighting"], - - "current_context": [{ - "subset_name_filters": [".+[Mm]ain"], - "families": ["model"], - "repre_names": ["abc", "ma"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["animation", "pointcache"], - "repre_names": ["abc"], - "loaders": ["ReferenceLoader"] - },{ - "families": ["rendersetup"], - "repre_names": ["json"], - "loaders": ["RenderSetupLoader"] - }, { - "families": ["camera"], - "repre_names": ["abc"], - "loaders": ["ReferenceLoader"] - }], - - "linked_assets": [{ - "families": ["setdress"], - "repre_names": ["ma"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["ass"], - "repre_names": ["ass"], - "loaders":["assLoader"] - }] -}, { - "tasks": ["animation"], - - "current_context": [{ - "families": ["camera"], - "repre_names": ["abc", "ma"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["audio"], - "repre_names": ["wav"], - "loaders": ["RenderSetupLoader"] - }], - - "linked_assets": [{ - "families": ["setdress"], - "repre_names": ["proxy"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["rig"], - "repre_names": ["ass"], - "loaders": ["rigLoader"] - }] -}] diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/create.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/create.json deleted file mode 100644 index 4deb0b4ad5..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/nuke/create.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "CreateWriteRender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" - }, - "CreateWritePrerender": { - "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/load.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/load.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/nuke/load.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json deleted file mode 100644 index ab0d0e76a5..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/nuke/publish.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "ExtractThumbnail": { - "nodes": { - "Reformat": [ - ["type", "to format"], - ["format", "HD_1080"], - ["filter", "Lanczos6"], - ["black_outside", true], - ["pbb", false] - ] - } - }, - "ValidateNukeWriteKnobs": { - "enabled": false, - "knobs": { - "render": { - "review": true - } - } - }, - "ExtractReviewDataLut": { - "__documentation__": { - "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", - "enabled": "keep in on `false` if you want Nuke baking colorspace workflow applied else FFmpeg will convert imgsequence with baked LUT" - }, - "enabled": false - }, - "ExtractReviewDataMov": { - "__documentation__": { - "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", - "enabled": "keep in on `true` if you want Nuke baking colorspace workflow applied" - }, - "enabled": true, - "viewer_lut_raw": false - }, - "ExtractSlateFrame": { - "__documentation__": { - "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`" - }, - "viewer_lut_raw": false - }, - "NukeSubmitDeadline": { - "deadline_priority": 50, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_chunk_size": 1 - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json b/pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json deleted file mode 100644 index d3613c929e..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/nuke/workfile_build.json +++ /dev/null @@ -1,11 +0,0 @@ -[{ - "tasks": ["compositing"], - - "current_context": [{ - "families": ["render", "plate"], - "repre_names": ["exr" ,"dpx"], - "loaders": ["LoadSequence"] - }], - - "linked_assets": [] -}] diff --git a/pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json b/pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json deleted file mode 100644 index bd6a0dc1bd..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/nukestudio/filter.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "strict": { - "ValidateVersion": true, - "VersionUpWorkfile": true - }, - "benevolent": { - "ValidateVersion": false, - "VersionUpWorkfile": false - } -} \ No newline at end of file diff --git a/pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json b/pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json deleted file mode 100644 index 8c4ad133f1..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/nukestudio/publish.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "CollectInstanceVersion": { - "enabled": false - }, - "ExtractReviewCutUpVideo": { - "tags_addition": [] - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json b/pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json deleted file mode 100644 index ecfff12db9..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/standalonepublisher/publish.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ExtractReviewSP": { - "outputs": { - "h264": { - "input": [ - "-gamma 2.2" - ], - "output": [ - "-pix_fmt yuv420p", - "-crf 18" - ], - "tags": ["preview"], - "ext": "mov" - } - } - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/test/create.json b/pype/tools/config_setting/config/project_presets/plugins/test/create.json deleted file mode 100644 index fa0b2fc05f..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/test/create.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "MyTestCreator": { - "my_test_property": "B", - "active": false, - "new_property": "new", - "family": "new_family" - } -} diff --git a/pype/tools/config_setting/config/project_presets/plugins/test/publish.json b/pype/tools/config_setting/config/project_presets/plugins/test/publish.json deleted file mode 100644 index 3180dd5d8a..0000000000 --- a/pype/tools/config_setting/config/project_presets/plugins/test/publish.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "MyTestPlugin": { - "label": "loaded from preset", - "optional": true, - "families": ["changed", "by", "preset"] - }, - "MyTestRemovedPlugin": { - "enabled": false - } -} diff --git a/pype/tools/config_setting/config/project_presets/premiere/asset_default.json b/pype/tools/config_setting/config/project_presets/premiere/asset_default.json deleted file mode 100644 index 84d2bde3d8..0000000000 --- a/pype/tools/config_setting/config/project_presets/premiere/asset_default.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "frameStart": 1001, - "handleStart": 0, - "handleEnd": 0 -} diff --git a/pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json b/pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json deleted file mode 100644 index 333c9cd70b..0000000000 --- a/pype/tools/config_setting/config/project_presets/premiere/rules_tasks.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "defaultTasks": ["Layout", "Animation"], - "taskToSubsets": { - "Layout": ["reference", "audio"], - "Animation": ["audio"] - }, - "subsetToRepresentations": { - "reference": { - "preset": "h264", - "representation": "mp4" - }, - "thumbnail": { - "preset": "jpeg_thumb", - "representation": "jpg" - }, - "audio": { - "preset": "48khz", - "representation": "wav" - } - } -} diff --git a/pype/tools/config_setting/config/project_presets/unreal/project_setup.json b/pype/tools/config_setting/config/project_presets/unreal/project_setup.json deleted file mode 100644 index 8a4dffc526..0000000000 --- a/pype/tools/config_setting/config/project_presets/unreal/project_setup.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "dev_mode": false, - "install_unreal_python_engine": false -} From f2bb1af12836a9a298212525da6b9ea0a02e1215 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:03:35 +0200 Subject: [PATCH 416/580] moved config to folder configurations --- pype/api.py | 2 +- pype/{ => configurations}/config.py | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename pype/{ => configurations}/config.py (100%) diff --git a/pype/api.py b/pype/api.py index e2705f81ea..88dfab19ec 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,4 +1,4 @@ -from . import config +from .configurations import config from pypeapp import ( Logger, Anatomy, diff --git a/pype/config.py b/pype/configurations/config.py similarity index 100% rename from pype/config.py rename to pype/configurations/config.py From d5e7ccce3f9dbf3b9c5b76180d4cd256e8c0c44d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:04:37 +0200 Subject: [PATCH 417/580] copied pype-config to pype --- .../configurations/defaults/anatomy/README.md | 0 .../defaults/anatomy/default.yaml | 29 ++ .../defaults/anatomy/roots.json | 5 + .../defaults/environments/avalon.json | 16 ++ .../defaults/environments/blender.json | 7 + .../defaults/environments/celaction.json | 3 + .../defaults/environments/deadline.json | 3 + .../defaults/environments/ftrack.json | 18 ++ .../defaults/environments/global.json | 44 +++ .../defaults/environments/harmony.json | 4 + .../defaults/environments/houdini.json | 12 + .../defaults/environments/maya.json | 14 + .../defaults/environments/maya_2018.json | 11 + .../defaults/environments/maya_2020.json | 11 + .../defaults/environments/mayabatch.json | 14 + .../defaults/environments/mayabatch_2019.json | 11 + .../defaults/environments/mtoa_3.1.1.json | 23 ++ .../defaults/environments/muster.json | 3 + .../defaults/environments/nuke.json | 15 + .../defaults/environments/nukestudio.json | 11 + .../environments/nukestudio_10.0.json | 4 + .../defaults/environments/nukex.json | 10 + .../defaults/environments/nukex_10.0.json | 4 + .../defaults/environments/photoshop.json | 4 + .../defaults/environments/premiere.json | 11 + .../defaults/environments/resolve.json | 40 +++ .../defaults/environments/storyboardpro.json | 4 + .../defaults/environments/unreal_4.24.json | 5 + .../defaults/environments/vray_4300.json | 15 + .../defaults/launchers/blender_2.80.toml | 7 + .../defaults/launchers/blender_2.81.toml | 7 + .../defaults/launchers/blender_2.82.toml | 7 + .../defaults/launchers/blender_2.83.toml | 7 + .../defaults/launchers/celaction_local.toml | 8 + .../defaults/launchers/celaction_publish.toml | 7 + .../defaults/launchers/darwin/blender_2.82 | 2 + .../defaults/launchers/darwin/harmony_17 | 9 + .../launchers/darwin/harmony_17_launch | 5 + .../defaults/launchers/darwin/python3 | 2 + .../defaults/launchers/harmony_17.toml | 8 + .../defaults/launchers/houdini_16.toml | 7 + .../defaults/launchers/houdini_17.toml | 7 + .../defaults/launchers/houdini_18.toml | 7 + .../defaults/launchers/linux/maya2016 | 8 + .../defaults/launchers/linux/maya2017 | 8 + .../defaults/launchers/linux/maya2018 | 8 + .../defaults/launchers/linux/maya2019 | 8 + .../defaults/launchers/linux/maya2020 | 8 + .../defaults/launchers/linux/nuke11.3 | 2 + .../defaults/launchers/linux/nuke12.0 | 2 + .../defaults/launchers/linux/nukestudio11.3 | 2 + .../defaults/launchers/linux/nukestudio12.0 | 2 + .../defaults/launchers/linux/nukex11.3 | 2 + .../defaults/launchers/linux/nukex12.0 | 2 + .../defaults/launchers/maya_2016.toml | 26 ++ .../defaults/launchers/maya_2017.toml | 28 ++ .../defaults/launchers/maya_2018.toml | 14 + .../defaults/launchers/maya_2019.toml | 14 + .../defaults/launchers/maya_2020.toml | 14 + .../defaults/launchers/mayabatch_2019.toml | 17 ++ .../defaults/launchers/mayabatch_2020.toml | 17 ++ .../defaults/launchers/mayapy2016.toml | 17 ++ .../defaults/launchers/mayapy2017.toml | 17 ++ .../defaults/launchers/mayapy2018.toml | 17 ++ .../defaults/launchers/mayapy2019.toml | 17 ++ .../defaults/launchers/mayapy2020.toml | 17 ++ .../defaults/launchers/myapp.toml | 5 + .../defaults/launchers/nuke_10.0.toml | 7 + .../defaults/launchers/nuke_11.0.toml | 7 + .../defaults/launchers/nuke_11.2.toml | 7 + .../defaults/launchers/nuke_11.3.toml | 7 + .../defaults/launchers/nuke_12.0.toml | 7 + .../defaults/launchers/nukestudio_10.0.toml | 7 + .../defaults/launchers/nukestudio_11.0.toml | 7 + .../defaults/launchers/nukestudio_11.2.toml | 7 + .../defaults/launchers/nukestudio_11.3.toml | 7 + .../defaults/launchers/nukestudio_12.0.toml | 7 + .../defaults/launchers/nukex_10.0.toml | 7 + .../defaults/launchers/nukex_11.0.toml | 7 + .../defaults/launchers/nukex_11.2.toml | 7 + .../defaults/launchers/nukex_11.3.toml | 7 + .../defaults/launchers/nukex_12.0.toml | 7 + .../defaults/launchers/photoshop_2020.toml | 8 + .../defaults/launchers/premiere_2019.toml | 8 + .../defaults/launchers/premiere_2020.toml | 9 + .../defaults/launchers/python_2.toml | 10 + .../defaults/launchers/python_3.toml | 10 + .../defaults/launchers/resolve_16.toml | 9 + .../defaults/launchers/shell.toml | 7 + .../defaults/launchers/storyboardpro_7.toml | 8 + .../defaults/launchers/unreal_4.24.toml | 8 + .../launchers/windows/blender_2.80.bat | 11 + .../launchers/windows/blender_2.81.bat | 11 + .../launchers/windows/blender_2.82.bat | 11 + .../launchers/windows/blender_2.83.bat | 11 + .../launchers/windows/celaction_local.bat | 19 ++ .../launchers/windows/celaction_publish.bat | 3 + .../defaults/launchers/windows/harmony_17.bat | 13 + .../defaults/launchers/windows/houdini_16.bat | 13 + .../defaults/launchers/windows/houdini_17.bat | 13 + .../defaults/launchers/windows/houdini_18.bat | 13 + .../defaults/launchers/windows/maya2016.bat | 17 ++ .../defaults/launchers/windows/maya2017.bat | 17 ++ .../defaults/launchers/windows/maya2018.bat | 17 ++ .../defaults/launchers/windows/maya2019.bat | 17 ++ .../defaults/launchers/windows/maya2020.bat | 17 ++ .../launchers/windows/mayabatch2019.bat | 14 + .../launchers/windows/mayabatch2020.bat | 14 + .../defaults/launchers/windows/mayapy2016.bat | 13 + .../defaults/launchers/windows/mayapy2017.bat | 13 + .../defaults/launchers/windows/mayapy2018.bat | 13 + .../defaults/launchers/windows/mayapy2019.bat | 13 + .../defaults/launchers/windows/mayapy2020.bat | 13 + .../defaults/launchers/windows/nuke10.0.bat | 13 + .../defaults/launchers/windows/nuke11.0.bat | 13 + .../defaults/launchers/windows/nuke11.2.bat | 13 + .../defaults/launchers/windows/nuke11.3.bat | 13 + .../defaults/launchers/windows/nuke12.0.bat | 13 + .../launchers/windows/nukestudio10.0.bat | 13 + .../launchers/windows/nukestudio11.0.bat | 13 + .../launchers/windows/nukestudio11.2.bat | 13 + .../launchers/windows/nukestudio11.3.bat | 13 + .../launchers/windows/nukestudio12.0.bat | 13 + .../defaults/launchers/windows/nukex10.0.bat | 13 + .../defaults/launchers/windows/nukex11.0.bat | 13 + .../defaults/launchers/windows/nukex11.2.bat | 13 + .../defaults/launchers/windows/nukex11.3.bat | 13 + .../defaults/launchers/windows/nukex12.0.bat | 13 + .../launchers/windows/photoshop_2020.bat | 15 + .../launchers/windows/premiere_pro_2019.bat | 14 + .../launchers/windows/premiere_pro_2020.bat | 13 + .../defaults/launchers/windows/python3.bat | 13 + .../defaults/launchers/windows/resolve_16.bat | 17 ++ .../defaults/launchers/windows/shell.bat | 2 + .../launchers/windows/storyboardpro_7.bat | 13 + .../defaults/launchers/windows/unreal.bat | 11 + .../presets/colorspace/aces103-cg.json | 46 +++ .../defaults/presets/colorspace/default.json | 42 +++ .../defaults/presets/dataflow/aces-exr.json | 58 ++++ .../defaults/presets/dataflow/default.json | 55 ++++ .../presets/ftrack/ftrack_config.json | 16 ++ .../ftrack/ftrack_custom_attributes.json | 165 +++++++++++ .../ftrack/partnership_ftrack_cred.json | 5 + .../presets/ftrack/plugins/server.json | 1 + .../defaults/presets/ftrack/plugins/user.json | 5 + .../presets/ftrack/project_defaults.json | 18 ++ .../configurations/defaults/presets/init.json | 4 + .../defaults/presets/maya/capture.json | 108 ++++++++ .../presets/muster/templates_mapping.json | 19 ++ .../defaults/presets/nukestudio/tags.json | 262 ++++++++++++++++++ .../presets/plugins/celaction/publish.json | 10 + .../defaults/presets/plugins/config.json | 1 + .../presets/plugins/ftrack/publish.json | 6 + .../presets/plugins/global/create.json | 1 + .../presets/plugins/global/filter.json | 1 + .../defaults/presets/plugins/global/load.json | 1 + .../presets/plugins/global/publish.json | 86 ++++++ .../defaults/presets/plugins/maya/create.json | 1 + .../defaults/presets/plugins/maya/filter.json | 9 + .../defaults/presets/plugins/maya/load.json | 18 ++ .../presets/plugins/maya/publish.json | 17 ++ .../presets/plugins/maya/workfile_build.json | 54 ++++ .../defaults/presets/plugins/nuke/create.json | 8 + .../defaults/presets/plugins/nuke/load.json | 1 + .../presets/plugins/nuke/publish.json | 48 ++++ .../presets/plugins/nuke/workfile_build.json | 11 + .../presets/plugins/nukestudio/filter.json | 10 + .../presets/plugins/nukestudio/publish.json | 8 + .../presets/plugins/resolve/create.json | 7 + .../plugins/standalonepublisher/publish.json | 25 ++ .../defaults/presets/plugins/test/create.json | 8 + .../presets/plugins/test/publish.json | 10 + .../presets/premiere/asset_default.json | 5 + .../presets/premiere/rules_tasks.json | 21 ++ .../presets/standalone_publish/families.json | 90 ++++++ .../defaults/presets/tools/creator.json | 8 + .../tools/project_folder_structure.json | 22 ++ .../defaults/presets/tools/pyblish.json | 17 ++ .../presets/tools/slates/example_HD.json | 212 ++++++++++++++ .../defaults/presets/tools/sw_folders.json | 8 + .../defaults/presets/tools/workfiles.json | 7 + .../defaults/presets/tray/menu_items.json | 28 ++ .../presets/unreal/project_setup.json | 4 + .../plugins/celaction/publish.json | 11 + .../plugins/config.json | 1 + .../plugins/ftrack/publish.json | 7 + .../plugins/global/create.json | 1 + .../plugins/global/filter.json | 1 + .../plugins/global/load.json | 1 + .../plugins/global/publish.json | 97 +++++++ .../plugins/maya/create.json | 1 + .../plugins/maya/filter.json | 9 + .../plugins/maya/load.json | 18 ++ .../plugins/maya/publish.json | 17 ++ .../plugins/maya/workfile_build.json | 136 +++++++++ .../plugins/nuke/create.json | 8 + .../plugins/nuke/load.json | 1 + .../plugins/nuke/publish.json | 53 ++++ .../plugins/nuke/workfile_build.json | 23 ++ .../plugins/nukestudio/filter.json | 10 + .../plugins/nukestudio/publish.json | 9 + .../plugins/resolve/create.json | 7 + .../plugins/standalonepublisher/publish.json | 27 ++ .../plugins/test/create.json | 8 + .../plugins/test/publish.json | 10 + .../global/applications.json | 39 +++ .../studio_configurations/global/intent.json | 8 + .../studio_configurations/global/tools.json | 6 + .../global/tray_modules.json | 28 ++ .../muster/templates_mapping.json | 19 ++ .../standalone_publish/families.json | 90 ++++++ 211 files changed, 3697 insertions(+) create mode 100644 pype/configurations/defaults/anatomy/README.md create mode 100644 pype/configurations/defaults/anatomy/default.yaml create mode 100644 pype/configurations/defaults/anatomy/roots.json create mode 100644 pype/configurations/defaults/environments/avalon.json create mode 100644 pype/configurations/defaults/environments/blender.json create mode 100644 pype/configurations/defaults/environments/celaction.json create mode 100644 pype/configurations/defaults/environments/deadline.json create mode 100644 pype/configurations/defaults/environments/ftrack.json create mode 100644 pype/configurations/defaults/environments/global.json create mode 100644 pype/configurations/defaults/environments/harmony.json create mode 100644 pype/configurations/defaults/environments/houdini.json create mode 100644 pype/configurations/defaults/environments/maya.json create mode 100644 pype/configurations/defaults/environments/maya_2018.json create mode 100644 pype/configurations/defaults/environments/maya_2020.json create mode 100644 pype/configurations/defaults/environments/mayabatch.json create mode 100644 pype/configurations/defaults/environments/mayabatch_2019.json create mode 100644 pype/configurations/defaults/environments/mtoa_3.1.1.json create mode 100644 pype/configurations/defaults/environments/muster.json create mode 100644 pype/configurations/defaults/environments/nuke.json create mode 100644 pype/configurations/defaults/environments/nukestudio.json create mode 100644 pype/configurations/defaults/environments/nukestudio_10.0.json create mode 100644 pype/configurations/defaults/environments/nukex.json create mode 100644 pype/configurations/defaults/environments/nukex_10.0.json create mode 100644 pype/configurations/defaults/environments/photoshop.json create mode 100644 pype/configurations/defaults/environments/premiere.json create mode 100644 pype/configurations/defaults/environments/resolve.json create mode 100644 pype/configurations/defaults/environments/storyboardpro.json create mode 100644 pype/configurations/defaults/environments/unreal_4.24.json create mode 100644 pype/configurations/defaults/environments/vray_4300.json create mode 100644 pype/configurations/defaults/launchers/blender_2.80.toml create mode 100644 pype/configurations/defaults/launchers/blender_2.81.toml create mode 100644 pype/configurations/defaults/launchers/blender_2.82.toml create mode 100644 pype/configurations/defaults/launchers/blender_2.83.toml create mode 100644 pype/configurations/defaults/launchers/celaction_local.toml create mode 100644 pype/configurations/defaults/launchers/celaction_publish.toml create mode 100644 pype/configurations/defaults/launchers/darwin/blender_2.82 create mode 100644 pype/configurations/defaults/launchers/darwin/harmony_17 create mode 100644 pype/configurations/defaults/launchers/darwin/harmony_17_launch create mode 100644 pype/configurations/defaults/launchers/darwin/python3 create mode 100644 pype/configurations/defaults/launchers/harmony_17.toml create mode 100644 pype/configurations/defaults/launchers/houdini_16.toml create mode 100644 pype/configurations/defaults/launchers/houdini_17.toml create mode 100644 pype/configurations/defaults/launchers/houdini_18.toml create mode 100644 pype/configurations/defaults/launchers/linux/maya2016 create mode 100644 pype/configurations/defaults/launchers/linux/maya2017 create mode 100644 pype/configurations/defaults/launchers/linux/maya2018 create mode 100644 pype/configurations/defaults/launchers/linux/maya2019 create mode 100644 pype/configurations/defaults/launchers/linux/maya2020 create mode 100644 pype/configurations/defaults/launchers/linux/nuke11.3 create mode 100644 pype/configurations/defaults/launchers/linux/nuke12.0 create mode 100644 pype/configurations/defaults/launchers/linux/nukestudio11.3 create mode 100644 pype/configurations/defaults/launchers/linux/nukestudio12.0 create mode 100644 pype/configurations/defaults/launchers/linux/nukex11.3 create mode 100644 pype/configurations/defaults/launchers/linux/nukex12.0 create mode 100644 pype/configurations/defaults/launchers/maya_2016.toml create mode 100644 pype/configurations/defaults/launchers/maya_2017.toml create mode 100644 pype/configurations/defaults/launchers/maya_2018.toml create mode 100644 pype/configurations/defaults/launchers/maya_2019.toml create mode 100644 pype/configurations/defaults/launchers/maya_2020.toml create mode 100644 pype/configurations/defaults/launchers/mayabatch_2019.toml create mode 100644 pype/configurations/defaults/launchers/mayabatch_2020.toml create mode 100644 pype/configurations/defaults/launchers/mayapy2016.toml create mode 100644 pype/configurations/defaults/launchers/mayapy2017.toml create mode 100644 pype/configurations/defaults/launchers/mayapy2018.toml create mode 100644 pype/configurations/defaults/launchers/mayapy2019.toml create mode 100644 pype/configurations/defaults/launchers/mayapy2020.toml create mode 100644 pype/configurations/defaults/launchers/myapp.toml create mode 100644 pype/configurations/defaults/launchers/nuke_10.0.toml create mode 100644 pype/configurations/defaults/launchers/nuke_11.0.toml create mode 100644 pype/configurations/defaults/launchers/nuke_11.2.toml create mode 100644 pype/configurations/defaults/launchers/nuke_11.3.toml create mode 100644 pype/configurations/defaults/launchers/nuke_12.0.toml create mode 100644 pype/configurations/defaults/launchers/nukestudio_10.0.toml create mode 100644 pype/configurations/defaults/launchers/nukestudio_11.0.toml create mode 100644 pype/configurations/defaults/launchers/nukestudio_11.2.toml create mode 100644 pype/configurations/defaults/launchers/nukestudio_11.3.toml create mode 100644 pype/configurations/defaults/launchers/nukestudio_12.0.toml create mode 100644 pype/configurations/defaults/launchers/nukex_10.0.toml create mode 100644 pype/configurations/defaults/launchers/nukex_11.0.toml create mode 100644 pype/configurations/defaults/launchers/nukex_11.2.toml create mode 100644 pype/configurations/defaults/launchers/nukex_11.3.toml create mode 100644 pype/configurations/defaults/launchers/nukex_12.0.toml create mode 100644 pype/configurations/defaults/launchers/photoshop_2020.toml create mode 100644 pype/configurations/defaults/launchers/premiere_2019.toml create mode 100644 pype/configurations/defaults/launchers/premiere_2020.toml create mode 100644 pype/configurations/defaults/launchers/python_2.toml create mode 100644 pype/configurations/defaults/launchers/python_3.toml create mode 100644 pype/configurations/defaults/launchers/resolve_16.toml create mode 100644 pype/configurations/defaults/launchers/shell.toml create mode 100644 pype/configurations/defaults/launchers/storyboardpro_7.toml create mode 100644 pype/configurations/defaults/launchers/unreal_4.24.toml create mode 100644 pype/configurations/defaults/launchers/windows/blender_2.80.bat create mode 100644 pype/configurations/defaults/launchers/windows/blender_2.81.bat create mode 100644 pype/configurations/defaults/launchers/windows/blender_2.82.bat create mode 100644 pype/configurations/defaults/launchers/windows/blender_2.83.bat create mode 100644 pype/configurations/defaults/launchers/windows/celaction_local.bat create mode 100644 pype/configurations/defaults/launchers/windows/celaction_publish.bat create mode 100644 pype/configurations/defaults/launchers/windows/harmony_17.bat create mode 100644 pype/configurations/defaults/launchers/windows/houdini_16.bat create mode 100644 pype/configurations/defaults/launchers/windows/houdini_17.bat create mode 100644 pype/configurations/defaults/launchers/windows/houdini_18.bat create mode 100644 pype/configurations/defaults/launchers/windows/maya2016.bat create mode 100644 pype/configurations/defaults/launchers/windows/maya2017.bat create mode 100644 pype/configurations/defaults/launchers/windows/maya2018.bat create mode 100644 pype/configurations/defaults/launchers/windows/maya2019.bat create mode 100644 pype/configurations/defaults/launchers/windows/maya2020.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayabatch2019.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayabatch2020.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayapy2016.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayapy2017.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayapy2018.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayapy2019.bat create mode 100644 pype/configurations/defaults/launchers/windows/mayapy2020.bat create mode 100644 pype/configurations/defaults/launchers/windows/nuke10.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nuke11.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nuke11.2.bat create mode 100644 pype/configurations/defaults/launchers/windows/nuke11.3.bat create mode 100644 pype/configurations/defaults/launchers/windows/nuke12.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukestudio10.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukestudio11.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukestudio11.2.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukestudio11.3.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukestudio12.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukex10.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukex11.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukex11.2.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukex11.3.bat create mode 100644 pype/configurations/defaults/launchers/windows/nukex12.0.bat create mode 100644 pype/configurations/defaults/launchers/windows/photoshop_2020.bat create mode 100644 pype/configurations/defaults/launchers/windows/premiere_pro_2019.bat create mode 100644 pype/configurations/defaults/launchers/windows/premiere_pro_2020.bat create mode 100644 pype/configurations/defaults/launchers/windows/python3.bat create mode 100644 pype/configurations/defaults/launchers/windows/resolve_16.bat create mode 100644 pype/configurations/defaults/launchers/windows/shell.bat create mode 100644 pype/configurations/defaults/launchers/windows/storyboardpro_7.bat create mode 100644 pype/configurations/defaults/launchers/windows/unreal.bat create mode 100644 pype/configurations/defaults/presets/colorspace/aces103-cg.json create mode 100644 pype/configurations/defaults/presets/colorspace/default.json create mode 100644 pype/configurations/defaults/presets/dataflow/aces-exr.json create mode 100644 pype/configurations/defaults/presets/dataflow/default.json create mode 100644 pype/configurations/defaults/presets/ftrack/ftrack_config.json create mode 100644 pype/configurations/defaults/presets/ftrack/ftrack_custom_attributes.json create mode 100644 pype/configurations/defaults/presets/ftrack/partnership_ftrack_cred.json create mode 100644 pype/configurations/defaults/presets/ftrack/plugins/server.json create mode 100644 pype/configurations/defaults/presets/ftrack/plugins/user.json create mode 100644 pype/configurations/defaults/presets/ftrack/project_defaults.json create mode 100644 pype/configurations/defaults/presets/init.json create mode 100644 pype/configurations/defaults/presets/maya/capture.json create mode 100644 pype/configurations/defaults/presets/muster/templates_mapping.json create mode 100644 pype/configurations/defaults/presets/nukestudio/tags.json create mode 100644 pype/configurations/defaults/presets/plugins/celaction/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/config.json create mode 100644 pype/configurations/defaults/presets/plugins/ftrack/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/global/create.json create mode 100644 pype/configurations/defaults/presets/plugins/global/filter.json create mode 100644 pype/configurations/defaults/presets/plugins/global/load.json create mode 100644 pype/configurations/defaults/presets/plugins/global/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/maya/create.json create mode 100644 pype/configurations/defaults/presets/plugins/maya/filter.json create mode 100644 pype/configurations/defaults/presets/plugins/maya/load.json create mode 100644 pype/configurations/defaults/presets/plugins/maya/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/maya/workfile_build.json create mode 100644 pype/configurations/defaults/presets/plugins/nuke/create.json create mode 100644 pype/configurations/defaults/presets/plugins/nuke/load.json create mode 100644 pype/configurations/defaults/presets/plugins/nuke/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/nuke/workfile_build.json create mode 100644 pype/configurations/defaults/presets/plugins/nukestudio/filter.json create mode 100644 pype/configurations/defaults/presets/plugins/nukestudio/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/resolve/create.json create mode 100644 pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json create mode 100644 pype/configurations/defaults/presets/plugins/test/create.json create mode 100644 pype/configurations/defaults/presets/plugins/test/publish.json create mode 100644 pype/configurations/defaults/presets/premiere/asset_default.json create mode 100644 pype/configurations/defaults/presets/premiere/rules_tasks.json create mode 100644 pype/configurations/defaults/presets/standalone_publish/families.json create mode 100644 pype/configurations/defaults/presets/tools/creator.json create mode 100644 pype/configurations/defaults/presets/tools/project_folder_structure.json create mode 100644 pype/configurations/defaults/presets/tools/pyblish.json create mode 100644 pype/configurations/defaults/presets/tools/slates/example_HD.json create mode 100644 pype/configurations/defaults/presets/tools/sw_folders.json create mode 100644 pype/configurations/defaults/presets/tools/workfiles.json create mode 100644 pype/configurations/defaults/presets/tray/menu_items.json create mode 100644 pype/configurations/defaults/presets/unreal/project_setup.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/celaction/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/config.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/global/create.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/global/filter.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/global/load.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/global/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/maya/create.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/maya/filter.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/maya/load.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/maya/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/nuke/create.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/nuke/load.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/nuke/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/resolve/create.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/test/create.json create mode 100644 pype/configurations/defaults/project_configurations/plugins/test/publish.json create mode 100644 pype/configurations/defaults/studio_configurations/global/applications.json create mode 100644 pype/configurations/defaults/studio_configurations/global/intent.json create mode 100644 pype/configurations/defaults/studio_configurations/global/tools.json create mode 100644 pype/configurations/defaults/studio_configurations/global/tray_modules.json create mode 100644 pype/configurations/defaults/studio_configurations/muster/templates_mapping.json create mode 100644 pype/configurations/defaults/studio_configurations/standalone_publish/families.json diff --git a/pype/configurations/defaults/anatomy/README.md b/pype/configurations/defaults/anatomy/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pype/configurations/defaults/anatomy/default.yaml b/pype/configurations/defaults/anatomy/default.yaml new file mode 100644 index 0000000000..381aa05d4a --- /dev/null +++ b/pype/configurations/defaults/anatomy/default.yaml @@ -0,0 +1,29 @@ + +version_padding: 3 +version: "v{version:0>{@version_padding}}" +frame_padding: 4 +frame: "{frame:0>{@frame_padding}}" + +work: + folder: "{root}/{project[name]}/{hierarchy}/{asset}/work/{task}" + file: "{project[code]}_{asset}_{task}_{@version}<_{comment}>.{ext}" + path: "{@folder}/{@file}" + +render: + folder: "{root}/{project[name]}/{hierarchy}/{asset}/publish/render/{subset}/{@version}" + file: "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}" + path: "{@folder}/{@file}" + +texture: + path: "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}" + +publish: + folder: "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}" + file: "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}" + path: "{@folder}/{@file}" + thumbnail: "{thumbnail_root}/{project[name]}/{_id}_{thumbnail_type}{ext}" + +master: + folder: "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/master" + file: "{project[code]}_{asset}_{subset}_master<_{output}><.{frame}>.{representation}" + path: "{@folder}/{@file}" diff --git a/pype/configurations/defaults/anatomy/roots.json b/pype/configurations/defaults/anatomy/roots.json new file mode 100644 index 0000000000..0282471a60 --- /dev/null +++ b/pype/configurations/defaults/anatomy/roots.json @@ -0,0 +1,5 @@ +{ + "windows": "C:/projects", + "linux": "/mnt/share/projects", + "darwin": "/Volumes/path" +} diff --git a/pype/configurations/defaults/environments/avalon.json b/pype/configurations/defaults/environments/avalon.json new file mode 100644 index 0000000000..832ba07e71 --- /dev/null +++ b/pype/configurations/defaults/environments/avalon.json @@ -0,0 +1,16 @@ +{ + "AVALON_CONFIG": "pype", + "AVALON_PROJECTS": "{PYPE_PROJECTS_PATH}", + "AVALON_USERNAME": "avalon", + "AVALON_PASSWORD": "secret", + "AVALON_DEBUG": "1", + "AVALON_MONGO": "mongodb://localhost:2707", + "AVALON_DB": "avalon", + "AVALON_DB_DATA": "{PYPE_SETUP_PATH}/../mongo_db_data", + "AVALON_EARLY_ADOPTER": "1", + "AVALON_SCHEMA": "{PYPE_MODULE_ROOT}/schema", + "AVALON_LOCATION": "http://127.0.0.1", + "AVALON_LABEL": "Pype", + "AVALON_TIMEOUT": "1000", + "AVALON_THUMBNAIL_ROOT": "" +} diff --git a/pype/configurations/defaults/environments/blender.json b/pype/configurations/defaults/environments/blender.json new file mode 100644 index 0000000000..6f4f6a012d --- /dev/null +++ b/pype/configurations/defaults/environments/blender.json @@ -0,0 +1,7 @@ +{ + "BLENDER_USER_SCRIPTS": "{PYPE_SETUP_PATH}/repos/avalon-core/setup/blender", + "PYTHONPATH": [ + "{PYPE_SETUP_PATH}/repos/avalon-core/setup/blender", + "{PYTHONPATH}" + ] +} diff --git a/pype/configurations/defaults/environments/celaction.json b/pype/configurations/defaults/environments/celaction.json new file mode 100644 index 0000000000..cdd4e609ab --- /dev/null +++ b/pype/configurations/defaults/environments/celaction.json @@ -0,0 +1,3 @@ +{ + "CELACTION_TEMPLATE": "{PYPE_MODULE_ROOT}/pype/hosts/celaction/celaction_template_scene.scn" +} diff --git a/pype/configurations/defaults/environments/deadline.json b/pype/configurations/defaults/environments/deadline.json new file mode 100644 index 0000000000..e8ef52805b --- /dev/null +++ b/pype/configurations/defaults/environments/deadline.json @@ -0,0 +1,3 @@ +{ + "DEADLINE_REST_URL": "http://localhost:8082" +} diff --git a/pype/configurations/defaults/environments/ftrack.json b/pype/configurations/defaults/environments/ftrack.json new file mode 100644 index 0000000000..4f25de027b --- /dev/null +++ b/pype/configurations/defaults/environments/ftrack.json @@ -0,0 +1,18 @@ +{ + "FTRACK_SERVER": "https://pype.ftrackapp.com", + "FTRACK_ACTIONS_PATH": [ + "{PYPE_MODULE_ROOT}/pype/modules/ftrack/actions" + ], + "FTRACK_EVENTS_PATH": [ + "{PYPE_MODULE_ROOT}/pype/modules/ftrack/events" + ], + "PYTHONPATH": [ + "{PYPE_MODULE_ROOT}/pype/vendor", + "{PYTHONPATH}" + ], + "PYBLISHPLUGINPATH": [ + "{PYPE_MODULE_ROOT}/pype/plugins/ftrack/publish" + ], + "FTRACK_EVENTS_MONGO_DB": "pype", + "FTRACK_EVENTS_MONGO_COL": "ftrack_events" +} diff --git a/pype/configurations/defaults/environments/global.json b/pype/configurations/defaults/environments/global.json new file mode 100644 index 0000000000..ef528e6857 --- /dev/null +++ b/pype/configurations/defaults/environments/global.json @@ -0,0 +1,44 @@ +{ + "PYPE_STUDIO_NAME": "Studio Name", + "PYPE_STUDIO_CODE": "stu", + "PYPE_APP_ROOT": "{PYPE_SETUP_PATH}/pypeapp", + "PYPE_MODULE_ROOT": "{PYPE_SETUP_PATH}/repos/pype", + "PYPE_PROJECT_PLUGINS": "", + "STUDIO_SOFT": "{PYP_SETUP_ROOT}/soft", + "FFMPEG_PATH": { + "windows": "{VIRTUAL_ENV}/localized/ffmpeg_exec/windows/bin;{PYPE_SETUP_PATH}/vendor/ffmpeg_exec/windows/bin", + "darwin": "{VIRTUAL_ENV}/localized/ffmpeg_exec/darwin/bin:{PYPE_SETUP_PATH}/vendor/ffmpeg_exec/darwin/bin", + "linux": "{VIRTUAL_ENV}/localized/ffmpeg_exec/linux:{PYPE_SETUP_PATH}/vendor/ffmpeg_exec/linux" + }, + "DJV_PATH": { + "windows": [ + "C:/Program Files/djv-1.1.0-Windows-64/bin/djv_view.exe", + "C:/Program Files/DJV/bin/djv_view.exe", + "{STUDIO_SOFT}/djv/windows/bin/djv_view.exe" + ], + "linux": [ + "usr/local/djv/djv_view", + "{STUDIO_SOFT}/djv/linux/bin/djv_view" + ], + "darwin": "Application/DJV.app/Contents/MacOS/DJV" + }, + "PATH": [ + "{PYPE_CONFIG}/launchers", + "{PYPE_APP_ROOT}", + "{FFMPEG_PATH}", + "{PATH}" + ], + "PYPE_OCIO_CONFIG": "{STUDIO_SOFT}/OpenColorIO-Configs", + "PYTHONPATH": { + "windows": "{VIRTUAL_ENV}/Lib/site-packages;{PYPE_MODULE_ROOT}/pype/tools;{PYTHONPATH}", + "linux": "{VIRTUAL_ENV}/lib/python{PYTHON_VERSION}/site-packages:{PYPE_MODULE_ROOT}/pype/tools:{PYTHONPATH}", + "darwin": "{VIRTUAL_ENV}/lib/python{PYTHON_VERSION}/site-packages:{PYPE_MODULE_ROOT}/pype/tools:{PYTHONPATH}" + }, + "PYPE_PROJECT_CONFIGS": "{PYPE_SETUP_PATH}/../studio-project-configs", + "PYPE_PYTHON_EXE": { + "windows": "{VIRTUAL_ENV}/Scripts/python.exe", + "linux": "{VIRTUAL_ENV}/Scripts/python", + "darwin": "{VIRTUAL_ENV}/bin/python" + }, + "PYBLISH_GUI": "pyblish_pype" +} diff --git a/pype/configurations/defaults/environments/harmony.json b/pype/configurations/defaults/environments/harmony.json new file mode 100644 index 0000000000..d394343935 --- /dev/null +++ b/pype/configurations/defaults/environments/harmony.json @@ -0,0 +1,4 @@ +{ + "AVALON_HARMONY_WORKFILES_ON_LAUNCH": "1", + "PYBLISH_GUI_ALWAYS_EXEC": "1" +} diff --git a/pype/configurations/defaults/environments/houdini.json b/pype/configurations/defaults/environments/houdini.json new file mode 100644 index 0000000000..95c7d19088 --- /dev/null +++ b/pype/configurations/defaults/environments/houdini.json @@ -0,0 +1,12 @@ +{ + "HOUDINI_PATH": { + "darwin": "{PYPE_MODULE_ROOT}/setup/houdini:&", + "linux": "{PYPE_MODULE_ROOT}/setup/houdini:&", + "windows": "{PYPE_MODULE_ROOT}/setup/houdini;&" + }, + "HOUDINI_MENU_PATH": { + "darwin": "{PYPE_MODULE_ROOT}/setup/houdini:&", + "linux": "{PYPE_MODULE_ROOT}/setup/houdini:&", + "windows": "{PYPE_MODULE_ROOT}/setup/houdini;&" + } +} diff --git a/pype/configurations/defaults/environments/maya.json b/pype/configurations/defaults/environments/maya.json new file mode 100644 index 0000000000..7785b108f7 --- /dev/null +++ b/pype/configurations/defaults/environments/maya.json @@ -0,0 +1,14 @@ +{ + "PYTHONPATH": [ + "{PYPE_SETUP_PATH}/repos/avalon-core/setup/maya", + "{PYPE_SETUP_PATH}/repos/maya-look-assigner", + "{PYTHON_ENV}/python2/Lib/site-packages", + "{PYTHONPATH}" + ], + "MAYA_DISABLE_CLIC_IPM": "Yes", + "MAYA_DISABLE_CIP": "Yes", + "MAYA_DISABLE_CER": "Yes", + "PYMEL_SKIP_MEL_INIT": "Yes", + "LC_ALL": "C", + "PYPE_LOG_NO_COLORS": "Yes" +} diff --git a/pype/configurations/defaults/environments/maya_2018.json b/pype/configurations/defaults/environments/maya_2018.json new file mode 100644 index 0000000000..72a0c57ce3 --- /dev/null +++ b/pype/configurations/defaults/environments/maya_2018.json @@ -0,0 +1,11 @@ +{ + "MAYA_VERSION": "2018", + "MAYA_LOCATION": { + "darwin": "/Applications/Autodesk/maya{MAYA_VERSION}/Maya.app/Contents", + "linux": "/usr/autodesk/maya{MAYA_VERSION}", + "windows": "C:/Program Files/Autodesk/Maya{MAYA_VERSION}" + }, + "DYLD_LIBRARY_PATH": { + "darwin": "{MAYA_LOCATION}/MacOS" + } +} diff --git a/pype/configurations/defaults/environments/maya_2020.json b/pype/configurations/defaults/environments/maya_2020.json new file mode 100644 index 0000000000..efd0250bc8 --- /dev/null +++ b/pype/configurations/defaults/environments/maya_2020.json @@ -0,0 +1,11 @@ +{ + "MAYA_VERSION": "2020", + "MAYA_LOCATION": { + "darwin": "/Applications/Autodesk/maya{MAYA_VERSION}/Maya.app/Contents", + "linux": "/usr/autodesk/maya{MAYA_VERSION}", + "windows": "C:/Program Files/Autodesk/Maya{MAYA_VERSION}" + }, + "DYLD_LIBRARY_PATH": { + "darwin": "{MAYA_LOCATION}/MacOS" + } +} diff --git a/pype/configurations/defaults/environments/mayabatch.json b/pype/configurations/defaults/environments/mayabatch.json new file mode 100644 index 0000000000..7785b108f7 --- /dev/null +++ b/pype/configurations/defaults/environments/mayabatch.json @@ -0,0 +1,14 @@ +{ + "PYTHONPATH": [ + "{PYPE_SETUP_PATH}/repos/avalon-core/setup/maya", + "{PYPE_SETUP_PATH}/repos/maya-look-assigner", + "{PYTHON_ENV}/python2/Lib/site-packages", + "{PYTHONPATH}" + ], + "MAYA_DISABLE_CLIC_IPM": "Yes", + "MAYA_DISABLE_CIP": "Yes", + "MAYA_DISABLE_CER": "Yes", + "PYMEL_SKIP_MEL_INIT": "Yes", + "LC_ALL": "C", + "PYPE_LOG_NO_COLORS": "Yes" +} diff --git a/pype/configurations/defaults/environments/mayabatch_2019.json b/pype/configurations/defaults/environments/mayabatch_2019.json new file mode 100644 index 0000000000..aa7360a943 --- /dev/null +++ b/pype/configurations/defaults/environments/mayabatch_2019.json @@ -0,0 +1,11 @@ +{ + "MAYA_VERSION": "2019", + "MAYA_LOCATION": { + "darwin": "/Applications/Autodesk/maya{MAYA_VERSION}/Maya.app/Contents", + "linux": "/usr/autodesk/maya{MAYA_VERSION}", + "windows": "C:/Program Files/Autodesk/Maya{MAYA_VERSION}" + }, + "DYLD_LIBRARY_PATH": { + "darwin": "{MAYA_LOCATION}/MacOS" + } +} diff --git a/pype/configurations/defaults/environments/mtoa_3.1.1.json b/pype/configurations/defaults/environments/mtoa_3.1.1.json new file mode 100644 index 0000000000..f7b9f94d4e --- /dev/null +++ b/pype/configurations/defaults/environments/mtoa_3.1.1.json @@ -0,0 +1,23 @@ +{ + "MTOA": "{PYPE_STUDIO_SOFTWARE}/arnold/mtoa_{MAYA_VERSION}_{MTOA_VERSION}", + "MTOA_VERSION": "3.1.1", + "MAYA_RENDER_DESC_PATH": "{MTOA}", + "MAYA_MODULE_PATH": "{MTOA}", + "ARNOLD_PLUGIN_PATH": "{MTOA}/shaders", + "MTOA_EXTENSIONS_PATH": { + "darwin": "{MTOA}/extensions", + "linux": "{MTOA}/extensions", + "windows": "{MTOA}/extensions" + }, + "MTOA_EXTENSIONS": { + "darwin": "{MTOA}/extensions", + "linux": "{MTOA}/extensions", + "windows": "{MTOA}/extensions" + }, + "DYLD_LIBRARY_PATH": { + "darwin": "{MTOA}/bin" + }, + "PATH": { + "windows": "{PATH};{MTOA}/bin" + } +} diff --git a/pype/configurations/defaults/environments/muster.json b/pype/configurations/defaults/environments/muster.json new file mode 100644 index 0000000000..26f311146a --- /dev/null +++ b/pype/configurations/defaults/environments/muster.json @@ -0,0 +1,3 @@ +{ + "MUSTER_REST_URL": "http://127.0.0.1:9890" +} diff --git a/pype/configurations/defaults/environments/nuke.json b/pype/configurations/defaults/environments/nuke.json new file mode 100644 index 0000000000..50dd31ac91 --- /dev/null +++ b/pype/configurations/defaults/environments/nuke.json @@ -0,0 +1,15 @@ +{ + "NUKE_PATH": [ + "{PYPE_SETUP_PATH}/repos/avalon-core/setup/nuke/nuke_path", + "{PYPE_MODULE_ROOT}/setup/nuke/nuke_path", + "{PYPE_STUDIO_PLUGINS}/nuke" + ], + "PATH": { + "windows": "C:/Program Files (x86)/QuickTime/QTSystem/;{PATH}" + }, + "PYPE_LOG_NO_COLORS": "True", + "PYTHONPATH": { + "windows": "{VIRTUAL_ENV}/Lib/site-packages;{PYTHONPATH}", + "linux": "{VIRTUAL_ENV}/lib/python3.6/site-packages:{PYTHONPATH}" + } +} diff --git a/pype/configurations/defaults/environments/nukestudio.json b/pype/configurations/defaults/environments/nukestudio.json new file mode 100644 index 0000000000..b05e2411f0 --- /dev/null +++ b/pype/configurations/defaults/environments/nukestudio.json @@ -0,0 +1,11 @@ +{ + "HIERO_PLUGIN_PATH": [ + "{PYPE_MODULE_ROOT}/setup/nukestudio/hiero_plugin_path" + ], + "PATH": { + "windows": "C:/Program Files (x86)/QuickTime/QTSystem/;{PATH}" + }, + "WORKFILES_STARTUP": "0", + "TAG_ASSETBUILD_STARTUP": "0", + "PYPE_LOG_NO_COLORS": "True" +} diff --git a/pype/configurations/defaults/environments/nukestudio_10.0.json b/pype/configurations/defaults/environments/nukestudio_10.0.json new file mode 100644 index 0000000000..9bdcef53c9 --- /dev/null +++ b/pype/configurations/defaults/environments/nukestudio_10.0.json @@ -0,0 +1,4 @@ +{ + "PYPE_LOG_NO_COLORS": "Yes", + "QT_PREFERRED_BINDING": "PySide" +} \ No newline at end of file diff --git a/pype/configurations/defaults/environments/nukex.json b/pype/configurations/defaults/environments/nukex.json new file mode 100644 index 0000000000..2b77f44076 --- /dev/null +++ b/pype/configurations/defaults/environments/nukex.json @@ -0,0 +1,10 @@ +{ + "NUKE_PATH": [ + "{PYPE_SETUP_PATH}/repos/avalon-core/setup/nuke/nuke_path", + "{PYPE_MODULE_ROOT}/setup/nuke/nuke_path", + "{PYPE_STUDIO_PLUGINS}/nuke" + ], + "PATH": { + "windows": "C:/Program Files (x86)/QuickTime/QTSystem/;{PATH}" + } +} diff --git a/pype/configurations/defaults/environments/nukex_10.0.json b/pype/configurations/defaults/environments/nukex_10.0.json new file mode 100644 index 0000000000..9bdcef53c9 --- /dev/null +++ b/pype/configurations/defaults/environments/nukex_10.0.json @@ -0,0 +1,4 @@ +{ + "PYPE_LOG_NO_COLORS": "Yes", + "QT_PREFERRED_BINDING": "PySide" +} \ No newline at end of file diff --git a/pype/configurations/defaults/environments/photoshop.json b/pype/configurations/defaults/environments/photoshop.json new file mode 100644 index 0000000000..2208a88665 --- /dev/null +++ b/pype/configurations/defaults/environments/photoshop.json @@ -0,0 +1,4 @@ +{ + "AVALON_PHOTOSHOP_WORKFILES_ON_LAUNCH": "1", + "PYTHONPATH": "{PYTHONPATH}" +} diff --git a/pype/configurations/defaults/environments/premiere.json b/pype/configurations/defaults/environments/premiere.json new file mode 100644 index 0000000000..27dc5c564b --- /dev/null +++ b/pype/configurations/defaults/environments/premiere.json @@ -0,0 +1,11 @@ +{ + "EXTENSIONS_PATH": { + "windows": "{USERPROFILE}/AppData/Roaming/Adobe/CEP/extensions", + "darvin": "{USER}/Library/Application Support/Adobe/CEP/extensions" + }, + "EXTENSIONS_CACHE_PATH": { + "windows": "{USERPROFILE}/AppData/Local/Temp/cep_cache", + "darvin": "{USER}/Library/Application Support/Adobe/CEP/cep_cache" + }, + "installed_zxp": "" +} diff --git a/pype/configurations/defaults/environments/resolve.json b/pype/configurations/defaults/environments/resolve.json new file mode 100644 index 0000000000..1ff197dd5a --- /dev/null +++ b/pype/configurations/defaults/environments/resolve.json @@ -0,0 +1,40 @@ +{ + "RESOLVE_UTILITY_SCRIPTS_SOURCE_DIR": [ + "{STUDIO_SOFT}/davinci_resolve/scripts/python" + ], + "RESOLVE_SCRIPT_API": { + "windows": "{PROGRAMDATA}/Blackmagic Design/DaVinci Resolve/Support/Developer/Scripting", + "darvin": "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting", + "linux": "/opt/resolve/Developer/Scripting" + }, + "RESOLVE_SCRIPT_LIB": { + "windows": "C:/Program Files/Blackmagic Design/DaVinci Resolve/fusionscript.dll", + "darvin": "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so", + "linux": "/opt/resolve/libs/Fusion/fusionscript.so" + }, + "RESOLVE_UTILITY_SCRIPTS_DIR": { + "windows": "{PROGRAMDATA}/Blackmagic Design/DaVinci Resolve/Fusion/Scripts/Comp", + "darvin": "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Scripts/Comp", + "linux": "/opt/resolve/Fusion/Scripts/Comp" + }, + "PYTHON36_RESOLVE": { + "windows": "{LOCALAPPDATA}/Programs/Python/Python36", + "darvin": "~/Library/Python/3.6/bin", + "linux": "/opt/Python/3.6/bin" + }, + "PYTHONPATH": [ + "{PYTHON36_RESOLVE}/Lib/site-packages", + "{VIRTUAL_ENV}/Lib/site-packages", + "{PYTHONPATH}", + "{RESOLVE_SCRIPT_API}/Modules", + "{PYTHONPATH}" + ], + "PATH": [ + "{PYTHON36_RESOLVE}", + "{PYTHON36_RESOLVE}/Scripts", + "{PATH}" + ], + "PRE_PYTHON_SCRIPT": "{PYPE_MODULE_ROOT}/pype/resolve/preload_console.py", + "PYPE_LOG_NO_COLORS": "True", + "RESOLVE_DEV": "True" +} diff --git a/pype/configurations/defaults/environments/storyboardpro.json b/pype/configurations/defaults/environments/storyboardpro.json new file mode 100644 index 0000000000..581ad4db45 --- /dev/null +++ b/pype/configurations/defaults/environments/storyboardpro.json @@ -0,0 +1,4 @@ +{ + "AVALON_TOONBOOM_WORKFILES_ON_LAUNCH": "1", + "PYBLISH_LITE_ALWAYS_EXEC": "1" +} diff --git a/pype/configurations/defaults/environments/unreal_4.24.json b/pype/configurations/defaults/environments/unreal_4.24.json new file mode 100644 index 0000000000..8feeb0230f --- /dev/null +++ b/pype/configurations/defaults/environments/unreal_4.24.json @@ -0,0 +1,5 @@ +{ + "AVALON_UNREAL_PLUGIN": "{PYPE_SETUP_PATH}/repos/avalon-unreal-integration", + "PYPE_LOG_NO_COLORS": "True", + "QT_PREFERRED_BINDING": "PySide" +} diff --git a/pype/configurations/defaults/environments/vray_4300.json b/pype/configurations/defaults/environments/vray_4300.json new file mode 100644 index 0000000000..3212188441 --- /dev/null +++ b/pype/configurations/defaults/environments/vray_4300.json @@ -0,0 +1,15 @@ +{ + "VRAY_VERSION": "43001", + "VRAY_ROOT": "C:/vray/vray_{VRAY_VERSION}", + "MAYA_RENDER_DESC_PATH": "{VRAY_ROOT}/maya_root/bin/rendererDesc", + "VRAY_FOR_MAYA2019_MAIN": "{VRAY_ROOT}/maya_vray", + "VRAY_FOR_MAYA2019_PLUGINS": "{VRAY_ROOT}/maya_vray/vrayplugins", + "VRAY_PLUGINS": "{VRAY_ROOT}/maya_vray/vrayplugins", + "VRAY_OSL_PATH_MAYA2019": "{VRAY_ROOT}/vray/opensl", + "PATH": "{VRAY_ROOT}/maya_root/bin;{PATH}", + "MAYA_PLUG_IN_PATH": "{VRAY_ROOT}/maya_vray/plug-ins", + "MAYA_SCRIPT_PATH": "{VRAY_ROOT}/maya_vray/scripts", + "PYTHONPATH": "{VRAY_ROOT}/maya_vray/scripts;{PYTHONPATH}", + "XBMLANGPATH": "{VRAY_ROOT}/maya_vray/icons;{XBMLANGPATH}", + "VRAY_AUTH_CLIENT_FILE_PATH": "{VRAY_ROOT}" +} diff --git a/pype/configurations/defaults/launchers/blender_2.80.toml b/pype/configurations/defaults/launchers/blender_2.80.toml new file mode 100644 index 0000000000..5fea78b7b0 --- /dev/null +++ b/pype/configurations/defaults/launchers/blender_2.80.toml @@ -0,0 +1,7 @@ +application_dir = "blender" +executable = "blender_2.80" +schema = "avalon-core:application-1.0" +label = "Blender 2.80" +ftrack_label = "Blender" +icon ="blender" +ftrack_icon = '{}/app_icons/blender.png' diff --git a/pype/configurations/defaults/launchers/blender_2.81.toml b/pype/configurations/defaults/launchers/blender_2.81.toml new file mode 100644 index 0000000000..4f85ee5558 --- /dev/null +++ b/pype/configurations/defaults/launchers/blender_2.81.toml @@ -0,0 +1,7 @@ +application_dir = "blender" +executable = "blender_2.81" +schema = "avalon-core:application-1.0" +label = "Blender 2.81" +ftrack_label = "Blender" +icon ="blender" +ftrack_icon = '{}/app_icons/blender.png' diff --git a/pype/configurations/defaults/launchers/blender_2.82.toml b/pype/configurations/defaults/launchers/blender_2.82.toml new file mode 100644 index 0000000000..840001452e --- /dev/null +++ b/pype/configurations/defaults/launchers/blender_2.82.toml @@ -0,0 +1,7 @@ +application_dir = "blender" +executable = "blender_2.82" +schema = "avalon-core:application-1.0" +label = "Blender 2.82" +ftrack_label = "Blender" +icon ="blender" +ftrack_icon = '{}/app_icons/blender.png' diff --git a/pype/configurations/defaults/launchers/blender_2.83.toml b/pype/configurations/defaults/launchers/blender_2.83.toml new file mode 100644 index 0000000000..7fc8bf87b9 --- /dev/null +++ b/pype/configurations/defaults/launchers/blender_2.83.toml @@ -0,0 +1,7 @@ +application_dir = "blender" +executable = "blender_2.83" +schema = "avalon-core:application-1.0" +label = "Blender 2.83" +ftrack_label = "Blender" +icon ="blender" +ftrack_icon = '{}/app_icons/blender.png' diff --git a/pype/configurations/defaults/launchers/celaction_local.toml b/pype/configurations/defaults/launchers/celaction_local.toml new file mode 100644 index 0000000000..aef3548e08 --- /dev/null +++ b/pype/configurations/defaults/launchers/celaction_local.toml @@ -0,0 +1,8 @@ +executable = "celaction_local" +schema = "avalon-core:application-1.0" +application_dir = "celaction" +label = "CelAction2D" +ftrack_label = "CelAction2D" +icon ="celaction_local" +launch_hook = "pype/hooks/celaction/prelaunch.py/CelactionPrelaunchHook" +ftrack_icon = '{}/app_icons/celaction_local.png' diff --git a/pype/configurations/defaults/launchers/celaction_publish.toml b/pype/configurations/defaults/launchers/celaction_publish.toml new file mode 100644 index 0000000000..86f4ae39e7 --- /dev/null +++ b/pype/configurations/defaults/launchers/celaction_publish.toml @@ -0,0 +1,7 @@ +schema = "avalon-core:application-1.0" +application_dir = "shell" +executable = "celaction_publish" +label = "Shell" + +[environment] +CREATE_NEW_CONSOLE = "Yes" diff --git a/pype/configurations/defaults/launchers/darwin/blender_2.82 b/pype/configurations/defaults/launchers/darwin/blender_2.82 new file mode 100644 index 0000000000..8254411ea2 --- /dev/null +++ b/pype/configurations/defaults/launchers/darwin/blender_2.82 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +open -a blender $@ diff --git a/pype/configurations/defaults/launchers/darwin/harmony_17 b/pype/configurations/defaults/launchers/darwin/harmony_17 new file mode 100644 index 0000000000..b7eba2c2d0 --- /dev/null +++ b/pype/configurations/defaults/launchers/darwin/harmony_17 @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +DIRNAME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +set >~/environment.tmp +if [ $? -ne -0 ] ; then + echo "ERROR: cannot write to '~/environment.tmp'!" + read -n 1 -s -r -p "Press any key to exit" + return +fi +open -a Terminal.app "$DIRNAME/harmony_17_launch" diff --git a/pype/configurations/defaults/launchers/darwin/harmony_17_launch b/pype/configurations/defaults/launchers/darwin/harmony_17_launch new file mode 100644 index 0000000000..5dcf5db57e --- /dev/null +++ b/pype/configurations/defaults/launchers/darwin/harmony_17_launch @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +source ~/environment.tmp +export $(cut -d= -f1 ~/environment.tmp) +exe="/Applications/Toon Boom Harmony 17 Premium/Harmony Premium.app/Contents/MacOS/Harmony Premium" +$PYPE_PYTHON_EXE -c "import avalon.harmony;avalon.harmony.launch('$exe')" diff --git a/pype/configurations/defaults/launchers/darwin/python3 b/pype/configurations/defaults/launchers/darwin/python3 new file mode 100644 index 0000000000..c2b82c7638 --- /dev/null +++ b/pype/configurations/defaults/launchers/darwin/python3 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +open /usr/bin/python3 --args $@ diff --git a/pype/configurations/defaults/launchers/harmony_17.toml b/pype/configurations/defaults/launchers/harmony_17.toml new file mode 100644 index 0000000000..dbb76444a7 --- /dev/null +++ b/pype/configurations/defaults/launchers/harmony_17.toml @@ -0,0 +1,8 @@ +application_dir = "harmony" +label = "Harmony 17" +ftrack_label = "Harmony" +schema = "avalon-core:application-1.0" +executable = "harmony_17" +description = "" +icon ="harmony_icon" +ftrack_icon = '{}/app_icons/harmony.png' diff --git a/pype/configurations/defaults/launchers/houdini_16.toml b/pype/configurations/defaults/launchers/houdini_16.toml new file mode 100644 index 0000000000..e29fa74cad --- /dev/null +++ b/pype/configurations/defaults/launchers/houdini_16.toml @@ -0,0 +1,7 @@ +executable = "houdini_16" +schema = "avalon-core:application-1.0" +application_dir = "houdini" +label = "Houdini 16" +ftrack_label = "Houdini" +icon = "houdini_icon" +ftrack_icon = '{}/app_icons/houdini.png' diff --git a/pype/configurations/defaults/launchers/houdini_17.toml b/pype/configurations/defaults/launchers/houdini_17.toml new file mode 100644 index 0000000000..5d01364330 --- /dev/null +++ b/pype/configurations/defaults/launchers/houdini_17.toml @@ -0,0 +1,7 @@ +executable = "houdini_17" +schema = "avalon-core:application-1.0" +application_dir = "houdini" +label = "Houdini 17.0" +ftrack_label = "Houdini" +icon = "houdini_icon" +ftrack_icon = '{}/app_icons/houdini.png' diff --git a/pype/configurations/defaults/launchers/houdini_18.toml b/pype/configurations/defaults/launchers/houdini_18.toml new file mode 100644 index 0000000000..93b9a3334d --- /dev/null +++ b/pype/configurations/defaults/launchers/houdini_18.toml @@ -0,0 +1,7 @@ +executable = "houdini_18" +schema = "avalon-core:application-1.0" +application_dir = "houdini" +label = "Houdini 18" +ftrack_label = "Houdini" +icon = "houdini_icon" +ftrack_icon = '{}/app_icons/houdini.png' diff --git a/pype/configurations/defaults/launchers/linux/maya2016 b/pype/configurations/defaults/launchers/linux/maya2016 new file mode 100644 index 0000000000..98424304b1 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/maya2016 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +maya_path = "/usr/autodesk/maya2016/bin/maya" + +if [[ -z $PYPE_LOG_NO_COLORS ]]; then + $maya_path -file "$AVALON_LAST_WORKFILE" $@ +else + $maya_path $@ diff --git a/pype/configurations/defaults/launchers/linux/maya2017 b/pype/configurations/defaults/launchers/linux/maya2017 new file mode 100644 index 0000000000..7a2662a55e --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/maya2017 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +maya_path = "/usr/autodesk/maya2017/bin/maya" + +if [[ -z $AVALON_LAST_WORKFILE ]]; then + $maya_path -file "$AVALON_LAST_WORKFILE" $@ +else + $maya_path $@ diff --git a/pype/configurations/defaults/launchers/linux/maya2018 b/pype/configurations/defaults/launchers/linux/maya2018 new file mode 100644 index 0000000000..db832b3fe7 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/maya2018 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +maya_path = "/usr/autodesk/maya2018/bin/maya" + +if [[ -z $AVALON_LAST_WORKFILE ]]; then + $maya_path -file "$AVALON_LAST_WORKFILE" $@ +else + $maya_path $@ diff --git a/pype/configurations/defaults/launchers/linux/maya2019 b/pype/configurations/defaults/launchers/linux/maya2019 new file mode 100644 index 0000000000..8398734ab9 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/maya2019 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +maya_path = "/usr/autodesk/maya2019/bin/maya" + +if [[ -z $AVALON_LAST_WORKFILE ]]; then + $maya_path -file "$AVALON_LAST_WORKFILE" $@ +else + $maya_path $@ diff --git a/pype/configurations/defaults/launchers/linux/maya2020 b/pype/configurations/defaults/launchers/linux/maya2020 new file mode 100644 index 0000000000..18a1edd598 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/maya2020 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +maya_path = "/usr/autodesk/maya2020/bin/maya" + +if [[ -z $AVALON_LAST_WORKFILE ]]; then + $maya_path -file "$AVALON_LAST_WORKFILE" $@ +else + $maya_path $@ diff --git a/pype/configurations/defaults/launchers/linux/nuke11.3 b/pype/configurations/defaults/launchers/linux/nuke11.3 new file mode 100644 index 0000000000..b1c9a90d74 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/nuke11.3 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gnome-terminal -e '/usr/local/Nuke11.3v5/Nuke11.3' diff --git a/pype/configurations/defaults/launchers/linux/nuke12.0 b/pype/configurations/defaults/launchers/linux/nuke12.0 new file mode 100644 index 0000000000..99ea1a6b0c --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/nuke12.0 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gnome-terminal -e '/usr/local/Nuke12.0v1/Nuke12.0' diff --git a/pype/configurations/defaults/launchers/linux/nukestudio11.3 b/pype/configurations/defaults/launchers/linux/nukestudio11.3 new file mode 100644 index 0000000000..750d54a7d5 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/nukestudio11.3 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gnome-terminal -e '/usr/local/Nuke11.3v5/Nuke11.3 --studio' diff --git a/pype/configurations/defaults/launchers/linux/nukestudio12.0 b/pype/configurations/defaults/launchers/linux/nukestudio12.0 new file mode 100644 index 0000000000..ba5cf654a8 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/nukestudio12.0 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gnome-terminal -e '/usr/local/Nuke12.0v1/Nuke12.0 --studio' diff --git a/pype/configurations/defaults/launchers/linux/nukex11.3 b/pype/configurations/defaults/launchers/linux/nukex11.3 new file mode 100644 index 0000000000..d913e4b961 --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/nukex11.3 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gnome-terminal -e '/usr/local/Nuke11.3v5/Nuke11.3 -nukex' diff --git a/pype/configurations/defaults/launchers/linux/nukex12.0 b/pype/configurations/defaults/launchers/linux/nukex12.0 new file mode 100644 index 0000000000..da2721c48b --- /dev/null +++ b/pype/configurations/defaults/launchers/linux/nukex12.0 @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +gnome-terminal -e '/usr/local/Nuke12.0v1/Nuke12.0 -nukex' diff --git a/pype/configurations/defaults/launchers/maya_2016.toml b/pype/configurations/defaults/launchers/maya_2016.toml new file mode 100644 index 0000000000..d69c4effaf --- /dev/null +++ b/pype/configurations/defaults/launchers/maya_2016.toml @@ -0,0 +1,26 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2016x64" +ftrack_label = "Maya" +schema = "avalon-core:application-1.0" +executable = "maya2016" +description = "" +icon ="maya_icon" +ftrack_icon = '{}/app_icons/maya.png' + +[copy] +"{PYPE_MODULE_ROOT}/pype/resources/maya/workspace.mel" = "workspace.mel" + +[environment] +MAYA_DISABLE_CLIC_IPM = "Yes" # Disable the AdSSO process +MAYA_DISABLE_CIP = "Yes" # Shorten time to boot +MAYA_DISABLE_CER = "Yes" +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/maya_2017.toml b/pype/configurations/defaults/launchers/maya_2017.toml new file mode 100644 index 0000000000..2d1c35b530 --- /dev/null +++ b/pype/configurations/defaults/launchers/maya_2017.toml @@ -0,0 +1,28 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2017" +ftrack_label = "Maya" +schema = "avalon-core:application-1.0" +executable = "maya2017" +description = "" +icon ="maya_icon" +ftrack_icon = '{}/app_icons/maya.png' + +[copy] +"{PYPE_MODULE_ROOT}/pype/resources/maya/workspace.mel" = "workspace.mel" + +[environment] +MAYA_DISABLE_CLIC_IPM = "Yes" # Disable the AdSSO process +MAYA_DISABLE_CIP = "Yes" # Shorten time to boot +MAYA_DISABLE_CER = "Yes" +PYMEL_SKIP_MEL_INIT = "Yes" +LC_ALL= "C" # Mute color management warnings +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/maya_2018.toml b/pype/configurations/defaults/launchers/maya_2018.toml new file mode 100644 index 0000000000..f180263fa2 --- /dev/null +++ b/pype/configurations/defaults/launchers/maya_2018.toml @@ -0,0 +1,14 @@ +application_dir = "maya" +default_dirs = [ + "renders" +] +label = "Autodesk Maya 2018" +ftrack_label = "Maya" +schema = "avalon-core:application-1.0" +executable = "maya2018" +description = "" +icon ="maya_icon" +ftrack_icon = '{}/app_icons/maya.png' + +[copy] +"{PYPE_MODULE_ROOT}/pype/resources/maya/workspace.mel" = "workspace.mel" diff --git a/pype/configurations/defaults/launchers/maya_2019.toml b/pype/configurations/defaults/launchers/maya_2019.toml new file mode 100644 index 0000000000..7ec2cbcedd --- /dev/null +++ b/pype/configurations/defaults/launchers/maya_2019.toml @@ -0,0 +1,14 @@ +application_dir = "maya" +default_dirs = [ + "renders" +] +label = "Autodesk Maya 2019" +ftrack_label = "Maya" +schema = "avalon-core:application-1.0" +executable = "maya2019" +description = "" +icon ="maya_icon" +ftrack_icon = '{}/app_icons/maya.png' + +[copy] +"{PYPE_MODULE_ROOT}/pype/resources/maya/workspace.mel" = "workspace.mel" diff --git a/pype/configurations/defaults/launchers/maya_2020.toml b/pype/configurations/defaults/launchers/maya_2020.toml new file mode 100644 index 0000000000..49d84ef9a0 --- /dev/null +++ b/pype/configurations/defaults/launchers/maya_2020.toml @@ -0,0 +1,14 @@ +application_dir = "maya" +default_dirs = [ + "renders" +] +label = "Autodesk Maya 2020" +ftrack_label = "Maya" +schema = "avalon-core:application-1.0" +executable = "maya2020" +description = "" +icon ="maya_icon" +ftrack_icon = '{}/app_icons/maya.png' + +[copy] +"{PYPE_MODULE_ROOT}/pype/resources/maya/workspace.mel" = "workspace.mel" diff --git a/pype/configurations/defaults/launchers/mayabatch_2019.toml b/pype/configurations/defaults/launchers/mayabatch_2019.toml new file mode 100644 index 0000000000..a928618d2b --- /dev/null +++ b/pype/configurations/defaults/launchers/mayabatch_2019.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2019x64" +schema = "avalon-core:application-1.0" +executable = "mayabatch2019" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/mayabatch_2020.toml b/pype/configurations/defaults/launchers/mayabatch_2020.toml new file mode 100644 index 0000000000..cd1e1e4474 --- /dev/null +++ b/pype/configurations/defaults/launchers/mayabatch_2020.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2020x64" +schema = "avalon-core:application-1.0" +executable = "mayabatch2020" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/mayapy2016.toml b/pype/configurations/defaults/launchers/mayapy2016.toml new file mode 100644 index 0000000000..ad1e3dee86 --- /dev/null +++ b/pype/configurations/defaults/launchers/mayapy2016.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2016x64" +schema = "avalon-core:application-1.0" +executable = "mayapy2016" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/mayapy2017.toml b/pype/configurations/defaults/launchers/mayapy2017.toml new file mode 100644 index 0000000000..8d2095ff47 --- /dev/null +++ b/pype/configurations/defaults/launchers/mayapy2017.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2017x64" +schema = "avalon-core:application-1.0" +executable = "mayapy2017" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/mayapy2018.toml b/pype/configurations/defaults/launchers/mayapy2018.toml new file mode 100644 index 0000000000..597744fd85 --- /dev/null +++ b/pype/configurations/defaults/launchers/mayapy2018.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2018x64" +schema = "avalon-core:application-1.0" +executable = "mayapy2017" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/mayapy2019.toml b/pype/configurations/defaults/launchers/mayapy2019.toml new file mode 100644 index 0000000000..3c8a9860f9 --- /dev/null +++ b/pype/configurations/defaults/launchers/mayapy2019.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2019x64" +schema = "avalon-core:application-1.0" +executable = "mayapy2019" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/mayapy2020.toml b/pype/configurations/defaults/launchers/mayapy2020.toml new file mode 100644 index 0000000000..8f2d2e4a67 --- /dev/null +++ b/pype/configurations/defaults/launchers/mayapy2020.toml @@ -0,0 +1,17 @@ +application_dir = "maya" +default_dirs = [ + "scenes", + "data", + "renderData/shaders", + "images" +] +label = "Autodesk Maya 2020x64" +schema = "avalon-core:application-1.0" +executable = "mayapy2020" +description = "" + +[environment] +PYTHONPATH = [ + "{AVALON_CORE}/setup/maya", + "{PYTHONPATH}" +] diff --git a/pype/configurations/defaults/launchers/myapp.toml b/pype/configurations/defaults/launchers/myapp.toml new file mode 100644 index 0000000000..21da0d52b2 --- /dev/null +++ b/pype/configurations/defaults/launchers/myapp.toml @@ -0,0 +1,5 @@ +executable = "python" +schema = "avalon-core:application-1.0" +application_dir = "myapp" +label = "My App" +arguments = [ "-c", "import sys; from Qt import QtWidgets; if __name__ == '__main__':;\n app = QtWidgets.QApplication(sys.argv);\n window = QtWidgets.QWidget();\n window.setWindowTitle(\"My App\");\n window.resize(400, 300);\n window.show();\n app.exec_();\n",] \ No newline at end of file diff --git a/pype/configurations/defaults/launchers/nuke_10.0.toml b/pype/configurations/defaults/launchers/nuke_10.0.toml new file mode 100644 index 0000000000..2195fd3e82 --- /dev/null +++ b/pype/configurations/defaults/launchers/nuke_10.0.toml @@ -0,0 +1,7 @@ +executable = "nuke10.0" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "Nuke 10.0v4" +ftrack_label = "Nuke" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nuke_11.0.toml b/pype/configurations/defaults/launchers/nuke_11.0.toml new file mode 100644 index 0000000000..0c981b479a --- /dev/null +++ b/pype/configurations/defaults/launchers/nuke_11.0.toml @@ -0,0 +1,7 @@ +executable = "nuke11.0" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "Nuke 11.0" +ftrack_label = "Nuke" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nuke_11.2.toml b/pype/configurations/defaults/launchers/nuke_11.2.toml new file mode 100644 index 0000000000..57c962d126 --- /dev/null +++ b/pype/configurations/defaults/launchers/nuke_11.2.toml @@ -0,0 +1,7 @@ +executable = "nuke11.2" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "Nuke 11.2" +ftrack_label = "Nuke" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nuke_11.3.toml b/pype/configurations/defaults/launchers/nuke_11.3.toml new file mode 100644 index 0000000000..87f769c23b --- /dev/null +++ b/pype/configurations/defaults/launchers/nuke_11.3.toml @@ -0,0 +1,7 @@ +executable = "nuke11.3" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "Nuke 11.3" +ftrack_label = "Nuke" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nuke_12.0.toml b/pype/configurations/defaults/launchers/nuke_12.0.toml new file mode 100644 index 0000000000..62936b4cdb --- /dev/null +++ b/pype/configurations/defaults/launchers/nuke_12.0.toml @@ -0,0 +1,7 @@ +executable = "nuke12.0" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "Nuke 12.0" +ftrack_label = "Nuke" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nukestudio_10.0.toml b/pype/configurations/defaults/launchers/nukestudio_10.0.toml new file mode 100644 index 0000000000..41601e4d40 --- /dev/null +++ b/pype/configurations/defaults/launchers/nukestudio_10.0.toml @@ -0,0 +1,7 @@ +executable = "nukestudio10.0" +schema = "avalon-core:application-1.0" +application_dir = "nukestudio" +label = "NukeStudio 10.0" +ftrack_label = "NukeStudio" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nukestudio_11.0.toml b/pype/configurations/defaults/launchers/nukestudio_11.0.toml new file mode 100644 index 0000000000..7a9d84707a --- /dev/null +++ b/pype/configurations/defaults/launchers/nukestudio_11.0.toml @@ -0,0 +1,7 @@ +executable = "nukestudio11.0" +schema = "avalon-core:application-1.0" +application_dir = "nukestudio" +label = "NukeStudio 11.0" +ftrack_label = "NukeStudio" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nukestudio_11.2.toml b/pype/configurations/defaults/launchers/nukestudio_11.2.toml new file mode 100644 index 0000000000..21557033ca --- /dev/null +++ b/pype/configurations/defaults/launchers/nukestudio_11.2.toml @@ -0,0 +1,7 @@ +executable = "nukestudio11.2" +schema = "avalon-core:application-1.0" +application_dir = "nukestudio" +label = "NukeStudio 11.2" +ftrack_label = "NukeStudio" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nukestudio_11.3.toml b/pype/configurations/defaults/launchers/nukestudio_11.3.toml new file mode 100644 index 0000000000..1946ad6c3b --- /dev/null +++ b/pype/configurations/defaults/launchers/nukestudio_11.3.toml @@ -0,0 +1,7 @@ +executable = "nukestudio11.3" +schema = "avalon-core:application-1.0" +application_dir = "nukestudio" +label = "NukeStudio 11.3" +ftrack_label = "NukeStudio" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nukestudio_12.0.toml b/pype/configurations/defaults/launchers/nukestudio_12.0.toml new file mode 100644 index 0000000000..4ce7f9b538 --- /dev/null +++ b/pype/configurations/defaults/launchers/nukestudio_12.0.toml @@ -0,0 +1,7 @@ +executable = "nukestudio12.0" +schema = "avalon-core:application-1.0" +application_dir = "nukestudio" +label = "NukeStudio 12.0" +ftrack_label = "NukeStudio" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nuke.png' diff --git a/pype/configurations/defaults/launchers/nukex_10.0.toml b/pype/configurations/defaults/launchers/nukex_10.0.toml new file mode 100644 index 0000000000..7dee22996d --- /dev/null +++ b/pype/configurations/defaults/launchers/nukex_10.0.toml @@ -0,0 +1,7 @@ +executable = "nukex10.0" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "NukeX 10.0" +ftrack_label = "NukeX" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nukex.png' diff --git a/pype/configurations/defaults/launchers/nukex_11.0.toml b/pype/configurations/defaults/launchers/nukex_11.0.toml new file mode 100644 index 0000000000..c2b4970a26 --- /dev/null +++ b/pype/configurations/defaults/launchers/nukex_11.0.toml @@ -0,0 +1,7 @@ +executable = "nukex11.0" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "NukeX 11.2" +ftrack_label = "NukeX" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nukex.png' diff --git a/pype/configurations/defaults/launchers/nukex_11.2.toml b/pype/configurations/defaults/launchers/nukex_11.2.toml new file mode 100644 index 0000000000..3857b9995c --- /dev/null +++ b/pype/configurations/defaults/launchers/nukex_11.2.toml @@ -0,0 +1,7 @@ +executable = "nukex11.2" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "NukeX 11.2" +ftrack_label = "NukeX" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nukex.png' diff --git a/pype/configurations/defaults/launchers/nukex_11.3.toml b/pype/configurations/defaults/launchers/nukex_11.3.toml new file mode 100644 index 0000000000..56428470eb --- /dev/null +++ b/pype/configurations/defaults/launchers/nukex_11.3.toml @@ -0,0 +1,7 @@ +executable = "nukex11.3" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "NukeX 11.3" +ftrack_label = "NukeX" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nukex.png' diff --git a/pype/configurations/defaults/launchers/nukex_12.0.toml b/pype/configurations/defaults/launchers/nukex_12.0.toml new file mode 100644 index 0000000000..33d7fddb88 --- /dev/null +++ b/pype/configurations/defaults/launchers/nukex_12.0.toml @@ -0,0 +1,7 @@ +executable = "nukex12.0" +schema = "avalon-core:application-1.0" +application_dir = "nuke" +label = "NukeX 12.0" +ftrack_label = "NukeX" +icon ="nuke_icon" +ftrack_icon = '{}/app_icons/nukex.png' diff --git a/pype/configurations/defaults/launchers/photoshop_2020.toml b/pype/configurations/defaults/launchers/photoshop_2020.toml new file mode 100644 index 0000000000..117b668232 --- /dev/null +++ b/pype/configurations/defaults/launchers/photoshop_2020.toml @@ -0,0 +1,8 @@ +executable = "photoshop_2020" +schema = "avalon-core:application-1.0" +application_dir = "photoshop" +label = "Adobe Photoshop 2020" +icon ="photoshop_icon" +ftrack_label = "Photoshop" +ftrack_icon = '{}/app_icons/photoshop.png' +launch_hook = "pype/hooks/photoshop/prelaunch.py/PhotoshopPrelaunch" diff --git a/pype/configurations/defaults/launchers/premiere_2019.toml b/pype/configurations/defaults/launchers/premiere_2019.toml new file mode 100644 index 0000000000..f4c19c62cb --- /dev/null +++ b/pype/configurations/defaults/launchers/premiere_2019.toml @@ -0,0 +1,8 @@ +executable = "premiere_pro_2019" +schema = "avalon-core:application-1.0" +application_dir = "premiere" +label = "Adobe Premiere Pro CC 2019" +icon ="premiere_icon" + +ftrack_label = "Premiere" +ftrack_icon = '{}/app_icons/premiere.png' diff --git a/pype/configurations/defaults/launchers/premiere_2020.toml b/pype/configurations/defaults/launchers/premiere_2020.toml new file mode 100644 index 0000000000..4d721c898f --- /dev/null +++ b/pype/configurations/defaults/launchers/premiere_2020.toml @@ -0,0 +1,9 @@ +executable = "premiere_pro_2020" +schema = "avalon-core:application-1.0" +application_dir = "premiere" +label = "Adobe Premiere Pro CC 2020" +launch_hook = "pype/hooks/premiere/prelaunch.py/PremierePrelaunch" +icon ="premiere_icon" + +ftrack_label = "Premiere" +ftrack_icon = '{}/app_icons/premiere.png' diff --git a/pype/configurations/defaults/launchers/python_2.toml b/pype/configurations/defaults/launchers/python_2.toml new file mode 100644 index 0000000000..e9e8dd7899 --- /dev/null +++ b/pype/configurations/defaults/launchers/python_2.toml @@ -0,0 +1,10 @@ +schema = "avalon-core:application-1.0" +application_dir = "python" +executable = "python" +label = "Python 2" +ftrack_label = "Python" +icon ="python_icon" +ftrack_icon = '{}/app_icons/python.png' + +[environment] +CREATE_NEW_CONSOLE = "Yes" diff --git a/pype/configurations/defaults/launchers/python_3.toml b/pype/configurations/defaults/launchers/python_3.toml new file mode 100644 index 0000000000..5cbd8b2943 --- /dev/null +++ b/pype/configurations/defaults/launchers/python_3.toml @@ -0,0 +1,10 @@ +schema = "avalon-core:application-1.0" +application_dir = "python" +executable = "python3" +label = "Python 3" +ftrack_label = "Python" +icon ="python_icon" +ftrack_icon = '{}/app_icons/python.png' + +[environment] +CREATE_NEW_CONSOLE = "Yes" diff --git a/pype/configurations/defaults/launchers/resolve_16.toml b/pype/configurations/defaults/launchers/resolve_16.toml new file mode 100644 index 0000000000..430fd1a638 --- /dev/null +++ b/pype/configurations/defaults/launchers/resolve_16.toml @@ -0,0 +1,9 @@ +executable = "resolve_16" +schema = "avalon-core:application-1.0" +application_dir = "resolve" +label = "BM DaVinci Resolve 16" +launch_hook = "pype/hooks/resolve/prelaunch.py/ResolvePrelaunch" +icon ="resolve" + +ftrack_label = "BM DaVinci Resolve" +ftrack_icon = '{}/app_icons/resolve.png' diff --git a/pype/configurations/defaults/launchers/shell.toml b/pype/configurations/defaults/launchers/shell.toml new file mode 100644 index 0000000000..959ad392ea --- /dev/null +++ b/pype/configurations/defaults/launchers/shell.toml @@ -0,0 +1,7 @@ +schema = "avalon-core:application-1.0" +application_dir = "shell" +executable = "shell" +label = "Shell" + +[environment] +CREATE_NEW_CONSOLE = "Yes" \ No newline at end of file diff --git a/pype/configurations/defaults/launchers/storyboardpro_7.toml b/pype/configurations/defaults/launchers/storyboardpro_7.toml new file mode 100644 index 0000000000..ce8e96a49d --- /dev/null +++ b/pype/configurations/defaults/launchers/storyboardpro_7.toml @@ -0,0 +1,8 @@ +application_dir = "storyboardpro" +label = "Storyboard Pro 7" +ftrack_label = "Storyboard Pro" +schema = "avalon-core:application-1.0" +executable = "storyboardpro_7" +description = "" +icon ="storyboardpro_icon" +ftrack_icon = '{}/app_icons/storyboardpro.png' diff --git a/pype/configurations/defaults/launchers/unreal_4.24.toml b/pype/configurations/defaults/launchers/unreal_4.24.toml new file mode 100644 index 0000000000..0a799e5dcb --- /dev/null +++ b/pype/configurations/defaults/launchers/unreal_4.24.toml @@ -0,0 +1,8 @@ +executable = "unreal" +schema = "avalon-core:application-1.0" +application_dir = "unreal" +label = "Unreal Editor 4.24" +ftrack_label = "UnrealEditor" +icon ="ue4_icon" +launch_hook = "pype/hooks/unreal/unreal_prelaunch.py/UnrealPrelaunch" +ftrack_icon = '{}/app_icons/ue4.png' diff --git a/pype/configurations/defaults/launchers/windows/blender_2.80.bat b/pype/configurations/defaults/launchers/windows/blender_2.80.bat new file mode 100644 index 0000000000..5b8a37356b --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/blender_2.80.bat @@ -0,0 +1,11 @@ +set __app__="Blender" +set __exe__="C:\Program Files\Blender Foundation\Blender 2.80\blender.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/blender_2.81.bat b/pype/configurations/defaults/launchers/windows/blender_2.81.bat new file mode 100644 index 0000000000..a900b18eda --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/blender_2.81.bat @@ -0,0 +1,11 @@ +set __app__="Blender" +set __exe__="C:\Program Files\Blender Foundation\Blender 2.81\blender.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/blender_2.82.bat b/pype/configurations/defaults/launchers/windows/blender_2.82.bat new file mode 100644 index 0000000000..7105c1efe1 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/blender_2.82.bat @@ -0,0 +1,11 @@ +set __app__="Blender" +set __exe__="C:\Program Files\Blender Foundation\Blender 2.82\blender.exe" --python-use-system-env +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/blender_2.83.bat b/pype/configurations/defaults/launchers/windows/blender_2.83.bat new file mode 100644 index 0000000000..671952f0d7 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/blender_2.83.bat @@ -0,0 +1,11 @@ +set __app__="Blender" +set __exe__="C:\Program Files\Blender Foundation\Blender 2.83\blender.exe" --python-use-system-env +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/celaction_local.bat b/pype/configurations/defaults/launchers/windows/celaction_local.bat new file mode 100644 index 0000000000..8f2171617e --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/celaction_local.bat @@ -0,0 +1,19 @@ +set __app__="CelAction2D" +set __app_dir__="C:\Program Files (x86)\CelAction\" +set __exe__="C:\Program Files (x86)\CelAction\CelAction2D.exe" + +if not exist %__exe__% goto :missing_app + +pushd %__app_dir__% + +if "%PYPE_CELACTION_PROJECT_FILE%"=="" ( + start %__app__% %__exe__% %* +) else ( + start %__app__% %__exe__% "%PYPE_CELACTION_PROJECT_FILE%" %* +) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/celaction_publish.bat b/pype/configurations/defaults/launchers/windows/celaction_publish.bat new file mode 100644 index 0000000000..77ec2ac24e --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/celaction_publish.bat @@ -0,0 +1,3 @@ +echo %* + +%PYPE_PYTHON_EXE% "%PYPE_MODULE_ROOT%\pype\hosts\celaction\cli.py" %* diff --git a/pype/configurations/defaults/launchers/windows/harmony_17.bat b/pype/configurations/defaults/launchers/windows/harmony_17.bat new file mode 100644 index 0000000000..0822650875 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/harmony_17.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Harmony 17" +set __exe__="C:/Program Files (x86)/Toon Boom Animation/Toon Boom Harmony 17 Premium/win64/bin/HarmonyPremium.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% cmd.exe /k "python -c ^"import avalon.harmony;avalon.harmony.launch("%__exe__%")^"" + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/houdini_16.bat b/pype/configurations/defaults/launchers/windows/houdini_16.bat new file mode 100644 index 0000000000..018ba08b4c --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/houdini_16.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Houdini 16.0" +set __exe__="C:\Program Files\Side Effects Software\Houdini 16.0.621\bin\houdini.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/houdini_17.bat b/pype/configurations/defaults/launchers/windows/houdini_17.bat new file mode 100644 index 0000000000..950a599623 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/houdini_17.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Houdini 17.0" +set __exe__="C:\Program Files\Side Effects Software\Houdini 17.0.459\bin\houdini.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/houdini_18.bat b/pype/configurations/defaults/launchers/windows/houdini_18.bat new file mode 100644 index 0000000000..3d6b1ae258 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/houdini_18.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Houdini 18.0" +set __exe__="C:\Program Files\Side Effects Software\Houdini 18.0.287\bin\houdini.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/maya2016.bat b/pype/configurations/defaults/launchers/windows/maya2016.bat new file mode 100644 index 0000000000..54f15cf269 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/maya2016.bat @@ -0,0 +1,17 @@ +@echo off + +set __app__="Maya 2016" +set __exe__="C:\Program Files\Autodesk\Maya2016\bin\maya.exe" +if not exist %__exe__% goto :missing_app + +if "%AVALON_LAST_WORKFILE%"=="" ( + start %__app__% %__exe__% %* +) else ( + start %__app__% %__exe__% -file "%AVALON_LAST_WORKFILE%" %* +) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/maya2017.bat b/pype/configurations/defaults/launchers/windows/maya2017.bat new file mode 100644 index 0000000000..5c2aeb495c --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/maya2017.bat @@ -0,0 +1,17 @@ +@echo off + +set __app__="Maya 2017" +set __exe__="C:\Program Files\Autodesk\Maya2017\bin\maya.exe" +if not exist %__exe__% goto :missing_app + +if "%AVALON_LAST_WORKFILE%"=="" ( + start %__app__% %__exe__% %* +) else ( + start %__app__% %__exe__% -file "%AVALON_LAST_WORKFILE%" %* +) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/maya2018.bat b/pype/configurations/defaults/launchers/windows/maya2018.bat new file mode 100644 index 0000000000..28cf776c77 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/maya2018.bat @@ -0,0 +1,17 @@ +@echo off + +set __app__="Maya 2018" +set __exe__="C:\Program Files\Autodesk\Maya2018\bin\maya.exe" +if not exist %__exe__% goto :missing_app + +if "%AVALON_LAST_WORKFILE%"=="" ( + start %__app__% %__exe__% %* +) else ( + start %__app__% %__exe__% -file "%AVALON_LAST_WORKFILE%" %* +) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/maya2019.bat b/pype/configurations/defaults/launchers/windows/maya2019.bat new file mode 100644 index 0000000000..7e80dd2557 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/maya2019.bat @@ -0,0 +1,17 @@ +@echo off + +set __app__="Maya 2019" +set __exe__="C:\Program Files\Autodesk\Maya2019\bin\maya.exe" +if not exist %__exe__% goto :missing_app + +if "%AVALON_LAST_WORKFILE%"=="" ( + start %__app__% %__exe__% %* +) else ( + start %__app__% %__exe__% -file "%AVALON_LAST_WORKFILE%" %* +) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/maya2020.bat b/pype/configurations/defaults/launchers/windows/maya2020.bat new file mode 100644 index 0000000000..b2acb5df5a --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/maya2020.bat @@ -0,0 +1,17 @@ +@echo off + +set __app__="Maya 2020" +set __exe__="C:\Program Files\Autodesk\maya2020\bin\maya.exe" +if not exist %__exe__% goto :missing_app + +if "%AVALON_LAST_WORKFILE%"=="" ( + start %__app__% %__exe__% %* +) else ( + start %__app__% %__exe__% -file "%AVALON_LAST_WORKFILE%" %* +) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayabatch2019.bat b/pype/configurations/defaults/launchers/windows/mayabatch2019.bat new file mode 100644 index 0000000000..ddd9b9b956 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayabatch2019.bat @@ -0,0 +1,14 @@ +@echo off + +set __app__="Maya Batch 2019" +set __exe__="C:\Program Files\Autodesk\Maya2019\bin\mayabatch.exe" +if not exist %__exe__% goto :missing_app + +echo "running maya : %*" +%__exe__% %* +echo "done." +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayabatch2020.bat b/pype/configurations/defaults/launchers/windows/mayabatch2020.bat new file mode 100644 index 0000000000..b1cbc6dbb6 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayabatch2020.bat @@ -0,0 +1,14 @@ +@echo off + +set __app__="Maya Batch 2020" +set __exe__="C:\Program Files\Autodesk\Maya2020\bin\mayabatch.exe" +if not exist %__exe__% goto :missing_app + +echo "running maya : %*" +%__exe__% %* +echo "done." +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayapy2016.bat b/pype/configurations/defaults/launchers/windows/mayapy2016.bat new file mode 100644 index 0000000000..205991fd3d --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayapy2016.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Mayapy 2016" +set __exe__="C:\Program Files\Autodesk\Maya2016\bin\mayapy.exe" +if not exist %__exe__% goto :missing_app + +call %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found at %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayapy2017.bat b/pype/configurations/defaults/launchers/windows/mayapy2017.bat new file mode 100644 index 0000000000..14aacc5a7f --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayapy2017.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Mayapy 2017" +set __exe__="C:\Program Files\Autodesk\Maya2017\bin\mayapy.exe" +if not exist %__exe__% goto :missing_app + +call %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found at %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayapy2018.bat b/pype/configurations/defaults/launchers/windows/mayapy2018.bat new file mode 100644 index 0000000000..c47c472f46 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayapy2018.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Mayapy 2018" +set __exe__="C:\Program Files\Autodesk\Maya2018\bin\mayapy.exe" +if not exist %__exe__% goto :missing_app + +call %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found at %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayapy2019.bat b/pype/configurations/defaults/launchers/windows/mayapy2019.bat new file mode 100644 index 0000000000..73ca5b2d40 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayapy2019.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Mayapy 2019" +set __exe__="C:\Program Files\Autodesk\Maya2019\bin\mayapy.exe" +if not exist %__exe__% goto :missing_app + +call %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found at %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/mayapy2020.bat b/pype/configurations/defaults/launchers/windows/mayapy2020.bat new file mode 100644 index 0000000000..770a03dcf5 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/mayapy2020.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Mayapy 2020" +set __exe__="C:\Program Files\Autodesk\Maya2020\bin\mayapy.exe" +if not exist %__exe__% goto :missing_app + +call %__exe__% %* + +goto :eofS + +:missing_app + echo ERROR: %__app__% not found at %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nuke10.0.bat b/pype/configurations/defaults/launchers/windows/nuke10.0.bat new file mode 100644 index 0000000000..a47cbdfb20 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nuke10.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Nuke10.0v4" +set __exe__="C:\Program Files\Nuke10.0v4\Nuke10.0.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nuke11.0.bat b/pype/configurations/defaults/launchers/windows/nuke11.0.bat new file mode 100644 index 0000000000..a374c5cf5b --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nuke11.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Nuke11.0v4" +set __exe__="C:\Program Files\Nuke11.0v4\Nuke11.0.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nuke11.2.bat b/pype/configurations/defaults/launchers/windows/nuke11.2.bat new file mode 100644 index 0000000000..4c777ac28c --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nuke11.2.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Nuke11.2v3" +set __exe__="C:\Program Files\Nuke11.2v3\Nuke11.2.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nuke11.3.bat b/pype/configurations/defaults/launchers/windows/nuke11.3.bat new file mode 100644 index 0000000000..a023f5f46f --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nuke11.3.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Nuke11.3v1" +set __exe__="C:\Program Files\Nuke11.3v1\Nuke11.3.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nuke12.0.bat b/pype/configurations/defaults/launchers/windows/nuke12.0.bat new file mode 100644 index 0000000000..d8fb5772bb --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nuke12.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Nuke12.0v1" +set __exe__="C:\Program Files\Nuke12.0v1\Nuke12.0.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukestudio10.0.bat b/pype/configurations/defaults/launchers/windows/nukestudio10.0.bat new file mode 100644 index 0000000000..82f833667c --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukestudio10.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeStudio10.0v4" +set __exe__="C:\Program Files\Nuke10.0v4\Nuke10.0.exe" --studio +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukestudio11.0.bat b/pype/configurations/defaults/launchers/windows/nukestudio11.0.bat new file mode 100644 index 0000000000..b66797727e --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukestudio11.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeStudio11.0v4" +set __exe__="C:\Program Files\Nuke11.0v4\Nuke11.0.exe" -studio +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukestudio11.2.bat b/pype/configurations/defaults/launchers/windows/nukestudio11.2.bat new file mode 100644 index 0000000000..a653d816b4 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukestudio11.2.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeStudio11.2v3" +set __exe__="C:\Program Files\Nuke11.2v3\Nuke11.2.exe" -studio +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukestudio11.3.bat b/pype/configurations/defaults/launchers/windows/nukestudio11.3.bat new file mode 100644 index 0000000000..62c8718873 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukestudio11.3.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeStudio11.3v1" +set __exe__="C:\Program Files\Nuke11.3v1\Nuke11.3.exe" --studio +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukestudio12.0.bat b/pype/configurations/defaults/launchers/windows/nukestudio12.0.bat new file mode 100644 index 0000000000..488232bcbf --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukestudio12.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeStudio12.0v1" +set __exe__="C:\Program Files\Nuke12.0v1\Nuke12.0.exe" --studio +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukex10.0.bat b/pype/configurations/defaults/launchers/windows/nukex10.0.bat new file mode 100644 index 0000000000..1759706a7b --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukex10.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeX10.0v4" +set __exe__="C:\Program Files\Nuke10.0v4\Nuke10.0.exe" -nukex +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukex11.0.bat b/pype/configurations/defaults/launchers/windows/nukex11.0.bat new file mode 100644 index 0000000000..b554a7b6fa --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukex11.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeX11.0v4" +set __exe__="C:\Program Files\Nuke11.0v4\Nuke11.0.exe" --nukex +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukex11.2.bat b/pype/configurations/defaults/launchers/windows/nukex11.2.bat new file mode 100644 index 0000000000..a4cb5dec5c --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukex11.2.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeX11.2v3" +set __exe__="C:\Program Files\Nuke11.2v3\Nuke11.2.exe" --nukex +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukex11.3.bat b/pype/configurations/defaults/launchers/windows/nukex11.3.bat new file mode 100644 index 0000000000..490b55cf4c --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukex11.3.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeX11.3v1" +set __exe__="C:\Program Files\Nuke11.3v1\Nuke11.3.exe" --nukex +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/nukex12.0.bat b/pype/configurations/defaults/launchers/windows/nukex12.0.bat new file mode 100644 index 0000000000..26adf0d3f1 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/nukex12.0.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="NukeX12.0v1" +set __exe__="C:\Program Files\Nuke12.0v1\Nuke12.0.exe" --nukex +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/photoshop_2020.bat b/pype/configurations/defaults/launchers/windows/photoshop_2020.bat new file mode 100644 index 0000000000..6b90922ef6 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/photoshop_2020.bat @@ -0,0 +1,15 @@ +@echo off + +set __app__="Photoshop 2020" +set __exe__="C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% cmd.exe /k "%PYPE_PYTHON_EXE% -c ^"import avalon.photoshop;avalon.photoshop.launch("%__exe__%")^"" + +goto :eof + +pause + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/premiere_pro_2019.bat b/pype/configurations/defaults/launchers/windows/premiere_pro_2019.bat new file mode 100644 index 0000000000..4886737d2f --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/premiere_pro_2019.bat @@ -0,0 +1,14 @@ +@echo off + +set __app__="Adobe Premiere Pro" +set __exe__="C:\Program Files\Adobe\Adobe Premiere Pro CC 2019\Adobe Premiere Pro.exe" +if not exist %__exe__% goto :missing_app + +python -u %PREMIERA_PATH%\init.py +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/premiere_pro_2020.bat b/pype/configurations/defaults/launchers/windows/premiere_pro_2020.bat new file mode 100644 index 0000000000..14662d3be3 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/premiere_pro_2020.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Adobe Premiere Pro" +set __exe__="C:\Program Files\Adobe\Adobe Premiere Pro 2020\Adobe Premiere Pro.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/python3.bat b/pype/configurations/defaults/launchers/windows/python3.bat new file mode 100644 index 0000000000..c7c116fe72 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/python3.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Python36" +set __exe__="C:\Python36\python.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/resolve_16.bat b/pype/configurations/defaults/launchers/windows/resolve_16.bat new file mode 100644 index 0000000000..1a5d964e6b --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/resolve_16.bat @@ -0,0 +1,17 @@ +@echo off + +set __app__="Resolve" +set __appy__="Resolve Python Console" +set __exe__="C:/Program Files/Blackmagic Design/DaVinci Resolve/Resolve.exe" +set __py__="%PYTHON36_RESOLVE%/python.exe" + +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %* +IF "%RESOLVE_DEV%"=="True" (start %__appy__% %__py__% -i %PRE_PYTHON_SCRIPT%) + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/shell.bat b/pype/configurations/defaults/launchers/windows/shell.bat new file mode 100644 index 0000000000..eb0895364f --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/shell.bat @@ -0,0 +1,2 @@ +@echo off +start cmd diff --git a/pype/configurations/defaults/launchers/windows/storyboardpro_7.bat b/pype/configurations/defaults/launchers/windows/storyboardpro_7.bat new file mode 100644 index 0000000000..122edac572 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/storyboardpro_7.bat @@ -0,0 +1,13 @@ +@echo off + +set __app__="Storyboard Pro 7" +set __exe__="C:/Program Files (x86)/Toon Boom Animation/Toon Boom Storyboard Pro 7/win64/bin/StoryboardPro.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% cmd.exe /k "python -c ^"import avalon.storyboardpro;avalon.storyboardpro.launch("%__exe__%")^"" + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/launchers/windows/unreal.bat b/pype/configurations/defaults/launchers/windows/unreal.bat new file mode 100644 index 0000000000..7771aaa5a5 --- /dev/null +++ b/pype/configurations/defaults/launchers/windows/unreal.bat @@ -0,0 +1,11 @@ +set __app__="Unreal Editor" +set __exe__="%AVALON_CURRENT_UNREAL_ENGINE%\Engine\Binaries\Win64\UE4Editor.exe" +if not exist %__exe__% goto :missing_app + +start %__app__% %__exe__% %PYPE_UNREAL_PROJECT_FILE% %* + +goto :eof + +:missing_app + echo ERROR: %__app__% not found in %__exe__% + exit /B 1 diff --git a/pype/configurations/defaults/presets/colorspace/aces103-cg.json b/pype/configurations/defaults/presets/colorspace/aces103-cg.json new file mode 100644 index 0000000000..dd3fca4c2d --- /dev/null +++ b/pype/configurations/defaults/presets/colorspace/aces103-cg.json @@ -0,0 +1,46 @@ +{ + "resolve": { + + }, + "nukestudio": { + + }, + "nuke": { + "root": { + "colorManagement": "OCIO", + "OCIO_config": "aces_1.0.3", + "workingSpaceLUT": "ACES - ACEScg", + "defaultViewerLUT": "OCIO LUTs", + "monitorLut": "ACES/sRGB", + "int8Lut": "Utility - sRGB - Texture", + "int16Lut": "Utility - sRGB - Texture", + "logLut": "Input - ADX - ADX10", + "floatLut": "ACES - ACES2065-1" + }, + "viewer": { + "viewerProcess": "sRGB (ACES)" + }, + "write": { + "render": { + "colorspace": "ACES - ACES2065-1" + }, + "prerender": { + "colorspace": "ACES - ACES2065-1" + }, + "still": { + "colorspace": "Utility - Curve - sRGB" + } + }, + "read": { + "[^-a-zA-Z0-9](beauty)[^-a-zA-Z0-9]": "lin_srgb", + "[^-a-zA-Z0-9](P|N|Z|crypto)[^-a-zA-Z0-9]": "raw", + "[^-a-zA-Z0-9](plateRef)[^-a-zA-Z0-9]": "crv_srgb" + } + }, + "maya": { + + }, + "houdini": { + + } +} diff --git a/pype/configurations/defaults/presets/colorspace/default.json b/pype/configurations/defaults/presets/colorspace/default.json new file mode 100644 index 0000000000..8b934f810d --- /dev/null +++ b/pype/configurations/defaults/presets/colorspace/default.json @@ -0,0 +1,42 @@ +{ + "nuke": { + "root": { + "colorManagement": "Nuke", + "OCIO_config": "nuke-default", + "defaultViewerLUT": "Nuke Root LUTs", + "monitorLut": "sRGB", + "int8Lut": "sRGB", + "int16Lut": "sRGB", + "logLut": "Cineon", + "floatLut": "linear" + }, + "viewer": { + "viewerProcess": "sRGB" + }, + "write": { + "render": { + "colorspace": "linear" + }, + "prerender": { + "colorspace": "linear" + }, + "still": { + "colorspace": "sRGB" + } + }, + "read": { + "[^-a-zA-Z0-9]beauty[^-a-zA-Z0-9]": "linear", + "[^-a-zA-Z0-9](P|N|Z|crypto)[^-a-zA-Z0-9]": "linear", + "[^-a-zA-Z0-9](plateRef)[^-a-zA-Z0-9]": "sRGB" + } + }, + "maya": { + + }, + "houdini": { + + }, + "resolve": { + + } +} diff --git a/pype/configurations/defaults/presets/dataflow/aces-exr.json b/pype/configurations/defaults/presets/dataflow/aces-exr.json new file mode 100644 index 0000000000..75846c0bd6 --- /dev/null +++ b/pype/configurations/defaults/presets/dataflow/aces-exr.json @@ -0,0 +1,58 @@ +{ + "nuke": { + "nodes": { + "connected": true, + "modifymetadata": { + "_id": "connect_metadata", + "_previous": "ENDING", + "metadata.set.pype_studio_name": "{PYPE_STUDIO_NAME}", + "metadata.set.avalon_project_name": "{AVALON_PROJECT}", + "metadata.set.avalon_project_code": "{PYPE_STUDIO_CODE}", + "metadata.set.avalon_asset_name": "{AVALON_ASSET}" + }, + "crop": { + "_id": "connect_crop", + "_previous": "connect_metadata", + "box": [ + "{metadata.crop.x}", + "{metadata.crop.y}", + "{metadata.crop.right}", + "{metadata.crop.top}" + ] + }, + "write": { + "render": { + "_id": "output_write", + "_previous": "connect_crop", + "file_type": "exr", + "datatype": "16 bit half", + "compression": "Zip (1 scanline)", + "create_directories": true, + "autocrop": true, + "tile_color": "0xff0000ff", + "channels": "rgb" + }, + "prerender": { + "_id": "output_write", + "_previous": "connect_crop", + "file_type": "exr", + "datatype": "16 bit half", + "compression": "Zip (1 scanline)", + "create_directories": true, + "autocrop": false, + "tile_color": "0xc9892aff", + "channels": "rgba" + }, + "still": { + "_previous": "connect_crop", + "channels": "rgba", + "file_type": "tiff", + "datatype": "16 bit", + "compression": "LZW", + "create_directories": true, + "tile_color": "0x4145afff" + } + } + } + } +} diff --git a/pype/configurations/defaults/presets/dataflow/default.json b/pype/configurations/defaults/presets/dataflow/default.json new file mode 100644 index 0000000000..d2f470b5bc --- /dev/null +++ b/pype/configurations/defaults/presets/dataflow/default.json @@ -0,0 +1,55 @@ +{ + "nuke": { + "nodes": { + "connected": true, + "modifymetadata": { + "_id": "connect_metadata", + "_previous": "ENDING", + "metadata.set.pype_studio_name": "{PYPE_STUDIO_NAME}", + "metadata.set.avalon_project_name": "{AVALON_PROJECT}", + "metadata.set.avalon_project_code": "{PYPE_STUDIO_CODE}", + "metadata.set.avalon_asset_name": "{AVALON_ASSET}" + }, + "crop": { + "_id": "connect_crop", + "_previous": "connect_metadata", + "box": [ + "{metadata.crop.x}", + "{metadata.crop.y}", + "{metadata.crop.right}", + "{metadata.crop.top}" + ] + }, + "write": { + "render": { + "_id": "output_write", + "_previous": "connect_crop", + "file_type": "exr", + "datatype": "16 bit half", + "compression": "Zip (1 scanline)", + "autocrop": true, + "tile_color": "0xff0000ff", + "channels": "rgb" + }, + "prerender": { + "_id": "output_write", + "_previous": "connect_crop", + "file_type": "exr", + "datatype": "16 bit half", + "compression": "Zip (1 scanline)", + "autocrop": false, + "tile_color": "0xc9892aff", + "channels": "rgba" + }, + "still": { + "_previous": "connect_crop", + "channels": "rgba", + "file_type": "tiff", + "datatype": "16 bit", + "compression": "LZW", + "tile_color": "0x4145afff" + } + } + } + } +} diff --git a/pype/configurations/defaults/presets/ftrack/ftrack_config.json b/pype/configurations/defaults/presets/ftrack/ftrack_config.json new file mode 100644 index 0000000000..1ef3a9d69f --- /dev/null +++ b/pype/configurations/defaults/presets/ftrack/ftrack_config.json @@ -0,0 +1,16 @@ +{ + "sync_to_avalon": { + "statuses_name_change": ["not ready", "ready"] + }, + + "status_update": { + "_ignore_": ["in progress", "ommited", "on hold"], + "Ready": ["not ready"], + "In Progress" : ["_any_"] + }, + "status_version_to_task": { + "__description__": "Status `from` (key) must be lowered!", + "in progress": "in progress", + "approved": "approved" + } +} diff --git a/pype/configurations/defaults/presets/ftrack/ftrack_custom_attributes.json b/pype/configurations/defaults/presets/ftrack/ftrack_custom_attributes.json new file mode 100644 index 0000000000..f03d473cd0 --- /dev/null +++ b/pype/configurations/defaults/presets/ftrack/ftrack_custom_attributes.json @@ -0,0 +1,165 @@ +[{ + "label": "FPS", + "key": "fps", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "write_security_role": ["ALL"], + "read_security_role": ["ALL"], + "default": null, + "config": { + "isdecimal": true + } +}, { + "label": "Applications", + "key": "applications", + "type": "enumerator", + "entity_type": "show", + "group": "avalon", + "config": { + "multiselect": true, + "data": [ + {"blender_2.80": "Blender 2.80"}, + {"blender_2.81": "Blender 2.81"}, + {"blender_2.82": "Blender 2.82"}, + {"blender_2.83": "Blender 2.83"}, + {"celaction_local": "CelAction2D Local"}, + {"maya_2017": "Maya 2017"}, + {"maya_2018": "Maya 2018"}, + {"maya_2019": "Maya 2019"}, + {"nuke_10.0": "Nuke 10.0"}, + {"nuke_11.2": "Nuke 11.2"}, + {"nuke_11.3": "Nuke 11.3"}, + {"nuke_12.0": "Nuke 12.0"}, + {"nukex_10.0": "NukeX 10.0"}, + {"nukex_11.2": "NukeX 11.2"}, + {"nukex_11.3": "NukeX 11.3"}, + {"nukex_12.0": "NukeX 12.0"}, + {"nukestudio_10.0": "NukeStudio 10.0"}, + {"nukestudio_11.2": "NukeStudio 11.2"}, + {"nukestudio_11.3": "NukeStudio 11.3"}, + {"nukestudio_12.0": "NukeStudio 12.0"}, + {"harmony_17": "Harmony 17"}, + {"houdini_16.5": "Houdini 16.5"}, + {"houdini_17": "Houdini 17"}, + {"houdini_18": "Houdini 18"}, + {"photoshop_2020": "Photoshop 2020"}, + {"python_3": "Python 3"}, + {"python_2": "Python 2"}, + {"premiere_2019": "Premiere Pro 2019"}, + {"premiere_2020": "Premiere Pro 2020"}, + {"resolve_16": "BM DaVinci Resolve 16"} + ] + } +}, { + "label": "Avalon auto-sync", + "key": "avalon_auto_sync", + "type": "boolean", + "entity_type": "show", + "group": "avalon", + "write_security_role": ["API", "Administrator"], + "read_security_role": ["API", "Administrator"] +}, { + "label": "Intent", + "key": "intent", + "type": "enumerator", + "entity_type": "assetversion", + "group": "avalon", + "config": { + "multiselect": false, + "data": [ + {"test": "Test"}, + {"wip": "WIP"}, + {"final": "Final"} + ] + } +}, { + "label": "Library Project", + "key": "library_project", + "type": "boolean", + "entity_type": "show", + "group": "avalon", + "write_security_role": ["API", "Administrator"], + "read_security_role": ["API", "Administrator"] +}, { + "label": "Clip in", + "key": "clipIn", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Clip out", + "key": "clipOut", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Frame start", + "key": "frameStart", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Frame end", + "key": "frameEnd", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Tools", + "key": "tools_env", + "type": "enumerator", + "is_hierarchical": true, + "group": "avalon", + "config": { + "multiselect": true, + "data": [ + {"mtoa_3.0.1": "mtoa_3.0.1"}, + {"mtoa_3.1.1": "mtoa_3.1.1"}, + {"mtoa_3.2.0": "mtoa_3.2.0"}, + {"yeti_2.1.2": "yeti_2.1"} + ] + } +}, { + "label": "Resolution Width", + "key": "resolutionWidth", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Resolution Height", + "key": "resolutionHeight", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Pixel aspect", + "key": "pixelAspect", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "config": { + "isdecimal": true + } +}, { + "label": "Frame handles start", + "key": "handleStart", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +}, { + "label": "Frame handles end", + "key": "handleEnd", + "type": "number", + "is_hierarchical": true, + "group": "avalon", + "default": null +} +] diff --git a/pype/configurations/defaults/presets/ftrack/partnership_ftrack_cred.json b/pype/configurations/defaults/presets/ftrack/partnership_ftrack_cred.json new file mode 100644 index 0000000000..6b3a32f181 --- /dev/null +++ b/pype/configurations/defaults/presets/ftrack/partnership_ftrack_cred.json @@ -0,0 +1,5 @@ +{ + "server_url": "", + "api_key": "", + "api_user": "" +} diff --git a/pype/configurations/defaults/presets/ftrack/plugins/server.json b/pype/configurations/defaults/presets/ftrack/plugins/server.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/presets/ftrack/plugins/server.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/presets/ftrack/plugins/user.json b/pype/configurations/defaults/presets/ftrack/plugins/user.json new file mode 100644 index 0000000000..1ba8e9b511 --- /dev/null +++ b/pype/configurations/defaults/presets/ftrack/plugins/user.json @@ -0,0 +1,5 @@ +{ + "TestAction": { + "ignore_me": true + } +} diff --git a/pype/configurations/defaults/presets/ftrack/project_defaults.json b/pype/configurations/defaults/presets/ftrack/project_defaults.json new file mode 100644 index 0000000000..a4e3aa3362 --- /dev/null +++ b/pype/configurations/defaults/presets/ftrack/project_defaults.json @@ -0,0 +1,18 @@ +{ + "fps": 25, + "frameStart": 1001, + "frameEnd": 1100, + "clipIn": 1001, + "clipOut": 1100, + "handleStart": 10, + "handleEnd": 10, + + "resolutionHeight": 1080, + "resolutionWidth": 1920, + "pixelAspect": 1.0, + "applications": [ + "maya_2019", "nuke_11.3", "nukex_11.3", "nukestudio_11.3", "deadline" + ], + "tools_env": [], + "avalon_auto_sync": true +} diff --git a/pype/configurations/defaults/presets/init.json b/pype/configurations/defaults/presets/init.json new file mode 100644 index 0000000000..361ee7445b --- /dev/null +++ b/pype/configurations/defaults/presets/init.json @@ -0,0 +1,4 @@ +{ + "colorspace": "default", + "dataflow": "default" +} diff --git a/pype/configurations/defaults/presets/maya/capture.json b/pype/configurations/defaults/presets/maya/capture.json new file mode 100644 index 0000000000..b6c4893034 --- /dev/null +++ b/pype/configurations/defaults/presets/maya/capture.json @@ -0,0 +1,108 @@ +{ + "Codec": { + "compression": "jpg", + "format": "image", + "quality": 95 + }, + "Display Options": { + "background": [ + 0.7137254901960784, + 0.7137254901960784, + 0.7137254901960784 + ], + "backgroundBottom": [ + 0.7137254901960784, + 0.7137254901960784, + 0.7137254901960784 + ], + "backgroundTop": [ + 0.7137254901960784, + 0.7137254901960784, + 0.7137254901960784 + ], + "override_display": true + }, + "Generic": { + "isolate_view": true, + "off_screen": true + }, + "IO": { + "name": "", + "open_finished": false, + "raw_frame_numbers": false, + "recent_playblasts": [], + "save_file": false + }, + "PanZoom": { + "pan_zoom": true + }, + "Renderer": { + "rendererName": "vp2Renderer" + }, + "Resolution": { + "height": 1080, + "mode": "Custom", + "percent": 1.0, + "width": 1920 + }, + "Time Range": { + "end_frame": 25, + "frame": "", + "start_frame": 0, + "time": "Time Slider" + }, + "Viewport Options": { + "cameras": false, + "clipGhosts": false, + "controlVertices": false, + "deformers": false, + "dimensions": false, + "displayLights": 0, + "dynamicConstraints": false, + "dynamics": false, + "fluids": false, + "follicles": false, + "gpuCacheDisplayFilter": false, + "greasePencils": false, + "grid": false, + "hairSystems": false, + "handles": false, + "high_quality": true, + "hud": false, + "hulls": false, + "ikHandles": false, + "imagePlane": false, + "joints": false, + "lights": false, + "locators": false, + "manipulators": false, + "motionTrails": false, + "nCloths": false, + "nParticles": false, + "nRigids": false, + "nurbsCurves": false, + "nurbsSurfaces": false, + "override_viewport_options": true, + "particleInstancers": false, + "pivots": false, + "planes": false, + "pluginShapes": false, + "polymeshes": true, + "shadows": false, + "strokes": false, + "subdivSurfaces": false, + "textures": false, + "twoSidedLighting": true + }, + "Camera Options": { + "displayGateMask": false, + "displayResolution": false, + "displayFilmGate": false, + "displayFieldChart": false, + "displaySafeAction": false, + "displaySafeTitle": false, + "displayFilmPivot": false, + "displayFilmOrigin": false, + "overscan": 1.0 + } +} diff --git a/pype/configurations/defaults/presets/muster/templates_mapping.json b/pype/configurations/defaults/presets/muster/templates_mapping.json new file mode 100644 index 0000000000..4edab9077d --- /dev/null +++ b/pype/configurations/defaults/presets/muster/templates_mapping.json @@ -0,0 +1,19 @@ +{ + "3delight": 41, + "arnold": 46, + "arnold_sf": 57, + "gelato": 30, + "harware": 3, + "krakatoa": 51, + "file_layers": 7, + "mentalray": 2, + "mentalray_sf": 6, + "redshift": 55, + "renderman": 29, + "software": 1, + "software_sf": 5, + "turtle": 10, + "vector": 4, + "vray": 37, + "ffmpeg": 48 +} diff --git a/pype/configurations/defaults/presets/nukestudio/tags.json b/pype/configurations/defaults/presets/nukestudio/tags.json new file mode 100644 index 0000000000..56fcfcbce9 --- /dev/null +++ b/pype/configurations/defaults/presets/nukestudio/tags.json @@ -0,0 +1,262 @@ +{ + "Hierarchy": { + "editable": "1", + "note": "{folder}/{sequence}/{shot}", + "icon": { + "path": "hierarchy.png" + }, + "metadata": { + "folder": "FOLDER_NAME", + "shot": "{clip}", + "track": "{track}", + "sequence": "{sequence}", + "episode": "EPISODE_NAME", + "root": "{projectroot}" + } + }, + "Source Resolution": { + "editable": "1", + "note": "Use source resolution", + "icon": { + "path": "resolution.png" + }, + "metadata": { + "family": "resolution" + } + }, + "Retiming": { + "editable": "1", + "note": "Clip has retime or TimeWarp effects (or multiple effects stacked on the clip)", + "icon": { + "path": "retiming.png" + }, + "metadata": { + "family": "retiming", + "marginIn": 1, + "marginOut": 1 + } + }, + "Frame start": { + "editable": "1", + "note": "Starting frame for comps. \n\n> Use `value` and add either number or write `source` (if you want to preserve source frame numbering)", + "icon": { + "path": "icons:TagBackground.png" + }, + "metadata": { + "family": "frameStart", + "value": "1001" + } + }, + "[Lenses]": { + "Set lense here": { + "editable": "1", + "note": "Adjust parameters of your lense and then drop to clip. Remember! You can always overwrite on clip", + "icon": { + "path": "lense.png" + }, + "metadata": { + "focalLengthMm": 57 + + } + } + }, + "[Subsets]": { + "Audio": { + "editable": "1", + "note": "Export with Audio", + "icon": { + "path": "volume.png" + }, + "metadata": { + "family": "audio", + "subset": "main" + } + }, + "plateFg": { + "editable": "1", + "note": "Add to publish to \"forground\" subset. Change metadata subset name if different order number", + "icon": { + "path": "z_layer_fg.png" + }, + "metadata": { + "family": "plate", + "subset": "Fg01" + } + }, + "plateBg": { + "editable": "1", + "note": "Add to publish to \"background\" subset. Change metadata subset name if different order number", + "icon": { + "path": "z_layer_bg.png" + }, + "metadata": { + "family": "plate", + "subset": "Bg01" + } + }, + "plateRef": { + "editable": "1", + "note": "Add to publish to \"reference\" subset.", + "icon": { + "path": "icons:Reference.png" + }, + "metadata": { + "family": "plate", + "subset": "Ref" + } + }, + "plateMain": { + "editable": "1", + "note": "Add to publish to \"main\" subset.", + "icon": { + "path": "z_layer_main.png" + }, + "metadata": { + "family": "plate", + "subset": "main" + } + }, + "plateProxy": { + "editable": "1", + "note": "Add to publish to \"proxy\" subset.", + "icon": { + "path": "z_layer_main.png" + }, + "metadata": { + "family": "plate", + "subset": "proxy" + } + }, + "review": { + "editable": "1", + "note": "Upload to Ftrack as review component.", + "icon": { + "path": "review.png" + }, + "metadata": { + "family": "review", + "track": "review" + } + } + }, + "[Handles]": { + "start: add 20 frames": { + "editable": "1", + "note": "Adding frames to start of selected clip", + "icon": { + "path": "3_add_handles_start.png" + }, + "metadata": { + "family": "handles", + "value": "20", + "args": "{'op':'add','where':'start'}" + } + }, + "start: add 10 frames": { + "editable": "1", + "note": "Adding frames to start of selected clip", + "icon": { + "path": "3_add_handles_start.png" + }, + "metadata": { + "family": "handles", + "value": "10", + "args": "{'op':'add','where':'start'}" + } + }, + "start: add 5 frames": { + "editable": "1", + "note": "Adding frames to start of selected clip", + "icon": { + "path": "3_add_handles_start.png" + }, + "metadata": { + "family": "handles", + "value": "5", + "args": "{'op':'add','where':'start'}" + } + }, + "start: add 0 frames": { + "editable": "1", + "note": "Adding frames to start of selected clip", + "icon": { + "path": "3_add_handles_start.png" + }, + "metadata": { + "family": "handles", + "value": "0", + "args": "{'op':'add','where':'start'}" + } + }, + "end: add 20 frames": { + "editable": "1", + "note": "Adding frames to end of selected clip", + "icon": { + "path": "1_add_handles_end.png" + }, + "metadata": { + "family": "handles", + "value": "20", + "args": "{'op':'add','where':'end'}" + } + }, + "end: add 10 frames": { + "editable": "1", + "note": "Adding frames to end of selected clip", + "icon": { + "path": "1_add_handles_end.png" + }, + "metadata": { + "family": "handles", + "value": "10", + "args": "{'op':'add','where':'end'}" + } + }, + "end: add 5 frames": { + "editable": "1", + "note": "Adding frames to end of selected clip", + "icon": { + "path": "1_add_handles_end.png" + }, + "metadata": { + "family": "handles", + "value": "5", + "args": "{'op':'add','where':'end'}" + } + }, + "end: add 0 frames": { + "editable": "1", + "note": "Adding frames to end of selected clip", + "icon": { + "path": "1_add_handles_end.png" + }, + "metadata": { + "family": "handles", + "value": "0", + "args": "{'op':'add','where':'end'}" + } + } + }, + "NukeScript": { + "editable": "1", + "note": "Collecting track items to Nuke scripts.", + "icon": { + "path": "icons:TagNuke.png" + }, + "metadata": { + "family": "nukescript", + "subset": "main" + } + }, + "Comment": { + "editable": "1", + "note": "Comment on a shot.", + "icon": { + "path": "icons:TagComment.png" + }, + "metadata": { + "family": "comment", + "subset": "main" + } + } +} diff --git a/pype/configurations/defaults/presets/plugins/celaction/publish.json b/pype/configurations/defaults/presets/plugins/celaction/publish.json new file mode 100644 index 0000000000..e791f574d9 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/celaction/publish.json @@ -0,0 +1,10 @@ +{ + "ExtractCelactionDeadline": { + "deadline_department": "", + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_group": "", + "deadline_chunk_size": 10 + } +} diff --git a/pype/configurations/defaults/presets/plugins/config.json b/pype/configurations/defaults/presets/plugins/config.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/pype/configurations/defaults/presets/plugins/ftrack/publish.json b/pype/configurations/defaults/presets/plugins/ftrack/publish.json new file mode 100644 index 0000000000..d0469ae4f7 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/ftrack/publish.json @@ -0,0 +1,6 @@ +{ + "IntegrateFtrackNote": { + "note_with_intent_template": "{intent}: {comment}", + "note_labels": [] + } +} diff --git a/pype/configurations/defaults/presets/plugins/global/create.json b/pype/configurations/defaults/presets/plugins/global/create.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/global/create.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/presets/plugins/global/filter.json b/pype/configurations/defaults/presets/plugins/global/filter.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/global/filter.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/presets/plugins/global/load.json b/pype/configurations/defaults/presets/plugins/global/load.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/global/load.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/presets/plugins/global/publish.json b/pype/configurations/defaults/presets/plugins/global/publish.json new file mode 100644 index 0000000000..016868fc92 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/global/publish.json @@ -0,0 +1,86 @@ +{ + "IntegrateMasterVersion": { + "enabled": false + }, + "ExtractJpegEXR": { + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "output": [] + } + }, + "ExtractReview": { + "__documentation__": "http://pype.club/docs/admin_presets_plugins", + "profiles": [ + { + "families": [], + "hosts": [], + "outputs": { + "h264": { + "filter": { + "families": ["render", "review", "ftrack"] + }, + "ext": "mp4", + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "video_filters": [], + "audio_filters": [], + "output": [ + "-pix_fmt yuv420p", + "-crf 18", + "-intra" + ] + }, + "tags": ["burnin", "ftrackreview"] + } + } + } + ] + }, + "ExtractBurnin": { + "options": { + "opacity": 1, + "x_offset": 5, + "y_offset": 5, + "bg_padding": 5, + "bg_opacity": 0.5, + "font_size": 42 + }, + "fields": { + + }, + "profiles": [ + { + "burnins": { + "burnin": { + "TOP_LEFT": "{yy}-{mm}-{dd}", + "TOP_RIGHT": "{anatomy[version]}", + "TOP_CENTERED": "", + "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", + "BOTTOM_CENTERED": "{asset}", + "BOTTOM_LEFT": "{username}" + } + } + } + ] + }, + "IntegrateAssetNew": { + "template_name_profiles": { + "publish": { + "families": [], + "tasks": [] + }, + "render": { + "families": ["review", "render", "prerender"] + } + } + }, + "ProcessSubmittedJobOnFarm": { + "deadline_department": "", + "deadline_pool": "", + "deadline_group": "" + } +} diff --git a/pype/configurations/defaults/presets/plugins/maya/create.json b/pype/configurations/defaults/presets/plugins/maya/create.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/maya/create.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/presets/plugins/maya/filter.json b/pype/configurations/defaults/presets/plugins/maya/filter.json new file mode 100644 index 0000000000..83d6f05f31 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/maya/filter.json @@ -0,0 +1,9 @@ +{ + "Preset n1": { + "ValidateNoAnimation": false, + "ValidateShapeDefaultNames": false + }, + "Preset n2": { + "ValidateNoAnimation": false + } +} diff --git a/pype/configurations/defaults/presets/plugins/maya/load.json b/pype/configurations/defaults/presets/plugins/maya/load.json new file mode 100644 index 0000000000..260fbb35ee --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/maya/load.json @@ -0,0 +1,18 @@ +{ + "colors": { + "model": [0.821, 0.518, 0.117], + "rig": [0.144, 0.443, 0.463], + "pointcache": [0.368, 0.821, 0.117], + "animation": [0.368, 0.821, 0.117], + "ass": [1.0, 0.332, 0.312], + "camera": [0.447, 0.312, 1.0], + "fbx": [1.0, 0.931, 0.312], + "mayaAscii": [0.312, 1.0, 0.747], + "setdress": [0.312, 1.0, 0.747], + "layout": [0.312, 1.0, 0.747], + "vdbcache": [0.312, 1.0, 0.428], + "vrayproxy": [0.258, 0.95, 0.541], + "yeticache": [0.2, 0.8, 0.3], + "yetiRig": [0, 0.8, 0.5] + } +} diff --git a/pype/configurations/defaults/presets/plugins/maya/publish.json b/pype/configurations/defaults/presets/plugins/maya/publish.json new file mode 100644 index 0000000000..2e2b3164f3 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/maya/publish.json @@ -0,0 +1,17 @@ +{ + "ValidateModelName": { + "enabled": false, + "material_file": "/path/to/shader_name_definition.txt", + "regex": "(.*)_(\\d)*_(?P.*)_(GEO)" + }, + "ValidateAssemblyName": { + "enabled": false + }, + "ValidateShaderName": { + "enabled": false, + "regex": "(?P.*)_(.*)_SHD" + }, + "ValidateMeshHasOverlappingUVs": { + "enabled": false + } +} diff --git a/pype/configurations/defaults/presets/plugins/maya/workfile_build.json b/pype/configurations/defaults/presets/plugins/maya/workfile_build.json new file mode 100644 index 0000000000..2872b783cb --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/maya/workfile_build.json @@ -0,0 +1,54 @@ +[{ + "tasks": ["lighting"], + + "current_context": [{ + "subset_name_filters": [".+[Mm]ain"], + "families": ["model"], + "repre_names": ["abc", "ma"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["animation", "pointcache"], + "repre_names": ["abc"], + "loaders": ["ReferenceLoader"] + },{ + "families": ["rendersetup"], + "repre_names": ["json"], + "loaders": ["RenderSetupLoader"] + }, { + "families": ["camera"], + "repre_names": ["abc"], + "loaders": ["ReferenceLoader"] + }], + + "linked_assets": [{ + "families": ["setdress"], + "repre_names": ["ma"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["ass"], + "repre_names": ["ass"], + "loaders":["assLoader"] + }] +}, { + "tasks": ["animation"], + + "current_context": [{ + "families": ["camera"], + "repre_names": ["abc", "ma"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["audio"], + "repre_names": ["wav"], + "loaders": ["RenderSetupLoader"] + }], + + "linked_assets": [{ + "families": ["setdress"], + "repre_names": ["proxy"], + "loaders": ["ReferenceLoader"] + }, { + "families": ["rig"], + "repre_names": ["ass"], + "loaders": ["rigLoader"] + }] +}] diff --git a/pype/configurations/defaults/presets/plugins/nuke/create.json b/pype/configurations/defaults/presets/plugins/nuke/create.json new file mode 100644 index 0000000000..4deb0b4ad5 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/nuke/create.json @@ -0,0 +1,8 @@ +{ + "CreateWriteRender": { + "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" + }, + "CreateWritePrerender": { + "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" + } +} diff --git a/pype/configurations/defaults/presets/plugins/nuke/load.json b/pype/configurations/defaults/presets/plugins/nuke/load.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/nuke/load.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/presets/plugins/nuke/publish.json b/pype/configurations/defaults/presets/plugins/nuke/publish.json new file mode 100644 index 0000000000..ab0d0e76a5 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/nuke/publish.json @@ -0,0 +1,48 @@ +{ + "ExtractThumbnail": { + "nodes": { + "Reformat": [ + ["type", "to format"], + ["format", "HD_1080"], + ["filter", "Lanczos6"], + ["black_outside", true], + ["pbb", false] + ] + } + }, + "ValidateNukeWriteKnobs": { + "enabled": false, + "knobs": { + "render": { + "review": true + } + } + }, + "ExtractReviewDataLut": { + "__documentation__": { + "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", + "enabled": "keep in on `false` if you want Nuke baking colorspace workflow applied else FFmpeg will convert imgsequence with baked LUT" + }, + "enabled": false + }, + "ExtractReviewDataMov": { + "__documentation__": { + "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", + "enabled": "keep in on `true` if you want Nuke baking colorspace workflow applied" + }, + "enabled": true, + "viewer_lut_raw": false + }, + "ExtractSlateFrame": { + "__documentation__": { + "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`" + }, + "viewer_lut_raw": false + }, + "NukeSubmitDeadline": { + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_chunk_size": 1 + } +} diff --git a/pype/configurations/defaults/presets/plugins/nuke/workfile_build.json b/pype/configurations/defaults/presets/plugins/nuke/workfile_build.json new file mode 100644 index 0000000000..d3613c929e --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/nuke/workfile_build.json @@ -0,0 +1,11 @@ +[{ + "tasks": ["compositing"], + + "current_context": [{ + "families": ["render", "plate"], + "repre_names": ["exr" ,"dpx"], + "loaders": ["LoadSequence"] + }], + + "linked_assets": [] +}] diff --git a/pype/configurations/defaults/presets/plugins/nukestudio/filter.json b/pype/configurations/defaults/presets/plugins/nukestudio/filter.json new file mode 100644 index 0000000000..bd6a0dc1bd --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/nukestudio/filter.json @@ -0,0 +1,10 @@ +{ + "strict": { + "ValidateVersion": true, + "VersionUpWorkfile": true + }, + "benevolent": { + "ValidateVersion": false, + "VersionUpWorkfile": false + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/presets/plugins/nukestudio/publish.json b/pype/configurations/defaults/presets/plugins/nukestudio/publish.json new file mode 100644 index 0000000000..8c4ad133f1 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/nukestudio/publish.json @@ -0,0 +1,8 @@ +{ + "CollectInstanceVersion": { + "enabled": false + }, + "ExtractReviewCutUpVideo": { + "tags_addition": [] + } +} diff --git a/pype/configurations/defaults/presets/plugins/resolve/create.json b/pype/configurations/defaults/presets/plugins/resolve/create.json new file mode 100644 index 0000000000..29ca5900fb --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/resolve/create.json @@ -0,0 +1,7 @@ +{ + "CreateShotClip": { + "clipName": "{track}{sequence}{shot}", + "folder": "takes", + "steps": 20 + } +} diff --git a/pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json b/pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json new file mode 100644 index 0000000000..2b2fb660c2 --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json @@ -0,0 +1,25 @@ +{ + "ExtractThumbnailSP": { + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "output": [] + } + }, + "ExtractReviewSP": { + "outputs": { + "h264": { + "input": [ + "-gamma 2.2" + ], + "output": [ + "-pix_fmt yuv420p", + "-crf 18" + ], + "tags": ["preview"], + "ext": "mov" + } + } + } +} diff --git a/pype/configurations/defaults/presets/plugins/test/create.json b/pype/configurations/defaults/presets/plugins/test/create.json new file mode 100644 index 0000000000..fa0b2fc05f --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/test/create.json @@ -0,0 +1,8 @@ +{ + "MyTestCreator": { + "my_test_property": "B", + "active": false, + "new_property": "new", + "family": "new_family" + } +} diff --git a/pype/configurations/defaults/presets/plugins/test/publish.json b/pype/configurations/defaults/presets/plugins/test/publish.json new file mode 100644 index 0000000000..3180dd5d8a --- /dev/null +++ b/pype/configurations/defaults/presets/plugins/test/publish.json @@ -0,0 +1,10 @@ +{ + "MyTestPlugin": { + "label": "loaded from preset", + "optional": true, + "families": ["changed", "by", "preset"] + }, + "MyTestRemovedPlugin": { + "enabled": false + } +} diff --git a/pype/configurations/defaults/presets/premiere/asset_default.json b/pype/configurations/defaults/presets/premiere/asset_default.json new file mode 100644 index 0000000000..84d2bde3d8 --- /dev/null +++ b/pype/configurations/defaults/presets/premiere/asset_default.json @@ -0,0 +1,5 @@ +{ + "frameStart": 1001, + "handleStart": 0, + "handleEnd": 0 +} diff --git a/pype/configurations/defaults/presets/premiere/rules_tasks.json b/pype/configurations/defaults/presets/premiere/rules_tasks.json new file mode 100644 index 0000000000..333c9cd70b --- /dev/null +++ b/pype/configurations/defaults/presets/premiere/rules_tasks.json @@ -0,0 +1,21 @@ +{ + "defaultTasks": ["Layout", "Animation"], + "taskToSubsets": { + "Layout": ["reference", "audio"], + "Animation": ["audio"] + }, + "subsetToRepresentations": { + "reference": { + "preset": "h264", + "representation": "mp4" + }, + "thumbnail": { + "preset": "jpeg_thumb", + "representation": "jpg" + }, + "audio": { + "preset": "48khz", + "representation": "wav" + } + } +} diff --git a/pype/configurations/defaults/presets/standalone_publish/families.json b/pype/configurations/defaults/presets/standalone_publish/families.json new file mode 100644 index 0000000000..d05941cc26 --- /dev/null +++ b/pype/configurations/defaults/presets/standalone_publish/families.json @@ -0,0 +1,90 @@ +{ + "create_look": { + "name": "look", + "label": "Look", + "family": "look", + "icon": "paint-brush", + "defaults": ["Main"], + "help": "Shader connections defining shape look" + }, + "create_model": { + "name": "model", + "label": "Model", + "family": "model", + "icon": "cube", + "defaults": ["Main", "Proxy", "Sculpt"], + "help": "Polygonal static geometry" + }, + "create_workfile": { + "name": "workfile", + "label": "Workfile", + "family": "workfile", + "icon": "cube", + "defaults": ["Main"], + "help": "Working scene backup" + }, + "create_camera": { + "name": "camera", + "label": "Camera", + "family": "camera", + "icon": "video-camera", + "defaults": ["Main"], + "help": "Single baked camera" + }, + "create_pointcache": { + "name": "pointcache", + "label": "Pointcache", + "family": "pointcache", + "icon": "gears", + "defaults": ["Main"], + "help": "Alembic pointcache for animated data" + }, + "create_rig": { + "name": "rig", + "label": "Rig", + "family": "rig", + "icon": "wheelchair", + "defaults": ["Main"], + "help": "Artist-friendly rig with controls" + }, + "create_layout": { + "name": "layout", + "label": "Layout", + "family": "layout", + "icon": "cubes", + "defaults": ["Main"], + "help": "Simple scene for animators with camera" + }, + "create_plate": { + "name": "plate", + "label": "Plate", + "family": "plate", + "icon": "camera", + "defaults": ["Main", "BG", "Reference"], + "help": "Plates for compositors" + }, + "create_matchmove": { + "name": "matchmove", + "label": "Matchmove script", + "family": "matchmove", + "icon": "empire", + "defaults": ["Camera", "Object", "Mocap"], + "help": "Script exported from matchmoving application" + }, + "create_images": { + "name": "image", + "label": "Image file", + "family": "image", + "icon": "image", + "defaults": ["ConceptArt", "Reference", "Texture", "MattePaint"], + "help": "Holder for all kinds of image data" + }, + "create_editorial": { + "name": "editorial", + "label": "Editorial", + "family": "editorial", + "icon": "image", + "defaults": ["Main"], + "help": "Editorial files to generate shots." + } +} diff --git a/pype/configurations/defaults/presets/tools/creator.json b/pype/configurations/defaults/presets/tools/creator.json new file mode 100644 index 0000000000..d14e779f01 --- /dev/null +++ b/pype/configurations/defaults/presets/tools/creator.json @@ -0,0 +1,8 @@ +{ + "Model": ["model"], + "Render Globals": ["light", "render"], + "Layout": ["layout"], + "Set Dress": ["setdress"], + "Look": ["look"], + "Rig": ["rigging"] +} diff --git a/pype/configurations/defaults/presets/tools/project_folder_structure.json b/pype/configurations/defaults/presets/tools/project_folder_structure.json new file mode 100644 index 0000000000..83bd5f12a9 --- /dev/null +++ b/pype/configurations/defaults/presets/tools/project_folder_structure.json @@ -0,0 +1,22 @@ +{ + "__project_root__": { + "prod" : {}, + "resources" : { + "footage": { + "plates": {}, + "offline": {} + }, + "audio": {}, + "art_dept": {} + }, + "editorial" : {}, + "assets[ftrack.Library]": { + "characters[ftrack]": {}, + "locations[ftrack]": {} + }, + "shots[ftrack.Sequence]": { + "scripts": {}, + "editorial[ftrack.Folder]": {} + } + } +} diff --git a/pype/configurations/defaults/presets/tools/pyblish.json b/pype/configurations/defaults/presets/tools/pyblish.json new file mode 100644 index 0000000000..e81932ec45 --- /dev/null +++ b/pype/configurations/defaults/presets/tools/pyblish.json @@ -0,0 +1,17 @@ +{ + "ui": { + "intents": { + "__description__": [ + "In items you can specify {label: value} of intents", + "`default` may be used for setting default value." + ], + "default": "wip", + "items": { + "": "", + "wip": "WIP", + "test": "TEST", + "final": "FINAL" + } + } + } +} diff --git a/pype/configurations/defaults/presets/tools/slates/example_HD.json b/pype/configurations/defaults/presets/tools/slates/example_HD.json new file mode 100644 index 0000000000..b06391fb63 --- /dev/null +++ b/pype/configurations/defaults/presets/tools/slates/example_HD.json @@ -0,0 +1,212 @@ +{ + "width": 1920, + "height": 1080, + "destination_path": "{destination_path}", + "style": { + "*": { + "font-family": "arial", + "font-color": "#ffffff", + "font-bold": false, + "font-italic": false, + "bg-color": "#0077ff", + "alignment-horizontal": "left", + "alignment-vertical": "top" + }, + "layer": { + "padding": 0, + "margin": 0 + }, + "rectangle": { + "padding": 0, + "margin": 0, + "bg-color": "#E9324B", + "fill": true + }, + "main_frame": { + "padding": 0, + "margin": 0, + "bg-color": "#252525" + }, + "table": { + "padding": 0, + "margin": 0, + "bg-color": "transparent" + }, + "table-item": { + "padding": 5, + "padding-bottom": 10, + "margin": 0, + "bg-color": "#212121", + "bg-alter-color": "#272727", + "font-color": "#dcdcdc", + "font-bold": false, + "font-italic": false, + "alignment-horizontal": "left", + "alignment-vertical": "top", + "word-wrap": false, + "ellide": true, + "max-lines": 1 + }, + "table-item-col[0]": { + "font-size": 20, + "font-color": "#898989", + "font-bold": true, + "ellide": false, + "word-wrap": true, + "max-lines": null + }, + "table-item-col[1]": { + "font-size": 40, + "padding-left": 10 + }, + "#colorbar": { + "bg-color": "#9932CC" + } + }, + "items": [{ + "type": "layer", + "direction": 1, + "name": "MainLayer", + "style": { + "#MainLayer": { + "width": 1094, + "height": 1000, + "margin": 25, + "padding": 0 + }, + "#LeftSide": { + "margin-right": 25 + } + }, + "items": [{ + "type": "layer", + "name": "LeftSide", + "items": [{ + "type": "layer", + "direction": 1, + "style": { + "table-item": { + "bg-color": "transparent", + "padding-bottom": 20 + }, + "table-item-col[0]": { + "font-size": 20, + "font-color": "#898989", + "alignment-horizontal": "right" + }, + "table-item-col[1]": { + "alignment-horizontal": "left", + "font-bold": true, + "font-size": 40 + } + }, + "items": [{ + "type": "table", + "values": [ + ["Show:", "{project[name]}"] + ], + "style": { + "table-item-field[0:0]": { + "width": 150 + }, + "table-item-field[0:1]": { + "width": 580 + } + } + }, { + "type": "table", + "values": [ + ["Submitting For:", "{intent}"] + ], + "style": { + "table-item-field[0:0]": { + "width": 160 + }, + "table-item-field[0:1]": { + "width": 218, + "alignment-horizontal": "right" + } + } + }] + }, { + "type": "rectangle", + "style": { + "bg-color": "#bc1015", + "width": 1108, + "height": 5, + "fill": true + } + }, { + "type": "table", + "use_alternate_color": true, + "values": [ + ["Version name:", "{version_name}"], + ["Date:", "{date}"], + ["Shot Types:", "{shot_type}"], + ["Submission Note:", "{submission_note}"] + ], + "style": { + "table-item": { + "padding-bottom": 20 + }, + "table-item-field[0:1]": { + "font-bold": true + }, + "table-item-field[3:0]": { + "word-wrap": true, + "ellide": true, + "max-lines": 4 + }, + "table-item-col[0]": { + "alignment-horizontal": "right", + "width": 150 + }, + "table-item-col[1]": { + "alignment-horizontal": "left", + "width": 958 + } + } + }] + }, { + "type": "layer", + "name": "RightSide", + "items": [{ + "type": "placeholder", + "name": "thumbnail", + "path": "{thumbnail_path}", + "style": { + "width": 730, + "height": 412 + } + }, { + "type": "placeholder", + "name": "colorbar", + "path": "{color_bar_path}", + "return_data": true, + "style": { + "width": 730, + "height": 55 + } + }, { + "type": "table", + "use_alternate_color": true, + "values": [ + ["Vendor:", "{vendor}"], + ["Shot Name:", "{shot_name}"], + ["Frames:", "{frame_start} - {frame_end} ({duration})"] + ], + "style": { + "table-item-col[0]": { + "alignment-horizontal": "left", + "width": 200 + }, + "table-item-col[1]": { + "alignment-horizontal": "right", + "width": 530, + "font-size": 30 + } + } + }] + }] + }] +} diff --git a/pype/configurations/defaults/presets/tools/sw_folders.json b/pype/configurations/defaults/presets/tools/sw_folders.json new file mode 100644 index 0000000000..a154935dce --- /dev/null +++ b/pype/configurations/defaults/presets/tools/sw_folders.json @@ -0,0 +1,8 @@ +{ + "compositing": ["nuke", "ae"], + "modeling": ["maya", "app2"], + "lookdev": ["substance"], + "animation": [], + "lighting": [], + "rigging": [] +} diff --git a/pype/configurations/defaults/presets/tools/workfiles.json b/pype/configurations/defaults/presets/tools/workfiles.json new file mode 100644 index 0000000000..393b2e3c10 --- /dev/null +++ b/pype/configurations/defaults/presets/tools/workfiles.json @@ -0,0 +1,7 @@ +{ + "last_workfile_on_startup": [ + { + "enabled": false + } + ] +} diff --git a/pype/configurations/defaults/presets/tray/menu_items.json b/pype/configurations/defaults/presets/tray/menu_items.json new file mode 100644 index 0000000000..6c6763848b --- /dev/null +++ b/pype/configurations/defaults/presets/tray/menu_items.json @@ -0,0 +1,28 @@ +{ + "item_usage": { + "User settings": false, + "Ftrack": true, + "Muster": false, + "Avalon": true, + "Clockify": false, + "Standalone Publish": true, + "Logging": true, + "Idle Manager": true, + "Timers Manager": true, + "Rest Api": true, + "Adobe Communicator": true + }, + "attributes": { + "Rest Api": { + "default_port": 8021, + "exclude_ports": [] + }, + "Timers Manager": { + "full_time": 15, + "message_time": 0.5 + }, + "Clockify": { + "workspace_name": null + } + } +} diff --git a/pype/configurations/defaults/presets/unreal/project_setup.json b/pype/configurations/defaults/presets/unreal/project_setup.json new file mode 100644 index 0000000000..8a4dffc526 --- /dev/null +++ b/pype/configurations/defaults/presets/unreal/project_setup.json @@ -0,0 +1,4 @@ +{ + "dev_mode": false, + "install_unreal_python_engine": false +} diff --git a/pype/configurations/defaults/project_configurations/plugins/celaction/publish.json b/pype/configurations/defaults/project_configurations/plugins/celaction/publish.json new file mode 100644 index 0000000000..fd1af23d84 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/celaction/publish.json @@ -0,0 +1,11 @@ +{ + "ExtractCelactionDeadline": { + "enabled": true, + "deadline_department": "", + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_group": "", + "deadline_chunk_size": 10 + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/config.json b/pype/configurations/defaults/project_configurations/plugins/config.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/config.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json b/pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json new file mode 100644 index 0000000000..d8d93a36ee --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json @@ -0,0 +1,7 @@ +{ + "IntegrateFtrackNote": { + "enabled": false, + "note_with_intent_template": "{intent}: {comment}", + "note_labels": [] + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/global/create.json b/pype/configurations/defaults/project_configurations/plugins/global/create.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/global/create.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/project_configurations/plugins/global/filter.json b/pype/configurations/defaults/project_configurations/plugins/global/filter.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/global/filter.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/project_configurations/plugins/global/load.json b/pype/configurations/defaults/project_configurations/plugins/global/load.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/global/load.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/project_configurations/plugins/global/publish.json b/pype/configurations/defaults/project_configurations/plugins/global/publish.json new file mode 100644 index 0000000000..3c5de85e68 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/global/publish.json @@ -0,0 +1,97 @@ +{ + "IntegrateMasterVersion": { + "enabled": false + }, + "ExtractJpegEXR": { + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "output": [] + } + }, + "ExtractReview": { + "enabled": true, + "profiles": [ + { + "families": [], + "hosts": [], + "outputs": { + "h264": { + "filter": { + "families": [ + "render", + "review", + "ftrack" + ] + }, + "ext": "mp4", + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "video_filters": [], + "audio_filters": [], + "output": [ + "-pix_fmt yuv420p", + "-crf 18", + "-intra" + ] + }, + "tags": [ + "burnin", + "ftrackreview" + ] + } + } + } + ] + }, + "ExtractBurnin": { + "enabled": false, + "options": { + "font_size": 42, + "opacity": 1, + "bg_opacity": 0, + "x_offset": 5, + "y_offset": 5, + "bg_padding": 5 + }, + "fields": {}, + "profiles": [ + { + "burnins": { + "burnin": { + "TOP_LEFT": "{yy}-{mm}-{dd}", + "TOP_RIGHT": "{anatomy[version]}", + "TOP_CENTERED": "", + "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", + "BOTTOM_CENTERED": "{asset}", + "BOTTOM_LEFT": "{username}" + } + } + } + ] + }, + "IntegrateAssetNew": { + "template_name_profiles": { + "publish": { + "families": [], + "tasks": [] + }, + "render": { + "families": [ + "review", + "render", + "prerender" + ] + } + } + }, + "ProcessSubmittedJobOnFarm": { + "enabled": false, + "deadline_department": "", + "deadline_pool": "", + "deadline_group": "" + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/create.json b/pype/configurations/defaults/project_configurations/plugins/maya/create.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/maya/create.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/filter.json b/pype/configurations/defaults/project_configurations/plugins/maya/filter.json new file mode 100644 index 0000000000..83d6f05f31 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/maya/filter.json @@ -0,0 +1,9 @@ +{ + "Preset n1": { + "ValidateNoAnimation": false, + "ValidateShapeDefaultNames": false + }, + "Preset n2": { + "ValidateNoAnimation": false + } +} diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/load.json b/pype/configurations/defaults/project_configurations/plugins/maya/load.json new file mode 100644 index 0000000000..260fbb35ee --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/maya/load.json @@ -0,0 +1,18 @@ +{ + "colors": { + "model": [0.821, 0.518, 0.117], + "rig": [0.144, 0.443, 0.463], + "pointcache": [0.368, 0.821, 0.117], + "animation": [0.368, 0.821, 0.117], + "ass": [1.0, 0.332, 0.312], + "camera": [0.447, 0.312, 1.0], + "fbx": [1.0, 0.931, 0.312], + "mayaAscii": [0.312, 1.0, 0.747], + "setdress": [0.312, 1.0, 0.747], + "layout": [0.312, 1.0, 0.747], + "vdbcache": [0.312, 1.0, 0.428], + "vrayproxy": [0.258, 0.95, 0.541], + "yeticache": [0.2, 0.8, 0.3], + "yetiRig": [0, 0.8, 0.5] + } +} diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/publish.json b/pype/configurations/defaults/project_configurations/plugins/maya/publish.json new file mode 100644 index 0000000000..2b3637ff80 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/maya/publish.json @@ -0,0 +1,17 @@ +{ + "ValidateModelName": { + "enabled": false, + "material_file": "/path/to/shader_name_definition.txt", + "regex": "(.*)_(\\d)*_(?P.*)_(GEO)" + }, + "ValidateAssemblyName": { + "enabled": false + }, + "ValidateShaderName": { + "enabled": false, + "regex": "(?P.*)_(.*)_SHD" + }, + "ValidateMeshHasOverlappingUVs": { + "enabled": false + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json b/pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json new file mode 100644 index 0000000000..443bc2cb2c --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json @@ -0,0 +1,136 @@ +[ + { + "tasks": [ + "lighting" + ], + "current_context": [ + { + "subset_name_filters": [ + ".+[Mm]ain" + ], + "families": [ + "model" + ], + "repre_names": [ + "abc", + "ma" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "families": [ + "animation", + "pointcache" + ], + "repre_names": [ + "abc" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "families": [ + "rendersetup" + ], + "repre_names": [ + "json" + ], + "loaders": [ + "RenderSetupLoader" + ] + }, + { + "families": [ + "camera" + ], + "repre_names": [ + "abc" + ], + "loaders": [ + "ReferenceLoader" + ] + } + ], + "linked_assets": [ + { + "families": [ + "setdress" + ], + "repre_names": [ + "ma" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "families": [ + "ass" + ], + "repre_names": [ + "ass" + ], + "loaders": [ + "assLoader" + ] + } + ] + }, + { + "tasks": [ + "animation" + ], + "current_context": [ + { + "families": [ + "camera" + ], + "repre_names": [ + "abc", + "ma" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "families": [ + "audio" + ], + "repre_names": [ + "wav" + ], + "loaders": [ + "RenderSetupLoader" + ] + } + ], + "linked_assets": [ + { + "families": [ + "setdress" + ], + "repre_names": [ + "proxy" + ], + "loaders": [ + "ReferenceLoader" + ] + }, + { + "families": [ + "rig" + ], + "repre_names": [ + "ass" + ], + "loaders": [ + "rigLoader" + ] + } + ] + } +] \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/create.json b/pype/configurations/defaults/project_configurations/plugins/nuke/create.json new file mode 100644 index 0000000000..79ab665696 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/nuke/create.json @@ -0,0 +1,8 @@ +{ + "CreateWriteRender": { + "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" + }, + "CreateWritePrerender": { + "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/load.json b/pype/configurations/defaults/project_configurations/plugins/nuke/load.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/nuke/load.json @@ -0,0 +1 @@ +{} diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/publish.json b/pype/configurations/defaults/project_configurations/plugins/nuke/publish.json new file mode 100644 index 0000000000..08a099a0a0 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/nuke/publish.json @@ -0,0 +1,53 @@ +{ + "ExtractThumbnail": { + "enabled": true, + "nodes": { + "Reformat": [ + [ + "type", + "to format" + ], + [ + "format", + "HD_1080" + ], + [ + "filter", + "Lanczos6" + ], + [ + "black_outside", + true + ], + [ + "pbb", + false + ] + ] + } + }, + "ValidateNukeWriteKnobs": { + "enabled": false, + "knobs": { + "render": { + "review": true + } + } + }, + "ExtractReviewDataLut": { + "enabled": false + }, + "ExtractReviewDataMov": { + "enabled": true, + "viewer_lut_raw": false + }, + "ExtractSlateFrame": { + "viewer_lut_raw": false + }, + "NukeSubmitDeadline": { + "deadline_priority": 50, + "deadline_pool": "", + "deadline_pool_secondary": "", + "deadline_chunk_size": 1 + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json b/pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json new file mode 100644 index 0000000000..4b48b46184 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json @@ -0,0 +1,23 @@ +[ + { + "tasks": [ + "compositing" + ], + "current_context": [ + { + "families": [ + "render", + "plate" + ], + "repre_names": [ + "exr", + "dpx" + ], + "loaders": [ + "LoadSequence" + ] + } + ], + "linked_assets": [] + } +] \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json b/pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json new file mode 100644 index 0000000000..bd6a0dc1bd --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json @@ -0,0 +1,10 @@ +{ + "strict": { + "ValidateVersion": true, + "VersionUpWorkfile": true + }, + "benevolent": { + "ValidateVersion": false, + "VersionUpWorkfile": false + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json b/pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json new file mode 100644 index 0000000000..d99a878c35 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json @@ -0,0 +1,9 @@ +{ + "CollectInstanceVersion": { + "enabled": false + }, + "ExtractReviewCutUpVideo": { + "enabled": true, + "tags_addition": [] + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/resolve/create.json b/pype/configurations/defaults/project_configurations/plugins/resolve/create.json new file mode 100644 index 0000000000..8ff5b15714 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/resolve/create.json @@ -0,0 +1,7 @@ +{ + "CreateShotClip": { + "clipName": "{track}{sequence}{shot}", + "folder": "takes", + "steps": 20 + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json b/pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json new file mode 100644 index 0000000000..2f1a3e7aca --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json @@ -0,0 +1,27 @@ +{ + "ExtractThumbnailSP": { + "ffmpeg_args": { + "input": [ + "-gamma 2.2" + ], + "output": [] + } + }, + "ExtractReviewSP": { + "outputs": { + "h264": { + "input": [ + "-gamma 2.2" + ], + "output": [ + "-pix_fmt yuv420p", + "-crf 18" + ], + "tags": [ + "preview" + ], + "ext": "mov" + } + } + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/test/create.json b/pype/configurations/defaults/project_configurations/plugins/test/create.json new file mode 100644 index 0000000000..fa0b2fc05f --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/test/create.json @@ -0,0 +1,8 @@ +{ + "MyTestCreator": { + "my_test_property": "B", + "active": false, + "new_property": "new", + "family": "new_family" + } +} diff --git a/pype/configurations/defaults/project_configurations/plugins/test/publish.json b/pype/configurations/defaults/project_configurations/plugins/test/publish.json new file mode 100644 index 0000000000..3180dd5d8a --- /dev/null +++ b/pype/configurations/defaults/project_configurations/plugins/test/publish.json @@ -0,0 +1,10 @@ +{ + "MyTestPlugin": { + "label": "loaded from preset", + "optional": true, + "families": ["changed", "by", "preset"] + }, + "MyTestRemovedPlugin": { + "enabled": false + } +} diff --git a/pype/configurations/defaults/studio_configurations/global/applications.json b/pype/configurations/defaults/studio_configurations/global/applications.json new file mode 100644 index 0000000000..8e27f11002 --- /dev/null +++ b/pype/configurations/defaults/studio_configurations/global/applications.json @@ -0,0 +1,39 @@ +{ + "blender_2.80": true, + "blender_2.81": true, + "blender_2.82": true, + "blender_2.83": true, + "celaction_local": true, + "celaction_remote": true, + "harmony_17": true, + "houdini_16": true, + "houdini_17": true, + "houdini_18": true, + "maya_2016": true, + "maya_2017": true, + "maya_2018": true, + "maya_2019": true, + "maya_2020": true, + "nukestudio_10.0": true, + "nukestudio_11.0": true, + "nukestudio_11.2": true, + "nukestudio_11.3": true, + "nukestudio_12.0": true, + "nukex_10.0": true, + "nukex_11.0": true, + "nukex_11.2": true, + "nukex_11.3": true, + "nukex_12.0": true, + "nuke_10.0": true, + "nuke_11.0": true, + "nuke_11.2": true, + "nuke_11.3": true, + "nuke_12.0": true, + "photoshop_2020": true, + "premiere_2019": true, + "premiere_2020": true, + "resolve_16": true, + "storyboardpro_7": true, + "unreal_4.24": true, + "houdini_16.5": false +} \ No newline at end of file diff --git a/pype/configurations/defaults/studio_configurations/global/intent.json b/pype/configurations/defaults/studio_configurations/global/intent.json new file mode 100644 index 0000000000..844bd1b518 --- /dev/null +++ b/pype/configurations/defaults/studio_configurations/global/intent.json @@ -0,0 +1,8 @@ +{ + "items": { + "wip": "WIP", + "test": "TEST", + "final": "FINAL" + }, + "default": "wip" +} \ No newline at end of file diff --git a/pype/configurations/defaults/studio_configurations/global/tools.json b/pype/configurations/defaults/studio_configurations/global/tools.json new file mode 100644 index 0000000000..93895c0e81 --- /dev/null +++ b/pype/configurations/defaults/studio_configurations/global/tools.json @@ -0,0 +1,6 @@ +{ + "mtoa_3.0.1": true, + "mtoa_3.1.1": true, + "mtoa_3.2.0": true, + "yeti_2.1.2": true +} \ No newline at end of file diff --git a/pype/configurations/defaults/studio_configurations/global/tray_modules.json b/pype/configurations/defaults/studio_configurations/global/tray_modules.json new file mode 100644 index 0000000000..0ff5b15552 --- /dev/null +++ b/pype/configurations/defaults/studio_configurations/global/tray_modules.json @@ -0,0 +1,28 @@ +{ + "item_usage": { + "User settings": false, + "Ftrack": true, + "Muster": false, + "Avalon": true, + "Clockify": false, + "Standalone Publish": true, + "Logging": true, + "Idle Manager": true, + "Timers Manager": true, + "Rest Api": true, + "Adobe Communicator": true + }, + "attributes": { + "Rest Api": { + "default_port": 8021, + "exclude_ports": [] + }, + "Timers Manager": { + "full_time": 15.0, + "message_time": 0.5 + }, + "Clockify": { + "workspace_name": "" + } + } +} \ No newline at end of file diff --git a/pype/configurations/defaults/studio_configurations/muster/templates_mapping.json b/pype/configurations/defaults/studio_configurations/muster/templates_mapping.json new file mode 100644 index 0000000000..0c09113515 --- /dev/null +++ b/pype/configurations/defaults/studio_configurations/muster/templates_mapping.json @@ -0,0 +1,19 @@ +{ + "3delight": 41, + "arnold": 46, + "arnold_sf": 57, + "gelato": 30, + "harware": 3, + "krakatoa": 51, + "file_layers": 7, + "mentalray": 2, + "mentalray_sf": 6, + "redshift": 55, + "renderman": 29, + "software": 1, + "software_sf": 5, + "turtle": 10, + "vector": 4, + "vray": 37, + "ffmpeg": 48 +} \ No newline at end of file diff --git a/pype/configurations/defaults/studio_configurations/standalone_publish/families.json b/pype/configurations/defaults/studio_configurations/standalone_publish/families.json new file mode 100644 index 0000000000..d05941cc26 --- /dev/null +++ b/pype/configurations/defaults/studio_configurations/standalone_publish/families.json @@ -0,0 +1,90 @@ +{ + "create_look": { + "name": "look", + "label": "Look", + "family": "look", + "icon": "paint-brush", + "defaults": ["Main"], + "help": "Shader connections defining shape look" + }, + "create_model": { + "name": "model", + "label": "Model", + "family": "model", + "icon": "cube", + "defaults": ["Main", "Proxy", "Sculpt"], + "help": "Polygonal static geometry" + }, + "create_workfile": { + "name": "workfile", + "label": "Workfile", + "family": "workfile", + "icon": "cube", + "defaults": ["Main"], + "help": "Working scene backup" + }, + "create_camera": { + "name": "camera", + "label": "Camera", + "family": "camera", + "icon": "video-camera", + "defaults": ["Main"], + "help": "Single baked camera" + }, + "create_pointcache": { + "name": "pointcache", + "label": "Pointcache", + "family": "pointcache", + "icon": "gears", + "defaults": ["Main"], + "help": "Alembic pointcache for animated data" + }, + "create_rig": { + "name": "rig", + "label": "Rig", + "family": "rig", + "icon": "wheelchair", + "defaults": ["Main"], + "help": "Artist-friendly rig with controls" + }, + "create_layout": { + "name": "layout", + "label": "Layout", + "family": "layout", + "icon": "cubes", + "defaults": ["Main"], + "help": "Simple scene for animators with camera" + }, + "create_plate": { + "name": "plate", + "label": "Plate", + "family": "plate", + "icon": "camera", + "defaults": ["Main", "BG", "Reference"], + "help": "Plates for compositors" + }, + "create_matchmove": { + "name": "matchmove", + "label": "Matchmove script", + "family": "matchmove", + "icon": "empire", + "defaults": ["Camera", "Object", "Mocap"], + "help": "Script exported from matchmoving application" + }, + "create_images": { + "name": "image", + "label": "Image file", + "family": "image", + "icon": "image", + "defaults": ["ConceptArt", "Reference", "Texture", "MattePaint"], + "help": "Holder for all kinds of image data" + }, + "create_editorial": { + "name": "editorial", + "label": "Editorial", + "family": "editorial", + "icon": "image", + "defaults": ["Main"], + "help": "Editorial files to generate shots." + } +} From 3e6cf0cdb8c329de03ef92b58cb6f467a75a8ec0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:34:14 +0200 Subject: [PATCH 418/580] basic reorganization of presets --- .../configurations/defaults/presets/init.json | 4 - .../presets/plugins/celaction/publish.json | 10 --- .../defaults/presets/plugins/config.json | 1 - .../presets/plugins/ftrack/publish.json | 6 -- .../presets/plugins/global/create.json | 1 - .../presets/plugins/global/filter.json | 1 - .../defaults/presets/plugins/global/load.json | 1 - .../presets/plugins/global/publish.json | 86 ------------------- .../defaults/presets/plugins/maya/create.json | 1 - .../defaults/presets/plugins/maya/filter.json | 9 -- .../defaults/presets/plugins/maya/load.json | 18 ---- .../presets/plugins/maya/publish.json | 17 ---- .../presets/plugins/maya/workfile_build.json | 54 ------------ .../defaults/presets/plugins/nuke/create.json | 8 -- .../defaults/presets/plugins/nuke/load.json | 1 - .../presets/plugins/nuke/publish.json | 48 ----------- .../presets/plugins/nuke/workfile_build.json | 11 --- .../presets/plugins/nukestudio/filter.json | 10 --- .../presets/plugins/nukestudio/publish.json | 8 -- .../presets/plugins/resolve/create.json | 7 -- .../plugins/standalonepublisher/publish.json | 25 ------ .../defaults/presets/plugins/test/create.json | 8 -- .../presets/plugins/test/publish.json | 10 --- .../defaults/presets/tools/pyblish.json | 17 ---- .../defaults/presets/tray/menu_items.json | 28 ------ .../anatomy/README.md | 0 .../anatomy/colorspace.json} | 0 .../anatomy}/colorspace/aces103-cg.json | 0 .../anatomy/dataflow.json} | 0 .../anatomy}/dataflow/aces-exr.json | 0 .../anatomy/default.yaml | 0 .../anatomy/roots.json | 0 .../anatomy/templates.json | 35 ++++++++ .../{plugins => }/celaction/publish.json | 0 .../{plugins => }/config.json | 0 .../ftrack/ftrack_config.json | 0 .../ftrack/ftrack_custom_attributes.json | 0 .../ftrack/partnership_ftrack_cred.json | 0 .../ftrack/plugins/server.json | 0 .../ftrack/plugins/user.json | 0 .../ftrack/project_defaults.json | 0 .../{plugins => }/ftrack/publish.json | 0 .../{plugins/maya => global}/create.json | 0 .../global}/creator.json | 0 .../{plugins => }/global/filter.json | 0 .../{plugins/nuke => global}/load.json | 0 .../global}/project_folder_structure.json | 0 .../{plugins => }/global/publish.json | 0 .../global}/sw_folders.json | 0 .../global}/workfiles.json | 0 .../maya/capture.json | 0 .../{plugins/global => maya}/create.json | 0 .../{plugins => }/maya/filter.json | 0 .../{plugins => }/maya/load.json | 0 .../{plugins => }/maya/publish.json | 0 .../{plugins => }/maya/workfile_build.json | 0 .../muster/templates_mapping.json | 0 .../{plugins => }/nuke/create.json | 0 .../{plugins/global => nuke}/load.json | 0 .../{plugins => }/nuke/publish.json | 0 .../{plugins => }/nuke/workfile_build.json | 0 .../{plugins => }/nukestudio/filter.json | 0 .../{plugins => }/nukestudio/publish.json | 0 .../nukestudio/tags.json | 0 .../premiere/asset_default.json | 0 .../premiere/rules_tasks.json | 0 .../{plugins => }/resolve/create.json | 0 .../standalonepublisher}/families.json | 0 .../standalonepublisher/publish.json | 0 .../{plugins => }/test/create.json | 0 .../{plugins => }/test/publish.json | 0 .../tools/slates/example_HD.json | 0 .../unreal/project_setup.json | 0 .../environments/avalon.json | 0 .../environments/blender.json | 0 .../environments/celaction.json | 0 .../environments/deadline.json | 0 .../environments/ftrack.json | 0 .../environments/global.json | 0 .../environments/harmony.json | 0 .../environments/houdini.json | 0 .../environments/maya.json | 0 .../environments/maya_2018.json | 0 .../environments/maya_2020.json | 0 .../environments/mayabatch.json | 0 .../environments/mayabatch_2019.json | 0 .../environments/mtoa_3.1.1.json | 0 .../environments/muster.json | 0 .../environments/nuke.json | 0 .../environments/nukestudio.json | 0 .../environments/nukestudio_10.0.json | 0 .../environments/nukex.json | 0 .../environments/nukex_10.0.json | 0 .../environments/photoshop.json | 0 .../environments/premiere.json | 0 .../environments/resolve.json | 0 .../environments/storyboardpro.json | 0 .../environments/unreal_4.24.json | 0 .../environments/vray_4300.json | 0 .../launchers/blender_2.80.toml | 0 .../launchers/blender_2.81.toml | 0 .../launchers/blender_2.82.toml | 0 .../launchers/blender_2.83.toml | 0 .../launchers/celaction_local.toml | 0 .../launchers/celaction_publish.toml | 0 .../launchers/darwin/blender_2.82 | 0 .../launchers/darwin/harmony_17 | 0 .../launchers/darwin/harmony_17_launch | 0 .../launchers/darwin/python3 | 0 .../launchers/harmony_17.toml | 0 .../launchers/houdini_16.toml | 0 .../launchers/houdini_17.toml | 0 .../launchers/houdini_18.toml | 0 .../launchers/linux/maya2016 | 0 .../launchers/linux/maya2017 | 0 .../launchers/linux/maya2018 | 0 .../launchers/linux/maya2019 | 0 .../launchers/linux/maya2020 | 0 .../launchers/linux/nuke11.3 | 0 .../launchers/linux/nuke12.0 | 0 .../launchers/linux/nukestudio11.3 | 0 .../launchers/linux/nukestudio12.0 | 0 .../launchers/linux/nukex11.3 | 0 .../launchers/linux/nukex12.0 | 0 .../launchers/maya_2016.toml | 0 .../launchers/maya_2017.toml | 0 .../launchers/maya_2018.toml | 0 .../launchers/maya_2019.toml | 0 .../launchers/maya_2020.toml | 0 .../launchers/mayabatch_2019.toml | 0 .../launchers/mayabatch_2020.toml | 0 .../launchers/mayapy2016.toml | 0 .../launchers/mayapy2017.toml | 0 .../launchers/mayapy2018.toml | 0 .../launchers/mayapy2019.toml | 0 .../launchers/mayapy2020.toml | 0 .../launchers/myapp.toml | 0 .../launchers/nuke_10.0.toml | 0 .../launchers/nuke_11.0.toml | 0 .../launchers/nuke_11.2.toml | 0 .../launchers/nuke_11.3.toml | 0 .../launchers/nuke_12.0.toml | 0 .../launchers/nukestudio_10.0.toml | 0 .../launchers/nukestudio_11.0.toml | 0 .../launchers/nukestudio_11.2.toml | 0 .../launchers/nukestudio_11.3.toml | 0 .../launchers/nukestudio_12.0.toml | 0 .../launchers/nukex_10.0.toml | 0 .../launchers/nukex_11.0.toml | 0 .../launchers/nukex_11.2.toml | 0 .../launchers/nukex_11.3.toml | 0 .../launchers/nukex_12.0.toml | 0 .../launchers/photoshop_2020.toml | 0 .../launchers/premiere_2019.toml | 0 .../launchers/premiere_2020.toml | 0 .../launchers/python_2.toml | 0 .../launchers/python_3.toml | 0 .../launchers/resolve_16.toml | 0 .../launchers/shell.toml | 0 .../launchers/storyboardpro_7.toml | 0 .../launchers/unreal_4.24.toml | 0 .../launchers/windows/blender_2.80.bat | 0 .../launchers/windows/blender_2.81.bat | 0 .../launchers/windows/blender_2.82.bat | 0 .../launchers/windows/blender_2.83.bat | 0 .../launchers/windows/celaction_local.bat | 0 .../launchers/windows/celaction_publish.bat | 0 .../launchers/windows/harmony_17.bat | 0 .../launchers/windows/houdini_16.bat | 0 .../launchers/windows/houdini_17.bat | 0 .../launchers/windows/houdini_18.bat | 0 .../launchers/windows/maya2016.bat | 0 .../launchers/windows/maya2017.bat | 0 .../launchers/windows/maya2018.bat | 0 .../launchers/windows/maya2019.bat | 0 .../launchers/windows/maya2020.bat | 0 .../launchers/windows/mayabatch2019.bat | 0 .../launchers/windows/mayabatch2020.bat | 0 .../launchers/windows/mayapy2016.bat | 0 .../launchers/windows/mayapy2017.bat | 0 .../launchers/windows/mayapy2018.bat | 0 .../launchers/windows/mayapy2019.bat | 0 .../launchers/windows/mayapy2020.bat | 0 .../launchers/windows/nuke10.0.bat | 0 .../launchers/windows/nuke11.0.bat | 0 .../launchers/windows/nuke11.2.bat | 0 .../launchers/windows/nuke11.3.bat | 0 .../launchers/windows/nuke12.0.bat | 0 .../launchers/windows/nukestudio10.0.bat | 0 .../launchers/windows/nukestudio11.0.bat | 0 .../launchers/windows/nukestudio11.2.bat | 0 .../launchers/windows/nukestudio11.3.bat | 0 .../launchers/windows/nukestudio12.0.bat | 0 .../launchers/windows/nukex10.0.bat | 0 .../launchers/windows/nukex11.0.bat | 0 .../launchers/windows/nukex11.2.bat | 0 .../launchers/windows/nukex11.3.bat | 0 .../launchers/windows/nukex12.0.bat | 0 .../launchers/windows/photoshop_2020.bat | 0 .../launchers/windows/premiere_pro_2019.bat | 0 .../launchers/windows/premiere_pro_2020.bat | 0 .../launchers/windows/python3.bat | 0 .../launchers/windows/resolve_16.bat | 0 .../launchers/windows/shell.bat | 0 .../launchers/windows/storyboardpro_7.bat | 0 .../launchers/windows/unreal.bat | 0 206 files changed, 35 insertions(+), 390 deletions(-) delete mode 100644 pype/configurations/defaults/presets/init.json delete mode 100644 pype/configurations/defaults/presets/plugins/celaction/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/config.json delete mode 100644 pype/configurations/defaults/presets/plugins/ftrack/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/global/create.json delete mode 100644 pype/configurations/defaults/presets/plugins/global/filter.json delete mode 100644 pype/configurations/defaults/presets/plugins/global/load.json delete mode 100644 pype/configurations/defaults/presets/plugins/global/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/maya/create.json delete mode 100644 pype/configurations/defaults/presets/plugins/maya/filter.json delete mode 100644 pype/configurations/defaults/presets/plugins/maya/load.json delete mode 100644 pype/configurations/defaults/presets/plugins/maya/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/maya/workfile_build.json delete mode 100644 pype/configurations/defaults/presets/plugins/nuke/create.json delete mode 100644 pype/configurations/defaults/presets/plugins/nuke/load.json delete mode 100644 pype/configurations/defaults/presets/plugins/nuke/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/nuke/workfile_build.json delete mode 100644 pype/configurations/defaults/presets/plugins/nukestudio/filter.json delete mode 100644 pype/configurations/defaults/presets/plugins/nukestudio/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/resolve/create.json delete mode 100644 pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json delete mode 100644 pype/configurations/defaults/presets/plugins/test/create.json delete mode 100644 pype/configurations/defaults/presets/plugins/test/publish.json delete mode 100644 pype/configurations/defaults/presets/tools/pyblish.json delete mode 100644 pype/configurations/defaults/presets/tray/menu_items.json rename pype/configurations/defaults/{ => project_configurations}/anatomy/README.md (100%) rename pype/configurations/defaults/{presets/colorspace/default.json => project_configurations/anatomy/colorspace.json} (100%) rename pype/configurations/defaults/{presets => project_configurations/anatomy}/colorspace/aces103-cg.json (100%) rename pype/configurations/defaults/{presets/dataflow/default.json => project_configurations/anatomy/dataflow.json} (100%) rename pype/configurations/defaults/{presets => project_configurations/anatomy}/dataflow/aces-exr.json (100%) rename pype/configurations/defaults/{ => project_configurations}/anatomy/default.yaml (100%) rename pype/configurations/defaults/{ => project_configurations}/anatomy/roots.json (100%) create mode 100644 pype/configurations/defaults/project_configurations/anatomy/templates.json rename pype/configurations/defaults/project_configurations/{plugins => }/celaction/publish.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/config.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/ftrack/ftrack_config.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/ftrack/ftrack_custom_attributes.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/ftrack/partnership_ftrack_cred.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/ftrack/plugins/server.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/ftrack/plugins/user.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/ftrack/project_defaults.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/ftrack/publish.json (100%) rename pype/configurations/defaults/project_configurations/{plugins/maya => global}/create.json (100%) rename pype/configurations/defaults/{presets/tools => project_configurations/global}/creator.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/global/filter.json (100%) rename pype/configurations/defaults/project_configurations/{plugins/nuke => global}/load.json (100%) rename pype/configurations/defaults/{presets/tools => project_configurations/global}/project_folder_structure.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/global/publish.json (100%) rename pype/configurations/defaults/{presets/tools => project_configurations/global}/sw_folders.json (100%) rename pype/configurations/defaults/{presets/tools => project_configurations/global}/workfiles.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/maya/capture.json (100%) rename pype/configurations/defaults/project_configurations/{plugins/global => maya}/create.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/maya/filter.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/maya/load.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/maya/publish.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/maya/workfile_build.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/muster/templates_mapping.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/nuke/create.json (100%) rename pype/configurations/defaults/project_configurations/{plugins/global => nuke}/load.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/nuke/publish.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/nuke/workfile_build.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/nukestudio/filter.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/nukestudio/publish.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/nukestudio/tags.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/premiere/asset_default.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/premiere/rules_tasks.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/resolve/create.json (100%) rename pype/configurations/defaults/{presets/standalone_publish => project_configurations/standalonepublisher}/families.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/standalonepublisher/publish.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/test/create.json (100%) rename pype/configurations/defaults/project_configurations/{plugins => }/test/publish.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/tools/slates/example_HD.json (100%) rename pype/configurations/defaults/{presets => project_configurations}/unreal/project_setup.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/avalon.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/blender.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/celaction.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/deadline.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/ftrack.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/global.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/harmony.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/houdini.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/maya.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/maya_2018.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/maya_2020.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/mayabatch.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/mayabatch_2019.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/mtoa_3.1.1.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/muster.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/nuke.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/nukestudio.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/nukestudio_10.0.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/nukex.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/nukex_10.0.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/photoshop.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/premiere.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/resolve.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/storyboardpro.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/unreal_4.24.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/environments/vray_4300.json (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/blender_2.80.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/blender_2.81.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/blender_2.82.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/blender_2.83.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/celaction_local.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/celaction_publish.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/darwin/blender_2.82 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/darwin/harmony_17 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/darwin/harmony_17_launch (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/darwin/python3 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/harmony_17.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/houdini_16.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/houdini_17.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/houdini_18.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/maya2016 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/maya2017 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/maya2018 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/maya2019 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/maya2020 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/nuke11.3 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/nuke12.0 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/nukestudio11.3 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/nukestudio12.0 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/nukex11.3 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/linux/nukex12.0 (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/maya_2016.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/maya_2017.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/maya_2018.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/maya_2019.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/maya_2020.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayabatch_2019.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayabatch_2020.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayapy2016.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayapy2017.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayapy2018.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayapy2019.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/mayapy2020.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/myapp.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nuke_10.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nuke_11.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nuke_11.2.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nuke_11.3.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nuke_12.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukestudio_10.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukestudio_11.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukestudio_11.2.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukestudio_11.3.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukestudio_12.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukex_10.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukex_11.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukex_11.2.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukex_11.3.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/nukex_12.0.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/photoshop_2020.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/premiere_2019.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/premiere_2020.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/python_2.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/python_3.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/resolve_16.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/shell.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/storyboardpro_7.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/unreal_4.24.toml (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/blender_2.80.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/blender_2.81.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/blender_2.82.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/blender_2.83.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/celaction_local.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/celaction_publish.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/harmony_17.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/houdini_16.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/houdini_17.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/houdini_18.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/maya2016.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/maya2017.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/maya2018.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/maya2019.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/maya2020.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayabatch2019.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayabatch2020.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayapy2016.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayapy2017.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayapy2018.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayapy2019.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/mayapy2020.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nuke10.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nuke11.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nuke11.2.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nuke11.3.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nuke12.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukestudio10.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukestudio11.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukestudio11.2.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukestudio11.3.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukestudio12.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukex10.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukex11.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukex11.2.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukex11.3.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/nukex12.0.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/photoshop_2020.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/premiere_pro_2019.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/premiere_pro_2020.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/python3.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/resolve_16.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/shell.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/storyboardpro_7.bat (100%) rename pype/configurations/defaults/{ => studio_configurations}/launchers/windows/unreal.bat (100%) diff --git a/pype/configurations/defaults/presets/init.json b/pype/configurations/defaults/presets/init.json deleted file mode 100644 index 361ee7445b..0000000000 --- a/pype/configurations/defaults/presets/init.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "colorspace": "default", - "dataflow": "default" -} diff --git a/pype/configurations/defaults/presets/plugins/celaction/publish.json b/pype/configurations/defaults/presets/plugins/celaction/publish.json deleted file mode 100644 index e791f574d9..0000000000 --- a/pype/configurations/defaults/presets/plugins/celaction/publish.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ExtractCelactionDeadline": { - "deadline_department": "", - "deadline_priority": 50, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_group": "", - "deadline_chunk_size": 10 - } -} diff --git a/pype/configurations/defaults/presets/plugins/config.json b/pype/configurations/defaults/presets/plugins/config.json deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/pype/configurations/defaults/presets/plugins/config.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/pype/configurations/defaults/presets/plugins/ftrack/publish.json b/pype/configurations/defaults/presets/plugins/ftrack/publish.json deleted file mode 100644 index d0469ae4f7..0000000000 --- a/pype/configurations/defaults/presets/plugins/ftrack/publish.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "IntegrateFtrackNote": { - "note_with_intent_template": "{intent}: {comment}", - "note_labels": [] - } -} diff --git a/pype/configurations/defaults/presets/plugins/global/create.json b/pype/configurations/defaults/presets/plugins/global/create.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/configurations/defaults/presets/plugins/global/create.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/configurations/defaults/presets/plugins/global/filter.json b/pype/configurations/defaults/presets/plugins/global/filter.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/configurations/defaults/presets/plugins/global/filter.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/configurations/defaults/presets/plugins/global/load.json b/pype/configurations/defaults/presets/plugins/global/load.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/configurations/defaults/presets/plugins/global/load.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/configurations/defaults/presets/plugins/global/publish.json b/pype/configurations/defaults/presets/plugins/global/publish.json deleted file mode 100644 index 016868fc92..0000000000 --- a/pype/configurations/defaults/presets/plugins/global/publish.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "IntegrateMasterVersion": { - "enabled": false - }, - "ExtractJpegEXR": { - "ffmpeg_args": { - "input": [ - "-gamma 2.2" - ], - "output": [] - } - }, - "ExtractReview": { - "__documentation__": "http://pype.club/docs/admin_presets_plugins", - "profiles": [ - { - "families": [], - "hosts": [], - "outputs": { - "h264": { - "filter": { - "families": ["render", "review", "ftrack"] - }, - "ext": "mp4", - "ffmpeg_args": { - "input": [ - "-gamma 2.2" - ], - "video_filters": [], - "audio_filters": [], - "output": [ - "-pix_fmt yuv420p", - "-crf 18", - "-intra" - ] - }, - "tags": ["burnin", "ftrackreview"] - } - } - } - ] - }, - "ExtractBurnin": { - "options": { - "opacity": 1, - "x_offset": 5, - "y_offset": 5, - "bg_padding": 5, - "bg_opacity": 0.5, - "font_size": 42 - }, - "fields": { - - }, - "profiles": [ - { - "burnins": { - "burnin": { - "TOP_LEFT": "{yy}-{mm}-{dd}", - "TOP_RIGHT": "{anatomy[version]}", - "TOP_CENTERED": "", - "BOTTOM_RIGHT": "{frame_start}-{current_frame}-{frame_end}", - "BOTTOM_CENTERED": "{asset}", - "BOTTOM_LEFT": "{username}" - } - } - } - ] - }, - "IntegrateAssetNew": { - "template_name_profiles": { - "publish": { - "families": [], - "tasks": [] - }, - "render": { - "families": ["review", "render", "prerender"] - } - } - }, - "ProcessSubmittedJobOnFarm": { - "deadline_department": "", - "deadline_pool": "", - "deadline_group": "" - } -} diff --git a/pype/configurations/defaults/presets/plugins/maya/create.json b/pype/configurations/defaults/presets/plugins/maya/create.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/configurations/defaults/presets/plugins/maya/create.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/configurations/defaults/presets/plugins/maya/filter.json b/pype/configurations/defaults/presets/plugins/maya/filter.json deleted file mode 100644 index 83d6f05f31..0000000000 --- a/pype/configurations/defaults/presets/plugins/maya/filter.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Preset n1": { - "ValidateNoAnimation": false, - "ValidateShapeDefaultNames": false - }, - "Preset n2": { - "ValidateNoAnimation": false - } -} diff --git a/pype/configurations/defaults/presets/plugins/maya/load.json b/pype/configurations/defaults/presets/plugins/maya/load.json deleted file mode 100644 index 260fbb35ee..0000000000 --- a/pype/configurations/defaults/presets/plugins/maya/load.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "colors": { - "model": [0.821, 0.518, 0.117], - "rig": [0.144, 0.443, 0.463], - "pointcache": [0.368, 0.821, 0.117], - "animation": [0.368, 0.821, 0.117], - "ass": [1.0, 0.332, 0.312], - "camera": [0.447, 0.312, 1.0], - "fbx": [1.0, 0.931, 0.312], - "mayaAscii": [0.312, 1.0, 0.747], - "setdress": [0.312, 1.0, 0.747], - "layout": [0.312, 1.0, 0.747], - "vdbcache": [0.312, 1.0, 0.428], - "vrayproxy": [0.258, 0.95, 0.541], - "yeticache": [0.2, 0.8, 0.3], - "yetiRig": [0, 0.8, 0.5] - } -} diff --git a/pype/configurations/defaults/presets/plugins/maya/publish.json b/pype/configurations/defaults/presets/plugins/maya/publish.json deleted file mode 100644 index 2e2b3164f3..0000000000 --- a/pype/configurations/defaults/presets/plugins/maya/publish.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ValidateModelName": { - "enabled": false, - "material_file": "/path/to/shader_name_definition.txt", - "regex": "(.*)_(\\d)*_(?P.*)_(GEO)" - }, - "ValidateAssemblyName": { - "enabled": false - }, - "ValidateShaderName": { - "enabled": false, - "regex": "(?P.*)_(.*)_SHD" - }, - "ValidateMeshHasOverlappingUVs": { - "enabled": false - } -} diff --git a/pype/configurations/defaults/presets/plugins/maya/workfile_build.json b/pype/configurations/defaults/presets/plugins/maya/workfile_build.json deleted file mode 100644 index 2872b783cb..0000000000 --- a/pype/configurations/defaults/presets/plugins/maya/workfile_build.json +++ /dev/null @@ -1,54 +0,0 @@ -[{ - "tasks": ["lighting"], - - "current_context": [{ - "subset_name_filters": [".+[Mm]ain"], - "families": ["model"], - "repre_names": ["abc", "ma"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["animation", "pointcache"], - "repre_names": ["abc"], - "loaders": ["ReferenceLoader"] - },{ - "families": ["rendersetup"], - "repre_names": ["json"], - "loaders": ["RenderSetupLoader"] - }, { - "families": ["camera"], - "repre_names": ["abc"], - "loaders": ["ReferenceLoader"] - }], - - "linked_assets": [{ - "families": ["setdress"], - "repre_names": ["ma"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["ass"], - "repre_names": ["ass"], - "loaders":["assLoader"] - }] -}, { - "tasks": ["animation"], - - "current_context": [{ - "families": ["camera"], - "repre_names": ["abc", "ma"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["audio"], - "repre_names": ["wav"], - "loaders": ["RenderSetupLoader"] - }], - - "linked_assets": [{ - "families": ["setdress"], - "repre_names": ["proxy"], - "loaders": ["ReferenceLoader"] - }, { - "families": ["rig"], - "repre_names": ["ass"], - "loaders": ["rigLoader"] - }] -}] diff --git a/pype/configurations/defaults/presets/plugins/nuke/create.json b/pype/configurations/defaults/presets/plugins/nuke/create.json deleted file mode 100644 index 4deb0b4ad5..0000000000 --- a/pype/configurations/defaults/presets/plugins/nuke/create.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "CreateWriteRender": { - "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" - }, - "CreateWritePrerender": { - "fpath_template": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" - } -} diff --git a/pype/configurations/defaults/presets/plugins/nuke/load.json b/pype/configurations/defaults/presets/plugins/nuke/load.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/pype/configurations/defaults/presets/plugins/nuke/load.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/pype/configurations/defaults/presets/plugins/nuke/publish.json b/pype/configurations/defaults/presets/plugins/nuke/publish.json deleted file mode 100644 index ab0d0e76a5..0000000000 --- a/pype/configurations/defaults/presets/plugins/nuke/publish.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "ExtractThumbnail": { - "nodes": { - "Reformat": [ - ["type", "to format"], - ["format", "HD_1080"], - ["filter", "Lanczos6"], - ["black_outside", true], - ["pbb", false] - ] - } - }, - "ValidateNukeWriteKnobs": { - "enabled": false, - "knobs": { - "render": { - "review": true - } - } - }, - "ExtractReviewDataLut": { - "__documentation__": { - "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", - "enabled": "keep in on `false` if you want Nuke baking colorspace workflow applied else FFmpeg will convert imgsequence with baked LUT" - }, - "enabled": false - }, - "ExtractReviewDataMov": { - "__documentation__": { - "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`", - "enabled": "keep in on `true` if you want Nuke baking colorspace workflow applied" - }, - "enabled": true, - "viewer_lut_raw": false - }, - "ExtractSlateFrame": { - "__documentation__": { - "viewer_lut_raw": "set to `true` if you Input_process node on viewer is used with baked screen space, so you have to look with RAW viewer lut. Else just keep it on `false`" - }, - "viewer_lut_raw": false - }, - "NukeSubmitDeadline": { - "deadline_priority": 50, - "deadline_pool": "", - "deadline_pool_secondary": "", - "deadline_chunk_size": 1 - } -} diff --git a/pype/configurations/defaults/presets/plugins/nuke/workfile_build.json b/pype/configurations/defaults/presets/plugins/nuke/workfile_build.json deleted file mode 100644 index d3613c929e..0000000000 --- a/pype/configurations/defaults/presets/plugins/nuke/workfile_build.json +++ /dev/null @@ -1,11 +0,0 @@ -[{ - "tasks": ["compositing"], - - "current_context": [{ - "families": ["render", "plate"], - "repre_names": ["exr" ,"dpx"], - "loaders": ["LoadSequence"] - }], - - "linked_assets": [] -}] diff --git a/pype/configurations/defaults/presets/plugins/nukestudio/filter.json b/pype/configurations/defaults/presets/plugins/nukestudio/filter.json deleted file mode 100644 index bd6a0dc1bd..0000000000 --- a/pype/configurations/defaults/presets/plugins/nukestudio/filter.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "strict": { - "ValidateVersion": true, - "VersionUpWorkfile": true - }, - "benevolent": { - "ValidateVersion": false, - "VersionUpWorkfile": false - } -} \ No newline at end of file diff --git a/pype/configurations/defaults/presets/plugins/nukestudio/publish.json b/pype/configurations/defaults/presets/plugins/nukestudio/publish.json deleted file mode 100644 index 8c4ad133f1..0000000000 --- a/pype/configurations/defaults/presets/plugins/nukestudio/publish.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "CollectInstanceVersion": { - "enabled": false - }, - "ExtractReviewCutUpVideo": { - "tags_addition": [] - } -} diff --git a/pype/configurations/defaults/presets/plugins/resolve/create.json b/pype/configurations/defaults/presets/plugins/resolve/create.json deleted file mode 100644 index 29ca5900fb..0000000000 --- a/pype/configurations/defaults/presets/plugins/resolve/create.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "CreateShotClip": { - "clipName": "{track}{sequence}{shot}", - "folder": "takes", - "steps": 20 - } -} diff --git a/pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json b/pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json deleted file mode 100644 index 2b2fb660c2..0000000000 --- a/pype/configurations/defaults/presets/plugins/standalonepublisher/publish.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "ExtractThumbnailSP": { - "ffmpeg_args": { - "input": [ - "-gamma 2.2" - ], - "output": [] - } - }, - "ExtractReviewSP": { - "outputs": { - "h264": { - "input": [ - "-gamma 2.2" - ], - "output": [ - "-pix_fmt yuv420p", - "-crf 18" - ], - "tags": ["preview"], - "ext": "mov" - } - } - } -} diff --git a/pype/configurations/defaults/presets/plugins/test/create.json b/pype/configurations/defaults/presets/plugins/test/create.json deleted file mode 100644 index fa0b2fc05f..0000000000 --- a/pype/configurations/defaults/presets/plugins/test/create.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "MyTestCreator": { - "my_test_property": "B", - "active": false, - "new_property": "new", - "family": "new_family" - } -} diff --git a/pype/configurations/defaults/presets/plugins/test/publish.json b/pype/configurations/defaults/presets/plugins/test/publish.json deleted file mode 100644 index 3180dd5d8a..0000000000 --- a/pype/configurations/defaults/presets/plugins/test/publish.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "MyTestPlugin": { - "label": "loaded from preset", - "optional": true, - "families": ["changed", "by", "preset"] - }, - "MyTestRemovedPlugin": { - "enabled": false - } -} diff --git a/pype/configurations/defaults/presets/tools/pyblish.json b/pype/configurations/defaults/presets/tools/pyblish.json deleted file mode 100644 index e81932ec45..0000000000 --- a/pype/configurations/defaults/presets/tools/pyblish.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ui": { - "intents": { - "__description__": [ - "In items you can specify {label: value} of intents", - "`default` may be used for setting default value." - ], - "default": "wip", - "items": { - "": "", - "wip": "WIP", - "test": "TEST", - "final": "FINAL" - } - } - } -} diff --git a/pype/configurations/defaults/presets/tray/menu_items.json b/pype/configurations/defaults/presets/tray/menu_items.json deleted file mode 100644 index 6c6763848b..0000000000 --- a/pype/configurations/defaults/presets/tray/menu_items.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "item_usage": { - "User settings": false, - "Ftrack": true, - "Muster": false, - "Avalon": true, - "Clockify": false, - "Standalone Publish": true, - "Logging": true, - "Idle Manager": true, - "Timers Manager": true, - "Rest Api": true, - "Adobe Communicator": true - }, - "attributes": { - "Rest Api": { - "default_port": 8021, - "exclude_ports": [] - }, - "Timers Manager": { - "full_time": 15, - "message_time": 0.5 - }, - "Clockify": { - "workspace_name": null - } - } -} diff --git a/pype/configurations/defaults/anatomy/README.md b/pype/configurations/defaults/project_configurations/anatomy/README.md similarity index 100% rename from pype/configurations/defaults/anatomy/README.md rename to pype/configurations/defaults/project_configurations/anatomy/README.md diff --git a/pype/configurations/defaults/presets/colorspace/default.json b/pype/configurations/defaults/project_configurations/anatomy/colorspace.json similarity index 100% rename from pype/configurations/defaults/presets/colorspace/default.json rename to pype/configurations/defaults/project_configurations/anatomy/colorspace.json diff --git a/pype/configurations/defaults/presets/colorspace/aces103-cg.json b/pype/configurations/defaults/project_configurations/anatomy/colorspace/aces103-cg.json similarity index 100% rename from pype/configurations/defaults/presets/colorspace/aces103-cg.json rename to pype/configurations/defaults/project_configurations/anatomy/colorspace/aces103-cg.json diff --git a/pype/configurations/defaults/presets/dataflow/default.json b/pype/configurations/defaults/project_configurations/anatomy/dataflow.json similarity index 100% rename from pype/configurations/defaults/presets/dataflow/default.json rename to pype/configurations/defaults/project_configurations/anatomy/dataflow.json diff --git a/pype/configurations/defaults/presets/dataflow/aces-exr.json b/pype/configurations/defaults/project_configurations/anatomy/dataflow/aces-exr.json similarity index 100% rename from pype/configurations/defaults/presets/dataflow/aces-exr.json rename to pype/configurations/defaults/project_configurations/anatomy/dataflow/aces-exr.json diff --git a/pype/configurations/defaults/anatomy/default.yaml b/pype/configurations/defaults/project_configurations/anatomy/default.yaml similarity index 100% rename from pype/configurations/defaults/anatomy/default.yaml rename to pype/configurations/defaults/project_configurations/anatomy/default.yaml diff --git a/pype/configurations/defaults/anatomy/roots.json b/pype/configurations/defaults/project_configurations/anatomy/roots.json similarity index 100% rename from pype/configurations/defaults/anatomy/roots.json rename to pype/configurations/defaults/project_configurations/anatomy/roots.json diff --git a/pype/configurations/defaults/project_configurations/anatomy/templates.json b/pype/configurations/defaults/project_configurations/anatomy/templates.json new file mode 100644 index 0000000000..23e9f308f2 --- /dev/null +++ b/pype/configurations/defaults/project_configurations/anatomy/templates.json @@ -0,0 +1,35 @@ +{ + "version_padding": 3, + "version": "v{version:0>{@version_padding}}", + "frame_padding": 4, + "frame": "{frame:0>{@frame_padding}}", + + "work": { + "folder": "{root}/{project[name]}/{hierarchy}/{asset}/work/{task}", + "file": "{project[code]}_{asset}_{task}_{@version}<_{comment}>.{ext}", + "path": "{@folder}/{@file}" + }, + + "render": { + "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/render/{subset}/{@version}", + "file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}", + "path": "{@folder}/{@file}" + }, + + "texture": { + "path": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}" + }, + + "publish": { + "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}", + "file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}", + "path": "{@folder}/{@file}", + "thumbnail": "{thumbnail_root}/{project[name]}/{_id}_{thumbnail_type}{ext}" + }, + + "master": { + "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/master", + "file": "{project[code]}_{asset}_{subset}_master<_{output}><.{frame}>.{representation}", + "path": "{@folder}/{@file}" + } +} diff --git a/pype/configurations/defaults/project_configurations/plugins/celaction/publish.json b/pype/configurations/defaults/project_configurations/celaction/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/celaction/publish.json rename to pype/configurations/defaults/project_configurations/celaction/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/config.json b/pype/configurations/defaults/project_configurations/config.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/config.json rename to pype/configurations/defaults/project_configurations/config.json diff --git a/pype/configurations/defaults/presets/ftrack/ftrack_config.json b/pype/configurations/defaults/project_configurations/ftrack/ftrack_config.json similarity index 100% rename from pype/configurations/defaults/presets/ftrack/ftrack_config.json rename to pype/configurations/defaults/project_configurations/ftrack/ftrack_config.json diff --git a/pype/configurations/defaults/presets/ftrack/ftrack_custom_attributes.json b/pype/configurations/defaults/project_configurations/ftrack/ftrack_custom_attributes.json similarity index 100% rename from pype/configurations/defaults/presets/ftrack/ftrack_custom_attributes.json rename to pype/configurations/defaults/project_configurations/ftrack/ftrack_custom_attributes.json diff --git a/pype/configurations/defaults/presets/ftrack/partnership_ftrack_cred.json b/pype/configurations/defaults/project_configurations/ftrack/partnership_ftrack_cred.json similarity index 100% rename from pype/configurations/defaults/presets/ftrack/partnership_ftrack_cred.json rename to pype/configurations/defaults/project_configurations/ftrack/partnership_ftrack_cred.json diff --git a/pype/configurations/defaults/presets/ftrack/plugins/server.json b/pype/configurations/defaults/project_configurations/ftrack/plugins/server.json similarity index 100% rename from pype/configurations/defaults/presets/ftrack/plugins/server.json rename to pype/configurations/defaults/project_configurations/ftrack/plugins/server.json diff --git a/pype/configurations/defaults/presets/ftrack/plugins/user.json b/pype/configurations/defaults/project_configurations/ftrack/plugins/user.json similarity index 100% rename from pype/configurations/defaults/presets/ftrack/plugins/user.json rename to pype/configurations/defaults/project_configurations/ftrack/plugins/user.json diff --git a/pype/configurations/defaults/presets/ftrack/project_defaults.json b/pype/configurations/defaults/project_configurations/ftrack/project_defaults.json similarity index 100% rename from pype/configurations/defaults/presets/ftrack/project_defaults.json rename to pype/configurations/defaults/project_configurations/ftrack/project_defaults.json diff --git a/pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json b/pype/configurations/defaults/project_configurations/ftrack/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json rename to pype/configurations/defaults/project_configurations/ftrack/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/create.json b/pype/configurations/defaults/project_configurations/global/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/create.json rename to pype/configurations/defaults/project_configurations/global/create.json diff --git a/pype/configurations/defaults/presets/tools/creator.json b/pype/configurations/defaults/project_configurations/global/creator.json similarity index 100% rename from pype/configurations/defaults/presets/tools/creator.json rename to pype/configurations/defaults/project_configurations/global/creator.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/filter.json b/pype/configurations/defaults/project_configurations/global/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/filter.json rename to pype/configurations/defaults/project_configurations/global/filter.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/load.json b/pype/configurations/defaults/project_configurations/global/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/load.json rename to pype/configurations/defaults/project_configurations/global/load.json diff --git a/pype/configurations/defaults/presets/tools/project_folder_structure.json b/pype/configurations/defaults/project_configurations/global/project_folder_structure.json similarity index 100% rename from pype/configurations/defaults/presets/tools/project_folder_structure.json rename to pype/configurations/defaults/project_configurations/global/project_folder_structure.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/publish.json b/pype/configurations/defaults/project_configurations/global/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/publish.json rename to pype/configurations/defaults/project_configurations/global/publish.json diff --git a/pype/configurations/defaults/presets/tools/sw_folders.json b/pype/configurations/defaults/project_configurations/global/sw_folders.json similarity index 100% rename from pype/configurations/defaults/presets/tools/sw_folders.json rename to pype/configurations/defaults/project_configurations/global/sw_folders.json diff --git a/pype/configurations/defaults/presets/tools/workfiles.json b/pype/configurations/defaults/project_configurations/global/workfiles.json similarity index 100% rename from pype/configurations/defaults/presets/tools/workfiles.json rename to pype/configurations/defaults/project_configurations/global/workfiles.json diff --git a/pype/configurations/defaults/presets/maya/capture.json b/pype/configurations/defaults/project_configurations/maya/capture.json similarity index 100% rename from pype/configurations/defaults/presets/maya/capture.json rename to pype/configurations/defaults/project_configurations/maya/capture.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/create.json b/pype/configurations/defaults/project_configurations/maya/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/create.json rename to pype/configurations/defaults/project_configurations/maya/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/filter.json b/pype/configurations/defaults/project_configurations/maya/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/filter.json rename to pype/configurations/defaults/project_configurations/maya/filter.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/load.json b/pype/configurations/defaults/project_configurations/maya/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/load.json rename to pype/configurations/defaults/project_configurations/maya/load.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/publish.json b/pype/configurations/defaults/project_configurations/maya/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/publish.json rename to pype/configurations/defaults/project_configurations/maya/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json b/pype/configurations/defaults/project_configurations/maya/workfile_build.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json rename to pype/configurations/defaults/project_configurations/maya/workfile_build.json diff --git a/pype/configurations/defaults/presets/muster/templates_mapping.json b/pype/configurations/defaults/project_configurations/muster/templates_mapping.json similarity index 100% rename from pype/configurations/defaults/presets/muster/templates_mapping.json rename to pype/configurations/defaults/project_configurations/muster/templates_mapping.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/create.json b/pype/configurations/defaults/project_configurations/nuke/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/create.json rename to pype/configurations/defaults/project_configurations/nuke/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/load.json b/pype/configurations/defaults/project_configurations/nuke/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/load.json rename to pype/configurations/defaults/project_configurations/nuke/load.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/publish.json b/pype/configurations/defaults/project_configurations/nuke/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/publish.json rename to pype/configurations/defaults/project_configurations/nuke/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json b/pype/configurations/defaults/project_configurations/nuke/workfile_build.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json rename to pype/configurations/defaults/project_configurations/nuke/workfile_build.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json b/pype/configurations/defaults/project_configurations/nukestudio/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json rename to pype/configurations/defaults/project_configurations/nukestudio/filter.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json b/pype/configurations/defaults/project_configurations/nukestudio/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json rename to pype/configurations/defaults/project_configurations/nukestudio/publish.json diff --git a/pype/configurations/defaults/presets/nukestudio/tags.json b/pype/configurations/defaults/project_configurations/nukestudio/tags.json similarity index 100% rename from pype/configurations/defaults/presets/nukestudio/tags.json rename to pype/configurations/defaults/project_configurations/nukestudio/tags.json diff --git a/pype/configurations/defaults/presets/premiere/asset_default.json b/pype/configurations/defaults/project_configurations/premiere/asset_default.json similarity index 100% rename from pype/configurations/defaults/presets/premiere/asset_default.json rename to pype/configurations/defaults/project_configurations/premiere/asset_default.json diff --git a/pype/configurations/defaults/presets/premiere/rules_tasks.json b/pype/configurations/defaults/project_configurations/premiere/rules_tasks.json similarity index 100% rename from pype/configurations/defaults/presets/premiere/rules_tasks.json rename to pype/configurations/defaults/project_configurations/premiere/rules_tasks.json diff --git a/pype/configurations/defaults/project_configurations/plugins/resolve/create.json b/pype/configurations/defaults/project_configurations/resolve/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/resolve/create.json rename to pype/configurations/defaults/project_configurations/resolve/create.json diff --git a/pype/configurations/defaults/presets/standalone_publish/families.json b/pype/configurations/defaults/project_configurations/standalonepublisher/families.json similarity index 100% rename from pype/configurations/defaults/presets/standalone_publish/families.json rename to pype/configurations/defaults/project_configurations/standalonepublisher/families.json diff --git a/pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json b/pype/configurations/defaults/project_configurations/standalonepublisher/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json rename to pype/configurations/defaults/project_configurations/standalonepublisher/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/test/create.json b/pype/configurations/defaults/project_configurations/test/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/test/create.json rename to pype/configurations/defaults/project_configurations/test/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/test/publish.json b/pype/configurations/defaults/project_configurations/test/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/test/publish.json rename to pype/configurations/defaults/project_configurations/test/publish.json diff --git a/pype/configurations/defaults/presets/tools/slates/example_HD.json b/pype/configurations/defaults/project_configurations/tools/slates/example_HD.json similarity index 100% rename from pype/configurations/defaults/presets/tools/slates/example_HD.json rename to pype/configurations/defaults/project_configurations/tools/slates/example_HD.json diff --git a/pype/configurations/defaults/presets/unreal/project_setup.json b/pype/configurations/defaults/project_configurations/unreal/project_setup.json similarity index 100% rename from pype/configurations/defaults/presets/unreal/project_setup.json rename to pype/configurations/defaults/project_configurations/unreal/project_setup.json diff --git a/pype/configurations/defaults/environments/avalon.json b/pype/configurations/defaults/studio_configurations/environments/avalon.json similarity index 100% rename from pype/configurations/defaults/environments/avalon.json rename to pype/configurations/defaults/studio_configurations/environments/avalon.json diff --git a/pype/configurations/defaults/environments/blender.json b/pype/configurations/defaults/studio_configurations/environments/blender.json similarity index 100% rename from pype/configurations/defaults/environments/blender.json rename to pype/configurations/defaults/studio_configurations/environments/blender.json diff --git a/pype/configurations/defaults/environments/celaction.json b/pype/configurations/defaults/studio_configurations/environments/celaction.json similarity index 100% rename from pype/configurations/defaults/environments/celaction.json rename to pype/configurations/defaults/studio_configurations/environments/celaction.json diff --git a/pype/configurations/defaults/environments/deadline.json b/pype/configurations/defaults/studio_configurations/environments/deadline.json similarity index 100% rename from pype/configurations/defaults/environments/deadline.json rename to pype/configurations/defaults/studio_configurations/environments/deadline.json diff --git a/pype/configurations/defaults/environments/ftrack.json b/pype/configurations/defaults/studio_configurations/environments/ftrack.json similarity index 100% rename from pype/configurations/defaults/environments/ftrack.json rename to pype/configurations/defaults/studio_configurations/environments/ftrack.json diff --git a/pype/configurations/defaults/environments/global.json b/pype/configurations/defaults/studio_configurations/environments/global.json similarity index 100% rename from pype/configurations/defaults/environments/global.json rename to pype/configurations/defaults/studio_configurations/environments/global.json diff --git a/pype/configurations/defaults/environments/harmony.json b/pype/configurations/defaults/studio_configurations/environments/harmony.json similarity index 100% rename from pype/configurations/defaults/environments/harmony.json rename to pype/configurations/defaults/studio_configurations/environments/harmony.json diff --git a/pype/configurations/defaults/environments/houdini.json b/pype/configurations/defaults/studio_configurations/environments/houdini.json similarity index 100% rename from pype/configurations/defaults/environments/houdini.json rename to pype/configurations/defaults/studio_configurations/environments/houdini.json diff --git a/pype/configurations/defaults/environments/maya.json b/pype/configurations/defaults/studio_configurations/environments/maya.json similarity index 100% rename from pype/configurations/defaults/environments/maya.json rename to pype/configurations/defaults/studio_configurations/environments/maya.json diff --git a/pype/configurations/defaults/environments/maya_2018.json b/pype/configurations/defaults/studio_configurations/environments/maya_2018.json similarity index 100% rename from pype/configurations/defaults/environments/maya_2018.json rename to pype/configurations/defaults/studio_configurations/environments/maya_2018.json diff --git a/pype/configurations/defaults/environments/maya_2020.json b/pype/configurations/defaults/studio_configurations/environments/maya_2020.json similarity index 100% rename from pype/configurations/defaults/environments/maya_2020.json rename to pype/configurations/defaults/studio_configurations/environments/maya_2020.json diff --git a/pype/configurations/defaults/environments/mayabatch.json b/pype/configurations/defaults/studio_configurations/environments/mayabatch.json similarity index 100% rename from pype/configurations/defaults/environments/mayabatch.json rename to pype/configurations/defaults/studio_configurations/environments/mayabatch.json diff --git a/pype/configurations/defaults/environments/mayabatch_2019.json b/pype/configurations/defaults/studio_configurations/environments/mayabatch_2019.json similarity index 100% rename from pype/configurations/defaults/environments/mayabatch_2019.json rename to pype/configurations/defaults/studio_configurations/environments/mayabatch_2019.json diff --git a/pype/configurations/defaults/environments/mtoa_3.1.1.json b/pype/configurations/defaults/studio_configurations/environments/mtoa_3.1.1.json similarity index 100% rename from pype/configurations/defaults/environments/mtoa_3.1.1.json rename to pype/configurations/defaults/studio_configurations/environments/mtoa_3.1.1.json diff --git a/pype/configurations/defaults/environments/muster.json b/pype/configurations/defaults/studio_configurations/environments/muster.json similarity index 100% rename from pype/configurations/defaults/environments/muster.json rename to pype/configurations/defaults/studio_configurations/environments/muster.json diff --git a/pype/configurations/defaults/environments/nuke.json b/pype/configurations/defaults/studio_configurations/environments/nuke.json similarity index 100% rename from pype/configurations/defaults/environments/nuke.json rename to pype/configurations/defaults/studio_configurations/environments/nuke.json diff --git a/pype/configurations/defaults/environments/nukestudio.json b/pype/configurations/defaults/studio_configurations/environments/nukestudio.json similarity index 100% rename from pype/configurations/defaults/environments/nukestudio.json rename to pype/configurations/defaults/studio_configurations/environments/nukestudio.json diff --git a/pype/configurations/defaults/environments/nukestudio_10.0.json b/pype/configurations/defaults/studio_configurations/environments/nukestudio_10.0.json similarity index 100% rename from pype/configurations/defaults/environments/nukestudio_10.0.json rename to pype/configurations/defaults/studio_configurations/environments/nukestudio_10.0.json diff --git a/pype/configurations/defaults/environments/nukex.json b/pype/configurations/defaults/studio_configurations/environments/nukex.json similarity index 100% rename from pype/configurations/defaults/environments/nukex.json rename to pype/configurations/defaults/studio_configurations/environments/nukex.json diff --git a/pype/configurations/defaults/environments/nukex_10.0.json b/pype/configurations/defaults/studio_configurations/environments/nukex_10.0.json similarity index 100% rename from pype/configurations/defaults/environments/nukex_10.0.json rename to pype/configurations/defaults/studio_configurations/environments/nukex_10.0.json diff --git a/pype/configurations/defaults/environments/photoshop.json b/pype/configurations/defaults/studio_configurations/environments/photoshop.json similarity index 100% rename from pype/configurations/defaults/environments/photoshop.json rename to pype/configurations/defaults/studio_configurations/environments/photoshop.json diff --git a/pype/configurations/defaults/environments/premiere.json b/pype/configurations/defaults/studio_configurations/environments/premiere.json similarity index 100% rename from pype/configurations/defaults/environments/premiere.json rename to pype/configurations/defaults/studio_configurations/environments/premiere.json diff --git a/pype/configurations/defaults/environments/resolve.json b/pype/configurations/defaults/studio_configurations/environments/resolve.json similarity index 100% rename from pype/configurations/defaults/environments/resolve.json rename to pype/configurations/defaults/studio_configurations/environments/resolve.json diff --git a/pype/configurations/defaults/environments/storyboardpro.json b/pype/configurations/defaults/studio_configurations/environments/storyboardpro.json similarity index 100% rename from pype/configurations/defaults/environments/storyboardpro.json rename to pype/configurations/defaults/studio_configurations/environments/storyboardpro.json diff --git a/pype/configurations/defaults/environments/unreal_4.24.json b/pype/configurations/defaults/studio_configurations/environments/unreal_4.24.json similarity index 100% rename from pype/configurations/defaults/environments/unreal_4.24.json rename to pype/configurations/defaults/studio_configurations/environments/unreal_4.24.json diff --git a/pype/configurations/defaults/environments/vray_4300.json b/pype/configurations/defaults/studio_configurations/environments/vray_4300.json similarity index 100% rename from pype/configurations/defaults/environments/vray_4300.json rename to pype/configurations/defaults/studio_configurations/environments/vray_4300.json diff --git a/pype/configurations/defaults/launchers/blender_2.80.toml b/pype/configurations/defaults/studio_configurations/launchers/blender_2.80.toml similarity index 100% rename from pype/configurations/defaults/launchers/blender_2.80.toml rename to pype/configurations/defaults/studio_configurations/launchers/blender_2.80.toml diff --git a/pype/configurations/defaults/launchers/blender_2.81.toml b/pype/configurations/defaults/studio_configurations/launchers/blender_2.81.toml similarity index 100% rename from pype/configurations/defaults/launchers/blender_2.81.toml rename to pype/configurations/defaults/studio_configurations/launchers/blender_2.81.toml diff --git a/pype/configurations/defaults/launchers/blender_2.82.toml b/pype/configurations/defaults/studio_configurations/launchers/blender_2.82.toml similarity index 100% rename from pype/configurations/defaults/launchers/blender_2.82.toml rename to pype/configurations/defaults/studio_configurations/launchers/blender_2.82.toml diff --git a/pype/configurations/defaults/launchers/blender_2.83.toml b/pype/configurations/defaults/studio_configurations/launchers/blender_2.83.toml similarity index 100% rename from pype/configurations/defaults/launchers/blender_2.83.toml rename to pype/configurations/defaults/studio_configurations/launchers/blender_2.83.toml diff --git a/pype/configurations/defaults/launchers/celaction_local.toml b/pype/configurations/defaults/studio_configurations/launchers/celaction_local.toml similarity index 100% rename from pype/configurations/defaults/launchers/celaction_local.toml rename to pype/configurations/defaults/studio_configurations/launchers/celaction_local.toml diff --git a/pype/configurations/defaults/launchers/celaction_publish.toml b/pype/configurations/defaults/studio_configurations/launchers/celaction_publish.toml similarity index 100% rename from pype/configurations/defaults/launchers/celaction_publish.toml rename to pype/configurations/defaults/studio_configurations/launchers/celaction_publish.toml diff --git a/pype/configurations/defaults/launchers/darwin/blender_2.82 b/pype/configurations/defaults/studio_configurations/launchers/darwin/blender_2.82 similarity index 100% rename from pype/configurations/defaults/launchers/darwin/blender_2.82 rename to pype/configurations/defaults/studio_configurations/launchers/darwin/blender_2.82 diff --git a/pype/configurations/defaults/launchers/darwin/harmony_17 b/pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17 similarity index 100% rename from pype/configurations/defaults/launchers/darwin/harmony_17 rename to pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17 diff --git a/pype/configurations/defaults/launchers/darwin/harmony_17_launch b/pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17_launch similarity index 100% rename from pype/configurations/defaults/launchers/darwin/harmony_17_launch rename to pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17_launch diff --git a/pype/configurations/defaults/launchers/darwin/python3 b/pype/configurations/defaults/studio_configurations/launchers/darwin/python3 similarity index 100% rename from pype/configurations/defaults/launchers/darwin/python3 rename to pype/configurations/defaults/studio_configurations/launchers/darwin/python3 diff --git a/pype/configurations/defaults/launchers/harmony_17.toml b/pype/configurations/defaults/studio_configurations/launchers/harmony_17.toml similarity index 100% rename from pype/configurations/defaults/launchers/harmony_17.toml rename to pype/configurations/defaults/studio_configurations/launchers/harmony_17.toml diff --git a/pype/configurations/defaults/launchers/houdini_16.toml b/pype/configurations/defaults/studio_configurations/launchers/houdini_16.toml similarity index 100% rename from pype/configurations/defaults/launchers/houdini_16.toml rename to pype/configurations/defaults/studio_configurations/launchers/houdini_16.toml diff --git a/pype/configurations/defaults/launchers/houdini_17.toml b/pype/configurations/defaults/studio_configurations/launchers/houdini_17.toml similarity index 100% rename from pype/configurations/defaults/launchers/houdini_17.toml rename to pype/configurations/defaults/studio_configurations/launchers/houdini_17.toml diff --git a/pype/configurations/defaults/launchers/houdini_18.toml b/pype/configurations/defaults/studio_configurations/launchers/houdini_18.toml similarity index 100% rename from pype/configurations/defaults/launchers/houdini_18.toml rename to pype/configurations/defaults/studio_configurations/launchers/houdini_18.toml diff --git a/pype/configurations/defaults/launchers/linux/maya2016 b/pype/configurations/defaults/studio_configurations/launchers/linux/maya2016 similarity index 100% rename from pype/configurations/defaults/launchers/linux/maya2016 rename to pype/configurations/defaults/studio_configurations/launchers/linux/maya2016 diff --git a/pype/configurations/defaults/launchers/linux/maya2017 b/pype/configurations/defaults/studio_configurations/launchers/linux/maya2017 similarity index 100% rename from pype/configurations/defaults/launchers/linux/maya2017 rename to pype/configurations/defaults/studio_configurations/launchers/linux/maya2017 diff --git a/pype/configurations/defaults/launchers/linux/maya2018 b/pype/configurations/defaults/studio_configurations/launchers/linux/maya2018 similarity index 100% rename from pype/configurations/defaults/launchers/linux/maya2018 rename to pype/configurations/defaults/studio_configurations/launchers/linux/maya2018 diff --git a/pype/configurations/defaults/launchers/linux/maya2019 b/pype/configurations/defaults/studio_configurations/launchers/linux/maya2019 similarity index 100% rename from pype/configurations/defaults/launchers/linux/maya2019 rename to pype/configurations/defaults/studio_configurations/launchers/linux/maya2019 diff --git a/pype/configurations/defaults/launchers/linux/maya2020 b/pype/configurations/defaults/studio_configurations/launchers/linux/maya2020 similarity index 100% rename from pype/configurations/defaults/launchers/linux/maya2020 rename to pype/configurations/defaults/studio_configurations/launchers/linux/maya2020 diff --git a/pype/configurations/defaults/launchers/linux/nuke11.3 b/pype/configurations/defaults/studio_configurations/launchers/linux/nuke11.3 similarity index 100% rename from pype/configurations/defaults/launchers/linux/nuke11.3 rename to pype/configurations/defaults/studio_configurations/launchers/linux/nuke11.3 diff --git a/pype/configurations/defaults/launchers/linux/nuke12.0 b/pype/configurations/defaults/studio_configurations/launchers/linux/nuke12.0 similarity index 100% rename from pype/configurations/defaults/launchers/linux/nuke12.0 rename to pype/configurations/defaults/studio_configurations/launchers/linux/nuke12.0 diff --git a/pype/configurations/defaults/launchers/linux/nukestudio11.3 b/pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio11.3 similarity index 100% rename from pype/configurations/defaults/launchers/linux/nukestudio11.3 rename to pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio11.3 diff --git a/pype/configurations/defaults/launchers/linux/nukestudio12.0 b/pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio12.0 similarity index 100% rename from pype/configurations/defaults/launchers/linux/nukestudio12.0 rename to pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio12.0 diff --git a/pype/configurations/defaults/launchers/linux/nukex11.3 b/pype/configurations/defaults/studio_configurations/launchers/linux/nukex11.3 similarity index 100% rename from pype/configurations/defaults/launchers/linux/nukex11.3 rename to pype/configurations/defaults/studio_configurations/launchers/linux/nukex11.3 diff --git a/pype/configurations/defaults/launchers/linux/nukex12.0 b/pype/configurations/defaults/studio_configurations/launchers/linux/nukex12.0 similarity index 100% rename from pype/configurations/defaults/launchers/linux/nukex12.0 rename to pype/configurations/defaults/studio_configurations/launchers/linux/nukex12.0 diff --git a/pype/configurations/defaults/launchers/maya_2016.toml b/pype/configurations/defaults/studio_configurations/launchers/maya_2016.toml similarity index 100% rename from pype/configurations/defaults/launchers/maya_2016.toml rename to pype/configurations/defaults/studio_configurations/launchers/maya_2016.toml diff --git a/pype/configurations/defaults/launchers/maya_2017.toml b/pype/configurations/defaults/studio_configurations/launchers/maya_2017.toml similarity index 100% rename from pype/configurations/defaults/launchers/maya_2017.toml rename to pype/configurations/defaults/studio_configurations/launchers/maya_2017.toml diff --git a/pype/configurations/defaults/launchers/maya_2018.toml b/pype/configurations/defaults/studio_configurations/launchers/maya_2018.toml similarity index 100% rename from pype/configurations/defaults/launchers/maya_2018.toml rename to pype/configurations/defaults/studio_configurations/launchers/maya_2018.toml diff --git a/pype/configurations/defaults/launchers/maya_2019.toml b/pype/configurations/defaults/studio_configurations/launchers/maya_2019.toml similarity index 100% rename from pype/configurations/defaults/launchers/maya_2019.toml rename to pype/configurations/defaults/studio_configurations/launchers/maya_2019.toml diff --git a/pype/configurations/defaults/launchers/maya_2020.toml b/pype/configurations/defaults/studio_configurations/launchers/maya_2020.toml similarity index 100% rename from pype/configurations/defaults/launchers/maya_2020.toml rename to pype/configurations/defaults/studio_configurations/launchers/maya_2020.toml diff --git a/pype/configurations/defaults/launchers/mayabatch_2019.toml b/pype/configurations/defaults/studio_configurations/launchers/mayabatch_2019.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayabatch_2019.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayabatch_2019.toml diff --git a/pype/configurations/defaults/launchers/mayabatch_2020.toml b/pype/configurations/defaults/studio_configurations/launchers/mayabatch_2020.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayabatch_2020.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayabatch_2020.toml diff --git a/pype/configurations/defaults/launchers/mayapy2016.toml b/pype/configurations/defaults/studio_configurations/launchers/mayapy2016.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayapy2016.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayapy2016.toml diff --git a/pype/configurations/defaults/launchers/mayapy2017.toml b/pype/configurations/defaults/studio_configurations/launchers/mayapy2017.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayapy2017.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayapy2017.toml diff --git a/pype/configurations/defaults/launchers/mayapy2018.toml b/pype/configurations/defaults/studio_configurations/launchers/mayapy2018.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayapy2018.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayapy2018.toml diff --git a/pype/configurations/defaults/launchers/mayapy2019.toml b/pype/configurations/defaults/studio_configurations/launchers/mayapy2019.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayapy2019.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayapy2019.toml diff --git a/pype/configurations/defaults/launchers/mayapy2020.toml b/pype/configurations/defaults/studio_configurations/launchers/mayapy2020.toml similarity index 100% rename from pype/configurations/defaults/launchers/mayapy2020.toml rename to pype/configurations/defaults/studio_configurations/launchers/mayapy2020.toml diff --git a/pype/configurations/defaults/launchers/myapp.toml b/pype/configurations/defaults/studio_configurations/launchers/myapp.toml similarity index 100% rename from pype/configurations/defaults/launchers/myapp.toml rename to pype/configurations/defaults/studio_configurations/launchers/myapp.toml diff --git a/pype/configurations/defaults/launchers/nuke_10.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nuke_10.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nuke_10.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nuke_10.0.toml diff --git a/pype/configurations/defaults/launchers/nuke_11.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nuke_11.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nuke_11.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nuke_11.0.toml diff --git a/pype/configurations/defaults/launchers/nuke_11.2.toml b/pype/configurations/defaults/studio_configurations/launchers/nuke_11.2.toml similarity index 100% rename from pype/configurations/defaults/launchers/nuke_11.2.toml rename to pype/configurations/defaults/studio_configurations/launchers/nuke_11.2.toml diff --git a/pype/configurations/defaults/launchers/nuke_11.3.toml b/pype/configurations/defaults/studio_configurations/launchers/nuke_11.3.toml similarity index 100% rename from pype/configurations/defaults/launchers/nuke_11.3.toml rename to pype/configurations/defaults/studio_configurations/launchers/nuke_11.3.toml diff --git a/pype/configurations/defaults/launchers/nuke_12.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nuke_12.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nuke_12.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nuke_12.0.toml diff --git a/pype/configurations/defaults/launchers/nukestudio_10.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nukestudio_10.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukestudio_10.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukestudio_10.0.toml diff --git a/pype/configurations/defaults/launchers/nukestudio_11.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukestudio_11.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.0.toml diff --git a/pype/configurations/defaults/launchers/nukestudio_11.2.toml b/pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.2.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukestudio_11.2.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.2.toml diff --git a/pype/configurations/defaults/launchers/nukestudio_11.3.toml b/pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.3.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukestudio_11.3.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.3.toml diff --git a/pype/configurations/defaults/launchers/nukestudio_12.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nukestudio_12.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukestudio_12.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukestudio_12.0.toml diff --git a/pype/configurations/defaults/launchers/nukex_10.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nukex_10.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukex_10.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukex_10.0.toml diff --git a/pype/configurations/defaults/launchers/nukex_11.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nukex_11.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukex_11.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukex_11.0.toml diff --git a/pype/configurations/defaults/launchers/nukex_11.2.toml b/pype/configurations/defaults/studio_configurations/launchers/nukex_11.2.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukex_11.2.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukex_11.2.toml diff --git a/pype/configurations/defaults/launchers/nukex_11.3.toml b/pype/configurations/defaults/studio_configurations/launchers/nukex_11.3.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukex_11.3.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukex_11.3.toml diff --git a/pype/configurations/defaults/launchers/nukex_12.0.toml b/pype/configurations/defaults/studio_configurations/launchers/nukex_12.0.toml similarity index 100% rename from pype/configurations/defaults/launchers/nukex_12.0.toml rename to pype/configurations/defaults/studio_configurations/launchers/nukex_12.0.toml diff --git a/pype/configurations/defaults/launchers/photoshop_2020.toml b/pype/configurations/defaults/studio_configurations/launchers/photoshop_2020.toml similarity index 100% rename from pype/configurations/defaults/launchers/photoshop_2020.toml rename to pype/configurations/defaults/studio_configurations/launchers/photoshop_2020.toml diff --git a/pype/configurations/defaults/launchers/premiere_2019.toml b/pype/configurations/defaults/studio_configurations/launchers/premiere_2019.toml similarity index 100% rename from pype/configurations/defaults/launchers/premiere_2019.toml rename to pype/configurations/defaults/studio_configurations/launchers/premiere_2019.toml diff --git a/pype/configurations/defaults/launchers/premiere_2020.toml b/pype/configurations/defaults/studio_configurations/launchers/premiere_2020.toml similarity index 100% rename from pype/configurations/defaults/launchers/premiere_2020.toml rename to pype/configurations/defaults/studio_configurations/launchers/premiere_2020.toml diff --git a/pype/configurations/defaults/launchers/python_2.toml b/pype/configurations/defaults/studio_configurations/launchers/python_2.toml similarity index 100% rename from pype/configurations/defaults/launchers/python_2.toml rename to pype/configurations/defaults/studio_configurations/launchers/python_2.toml diff --git a/pype/configurations/defaults/launchers/python_3.toml b/pype/configurations/defaults/studio_configurations/launchers/python_3.toml similarity index 100% rename from pype/configurations/defaults/launchers/python_3.toml rename to pype/configurations/defaults/studio_configurations/launchers/python_3.toml diff --git a/pype/configurations/defaults/launchers/resolve_16.toml b/pype/configurations/defaults/studio_configurations/launchers/resolve_16.toml similarity index 100% rename from pype/configurations/defaults/launchers/resolve_16.toml rename to pype/configurations/defaults/studio_configurations/launchers/resolve_16.toml diff --git a/pype/configurations/defaults/launchers/shell.toml b/pype/configurations/defaults/studio_configurations/launchers/shell.toml similarity index 100% rename from pype/configurations/defaults/launchers/shell.toml rename to pype/configurations/defaults/studio_configurations/launchers/shell.toml diff --git a/pype/configurations/defaults/launchers/storyboardpro_7.toml b/pype/configurations/defaults/studio_configurations/launchers/storyboardpro_7.toml similarity index 100% rename from pype/configurations/defaults/launchers/storyboardpro_7.toml rename to pype/configurations/defaults/studio_configurations/launchers/storyboardpro_7.toml diff --git a/pype/configurations/defaults/launchers/unreal_4.24.toml b/pype/configurations/defaults/studio_configurations/launchers/unreal_4.24.toml similarity index 100% rename from pype/configurations/defaults/launchers/unreal_4.24.toml rename to pype/configurations/defaults/studio_configurations/launchers/unreal_4.24.toml diff --git a/pype/configurations/defaults/launchers/windows/blender_2.80.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.80.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/blender_2.80.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.80.bat diff --git a/pype/configurations/defaults/launchers/windows/blender_2.81.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.81.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/blender_2.81.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.81.bat diff --git a/pype/configurations/defaults/launchers/windows/blender_2.82.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.82.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/blender_2.82.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.82.bat diff --git a/pype/configurations/defaults/launchers/windows/blender_2.83.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.83.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/blender_2.83.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.83.bat diff --git a/pype/configurations/defaults/launchers/windows/celaction_local.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/celaction_local.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/celaction_local.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/celaction_local.bat diff --git a/pype/configurations/defaults/launchers/windows/celaction_publish.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/celaction_publish.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/celaction_publish.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/celaction_publish.bat diff --git a/pype/configurations/defaults/launchers/windows/harmony_17.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/harmony_17.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/harmony_17.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/harmony_17.bat diff --git a/pype/configurations/defaults/launchers/windows/houdini_16.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/houdini_16.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/houdini_16.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/houdini_16.bat diff --git a/pype/configurations/defaults/launchers/windows/houdini_17.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/houdini_17.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/houdini_17.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/houdini_17.bat diff --git a/pype/configurations/defaults/launchers/windows/houdini_18.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/houdini_18.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/houdini_18.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/houdini_18.bat diff --git a/pype/configurations/defaults/launchers/windows/maya2016.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/maya2016.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/maya2016.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/maya2016.bat diff --git a/pype/configurations/defaults/launchers/windows/maya2017.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/maya2017.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/maya2017.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/maya2017.bat diff --git a/pype/configurations/defaults/launchers/windows/maya2018.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/maya2018.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/maya2018.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/maya2018.bat diff --git a/pype/configurations/defaults/launchers/windows/maya2019.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/maya2019.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/maya2019.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/maya2019.bat diff --git a/pype/configurations/defaults/launchers/windows/maya2020.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/maya2020.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/maya2020.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/maya2020.bat diff --git a/pype/configurations/defaults/launchers/windows/mayabatch2019.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2019.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayabatch2019.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2019.bat diff --git a/pype/configurations/defaults/launchers/windows/mayabatch2020.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2020.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayabatch2020.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2020.bat diff --git a/pype/configurations/defaults/launchers/windows/mayapy2016.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2016.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayapy2016.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2016.bat diff --git a/pype/configurations/defaults/launchers/windows/mayapy2017.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2017.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayapy2017.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2017.bat diff --git a/pype/configurations/defaults/launchers/windows/mayapy2018.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2018.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayapy2018.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2018.bat diff --git a/pype/configurations/defaults/launchers/windows/mayapy2019.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2019.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayapy2019.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2019.bat diff --git a/pype/configurations/defaults/launchers/windows/mayapy2020.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2020.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/mayapy2020.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2020.bat diff --git a/pype/configurations/defaults/launchers/windows/nuke10.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nuke10.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nuke10.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nuke10.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nuke11.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nuke11.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nuke11.2.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.2.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nuke11.2.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.2.bat diff --git a/pype/configurations/defaults/launchers/windows/nuke11.3.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.3.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nuke11.3.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.3.bat diff --git a/pype/configurations/defaults/launchers/windows/nuke12.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nuke12.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nuke12.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nuke12.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nukestudio10.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio10.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukestudio10.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio10.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nukestudio11.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukestudio11.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nukestudio11.2.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.2.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukestudio11.2.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.2.bat diff --git a/pype/configurations/defaults/launchers/windows/nukestudio11.3.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.3.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukestudio11.3.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.3.bat diff --git a/pype/configurations/defaults/launchers/windows/nukestudio12.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio12.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukestudio12.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio12.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nukex10.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukex10.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukex10.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukex10.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nukex11.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukex11.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.0.bat diff --git a/pype/configurations/defaults/launchers/windows/nukex11.2.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.2.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukex11.2.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.2.bat diff --git a/pype/configurations/defaults/launchers/windows/nukex11.3.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.3.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukex11.3.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.3.bat diff --git a/pype/configurations/defaults/launchers/windows/nukex12.0.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/nukex12.0.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/nukex12.0.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/nukex12.0.bat diff --git a/pype/configurations/defaults/launchers/windows/photoshop_2020.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/photoshop_2020.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/photoshop_2020.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/photoshop_2020.bat diff --git a/pype/configurations/defaults/launchers/windows/premiere_pro_2019.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2019.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/premiere_pro_2019.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2019.bat diff --git a/pype/configurations/defaults/launchers/windows/premiere_pro_2020.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2020.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/premiere_pro_2020.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2020.bat diff --git a/pype/configurations/defaults/launchers/windows/python3.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/python3.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/python3.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/python3.bat diff --git a/pype/configurations/defaults/launchers/windows/resolve_16.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/resolve_16.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/resolve_16.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/resolve_16.bat diff --git a/pype/configurations/defaults/launchers/windows/shell.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/shell.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/shell.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/shell.bat diff --git a/pype/configurations/defaults/launchers/windows/storyboardpro_7.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/storyboardpro_7.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/storyboardpro_7.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/storyboardpro_7.bat diff --git a/pype/configurations/defaults/launchers/windows/unreal.bat b/pype/configurations/defaults/studio_configurations/launchers/windows/unreal.bat similarity index 100% rename from pype/configurations/defaults/launchers/windows/unreal.bat rename to pype/configurations/defaults/studio_configurations/launchers/windows/unreal.bat From 7d7a2e1b230584d4cc99b126ac155c4434f408c0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:37:11 +0200 Subject: [PATCH 419/580] initial commit to save studio configurations to different place --- pype/configurations/config.py | 43 +++++++++++++------ .../config_setting/widgets/base.py | 3 +- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/pype/configurations/config.py b/pype/configurations/config.py index 416704649c..147570acd4 100644 --- a/pype/configurations/config.py +++ b/pype/configurations/config.py @@ -5,18 +5,37 @@ import copy log = logging.getLogger(__name__) -STUDIO_PRESETS_PATH = os.path.normpath( - os.path.join(os.environ["PYPE_CONFIG"], "studio_configurations") +# Metadata keys for work with studio and project overrides +OVERRIDEN_KEY = "__overriden_keys__" +# NOTE key popping not implemented yet +POP_KEY = "__pop_key__" + +# Paths to studio and project overrides +STUDIO_OVERRIDES_PATH = os.environ["PYPE_CONFIG"] + +SYSTEM_CONFIGURATIONS_DIR = "studio_configurations" +SYSTEM_CONFIGURATIONS_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, SYSTEM_CONFIGURATIONS_DIR ) -PROJECT_CONFIGURATION_DIR = "project_configurations" -PROJECT_PRESETS_PATH = os.path.normpath(os.path.join( - os.environ["PYPE_CONFIG"], PROJECT_CONFIGURATION_DIR -)) +PROJECT_CONFIGURATIONS_DIR = "project_configurations" +PROJECT_CONFIGURATIONS_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, PROJECT_CONFIGURATIONS_DIR +) + +# Variable where cache of default configurations are stored +_DEFAULT_CONFIGURATIONS = None + +# TODO remove this as is maybe deprecated first_run = False -# TODO key popping not implemented yet -POP_KEY = "__pop_key__" -OVERRIDEN_KEY = "__overriden_keys__" + +def default_configuration(): + global _DEFAULT_CONFIGURATIONS + if _DEFAULT_CONFIGURATIONS is None: + current_dir = os.path.dirname(__file__) + defaults_path = os.path.join(current_dir, "defaults") + _DEFAULT_CONFIGURATIONS = load_jsons_from_dir(defaults_path) + return _DEFAULT_CONFIGURATIONS def load_json(fpath): @@ -129,17 +148,17 @@ def load_jsons_from_dir(path, *args, **kwargs): def studio_configurations(*args, **kwargs): - return load_jsons_from_dir(STUDIO_PRESETS_PATH, *args, **kwargs) + return load_jsons_from_dir(SYSTEM_CONFIGURATIONS_PATH, *args, **kwargs) def global_project_configurations(**kwargs): - return load_jsons_from_dir(PROJECT_PRESETS_PATH, **kwargs) + return load_jsons_from_dir(PROJECT_CONFIGURATIONS_PATH, **kwargs) def path_to_project_overrides(project_name): project_configs_path = os.environ["PYPE_PROJECT_CONFIGS"] dirpath = os.path.join(project_configs_path, project_name) - return os.path.join(dirpath, PROJECT_CONFIGURATION_DIR + ".json") + return os.path.join(dirpath, PROJECT_CONFIGURATIONS_DIR + ".json") def project_configurations_overrides(project_name, **kwargs): diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index d39b5789d9..0660ab1e06 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -156,7 +156,7 @@ class SystemWidget(QtWidgets.QWidget): for key in key_sequence: new_values = new_values[key] origin_values.update(new_values) - + raise NotImplementedError("Output from global values has changed") output_path = os.path.join( config.STUDIO_PRESETS_PATH, subpath ) @@ -537,6 +537,7 @@ class ProjectWidget(QtWidgets.QWidget): else: origin_values = new_values + raise NotImplementedError("Output from global values has changed") output_path = os.path.join( config.PROJECT_PRESETS_PATH, subpath ) From 4fabd706e820d45755608b7605c32741ab4da5a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:54:16 +0200 Subject: [PATCH 420/580] renamed studio to system --- .../studio_schema/0_studio_gui_schema.json | 3 +-- .../config_setting/widgets/base.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json index bde340250e..de17328860 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json @@ -1,7 +1,6 @@ { - "key": "studio", + "key": "system", "type": "dict-invisible", - "label": "Studio", "children": [ { "type": "dict-invisible", diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 0660ab1e06..3d255b416e 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -95,7 +95,7 @@ class SystemWidget(QtWidgets.QWidget): self.schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") self.keys = self.schema.get("keys", []) self.add_children_gui(self.schema) - self._update_global_values() + self._update_values() self.hierarchical_style_update() def _save(self): @@ -132,7 +132,7 @@ class SystemWidget(QtWidgets.QWidget): all_values = _all_values # Skip first key - all_values = all_values["studio"] + all_values = all_values["system"] # Load studio data with metadata current_configurations = config.studio_configurations() @@ -168,10 +168,10 @@ class SystemWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(origin_values, file_stream, indent=4) - self._update_global_values() + self._update_values() - def _update_global_values(self): - values = {"studio": config.studio_configurations()} + def _update_values(self): + values = {"system": config.studio_configurations()} for input_field in self.input_fields: input_field.update_global_values(values) @@ -408,7 +408,7 @@ class ProjectWidget(QtWidgets.QWidget): self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = self.schema.get("keys", []) self.add_children_gui(self.schema) - self._update_global_values() + self._update_values() self.hierarchical_style_update() def add_children_gui(self, child_configuration): @@ -549,9 +549,9 @@ class ProjectWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(origin_values, file_stream, indent=4) - self._update_global_values() + self._update_values() - def _update_global_values(self): + def _update_values(self): values = {"project": config.global_project_configurations()} for input_field in self.input_fields: input_field.update_global_values(values) From 8ad8b00713e15556b346c75a31b38df2fb18a2f6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:55:00 +0200 Subject: [PATCH 421/580] renamed also files and folder from studio to system --- .../0_system_gui_schema.json} | 0 .../1_applications_gui_schema.json | 0 .../{studio_schema => system_schema}/1_intents_gui_schema.json | 0 .../{studio_schema => system_schema}/1_tools_gui_schema.json | 0 .../{studio_schema => system_schema}/1_tray_items.json | 0 pype/tools/config_setting/config_setting/widgets/base.py | 3 ++- 6 files changed, 2 insertions(+), 1 deletion(-) rename pype/tools/config_setting/config_setting/config_gui_schema/{studio_schema/0_studio_gui_schema.json => system_schema/0_system_gui_schema.json} (100%) rename pype/tools/config_setting/config_setting/config_gui_schema/{studio_schema => system_schema}/1_applications_gui_schema.json (100%) rename pype/tools/config_setting/config_setting/config_gui_schema/{studio_schema => system_schema}/1_intents_gui_schema.json (100%) rename pype/tools/config_setting/config_setting/config_gui_schema/{studio_schema => system_schema}/1_tools_gui_schema.json (100%) rename pype/tools/config_setting/config_setting/config_gui_schema/{studio_schema => system_schema}/1_tray_items.json (100%) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/0_studio_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_applications_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_intents_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tools_gui_schema.json rename to pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/studio_schema/1_tray_items.json rename to pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 3d255b416e..e5bbe6d929 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -92,7 +92,7 @@ class SystemWidget(QtWidgets.QWidget): widget.deleteLater() self.input_fields.clear() - self.schema = lib.gui_schema("studio_schema", "0_studio_gui_schema") + self.schema = lib.gui_schema("system_schema", "0_system_gui_schema") self.keys = self.schema.get("keys", []) self.add_children_gui(self.schema) self._update_values() @@ -171,6 +171,7 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() def _update_values(self): + config.default_configuration() values = {"system": config.studio_configurations()} for input_field in self.input_fields: input_field.update_global_values(values) From d2f25b0a0cce496f4fbcbceef2bf4ff30b5fdd58 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 10:59:52 +0200 Subject: [PATCH 422/580] is_file removed from schemas --- .../projects_schema/0_project_gui_schema.json | 3 +-- .../1_ftrack_projects_gui_schema.json | 2 -- .../projects_schema/1_plugins_gui_schema.json | 15 ++------------- .../system_schema/0_system_gui_schema.json | 1 - .../system_schema/1_applications_gui_schema.json | 1 - .../system_schema/1_intents_gui_schema.json | 1 - .../system_schema/1_tools_gui_schema.json | 1 - .../system_schema/1_tray_items.json | 1 - 8 files changed, 3 insertions(+), 22 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json index 91bacf2e5a..86504eefd2 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json @@ -4,8 +4,7 @@ "children": [ { "type": "anatomy", - "key": "anatomy", - "is_file": true + "key": "anatomy" }, { "type": "schema", "children": [ diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json index 6608463100..e9937e64b8 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json @@ -10,7 +10,6 @@ "expandable": true, "label": "Status updates", "is_group": true, - "is_file": true, "children": [ { "key": "Ready", @@ -28,7 +27,6 @@ "expandable": true, "label": "Version status to Task status", "is_group": true, - "is_file": true, "children": [ { "key": "in progress", diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 98fbfb206d..302d1dad0a 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -15,7 +15,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "dict", @@ -82,7 +81,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "dict", @@ -125,7 +123,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "dict", @@ -299,7 +296,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "dict", @@ -376,8 +372,7 @@ }, { "type": "raw-json", "key": "workfile_build", - "label": "Workfile Build logic", - "is_file": true + "label": "Workfile Build logic" } ] }, { @@ -391,7 +386,6 @@ "expandable": true, "key": "create", "label": "Create plugins", - "is_file": true, "children": [ { "type": "dict", @@ -428,7 +422,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "dict", @@ -551,8 +544,7 @@ }, { "type": "raw-json", "key": "workfile_build", - "label": "Workfile Build logic", - "is_file": true + "label": "Workfile Build logic" } ] }, { @@ -566,7 +558,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [ { "type": "dict", @@ -619,7 +610,6 @@ "expandable": true, "key": "create", "label": "Creator plugins", - "is_file": true, "children": [ { "type": "dict", @@ -661,7 +651,6 @@ "expandable": true, "key": "publish", "label": "Publish plugins", - "is_file": true, "children": [] } ] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json index de17328860..0b51267f4e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json @@ -26,7 +26,6 @@ "maximum": 300 }, "is_group": true, - "is_file": true, "key": "templates_mapping", "label": "Muster - Templates mapping" }] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json index bc2c9f239c..af128b138f 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json @@ -3,7 +3,6 @@ "type": "dict", "label": "Applications", "expandable": true, - "is_file": true, "is_group": true, "children": [ { diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json index a4b5e16fa1..11b45c8409 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json @@ -4,7 +4,6 @@ "label": "Intent Setting", "expandable": true, "is_group": true, - "is_file": true, "children": [ { "type": "dict-modifiable", diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json index bf35326d1c..a16f00547e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json @@ -4,7 +4,6 @@ "label": "Tools", "expandable": true, "is_group": true, - "is_file": true, "children": [ { "type": "dict-form", diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json index 13ab0293de..afa509254e 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json @@ -3,7 +3,6 @@ "type": "dict", "label": "Modules", "expandable": true, - "is_file": true, "is_group": true, "children": [ { From 0c256fa30a16934cbc8a08da1841086abe1ca5eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:00:03 +0200 Subject: [PATCH 423/580] skipped validation of is_file attribute --- .../config_setting/widgets/lib.py | 69 ------------------- 1 file changed, 69 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index 08b0dfc3c4..b32fb734c6 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -81,19 +81,6 @@ def replace_inner_schemas(schema_data, schema_collection): return schema_data -class SchemaMissingFileInfo(Exception): - def __init__(self, invalid): - full_path_keys = [] - for item in invalid: - full_path_keys.append("\"{}\"".format("/".join(item))) - - msg = ( - "Schema has missing definition of output file (\"is_file\" key)" - " for keys. [{}]" - ).format(", ".join(full_path_keys)) - super(SchemaMissingFileInfo, self).__init__(msg) - - class SchemeGroupHierarchyBug(Exception): def __init__(self, invalid): full_path_keys = [] @@ -122,59 +109,6 @@ class SchemaDuplicatedKeys(Exception): super(SchemaDuplicatedKeys, self).__init__(msg) -def file_keys_from_schema(schema_data): - output = [] - keys = [] - key = schema_data.get("key") - if key: - keys.append(key) - - for child in schema_data["children"]: - if child.get("is_file"): - _keys = copy.deepcopy(keys) - _keys.append(child["key"]) - output.append(_keys) - continue - - for result in file_keys_from_schema(child): - _keys = copy.deepcopy(keys) - _keys.extend(result) - output.append(_keys) - return output - - -def validate_all_has_ending_file(schema_data, is_top=True): - if schema_data.get("is_file"): - return None - - children = schema_data.get("children") - if not children: - return [[schema_data["key"]]] - - invalid = [] - keyless = "key" not in schema_data - for child in children: - result = validate_all_has_ending_file(child, False) - if result is None: - continue - - if keyless: - invalid.extend(result) - else: - for item in result: - new_invalid = [schema_data["key"]] - new_invalid.extend(item) - invalid.append(new_invalid) - - if not invalid: - return None - - if not is_top: - return invalid - - raise SchemaMissingFileInfo(invalid) - - def validate_is_group_is_unique_in_hierarchy( schema_data, any_parent_is_group=False, keys=None ): @@ -270,9 +204,6 @@ def validate_keys_are_unique(schema_data, keys=None): def validate_schema(schema_data): - # TODO validator that is_group key is not before is_file child - # TODO validator that is_group or is_file is not on child without key - validate_all_has_ending_file(schema_data) validate_is_group_is_unique_in_hierarchy(schema_data) validate_keys_are_unique(schema_data) From a338b8c04e0e8c5445d1f0ca4533e7e97a66b8e4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:20:34 +0200 Subject: [PATCH 424/580] renamed function for inner schemas --- pype/tools/config_setting/config_setting/widgets/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index b32fb734c6..69c3259b3b 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -55,7 +55,7 @@ def convert_overrides_to_gui_data(data, first=True): return output -def replace_inner_schemas(schema_data, schema_collection): +def _fill_inner_schemas(schema_data, schema_collection): if schema_data["type"] == "schema": raise ValueError("First item in schema data can't be schema.") @@ -66,12 +66,12 @@ def replace_inner_schemas(schema_data, schema_collection): new_children = [] for child in children: if child["type"] != "schema": - new_child = replace_inner_schemas(child, schema_collection) + new_child = _fill_inner_schemas(child, schema_collection) new_children.append(new_child) continue for schema_name in child["children"]: - new_child = replace_inner_schemas( + new_child = _fill_inner_schemas( schema_collection[schema_name], schema_collection ) @@ -227,7 +227,7 @@ def gui_schema(subfolder, main_schema_name): schema_data = json.load(json_stream) loaded_schemas[basename] = schema_data - main_schema = replace_inner_schemas( + main_schema = _fill_inner_schemas( loaded_schemas[main_schema_name], loaded_schemas ) From afcd282ada6c5c8e3c0f1abe50bd800c04cad0ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:20:50 +0200 Subject: [PATCH 425/580] ConfigObject has is from defaults --- pype/tools/config_setting/config_setting/widgets/inputs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index f975567a6a..fed9c6b5c7 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -16,6 +16,7 @@ class ConfigObject(AbstractConfigObject): default_state = "" + _is_from_defaults = True _as_widget = False _is_overriden = False _is_modified = False @@ -32,6 +33,10 @@ class ConfigObject(AbstractConfigObject): self._log = logging.getLogger(self.__class__.__name__) return self._log + @property + def is_from_defaults(self): + return self._is_from_defaults + @property def is_modified(self): """Has object any changes that require saving.""" From 7198576e59c0f3ca487f3972a78f017024d8b724 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:39:02 +0200 Subject: [PATCH 426/580] reverse logic of defaults, better is to know if has studi ooverrides --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index fed9c6b5c7..14cf573398 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -16,7 +16,7 @@ class ConfigObject(AbstractConfigObject): default_state = "" - _is_from_defaults = True + _has_studio_override = True _as_widget = False _is_overriden = False _is_modified = False @@ -34,8 +34,8 @@ class ConfigObject(AbstractConfigObject): return self._log @property - def is_from_defaults(self): - return self._is_from_defaults + def has_studio_override(self): + return self._has_studio_override @property def is_modified(self): From 918d592777d41a5e87617acd5562cb4b3a80fcf1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:42:08 +0200 Subject: [PATCH 427/580] renamed global_value to studio_value --- .../config_setting/widgets/anatomy_inputs.py | 20 ++-- .../config_setting/widgets/base.py | 4 +- .../config_setting/widgets/inputs.py | 106 +++++++++--------- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index e59de3980f..957691cbdc 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -75,7 +75,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.value_changed.connect(self._on_value_change) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): self._state = None self._child_state = None @@ -84,8 +84,8 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): else: value = NOT_SET - self.root_widget.update_global_values(value) - self.templates_widget.update_global_values(value) + self.root_widget.update_studio_values(value) + self.templates_widget.update_studio_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -258,7 +258,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def is_multiroot(self): return self.multiroot_checkbox.isChecked() - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): self._state = None self._multiroot_state = None @@ -279,11 +279,11 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(is_multiroot) if is_multiroot: - self.singleroot_widget.update_global_values(NOT_SET) - self.multiroot_widget.update_global_values(value) + self.singleroot_widget.update_studio_values(NOT_SET) + self.multiroot_widget.update_studio_values(value) else: - self.singleroot_widget.update_global_values(value) - self.multiroot_widget.update_global_values(NOT_SET) + self.singleroot_widget.update_studio_values(value) + self.multiroot_widget.update_studio_values(NOT_SET) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -489,9 +489,9 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): layout.addWidget(body_widget) - def update_global_values(self, values): + def update_studio_values(self, values): self._state = None - self.value_input.update_global_values(values) + self.value_input.update_studio_values(values) def apply_overrides(self, parent_values): self._state = None diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index e5bbe6d929..82a5d024b0 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -174,7 +174,7 @@ class SystemWidget(QtWidgets.QWidget): config.default_configuration() values = {"system": config.studio_configurations()} for input_field in self.input_fields: - input_field.update_global_values(values) + input_field.update_studio_values(values) for input_field in self.input_fields: input_field.hierarchical_style_update() @@ -555,7 +555,7 @@ class ProjectWidget(QtWidgets.QWidget): def _update_values(self): values = {"project": config.global_project_configurations()} for input_field in self.input_fields: - input_field.update_global_values(values) + input_field.update_studio_values(values) for input_field in self.input_fields: input_field.hierarchical_style_update() diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 14cf573398..e70b2a9b3a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -221,7 +221,7 @@ class InputObject(ConfigObject): self.set_value(self.start_value) if not self.is_overidable: - self._is_modified = self.global_value != self.item_value() + self._is_modified = self.studio_value != self.item_value() self._is_overriden = False return @@ -273,7 +273,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -300,7 +300,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.checkbox.stateChanged.connect(self._on_value_change) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if self._as_widget: value = parent_values @@ -313,10 +313,10 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): elif self.default_value is not NOT_SET: self.set_value(self.default_value) - self.global_value = value + self.studio_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def set_value(self, value): # Ignore value change because if `self.isChecked()` has same @@ -338,7 +338,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -385,7 +385,7 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -413,7 +413,7 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.input_field.valueChanged.connect(self._on_value_change) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if self._as_widget: value = parent_values @@ -427,10 +427,10 @@ class NumberWidget(QtWidgets.QWidget, InputObject): elif self.default_value is not NOT_SET: self.set_value(self.default_value) - self.global_value = value + self.studio_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def set_value(self, value): self.input_field.setValue(value) @@ -453,7 +453,7 @@ class NumberWidget(QtWidgets.QWidget, InputObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -502,7 +502,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.multiline = input_data.get("multiline", False) self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -528,7 +528,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.text_input.textChanged.connect(self._on_value_change) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if self._as_widget: value = parent_values @@ -541,10 +541,10 @@ class TextWidget(QtWidgets.QWidget, InputObject): elif self.default_value is not NOT_SET: self.set_value(self.default_value) - self.global_value = value + self.studio_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def set_value(self, value): if self.multiline: @@ -570,7 +570,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -620,7 +620,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -641,7 +641,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.path_input.textChanged.connect(self._on_value_change) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if self._as_widget: value = parent_values @@ -654,10 +654,10 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): elif self.default_value is not NOT_SET: self.set_value(self.default_value) - self.global_value = value + self.studio_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def set_value(self, value): self.path_input.setText(value) @@ -684,7 +684,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): elif self.is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -789,7 +789,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QVBoxLayout(self) @@ -815,7 +815,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.text_input.textChanged.connect(self._on_value_change) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if self._as_widget: value = parent_values @@ -830,10 +830,10 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._is_invalid = self.text_input.has_invalid_value() - self.global_value = value + self.studio_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def set_value(self, value): self.text_input.set_value(value) @@ -857,7 +857,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -992,7 +992,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.input_modifiers = input_data.get("input_modifiers") or {} self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET self.key = input_data["key"] @@ -1031,7 +1031,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): def clear_value(self): self.set_value([]) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): old_inputs = tuple(self.input_fields) value = NOT_SET @@ -1040,7 +1040,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): elif parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) - self.global_value = value + self.studio_value = value if value is not NOT_SET: for item_value in value: @@ -1058,7 +1058,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value self.hierarchical_style_update() def set_value(self, value): @@ -1081,7 +1081,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -1114,7 +1114,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` if value is not None: - item_widget.value_input.update_global_values(value) + item_widget.value_input.update_studio_values(value) else: self._on_value_change() self.updateGeometry() @@ -1248,10 +1248,10 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.update_style() self.value_changed.emit(self) - def update_global_values(self, key, value): + def update_studio_values(self, key, value): self.origin_key = key self.key_input.setText(key) - self.value_input.update_global_values(value) + self.value_input.update_studio_values(value) def apply_overrides(self, key, value): self.origin_key = key @@ -1341,7 +1341,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._as_widget = as_widget self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET any_parent_is_group = parent.is_group @@ -1397,7 +1397,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def count(self): return len(self.input_fields) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): old_inputs = tuple(self.input_fields) value = NOT_SET @@ -1406,7 +1406,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): elif parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) - self.global_value = value + self.studio_value = value if value is not NOT_SET: for item_key, item_value in value.items(): @@ -1424,7 +1424,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def set_value(self, value): previous_inputs = tuple(self.input_fields) @@ -1462,7 +1462,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.update_style() @@ -1534,7 +1534,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if self._is_overriden: item_widget.apply_overrides(key, value) else: - item_widget.update_global_values(key, value) + item_widget.update_studio_values(key, value) self.hierarchical_style_update() else: self._on_value_change() @@ -1699,13 +1699,13 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) for item in self.input_fields: - item.update_global_values(value) + item.update_studio_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -1965,13 +1965,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) for item in self.input_fields: - item.update_global_values(value) + item.update_studio_values(value) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -2062,7 +2062,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.multipath = input_data.get("multipath", False) self.override_value = NOT_SET - self.global_value = NOT_SET + self.studio_value = NOT_SET self.start_value = NOT_SET self.input_fields = [] @@ -2140,7 +2140,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.setFocusProxy(self.input_fields[0]) self.content_layout.addWidget(proxy_widget) - def update_global_values(self, parent_values): + def update_studio_values(self, parent_values): value = NOT_SET if self._as_widget: value = parent_values @@ -2148,15 +2148,15 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): value = parent_values.get(self.key, NOT_SET) if not self.multiplatform: - self.input_fields[0].update_global_values(parent_values) + self.input_fields[0].update_studio_values(parent_values) elif self.multiplatform: for input_field in self.input_fields: - input_field.update_global_values(value) + input_field.update_studio_values(value) - self.global_value = value + self.studio_value = value self.start_value = self.item_value() - self._is_modified = self.global_value != self.start_value + self._is_modified = self.studio_value != self.start_value def apply_overrides(self, parent_values): self._is_modified = False @@ -2215,7 +2215,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): elif self._is_overriden: self._is_modified = self.item_value() != self.override_value else: - self._is_modified = self.item_value() != self.global_value + self._is_modified = self.item_value() != self.studio_value self.hierarchical_style_update() @@ -2408,9 +2408,9 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() - def update_global_values(self, value): + def update_studio_values(self, value): for item in self.input_fields: - item.update_global_values(value) + item.update_studio_values(value) def _on_value_change(self, item=None): if self.ignore_value_changes: From 4d44eda38816b874bdb81581163dca28006d668c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:47:53 +0200 Subject: [PATCH 428/580] added default_value next to studio_value and override_value --- .../config_setting/widgets/inputs.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e70b2a9b3a..5ad97fb698 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -272,8 +272,9 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -384,8 +385,9 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -501,8 +503,9 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.multiline = input_data.get("multiline", False) - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -619,8 +622,9 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) @@ -788,8 +792,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.default_value = input_data.get("default", NOT_SET) - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET layout = QtWidgets.QVBoxLayout(self) @@ -991,8 +996,9 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET self.key = input_data["key"] @@ -1340,8 +1346,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._state = None self._as_widget = as_widget - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET any_parent_is_group = parent.is_group @@ -2061,8 +2068,9 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.multiplatform = input_data.get("multiplatform", False) self.multipath = input_data.get("multipath", False) - self.override_value = NOT_SET + self.default_value = NOT_SET self.studio_value = NOT_SET + self.override_value = NOT_SET self.start_value = NOT_SET self.input_fields = [] From 782424139648021798517cd24a5949a7f292d1ba Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:54:59 +0200 Subject: [PATCH 429/580] removed reset_value method --- .../config_setting/widgets/inputs.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 5ad97fb698..54b7bf96e4 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -440,9 +440,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): def clear_value(self): self.set_value(0) - def reset_value(self): - self.set_value(self.start_value) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -555,9 +552,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.text_input.setText(value) - def reset_value(self): - self.set_value(self.start_value) - def clear_value(self): self.set_value("") @@ -666,9 +660,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.path_input.setText(value) - def reset_value(self): - self.set_value(self.start_value) - def clear_value(self): self.set_value("") @@ -843,9 +834,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.text_input.set_value(value) - def reset_value(self): - self.set_value(self.start_value) - def clear_value(self): self.set_value("") @@ -1031,9 +1019,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): def count(self): return len(self.input_fields) - def reset_value(self): - self.set_value(self.start_value) - def clear_value(self): self.set_value([]) @@ -2203,10 +2188,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): _value = value[input_field.key] input_field.set_value(_value) - def reset_value(self): - for input_field in self.input_fields: - input_field.reset_value() - def clear_value(self): for input_field in self.input_fields: input_field.clear_value() From f263a71e6b02bd25ea804b741f70d2b7a8aef292 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 11:56:24 +0200 Subject: [PATCH 430/580] removed clear value --- .../config_setting/widgets/anatomy_inputs.py | 3 --- .../config_setting/widgets/inputs.py | 22 ------------------- 2 files changed, 25 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 957691cbdc..fbc3a3a2ed 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -102,9 +102,6 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): def set_value(self, value): raise TypeError("AnatomyWidget does not allow to use `set_value`") - def clear_value(self): - raise TypeError("AnatomyWidget does not allow to use `clear_value`") - def _on_value_change(self, item=None): if self.ignore_value_changes: return diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 54b7bf96e4..40de1c1347 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -324,9 +324,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): # value as `value` the `_on_value_change` is not triggered self.checkbox.setChecked(value) - def clear_value(self): - self.set_value(False) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -437,9 +434,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.input_field.setValue(value) - def clear_value(self): - self.set_value(0) - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -552,9 +546,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.text_input.setText(value) - def clear_value(self): - self.set_value("") - def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -660,9 +651,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.path_input.setText(value) - def clear_value(self): - self.set_value("") - def focusOutEvent(self, event): self.path_input.clear_end_path() super(PathInput, self).focusOutEvent(event) @@ -834,9 +822,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.text_input.set_value(value) - def clear_value(self): - self.set_value("") - def _on_value_change(self, item=None): self._is_invalid = self.text_input.has_invalid_value() if self.ignore_value_changes: @@ -1019,9 +1004,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): def count(self): return len(self.input_fields) - def clear_value(self): - self.set_value([]) - def update_studio_values(self, parent_values): old_inputs = tuple(self.input_fields) @@ -2188,10 +2170,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): _value = value[input_field.key] input_field.set_value(_value) - def clear_value(self): - for input_field in self.input_fields: - input_field.clear_value() - def _on_value_change(self, item=None): if self.ignore_value_changes: return From 9924b2899e39a4c9c6d839430076184c865cdd22 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:06:19 +0200 Subject: [PATCH 431/580] removed default from schemas and laoding from schemas --- .../projects_schema/1_plugins_gui_schema.json | 120 ++++++------------ .../config_setting/widgets/inputs.py | 8 -- 2 files changed, 40 insertions(+), 88 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 302d1dad0a..597f51d6fd 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -27,41 +27,34 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": true + "label": "Enabled" }, { "type": "dict-form", "children": [ { "type": "text", "key": "deadline_department", - "label": "Deadline apartment", - "default": "" + "label": "Deadline apartment" }, { "type": "number", "key": "deadline_priority", - "label": "Deadline priority", - "default": 50 + "label": "Deadline priority" }, { "type": "text", "key": "deadline_pool", - "label": "Deadline pool", - "default": "" + "label": "Deadline pool" }, { "type": "text", "key": "deadline_pool_secondary", - "label": "Deadline pool (secondary)", - "default": "" + "label": "Deadline pool (secondary)" }, { "type": "text", "key": "deadline_group", - "label": "Deadline Group", - "default": "" + "label": "Deadline Group" }, { "type": "number", "key": "deadline_chunk_size", - "label": "Deadline Chunk size", - "default": 10 + "label": "Deadline Chunk size" } ] } @@ -93,19 +86,16 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": false + "label": "Enabled" }, { "type": "text", "key": "note_with_intent_template", - "label": "Note with intent template", - "default": "{intent}: {comment}" + "label": "Note with intent template" }, { "type": "list", "object_type": "text", "key": "note_labels", - "label": "Note labels", - "default": [] + "label": "Note labels" } ] } @@ -154,14 +144,12 @@ "type": "list", "object_type": "text", "key": "input", - "label": "FFmpeg input arguments", - "default": [] + "label": "FFmpeg input arguments" }, { "type": "list", "object_type": "text", "key": "output", - "label": "FFmpeg output arguments", - "default": [] + "label": "FFmpeg output arguments" } ] } @@ -177,13 +165,11 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": true + "label": "Enabled" }, { "type": "raw-json", "key": "profiles", - "label": "Profiles", - "default": [] + "label": "Profiles" } ] }, { @@ -207,33 +193,27 @@ { "type": "number", "key": "font_size", - "label": "Font size", - "default": 42 + "label": "Font size" }, { "type": "number", "key": "opacity", - "label": "Font opacity", - "default": 1 + "label": "Font opacity" }, { "type": "number", "key": "bg_opacity", - "label": "Background opacity", - "default": 1 + "label": "Background opacity" }, { "type": "number", "key": "x_offset", - "label": "X Offset", - "default": 5 + "label": "X Offset" }, { "type": "number", "key": "y_offset", - "label": "Y Offset", - "default": 5 + "label": "Y Offset" }, { "type": "number", "key": "bg_padding", - "label": "Padding aroung text", - "default": 5 + "label": "Padding aroung text" } ] }, { @@ -316,8 +296,7 @@ }, { "type": "text", "key": "regex", - "label": "Validation regex", - "default": "(.*)_(\\d)*_(?P.*)_(GEO)" + "label": "Validation regex" } ] }, { @@ -349,8 +328,7 @@ }, { "type": "text", "key": "regex", - "label": "Validation regex", - "default": "(?P.*)_(.*)_SHD" + "label": "Validation regex" } ] }, { @@ -397,8 +375,7 @@ { "type": "text", "key": "fpath_template", - "label": "Path template", - "default": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" + "label": "Path template" } ] }, { @@ -411,8 +388,7 @@ { "type": "text", "key": "fpath_template", - "label": "Path template", - "default": "{work}/prerenders/nuke/{subset}/{subset}.{frame}.{ext}" + "label": "Path template" } ] } @@ -434,8 +410,7 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": true + "label": "Enabled" }, { "type": "raw-json", "key": "nodes", @@ -453,8 +428,7 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": false + "label": "Enabled" }, { "type": "raw-json", "key": "knobs", @@ -472,8 +446,7 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": false + "label": "Enabled" } ] }, { @@ -487,13 +460,11 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": true + "label": "Enabled" }, { "type": "boolean", "key": "viewer_lut_raw", - "label": "Viewer LUT raw", - "default": false + "label": "Viewer LUT raw" } ] }, { @@ -506,8 +477,7 @@ { "type": "boolean", "key": "viewer_lut_raw", - "label": "Viewer LUT raw", - "default": false + "label": "Viewer LUT raw" } ] }, { @@ -520,23 +490,19 @@ { "type": "number", "key": "deadline_priority", - "label": "deadline_priority", - "default": 50 + "label": "deadline_priority" }, { "type": "text", "key": "deadline_pool", - "label": "deadline_pool", - "default": "" + "label": "deadline_pool" }, { "type": "text", "key": "deadline_pool_secondary", - "label": "deadline_pool_secondary", - "default": "" + "label": "deadline_pool_secondary" }, { "type": "number", "key": "deadline_chunk_size", - "label": "deadline_chunk_size", - "default": 1 + "label": "deadline_chunk_size" } ] } @@ -570,8 +536,7 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": false + "label": "Enabled" } ] }, { @@ -585,14 +550,12 @@ { "type": "boolean", "key": "enabled", - "label": "Enabled", - "default": true + "label": "Enabled" }, { "type": "list", "object_type": "text", "key": "tags_addition", - "label": "Tags addition", - "default": [] + "label": "Tags addition" } ] } @@ -621,18 +584,15 @@ { "type": "text", "key": "clipName", - "label": "Clip name template", - "default": "{track}{sequence}{shot}" + "label": "Clip name template" }, { "type": "text", "key": "folder", - "label": "Folder", - "default": "takes" + "label": "Folder" }, { "type": "number", "key": "steps", - "label": "Steps", - "default": 20 + "label": "Steps" } ] } diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 40de1c1347..16ecd5cd1a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -270,7 +270,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) self.default_value = NOT_SET self.studio_value = NOT_SET @@ -380,7 +379,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) self.default_value = NOT_SET self.studio_value = NOT_SET @@ -490,7 +488,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) self.multiline = input_data.get("multiline", False) @@ -605,7 +602,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) self.default_value = NOT_SET self.studio_value = NOT_SET @@ -769,7 +765,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) self.default_value = NOT_SET self.studio_value = NOT_SET @@ -966,7 +961,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): self._is_nullable = input_data.get("is_nullable", False) self.object_type = input_data["object_type"] - self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} self.default_value = NOT_SET @@ -1363,7 +1357,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.object_type = input_data["object_type"] - self.default_value = input_data.get("default", NOT_SET) self.input_modifiers = input_data.get("input_modifiers") or {} self.add_row(is_empty=True) @@ -2031,7 +2024,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self._is_group = False self._is_nullable = input_data.get("is_nullable", False) - self.default_value = input_data.get("default", NOT_SET) self.multiplatform = input_data.get("multiplatform", False) self.multipath = input_data.get("multipath", False) From 022214a992e0468d16b1f73c41ac2da618b4aeb5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:08:48 +0200 Subject: [PATCH 432/580] has studi ooverrides is False by default --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 16ecd5cd1a..057ed3b584 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -16,7 +16,7 @@ class ConfigObject(AbstractConfigObject): default_state = "" - _has_studio_override = True + _has_studio_override = False _as_widget = False _is_overriden = False _is_modified = False From ef2b0c955e5c7466a45ebf3c58ff8e32e924c212 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:12:08 +0200 Subject: [PATCH 433/580] studio_configuration folder renamed to system_configuration --- .../environments/avalon.json | 0 .../environments/blender.json | 0 .../environments/celaction.json | 0 .../environments/deadline.json | 0 .../environments/ftrack.json | 0 .../environments/global.json | 0 .../environments/harmony.json | 0 .../environments/houdini.json | 0 .../environments/maya.json | 0 .../environments/maya_2018.json | 0 .../environments/maya_2020.json | 0 .../environments/mayabatch.json | 0 .../environments/mayabatch_2019.json | 0 .../environments/mtoa_3.1.1.json | 0 .../environments/muster.json | 0 .../environments/nuke.json | 0 .../environments/nukestudio.json | 0 .../environments/nukestudio_10.0.json | 0 .../environments/nukex.json | 0 .../environments/nukex_10.0.json | 0 .../environments/photoshop.json | 0 .../environments/premiere.json | 0 .../environments/resolve.json | 0 .../environments/storyboardpro.json | 0 .../environments/unreal_4.24.json | 0 .../environments/vray_4300.json | 0 .../global/applications.json | 0 .../global/intent.json | 0 .../global/tools.json | 0 .../global/tray_modules.json | 0 .../launchers/blender_2.80.toml | 0 .../launchers/blender_2.81.toml | 0 .../launchers/blender_2.82.toml | 0 .../launchers/blender_2.83.toml | 0 .../launchers/celaction_local.toml | 0 .../launchers/celaction_publish.toml | 0 .../launchers/darwin/blender_2.82 | 0 .../launchers/darwin/harmony_17 | 0 .../launchers/darwin/harmony_17_launch | 0 .../launchers/darwin/python3 | 0 .../launchers/harmony_17.toml | 0 .../launchers/houdini_16.toml | 0 .../launchers/houdini_17.toml | 0 .../launchers/houdini_18.toml | 0 .../launchers/linux/maya2016 | 0 .../launchers/linux/maya2017 | 0 .../launchers/linux/maya2018 | 0 .../launchers/linux/maya2019 | 0 .../launchers/linux/maya2020 | 0 .../launchers/linux/nuke11.3 | 0 .../launchers/linux/nuke12.0 | 0 .../launchers/linux/nukestudio11.3 | 0 .../launchers/linux/nukestudio12.0 | 0 .../launchers/linux/nukex11.3 | 0 .../launchers/linux/nukex12.0 | 0 .../launchers/maya_2016.toml | 0 .../launchers/maya_2017.toml | 0 .../launchers/maya_2018.toml | 0 .../launchers/maya_2019.toml | 0 .../launchers/maya_2020.toml | 0 .../launchers/mayabatch_2019.toml | 0 .../launchers/mayabatch_2020.toml | 0 .../launchers/mayapy2016.toml | 0 .../launchers/mayapy2017.toml | 0 .../launchers/mayapy2018.toml | 0 .../launchers/mayapy2019.toml | 0 .../launchers/mayapy2020.toml | 0 .../launchers/myapp.toml | 0 .../launchers/nuke_10.0.toml | 0 .../launchers/nuke_11.0.toml | 0 .../launchers/nuke_11.2.toml | 0 .../launchers/nuke_11.3.toml | 0 .../launchers/nuke_12.0.toml | 0 .../launchers/nukestudio_10.0.toml | 0 .../launchers/nukestudio_11.0.toml | 0 .../launchers/nukestudio_11.2.toml | 0 .../launchers/nukestudio_11.3.toml | 0 .../launchers/nukestudio_12.0.toml | 0 .../launchers/nukex_10.0.toml | 0 .../launchers/nukex_11.0.toml | 0 .../launchers/nukex_11.2.toml | 0 .../launchers/nukex_11.3.toml | 0 .../launchers/nukex_12.0.toml | 0 .../launchers/photoshop_2020.toml | 0 .../launchers/premiere_2019.toml | 0 .../launchers/premiere_2020.toml | 0 .../launchers/python_2.toml | 0 .../launchers/python_3.toml | 0 .../launchers/resolve_16.toml | 0 .../launchers/shell.toml | 0 .../launchers/storyboardpro_7.toml | 0 .../launchers/unreal_4.24.toml | 0 .../launchers/windows/blender_2.80.bat | 0 .../launchers/windows/blender_2.81.bat | 0 .../launchers/windows/blender_2.82.bat | 0 .../launchers/windows/blender_2.83.bat | 0 .../launchers/windows/celaction_local.bat | 0 .../launchers/windows/celaction_publish.bat | 0 .../launchers/windows/harmony_17.bat | 0 .../launchers/windows/houdini_16.bat | 0 .../launchers/windows/houdini_17.bat | 0 .../launchers/windows/houdini_18.bat | 0 .../launchers/windows/maya2016.bat | 0 .../launchers/windows/maya2017.bat | 0 .../launchers/windows/maya2018.bat | 0 .../launchers/windows/maya2019.bat | 0 .../launchers/windows/maya2020.bat | 0 .../launchers/windows/mayabatch2019.bat | 0 .../launchers/windows/mayabatch2020.bat | 0 .../launchers/windows/mayapy2016.bat | 0 .../launchers/windows/mayapy2017.bat | 0 .../launchers/windows/mayapy2018.bat | 0 .../launchers/windows/mayapy2019.bat | 0 .../launchers/windows/mayapy2020.bat | 0 .../launchers/windows/nuke10.0.bat | 0 .../launchers/windows/nuke11.0.bat | 0 .../launchers/windows/nuke11.2.bat | 0 .../launchers/windows/nuke11.3.bat | 0 .../launchers/windows/nuke12.0.bat | 0 .../launchers/windows/nukestudio10.0.bat | 0 .../launchers/windows/nukestudio11.0.bat | 0 .../launchers/windows/nukestudio11.2.bat | 0 .../launchers/windows/nukestudio11.3.bat | 0 .../launchers/windows/nukestudio12.0.bat | 0 .../launchers/windows/nukex10.0.bat | 0 .../launchers/windows/nukex11.0.bat | 0 .../launchers/windows/nukex11.2.bat | 0 .../launchers/windows/nukex11.3.bat | 0 .../launchers/windows/nukex12.0.bat | 0 .../launchers/windows/photoshop_2020.bat | 0 .../launchers/windows/premiere_pro_2019.bat | 0 .../launchers/windows/premiere_pro_2020.bat | 0 .../launchers/windows/python3.bat | 0 .../launchers/windows/resolve_16.bat | 0 .../launchers/windows/shell.bat | 0 .../launchers/windows/storyboardpro_7.bat | 0 .../launchers/windows/unreal.bat | 0 .../muster/templates_mapping.json | 0 .../standalone_publish/families.json | 0 139 files changed, 0 insertions(+), 0 deletions(-) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/avalon.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/blender.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/celaction.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/deadline.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/ftrack.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/global.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/harmony.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/houdini.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/maya.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/maya_2018.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/maya_2020.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/mayabatch.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/mayabatch_2019.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/mtoa_3.1.1.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/muster.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/nuke.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/nukestudio.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/nukestudio_10.0.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/nukex.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/nukex_10.0.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/photoshop.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/premiere.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/resolve.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/storyboardpro.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/unreal_4.24.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/environments/vray_4300.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/global/applications.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/global/intent.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/global/tools.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/global/tray_modules.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/blender_2.80.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/blender_2.81.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/blender_2.82.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/blender_2.83.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/celaction_local.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/celaction_publish.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/darwin/blender_2.82 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/darwin/harmony_17 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/darwin/harmony_17_launch (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/darwin/python3 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/harmony_17.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/houdini_16.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/houdini_17.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/houdini_18.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/maya2016 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/maya2017 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/maya2018 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/maya2019 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/maya2020 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/nuke11.3 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/nuke12.0 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/nukestudio11.3 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/nukestudio12.0 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/nukex11.3 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/linux/nukex12.0 (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/maya_2016.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/maya_2017.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/maya_2018.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/maya_2019.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/maya_2020.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayabatch_2019.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayabatch_2020.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayapy2016.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayapy2017.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayapy2018.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayapy2019.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/mayapy2020.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/myapp.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nuke_10.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nuke_11.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nuke_11.2.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nuke_11.3.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nuke_12.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukestudio_10.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukestudio_11.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukestudio_11.2.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukestudio_11.3.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukestudio_12.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukex_10.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukex_11.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukex_11.2.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukex_11.3.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/nukex_12.0.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/photoshop_2020.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/premiere_2019.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/premiere_2020.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/python_2.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/python_3.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/resolve_16.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/shell.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/storyboardpro_7.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/unreal_4.24.toml (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/blender_2.80.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/blender_2.81.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/blender_2.82.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/blender_2.83.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/celaction_local.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/celaction_publish.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/harmony_17.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/houdini_16.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/houdini_17.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/houdini_18.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/maya2016.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/maya2017.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/maya2018.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/maya2019.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/maya2020.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayabatch2019.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayabatch2020.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayapy2016.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayapy2017.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayapy2018.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayapy2019.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/mayapy2020.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nuke10.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nuke11.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nuke11.2.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nuke11.3.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nuke12.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukestudio10.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukestudio11.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukestudio11.2.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukestudio11.3.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukestudio12.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukex10.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukex11.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukex11.2.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukex11.3.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/nukex12.0.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/photoshop_2020.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/premiere_pro_2019.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/premiere_pro_2020.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/python3.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/resolve_16.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/shell.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/storyboardpro_7.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/launchers/windows/unreal.bat (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/muster/templates_mapping.json (100%) rename pype/configurations/defaults/{studio_configurations => system_configurations}/standalone_publish/families.json (100%) diff --git a/pype/configurations/defaults/studio_configurations/environments/avalon.json b/pype/configurations/defaults/system_configurations/environments/avalon.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/avalon.json rename to pype/configurations/defaults/system_configurations/environments/avalon.json diff --git a/pype/configurations/defaults/studio_configurations/environments/blender.json b/pype/configurations/defaults/system_configurations/environments/blender.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/blender.json rename to pype/configurations/defaults/system_configurations/environments/blender.json diff --git a/pype/configurations/defaults/studio_configurations/environments/celaction.json b/pype/configurations/defaults/system_configurations/environments/celaction.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/celaction.json rename to pype/configurations/defaults/system_configurations/environments/celaction.json diff --git a/pype/configurations/defaults/studio_configurations/environments/deadline.json b/pype/configurations/defaults/system_configurations/environments/deadline.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/deadline.json rename to pype/configurations/defaults/system_configurations/environments/deadline.json diff --git a/pype/configurations/defaults/studio_configurations/environments/ftrack.json b/pype/configurations/defaults/system_configurations/environments/ftrack.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/ftrack.json rename to pype/configurations/defaults/system_configurations/environments/ftrack.json diff --git a/pype/configurations/defaults/studio_configurations/environments/global.json b/pype/configurations/defaults/system_configurations/environments/global.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/global.json rename to pype/configurations/defaults/system_configurations/environments/global.json diff --git a/pype/configurations/defaults/studio_configurations/environments/harmony.json b/pype/configurations/defaults/system_configurations/environments/harmony.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/harmony.json rename to pype/configurations/defaults/system_configurations/environments/harmony.json diff --git a/pype/configurations/defaults/studio_configurations/environments/houdini.json b/pype/configurations/defaults/system_configurations/environments/houdini.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/houdini.json rename to pype/configurations/defaults/system_configurations/environments/houdini.json diff --git a/pype/configurations/defaults/studio_configurations/environments/maya.json b/pype/configurations/defaults/system_configurations/environments/maya.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/maya.json rename to pype/configurations/defaults/system_configurations/environments/maya.json diff --git a/pype/configurations/defaults/studio_configurations/environments/maya_2018.json b/pype/configurations/defaults/system_configurations/environments/maya_2018.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/maya_2018.json rename to pype/configurations/defaults/system_configurations/environments/maya_2018.json diff --git a/pype/configurations/defaults/studio_configurations/environments/maya_2020.json b/pype/configurations/defaults/system_configurations/environments/maya_2020.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/maya_2020.json rename to pype/configurations/defaults/system_configurations/environments/maya_2020.json diff --git a/pype/configurations/defaults/studio_configurations/environments/mayabatch.json b/pype/configurations/defaults/system_configurations/environments/mayabatch.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/mayabatch.json rename to pype/configurations/defaults/system_configurations/environments/mayabatch.json diff --git a/pype/configurations/defaults/studio_configurations/environments/mayabatch_2019.json b/pype/configurations/defaults/system_configurations/environments/mayabatch_2019.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/mayabatch_2019.json rename to pype/configurations/defaults/system_configurations/environments/mayabatch_2019.json diff --git a/pype/configurations/defaults/studio_configurations/environments/mtoa_3.1.1.json b/pype/configurations/defaults/system_configurations/environments/mtoa_3.1.1.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/mtoa_3.1.1.json rename to pype/configurations/defaults/system_configurations/environments/mtoa_3.1.1.json diff --git a/pype/configurations/defaults/studio_configurations/environments/muster.json b/pype/configurations/defaults/system_configurations/environments/muster.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/muster.json rename to pype/configurations/defaults/system_configurations/environments/muster.json diff --git a/pype/configurations/defaults/studio_configurations/environments/nuke.json b/pype/configurations/defaults/system_configurations/environments/nuke.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/nuke.json rename to pype/configurations/defaults/system_configurations/environments/nuke.json diff --git a/pype/configurations/defaults/studio_configurations/environments/nukestudio.json b/pype/configurations/defaults/system_configurations/environments/nukestudio.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/nukestudio.json rename to pype/configurations/defaults/system_configurations/environments/nukestudio.json diff --git a/pype/configurations/defaults/studio_configurations/environments/nukestudio_10.0.json b/pype/configurations/defaults/system_configurations/environments/nukestudio_10.0.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/nukestudio_10.0.json rename to pype/configurations/defaults/system_configurations/environments/nukestudio_10.0.json diff --git a/pype/configurations/defaults/studio_configurations/environments/nukex.json b/pype/configurations/defaults/system_configurations/environments/nukex.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/nukex.json rename to pype/configurations/defaults/system_configurations/environments/nukex.json diff --git a/pype/configurations/defaults/studio_configurations/environments/nukex_10.0.json b/pype/configurations/defaults/system_configurations/environments/nukex_10.0.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/nukex_10.0.json rename to pype/configurations/defaults/system_configurations/environments/nukex_10.0.json diff --git a/pype/configurations/defaults/studio_configurations/environments/photoshop.json b/pype/configurations/defaults/system_configurations/environments/photoshop.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/photoshop.json rename to pype/configurations/defaults/system_configurations/environments/photoshop.json diff --git a/pype/configurations/defaults/studio_configurations/environments/premiere.json b/pype/configurations/defaults/system_configurations/environments/premiere.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/premiere.json rename to pype/configurations/defaults/system_configurations/environments/premiere.json diff --git a/pype/configurations/defaults/studio_configurations/environments/resolve.json b/pype/configurations/defaults/system_configurations/environments/resolve.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/resolve.json rename to pype/configurations/defaults/system_configurations/environments/resolve.json diff --git a/pype/configurations/defaults/studio_configurations/environments/storyboardpro.json b/pype/configurations/defaults/system_configurations/environments/storyboardpro.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/storyboardpro.json rename to pype/configurations/defaults/system_configurations/environments/storyboardpro.json diff --git a/pype/configurations/defaults/studio_configurations/environments/unreal_4.24.json b/pype/configurations/defaults/system_configurations/environments/unreal_4.24.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/unreal_4.24.json rename to pype/configurations/defaults/system_configurations/environments/unreal_4.24.json diff --git a/pype/configurations/defaults/studio_configurations/environments/vray_4300.json b/pype/configurations/defaults/system_configurations/environments/vray_4300.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/environments/vray_4300.json rename to pype/configurations/defaults/system_configurations/environments/vray_4300.json diff --git a/pype/configurations/defaults/studio_configurations/global/applications.json b/pype/configurations/defaults/system_configurations/global/applications.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/global/applications.json rename to pype/configurations/defaults/system_configurations/global/applications.json diff --git a/pype/configurations/defaults/studio_configurations/global/intent.json b/pype/configurations/defaults/system_configurations/global/intent.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/global/intent.json rename to pype/configurations/defaults/system_configurations/global/intent.json diff --git a/pype/configurations/defaults/studio_configurations/global/tools.json b/pype/configurations/defaults/system_configurations/global/tools.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/global/tools.json rename to pype/configurations/defaults/system_configurations/global/tools.json diff --git a/pype/configurations/defaults/studio_configurations/global/tray_modules.json b/pype/configurations/defaults/system_configurations/global/tray_modules.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/global/tray_modules.json rename to pype/configurations/defaults/system_configurations/global/tray_modules.json diff --git a/pype/configurations/defaults/studio_configurations/launchers/blender_2.80.toml b/pype/configurations/defaults/system_configurations/launchers/blender_2.80.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/blender_2.80.toml rename to pype/configurations/defaults/system_configurations/launchers/blender_2.80.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/blender_2.81.toml b/pype/configurations/defaults/system_configurations/launchers/blender_2.81.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/blender_2.81.toml rename to pype/configurations/defaults/system_configurations/launchers/blender_2.81.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/blender_2.82.toml b/pype/configurations/defaults/system_configurations/launchers/blender_2.82.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/blender_2.82.toml rename to pype/configurations/defaults/system_configurations/launchers/blender_2.82.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/blender_2.83.toml b/pype/configurations/defaults/system_configurations/launchers/blender_2.83.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/blender_2.83.toml rename to pype/configurations/defaults/system_configurations/launchers/blender_2.83.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/celaction_local.toml b/pype/configurations/defaults/system_configurations/launchers/celaction_local.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/celaction_local.toml rename to pype/configurations/defaults/system_configurations/launchers/celaction_local.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/celaction_publish.toml b/pype/configurations/defaults/system_configurations/launchers/celaction_publish.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/celaction_publish.toml rename to pype/configurations/defaults/system_configurations/launchers/celaction_publish.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/darwin/blender_2.82 b/pype/configurations/defaults/system_configurations/launchers/darwin/blender_2.82 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/darwin/blender_2.82 rename to pype/configurations/defaults/system_configurations/launchers/darwin/blender_2.82 diff --git a/pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17 b/pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17 rename to pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17 diff --git a/pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17_launch b/pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17_launch similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/darwin/harmony_17_launch rename to pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17_launch diff --git a/pype/configurations/defaults/studio_configurations/launchers/darwin/python3 b/pype/configurations/defaults/system_configurations/launchers/darwin/python3 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/darwin/python3 rename to pype/configurations/defaults/system_configurations/launchers/darwin/python3 diff --git a/pype/configurations/defaults/studio_configurations/launchers/harmony_17.toml b/pype/configurations/defaults/system_configurations/launchers/harmony_17.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/harmony_17.toml rename to pype/configurations/defaults/system_configurations/launchers/harmony_17.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/houdini_16.toml b/pype/configurations/defaults/system_configurations/launchers/houdini_16.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/houdini_16.toml rename to pype/configurations/defaults/system_configurations/launchers/houdini_16.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/houdini_17.toml b/pype/configurations/defaults/system_configurations/launchers/houdini_17.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/houdini_17.toml rename to pype/configurations/defaults/system_configurations/launchers/houdini_17.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/houdini_18.toml b/pype/configurations/defaults/system_configurations/launchers/houdini_18.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/houdini_18.toml rename to pype/configurations/defaults/system_configurations/launchers/houdini_18.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/maya2016 b/pype/configurations/defaults/system_configurations/launchers/linux/maya2016 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/maya2016 rename to pype/configurations/defaults/system_configurations/launchers/linux/maya2016 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/maya2017 b/pype/configurations/defaults/system_configurations/launchers/linux/maya2017 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/maya2017 rename to pype/configurations/defaults/system_configurations/launchers/linux/maya2017 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/maya2018 b/pype/configurations/defaults/system_configurations/launchers/linux/maya2018 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/maya2018 rename to pype/configurations/defaults/system_configurations/launchers/linux/maya2018 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/maya2019 b/pype/configurations/defaults/system_configurations/launchers/linux/maya2019 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/maya2019 rename to pype/configurations/defaults/system_configurations/launchers/linux/maya2019 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/maya2020 b/pype/configurations/defaults/system_configurations/launchers/linux/maya2020 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/maya2020 rename to pype/configurations/defaults/system_configurations/launchers/linux/maya2020 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/nuke11.3 b/pype/configurations/defaults/system_configurations/launchers/linux/nuke11.3 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/nuke11.3 rename to pype/configurations/defaults/system_configurations/launchers/linux/nuke11.3 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/nuke12.0 b/pype/configurations/defaults/system_configurations/launchers/linux/nuke12.0 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/nuke12.0 rename to pype/configurations/defaults/system_configurations/launchers/linux/nuke12.0 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio11.3 b/pype/configurations/defaults/system_configurations/launchers/linux/nukestudio11.3 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio11.3 rename to pype/configurations/defaults/system_configurations/launchers/linux/nukestudio11.3 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio12.0 b/pype/configurations/defaults/system_configurations/launchers/linux/nukestudio12.0 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/nukestudio12.0 rename to pype/configurations/defaults/system_configurations/launchers/linux/nukestudio12.0 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/nukex11.3 b/pype/configurations/defaults/system_configurations/launchers/linux/nukex11.3 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/nukex11.3 rename to pype/configurations/defaults/system_configurations/launchers/linux/nukex11.3 diff --git a/pype/configurations/defaults/studio_configurations/launchers/linux/nukex12.0 b/pype/configurations/defaults/system_configurations/launchers/linux/nukex12.0 similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/linux/nukex12.0 rename to pype/configurations/defaults/system_configurations/launchers/linux/nukex12.0 diff --git a/pype/configurations/defaults/studio_configurations/launchers/maya_2016.toml b/pype/configurations/defaults/system_configurations/launchers/maya_2016.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/maya_2016.toml rename to pype/configurations/defaults/system_configurations/launchers/maya_2016.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/maya_2017.toml b/pype/configurations/defaults/system_configurations/launchers/maya_2017.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/maya_2017.toml rename to pype/configurations/defaults/system_configurations/launchers/maya_2017.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/maya_2018.toml b/pype/configurations/defaults/system_configurations/launchers/maya_2018.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/maya_2018.toml rename to pype/configurations/defaults/system_configurations/launchers/maya_2018.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/maya_2019.toml b/pype/configurations/defaults/system_configurations/launchers/maya_2019.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/maya_2019.toml rename to pype/configurations/defaults/system_configurations/launchers/maya_2019.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/maya_2020.toml b/pype/configurations/defaults/system_configurations/launchers/maya_2020.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/maya_2020.toml rename to pype/configurations/defaults/system_configurations/launchers/maya_2020.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayabatch_2019.toml b/pype/configurations/defaults/system_configurations/launchers/mayabatch_2019.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayabatch_2019.toml rename to pype/configurations/defaults/system_configurations/launchers/mayabatch_2019.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayabatch_2020.toml b/pype/configurations/defaults/system_configurations/launchers/mayabatch_2020.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayabatch_2020.toml rename to pype/configurations/defaults/system_configurations/launchers/mayabatch_2020.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayapy2016.toml b/pype/configurations/defaults/system_configurations/launchers/mayapy2016.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayapy2016.toml rename to pype/configurations/defaults/system_configurations/launchers/mayapy2016.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayapy2017.toml b/pype/configurations/defaults/system_configurations/launchers/mayapy2017.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayapy2017.toml rename to pype/configurations/defaults/system_configurations/launchers/mayapy2017.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayapy2018.toml b/pype/configurations/defaults/system_configurations/launchers/mayapy2018.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayapy2018.toml rename to pype/configurations/defaults/system_configurations/launchers/mayapy2018.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayapy2019.toml b/pype/configurations/defaults/system_configurations/launchers/mayapy2019.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayapy2019.toml rename to pype/configurations/defaults/system_configurations/launchers/mayapy2019.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/mayapy2020.toml b/pype/configurations/defaults/system_configurations/launchers/mayapy2020.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/mayapy2020.toml rename to pype/configurations/defaults/system_configurations/launchers/mayapy2020.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/myapp.toml b/pype/configurations/defaults/system_configurations/launchers/myapp.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/myapp.toml rename to pype/configurations/defaults/system_configurations/launchers/myapp.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nuke_10.0.toml b/pype/configurations/defaults/system_configurations/launchers/nuke_10.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nuke_10.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nuke_10.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nuke_11.0.toml b/pype/configurations/defaults/system_configurations/launchers/nuke_11.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nuke_11.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nuke_11.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nuke_11.2.toml b/pype/configurations/defaults/system_configurations/launchers/nuke_11.2.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nuke_11.2.toml rename to pype/configurations/defaults/system_configurations/launchers/nuke_11.2.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nuke_11.3.toml b/pype/configurations/defaults/system_configurations/launchers/nuke_11.3.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nuke_11.3.toml rename to pype/configurations/defaults/system_configurations/launchers/nuke_11.3.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nuke_12.0.toml b/pype/configurations/defaults/system_configurations/launchers/nuke_12.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nuke_12.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nuke_12.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukestudio_10.0.toml b/pype/configurations/defaults/system_configurations/launchers/nukestudio_10.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukestudio_10.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nukestudio_10.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.0.toml b/pype/configurations/defaults/system_configurations/launchers/nukestudio_11.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nukestudio_11.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.2.toml b/pype/configurations/defaults/system_configurations/launchers/nukestudio_11.2.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.2.toml rename to pype/configurations/defaults/system_configurations/launchers/nukestudio_11.2.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.3.toml b/pype/configurations/defaults/system_configurations/launchers/nukestudio_11.3.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukestudio_11.3.toml rename to pype/configurations/defaults/system_configurations/launchers/nukestudio_11.3.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukestudio_12.0.toml b/pype/configurations/defaults/system_configurations/launchers/nukestudio_12.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukestudio_12.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nukestudio_12.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukex_10.0.toml b/pype/configurations/defaults/system_configurations/launchers/nukex_10.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukex_10.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nukex_10.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukex_11.0.toml b/pype/configurations/defaults/system_configurations/launchers/nukex_11.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukex_11.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nukex_11.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukex_11.2.toml b/pype/configurations/defaults/system_configurations/launchers/nukex_11.2.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukex_11.2.toml rename to pype/configurations/defaults/system_configurations/launchers/nukex_11.2.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukex_11.3.toml b/pype/configurations/defaults/system_configurations/launchers/nukex_11.3.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukex_11.3.toml rename to pype/configurations/defaults/system_configurations/launchers/nukex_11.3.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/nukex_12.0.toml b/pype/configurations/defaults/system_configurations/launchers/nukex_12.0.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/nukex_12.0.toml rename to pype/configurations/defaults/system_configurations/launchers/nukex_12.0.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/photoshop_2020.toml b/pype/configurations/defaults/system_configurations/launchers/photoshop_2020.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/photoshop_2020.toml rename to pype/configurations/defaults/system_configurations/launchers/photoshop_2020.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/premiere_2019.toml b/pype/configurations/defaults/system_configurations/launchers/premiere_2019.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/premiere_2019.toml rename to pype/configurations/defaults/system_configurations/launchers/premiere_2019.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/premiere_2020.toml b/pype/configurations/defaults/system_configurations/launchers/premiere_2020.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/premiere_2020.toml rename to pype/configurations/defaults/system_configurations/launchers/premiere_2020.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/python_2.toml b/pype/configurations/defaults/system_configurations/launchers/python_2.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/python_2.toml rename to pype/configurations/defaults/system_configurations/launchers/python_2.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/python_3.toml b/pype/configurations/defaults/system_configurations/launchers/python_3.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/python_3.toml rename to pype/configurations/defaults/system_configurations/launchers/python_3.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/resolve_16.toml b/pype/configurations/defaults/system_configurations/launchers/resolve_16.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/resolve_16.toml rename to pype/configurations/defaults/system_configurations/launchers/resolve_16.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/shell.toml b/pype/configurations/defaults/system_configurations/launchers/shell.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/shell.toml rename to pype/configurations/defaults/system_configurations/launchers/shell.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/storyboardpro_7.toml b/pype/configurations/defaults/system_configurations/launchers/storyboardpro_7.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/storyboardpro_7.toml rename to pype/configurations/defaults/system_configurations/launchers/storyboardpro_7.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/unreal_4.24.toml b/pype/configurations/defaults/system_configurations/launchers/unreal_4.24.toml similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/unreal_4.24.toml rename to pype/configurations/defaults/system_configurations/launchers/unreal_4.24.toml diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.80.bat b/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.80.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.80.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/blender_2.80.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.81.bat b/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.81.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.81.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/blender_2.81.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.82.bat b/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.82.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.82.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/blender_2.82.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.83.bat b/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.83.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/blender_2.83.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/blender_2.83.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/celaction_local.bat b/pype/configurations/defaults/system_configurations/launchers/windows/celaction_local.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/celaction_local.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/celaction_local.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/celaction_publish.bat b/pype/configurations/defaults/system_configurations/launchers/windows/celaction_publish.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/celaction_publish.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/celaction_publish.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/harmony_17.bat b/pype/configurations/defaults/system_configurations/launchers/windows/harmony_17.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/harmony_17.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/harmony_17.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/houdini_16.bat b/pype/configurations/defaults/system_configurations/launchers/windows/houdini_16.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/houdini_16.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/houdini_16.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/houdini_17.bat b/pype/configurations/defaults/system_configurations/launchers/windows/houdini_17.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/houdini_17.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/houdini_17.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/houdini_18.bat b/pype/configurations/defaults/system_configurations/launchers/windows/houdini_18.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/houdini_18.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/houdini_18.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/maya2016.bat b/pype/configurations/defaults/system_configurations/launchers/windows/maya2016.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/maya2016.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/maya2016.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/maya2017.bat b/pype/configurations/defaults/system_configurations/launchers/windows/maya2017.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/maya2017.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/maya2017.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/maya2018.bat b/pype/configurations/defaults/system_configurations/launchers/windows/maya2018.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/maya2018.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/maya2018.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/maya2019.bat b/pype/configurations/defaults/system_configurations/launchers/windows/maya2019.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/maya2019.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/maya2019.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/maya2020.bat b/pype/configurations/defaults/system_configurations/launchers/windows/maya2020.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/maya2020.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/maya2020.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2019.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2019.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2019.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2019.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2020.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2020.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayabatch2020.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2020.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2016.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2016.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2016.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayapy2016.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2017.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2017.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2017.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayapy2017.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2018.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2018.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2018.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayapy2018.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2019.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2019.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2019.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayapy2019.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2020.bat b/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2020.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/mayapy2020.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/mayapy2020.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nuke10.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nuke10.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nuke10.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nuke10.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nuke11.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nuke11.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.2.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nuke11.2.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.2.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nuke11.2.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.3.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nuke11.3.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nuke11.3.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nuke11.3.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nuke12.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nuke12.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nuke12.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nuke12.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio10.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio10.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio10.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukestudio10.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.2.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.2.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.2.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.2.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.3.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.3.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio11.3.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.3.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio12.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio12.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukestudio12.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukestudio12.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukex10.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukex10.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukex10.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukex10.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukex11.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukex11.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.2.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukex11.2.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.2.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukex11.2.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.3.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukex11.3.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukex11.3.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukex11.3.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/nukex12.0.bat b/pype/configurations/defaults/system_configurations/launchers/windows/nukex12.0.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/nukex12.0.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/nukex12.0.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/photoshop_2020.bat b/pype/configurations/defaults/system_configurations/launchers/windows/photoshop_2020.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/photoshop_2020.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/photoshop_2020.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2019.bat b/pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2019.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2020.bat b/pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/premiere_pro_2020.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/python3.bat b/pype/configurations/defaults/system_configurations/launchers/windows/python3.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/python3.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/python3.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/resolve_16.bat b/pype/configurations/defaults/system_configurations/launchers/windows/resolve_16.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/resolve_16.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/resolve_16.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/shell.bat b/pype/configurations/defaults/system_configurations/launchers/windows/shell.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/shell.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/shell.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/storyboardpro_7.bat b/pype/configurations/defaults/system_configurations/launchers/windows/storyboardpro_7.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/storyboardpro_7.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/storyboardpro_7.bat diff --git a/pype/configurations/defaults/studio_configurations/launchers/windows/unreal.bat b/pype/configurations/defaults/system_configurations/launchers/windows/unreal.bat similarity index 100% rename from pype/configurations/defaults/studio_configurations/launchers/windows/unreal.bat rename to pype/configurations/defaults/system_configurations/launchers/windows/unreal.bat diff --git a/pype/configurations/defaults/studio_configurations/muster/templates_mapping.json b/pype/configurations/defaults/system_configurations/muster/templates_mapping.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/muster/templates_mapping.json rename to pype/configurations/defaults/system_configurations/muster/templates_mapping.json diff --git a/pype/configurations/defaults/studio_configurations/standalone_publish/families.json b/pype/configurations/defaults/system_configurations/standalone_publish/families.json similarity index 100% rename from pype/configurations/defaults/studio_configurations/standalone_publish/families.json rename to pype/configurations/defaults/system_configurations/standalone_publish/families.json From 0cca3c68d10ca993cee378b3b9b52fc26eb80e77 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:19:46 +0200 Subject: [PATCH 434/580] fixed last place where is used stuido instead of system --- pype/configurations/config.py | 4 ++-- pype/tools/config_setting/config_setting/widgets/base.py | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/configurations/config.py b/pype/configurations/config.py index 147570acd4..de310645ac 100644 --- a/pype/configurations/config.py +++ b/pype/configurations/config.py @@ -13,7 +13,7 @@ POP_KEY = "__pop_key__" # Paths to studio and project overrides STUDIO_OVERRIDES_PATH = os.environ["PYPE_CONFIG"] -SYSTEM_CONFIGURATIONS_DIR = "studio_configurations" +SYSTEM_CONFIGURATIONS_DIR = "system_configurations" SYSTEM_CONFIGURATIONS_PATH = os.path.join( STUDIO_OVERRIDES_PATH, SYSTEM_CONFIGURATIONS_DIR ) @@ -147,7 +147,7 @@ def load_jsons_from_dir(path, *args, **kwargs): return output -def studio_configurations(*args, **kwargs): +def system_configurations(*args, **kwargs): return load_jsons_from_dir(SYSTEM_CONFIGURATIONS_PATH, *args, **kwargs) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 82a5d024b0..aaa9831c61 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -135,7 +135,7 @@ class SystemWidget(QtWidgets.QWidget): all_values = all_values["system"] # Load studio data with metadata - current_configurations = config.studio_configurations() + current_configurations = config.system_configurations() keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: @@ -171,10 +171,9 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() def _update_values(self): - config.default_configuration() - values = {"system": config.studio_configurations()} + system_values = {"system": config.system_configurations()} for input_field in self.input_fields: - input_field.update_studio_values(values) + input_field.update_studio_values(system_values) for input_field in self.input_fields: input_field.hierarchical_style_update() From 35bc72014e5046cdeb9774b7995ab02bb4cd81ed Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:21:22 +0200 Subject: [PATCH 435/580] bases sets also default values --- .../config_setting/config_setting/widgets/base.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index aaa9831c61..55ca6096de 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -171,6 +171,11 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() def _update_values(self): + default_values = config.default_configuration() + default_values = {"system": default_values["system_configurations"]} + for input_field in self.input_fields: + input_field.update_default_values(default_values) + system_values = {"system": config.system_configurations()} for input_field in self.input_fields: input_field.update_studio_values(system_values) @@ -552,9 +557,14 @@ class ProjectWidget(QtWidgets.QWidget): self._update_values() def _update_values(self): - values = {"project": config.global_project_configurations()} + default_values = config.default_configuration() + default_values = {"project": default_values["project_configurations"]} for input_field in self.input_fields: - input_field.update_studio_values(values) + input_field.update_default_values(default_values) + + studio_values = {"project": config.global_project_configurations()} + for input_field in self.input_fields: + input_field.update_studio_values(studio_values) for input_field in self.input_fields: input_field.hierarchical_style_update() From 3504f06d7b14f26e6068279bf3e238e03f555d47 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:32:26 +0200 Subject: [PATCH 436/580] removed log from abstract attributes --- pype/tools/config_setting/config_setting/widgets/widgets.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index a76f4f6f35..9e814a81e5 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -234,12 +234,6 @@ class AbstractConfigObject: ) return super(AbstractConfigObject, self).__getattribute__(name) - @property - def log(self): - raise NotImplementedError( - "{} does not have implemented `log`".format(self) - ) - @property def is_modified(self): """Has object any changes that require saving.""" From 2eb16374dc69c3118738c515f18a52092c181186 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:43:54 +0200 Subject: [PATCH 437/580] modified configurations files to match more current schemas for able to test --- .../nukestudio/tags.json | 262 ------------------ .../{ => plugins}/celaction/publish.json | 0 .../{ => plugins}/config.json | 0 .../{ => plugins}/ftrack/publish.json | 0 .../{ => plugins}/global/create.json | 0 .../{ => plugins}/global/filter.json | 0 .../{ => plugins}/global/load.json | 0 .../{ => plugins}/global/publish.json | 4 +- .../{ => plugins}/maya/create.json | 0 .../{ => plugins}/maya/filter.json | 0 .../{ => plugins}/maya/load.json | 0 .../{ => plugins}/maya/publish.json | 0 .../{ => plugins}/maya/workfile_build.json | 0 .../{ => plugins}/nuke/create.json | 0 .../{ => plugins}/nuke/load.json | 0 .../{ => plugins}/nuke/publish.json | 0 .../{ => plugins}/nuke/workfile_build.json | 0 .../{ => plugins}/nukestudio/filter.json | 0 .../{ => plugins}/nukestudio/publish.json | 0 .../{ => plugins}/resolve/create.json | 0 .../standalonepublisher/publish.json | 0 .../{ => plugins}/test/create.json | 0 .../{ => plugins}/test/publish.json | 0 23 files changed, 3 insertions(+), 263 deletions(-) delete mode 100644 pype/configurations/defaults/project_configurations/nukestudio/tags.json rename pype/configurations/defaults/project_configurations/{ => plugins}/celaction/publish.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/config.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/ftrack/publish.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/global/create.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/global/filter.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/global/load.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/global/publish.json (98%) rename pype/configurations/defaults/project_configurations/{ => plugins}/maya/create.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/maya/filter.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/maya/load.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/maya/publish.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/maya/workfile_build.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/nuke/create.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/nuke/load.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/nuke/publish.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/nuke/workfile_build.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/nukestudio/filter.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/nukestudio/publish.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/resolve/create.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/standalonepublisher/publish.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/test/create.json (100%) rename pype/configurations/defaults/project_configurations/{ => plugins}/test/publish.json (100%) diff --git a/pype/configurations/defaults/project_configurations/nukestudio/tags.json b/pype/configurations/defaults/project_configurations/nukestudio/tags.json deleted file mode 100644 index 56fcfcbce9..0000000000 --- a/pype/configurations/defaults/project_configurations/nukestudio/tags.json +++ /dev/null @@ -1,262 +0,0 @@ -{ - "Hierarchy": { - "editable": "1", - "note": "{folder}/{sequence}/{shot}", - "icon": { - "path": "hierarchy.png" - }, - "metadata": { - "folder": "FOLDER_NAME", - "shot": "{clip}", - "track": "{track}", - "sequence": "{sequence}", - "episode": "EPISODE_NAME", - "root": "{projectroot}" - } - }, - "Source Resolution": { - "editable": "1", - "note": "Use source resolution", - "icon": { - "path": "resolution.png" - }, - "metadata": { - "family": "resolution" - } - }, - "Retiming": { - "editable": "1", - "note": "Clip has retime or TimeWarp effects (or multiple effects stacked on the clip)", - "icon": { - "path": "retiming.png" - }, - "metadata": { - "family": "retiming", - "marginIn": 1, - "marginOut": 1 - } - }, - "Frame start": { - "editable": "1", - "note": "Starting frame for comps. \n\n> Use `value` and add either number or write `source` (if you want to preserve source frame numbering)", - "icon": { - "path": "icons:TagBackground.png" - }, - "metadata": { - "family": "frameStart", - "value": "1001" - } - }, - "[Lenses]": { - "Set lense here": { - "editable": "1", - "note": "Adjust parameters of your lense and then drop to clip. Remember! You can always overwrite on clip", - "icon": { - "path": "lense.png" - }, - "metadata": { - "focalLengthMm": 57 - - } - } - }, - "[Subsets]": { - "Audio": { - "editable": "1", - "note": "Export with Audio", - "icon": { - "path": "volume.png" - }, - "metadata": { - "family": "audio", - "subset": "main" - } - }, - "plateFg": { - "editable": "1", - "note": "Add to publish to \"forground\" subset. Change metadata subset name if different order number", - "icon": { - "path": "z_layer_fg.png" - }, - "metadata": { - "family": "plate", - "subset": "Fg01" - } - }, - "plateBg": { - "editable": "1", - "note": "Add to publish to \"background\" subset. Change metadata subset name if different order number", - "icon": { - "path": "z_layer_bg.png" - }, - "metadata": { - "family": "plate", - "subset": "Bg01" - } - }, - "plateRef": { - "editable": "1", - "note": "Add to publish to \"reference\" subset.", - "icon": { - "path": "icons:Reference.png" - }, - "metadata": { - "family": "plate", - "subset": "Ref" - } - }, - "plateMain": { - "editable": "1", - "note": "Add to publish to \"main\" subset.", - "icon": { - "path": "z_layer_main.png" - }, - "metadata": { - "family": "plate", - "subset": "main" - } - }, - "plateProxy": { - "editable": "1", - "note": "Add to publish to \"proxy\" subset.", - "icon": { - "path": "z_layer_main.png" - }, - "metadata": { - "family": "plate", - "subset": "proxy" - } - }, - "review": { - "editable": "1", - "note": "Upload to Ftrack as review component.", - "icon": { - "path": "review.png" - }, - "metadata": { - "family": "review", - "track": "review" - } - } - }, - "[Handles]": { - "start: add 20 frames": { - "editable": "1", - "note": "Adding frames to start of selected clip", - "icon": { - "path": "3_add_handles_start.png" - }, - "metadata": { - "family": "handles", - "value": "20", - "args": "{'op':'add','where':'start'}" - } - }, - "start: add 10 frames": { - "editable": "1", - "note": "Adding frames to start of selected clip", - "icon": { - "path": "3_add_handles_start.png" - }, - "metadata": { - "family": "handles", - "value": "10", - "args": "{'op':'add','where':'start'}" - } - }, - "start: add 5 frames": { - "editable": "1", - "note": "Adding frames to start of selected clip", - "icon": { - "path": "3_add_handles_start.png" - }, - "metadata": { - "family": "handles", - "value": "5", - "args": "{'op':'add','where':'start'}" - } - }, - "start: add 0 frames": { - "editable": "1", - "note": "Adding frames to start of selected clip", - "icon": { - "path": "3_add_handles_start.png" - }, - "metadata": { - "family": "handles", - "value": "0", - "args": "{'op':'add','where':'start'}" - } - }, - "end: add 20 frames": { - "editable": "1", - "note": "Adding frames to end of selected clip", - "icon": { - "path": "1_add_handles_end.png" - }, - "metadata": { - "family": "handles", - "value": "20", - "args": "{'op':'add','where':'end'}" - } - }, - "end: add 10 frames": { - "editable": "1", - "note": "Adding frames to end of selected clip", - "icon": { - "path": "1_add_handles_end.png" - }, - "metadata": { - "family": "handles", - "value": "10", - "args": "{'op':'add','where':'end'}" - } - }, - "end: add 5 frames": { - "editable": "1", - "note": "Adding frames to end of selected clip", - "icon": { - "path": "1_add_handles_end.png" - }, - "metadata": { - "family": "handles", - "value": "5", - "args": "{'op':'add','where':'end'}" - } - }, - "end: add 0 frames": { - "editable": "1", - "note": "Adding frames to end of selected clip", - "icon": { - "path": "1_add_handles_end.png" - }, - "metadata": { - "family": "handles", - "value": "0", - "args": "{'op':'add','where':'end'}" - } - } - }, - "NukeScript": { - "editable": "1", - "note": "Collecting track items to Nuke scripts.", - "icon": { - "path": "icons:TagNuke.png" - }, - "metadata": { - "family": "nukescript", - "subset": "main" - } - }, - "Comment": { - "editable": "1", - "note": "Comment on a shot.", - "icon": { - "path": "icons:TagComment.png" - }, - "metadata": { - "family": "comment", - "subset": "main" - } - } -} diff --git a/pype/configurations/defaults/project_configurations/celaction/publish.json b/pype/configurations/defaults/project_configurations/plugins/celaction/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/celaction/publish.json rename to pype/configurations/defaults/project_configurations/plugins/celaction/publish.json diff --git a/pype/configurations/defaults/project_configurations/config.json b/pype/configurations/defaults/project_configurations/plugins/config.json similarity index 100% rename from pype/configurations/defaults/project_configurations/config.json rename to pype/configurations/defaults/project_configurations/plugins/config.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/publish.json b/pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/publish.json rename to pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json diff --git a/pype/configurations/defaults/project_configurations/global/create.json b/pype/configurations/defaults/project_configurations/plugins/global/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/create.json rename to pype/configurations/defaults/project_configurations/plugins/global/create.json diff --git a/pype/configurations/defaults/project_configurations/global/filter.json b/pype/configurations/defaults/project_configurations/plugins/global/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/filter.json rename to pype/configurations/defaults/project_configurations/plugins/global/filter.json diff --git a/pype/configurations/defaults/project_configurations/global/load.json b/pype/configurations/defaults/project_configurations/plugins/global/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/load.json rename to pype/configurations/defaults/project_configurations/plugins/global/load.json diff --git a/pype/configurations/defaults/project_configurations/global/publish.json b/pype/configurations/defaults/project_configurations/plugins/global/publish.json similarity index 98% rename from pype/configurations/defaults/project_configurations/global/publish.json rename to pype/configurations/defaults/project_configurations/plugins/global/publish.json index 3c5de85e68..d531f1aa47 100644 --- a/pype/configurations/defaults/project_configurations/global/publish.json +++ b/pype/configurations/defaults/project_configurations/plugins/global/publish.json @@ -3,6 +3,7 @@ "enabled": false }, "ExtractJpegEXR": { + "enabled": true, "ffmpeg_args": { "input": [ "-gamma 2.2" @@ -74,6 +75,7 @@ ] }, "IntegrateAssetNew": { + "enabled": true, "template_name_profiles": { "publish": { "families": [], @@ -94,4 +96,4 @@ "deadline_pool": "", "deadline_group": "" } -} \ No newline at end of file +} diff --git a/pype/configurations/defaults/project_configurations/maya/create.json b/pype/configurations/defaults/project_configurations/plugins/maya/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/maya/create.json rename to pype/configurations/defaults/project_configurations/plugins/maya/create.json diff --git a/pype/configurations/defaults/project_configurations/maya/filter.json b/pype/configurations/defaults/project_configurations/plugins/maya/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/maya/filter.json rename to pype/configurations/defaults/project_configurations/plugins/maya/filter.json diff --git a/pype/configurations/defaults/project_configurations/maya/load.json b/pype/configurations/defaults/project_configurations/plugins/maya/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/maya/load.json rename to pype/configurations/defaults/project_configurations/plugins/maya/load.json diff --git a/pype/configurations/defaults/project_configurations/maya/publish.json b/pype/configurations/defaults/project_configurations/plugins/maya/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/maya/publish.json rename to pype/configurations/defaults/project_configurations/plugins/maya/publish.json diff --git a/pype/configurations/defaults/project_configurations/maya/workfile_build.json b/pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json similarity index 100% rename from pype/configurations/defaults/project_configurations/maya/workfile_build.json rename to pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json diff --git a/pype/configurations/defaults/project_configurations/nuke/create.json b/pype/configurations/defaults/project_configurations/plugins/nuke/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/nuke/create.json rename to pype/configurations/defaults/project_configurations/plugins/nuke/create.json diff --git a/pype/configurations/defaults/project_configurations/nuke/load.json b/pype/configurations/defaults/project_configurations/plugins/nuke/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/nuke/load.json rename to pype/configurations/defaults/project_configurations/plugins/nuke/load.json diff --git a/pype/configurations/defaults/project_configurations/nuke/publish.json b/pype/configurations/defaults/project_configurations/plugins/nuke/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/nuke/publish.json rename to pype/configurations/defaults/project_configurations/plugins/nuke/publish.json diff --git a/pype/configurations/defaults/project_configurations/nuke/workfile_build.json b/pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json similarity index 100% rename from pype/configurations/defaults/project_configurations/nuke/workfile_build.json rename to pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json diff --git a/pype/configurations/defaults/project_configurations/nukestudio/filter.json b/pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/nukestudio/filter.json rename to pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json diff --git a/pype/configurations/defaults/project_configurations/nukestudio/publish.json b/pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/nukestudio/publish.json rename to pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json diff --git a/pype/configurations/defaults/project_configurations/resolve/create.json b/pype/configurations/defaults/project_configurations/plugins/resolve/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/resolve/create.json rename to pype/configurations/defaults/project_configurations/plugins/resolve/create.json diff --git a/pype/configurations/defaults/project_configurations/standalonepublisher/publish.json b/pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/standalonepublisher/publish.json rename to pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json diff --git a/pype/configurations/defaults/project_configurations/test/create.json b/pype/configurations/defaults/project_configurations/plugins/test/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/test/create.json rename to pype/configurations/defaults/project_configurations/plugins/test/create.json diff --git a/pype/configurations/defaults/project_configurations/test/publish.json b/pype/configurations/defaults/project_configurations/plugins/test/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/test/publish.json rename to pype/configurations/defaults/project_configurations/plugins/test/publish.json From 9f9bad6c5425c97b944be59926db94450705571a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 12:44:16 +0200 Subject: [PATCH 438/580] first commit of update_default_values --- .../config_setting/widgets/anatomy_inputs.py | 35 +++++++++++++++ .../config_setting/widgets/inputs.py | 44 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index fbc3a3a2ed..43146f7442 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -75,6 +75,10 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.value_changed.connect(self._on_value_change) + def update_default_values(self, value): + self.root_widget.update_default_values(value) + self.templates_widget.update_default_values(value) + def update_studio_values(self, parent_values): self._state = None self._child_state = None @@ -255,6 +259,33 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def is_multiroot(self): return self.multiroot_checkbox.isChecked() + def update_default_values(self, parent_values): + self._state = None + self._multiroot_state = None + + if isinstance(parent_values, dict): + value = parent_values.get(self.key, NOT_SET) + else: + value = NOT_SET + + is_multiroot = False + if isinstance(value, dict): + for _value in value.values(): + if isinstance(_value, dict): + is_multiroot = True + break + + self.global_is_multiroot = is_multiroot + self.was_multiroot = is_multiroot + self.set_multiroot(is_multiroot) + + if is_multiroot: + self.singleroot_widget.update_studio_values(NOT_SET) + self.multiroot_widget.update_studio_values(value) + else: + self.singleroot_widget.update_studio_values(value) + self.multiroot_widget.update_studio_values(NOT_SET) + def update_studio_values(self, parent_values): self._state = None self._multiroot_state = None @@ -486,6 +517,10 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): layout.addWidget(body_widget) + def update_default_values(self, values): + self._state = None + self.value_input.update_default_values(values) + def update_studio_values(self, values): self._state = None self.value_input.update_studio_values(values) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 057ed3b584..27de95c402 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -174,6 +174,26 @@ class ConfigObject(AbstractConfigObject): class InputObject(ConfigObject): + def update_default_values(self, parent_values): + value = NOT_SET + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + if value is NOT_SET: + if self._as_widget: + print(self) + elif hasattr(self, "_parent"): + print(self._parent.key, self.key, self) + raise ValueError( + "Default value is not set. This is implementation BUG." + ) + self.default_value = value + if not self.has_studio_override: + print(value) + self.set_value(value) + def overrides(self): if not self.is_overriden: return NOT_SET, False @@ -1666,6 +1686,16 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() + def update_default_values(self, parent_values): + value = NOT_SET + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + for item in self.input_fields: + item.update_default_values(value) + def update_studio_values(self, parent_values): value = NOT_SET if parent_values is not NOT_SET: @@ -1932,6 +1962,16 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() + def update_default_values(self, parent_values): + value = NOT_SET + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + for item in self.input_fields: + item.update_default_values(value) + def update_studio_values(self, parent_values): value = NOT_SET if parent_values is not NOT_SET: @@ -2367,6 +2407,10 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): for item in self.input_fields: item.set_as_overriden() + def update_default_values(self, value): + for item in self.input_fields: + item.update_default_values(value) + def update_studio_values(self, value): for item in self.input_fields: item.update_studio_values(value) From 24753d6af787e511768c1d759ae8693fa9485162 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 13:34:27 +0200 Subject: [PATCH 439/580] cleaned debug part --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 27de95c402..989980f2a0 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -182,16 +182,12 @@ class InputObject(ConfigObject): value = parent_values.get(self.key, NOT_SET) if value is NOT_SET: - if self._as_widget: - print(self) - elif hasattr(self, "_parent"): - print(self._parent.key, self.key, self) raise ValueError( "Default value is not set. This is implementation BUG." ) + self.default_value = value if not self.has_studio_override: - print(value) self.set_value(value) def overrides(self): From dbfe43e821372445a0bceb48d8890e534d7c9d7b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 14:03:17 +0200 Subject: [PATCH 440/580] update studio_values should work with new default_values --- .../config_setting/widgets/inputs.py | 216 ++++-------------- 1 file changed, 42 insertions(+), 174 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 989980f2a0..fa07419fde 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -190,6 +190,24 @@ class InputObject(ConfigObject): if not self.has_studio_override: self.set_value(value) + def update_studio_values(self, parent_values): + value = NOT_SET + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + self.studio_value = value + if value is not NOT_SET: + self.set_value(value) + self._has_studio_override = True + + else: + self.set_value(self.default_value) + self._has_studio_override = False + + self._is_modified = False + def overrides(self): if not self.is_overriden: return NOT_SET, False @@ -199,7 +217,10 @@ class InputObject(ConfigObject): self.update_style() def remove_overrides(self): - self.set_value(self.start_value) + if self.has_studio_override: + self.set_value(self.studio_value) + else: + self.set_value(self.default_value) self._is_overriden = False self._is_modified = False @@ -217,7 +238,10 @@ class InputObject(ConfigObject): if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False - value = self.start_value + if self.has_studio_override: + value = self.studio_value + else: + value = self.default_value else: self._is_overriden = True self._was_overriden = True @@ -234,7 +258,10 @@ class InputObject(ConfigObject): ): self.set_value(self.override_value) else: - self.set_value(self.start_value) + if self.has_studio_override: + self.set_value(self.studio_value) + else: + self.set_value(self.defaul_value) if not self.is_overidable: self._is_modified = self.studio_value != self.item_value() @@ -290,7 +317,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -316,24 +342,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.checkbox.stateChanged.connect(self._on_value_change) - def update_studio_values(self, parent_values): - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.set_value(value) - - elif self.default_value is not NOT_SET: - self.set_value(self.default_value) - - self.studio_value = value - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value - def set_value(self, value): # Ignore value change because if `self.isChecked()` has same # value as `value` the `_on_value_change` is not triggered @@ -399,7 +407,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -426,25 +433,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.input_field.valueChanged.connect(self._on_value_change) - def update_studio_values(self, parent_values): - value = NOT_SET - if self._as_widget: - value = parent_values - else: - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.set_value(value) - - elif self.default_value is not NOT_SET: - self.set_value(self.default_value) - - self.studio_value = value - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value - def set_value(self, value): self.input_field.setValue(value) @@ -510,7 +498,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -535,24 +522,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.text_input.textChanged.connect(self._on_value_change) - def update_studio_values(self, parent_values): - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.set_value(value) - - elif self.default_value is not NOT_SET: - self.set_value(self.default_value) - - self.studio_value = value - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value - def set_value(self, value): if self.multiline: self.text_input.setPlainText(value) @@ -622,7 +591,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -642,24 +610,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.path_input.textChanged.connect(self._on_value_change) - def update_studio_values(self, parent_values): - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.set_value(value) - - elif self.default_value is not NOT_SET: - self.set_value(self.default_value) - - self.studio_value = value - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value - def set_value(self, value): self.path_input.setText(value) @@ -785,7 +735,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -811,25 +760,10 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.text_input.textChanged.connect(self._on_value_change) def update_studio_values(self, parent_values): - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if value is not NOT_SET: - self.set_value(value) - - elif self.default_value is not NOT_SET: - self.set_value(self.default_value) + super(RawJsonWidget, self).update_studio_values(parent_values) self._is_invalid = self.text_input.has_invalid_value() - self.studio_value = value - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value - def set_value(self, value): self.text_input.set_value(value) @@ -982,7 +916,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET self.key = input_data["key"] @@ -1015,33 +948,8 @@ class ListWidget(QtWidgets.QWidget, InputObject): return len(self.input_fields) def update_studio_values(self, parent_values): - old_inputs = tuple(self.input_fields) + super(ListWidget, self).update_studio_values(parent_values) - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - self.studio_value = value - - if value is not NOT_SET: - for item_value in value: - self.add_row(value=item_value) - - elif self.default_value is not NOT_SET: - for item_value in self.default_value: - self.add_row(value=item_value) - - for old_input in old_inputs: - self.remove_row(old_input) - - if self.count() == 0: - self.add_row(is_empty=True) - - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value self.hierarchical_style_update() def set_value(self, value): @@ -1052,6 +960,9 @@ class ListWidget(QtWidgets.QWidget, InputObject): for input_field in previous_inputs: self.remove_row(input_field) + if self.count() == 0: + self.add_row(is_empty=True) + def _on_value_change(self, item=None): if self.ignore_value_changes: return @@ -1128,7 +1039,10 @@ class ListWidget(QtWidgets.QWidget, InputObject): if override_value is NOT_SET: self._is_overriden = False self._was_overriden = False - value = self.start_value + if self.has_studio_override: + value = self.studio_value + else: + value = self.default_value else: self._is_overriden = True self._was_overriden = True @@ -1326,7 +1240,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET any_parent_is_group = parent.is_group if not any_parent_is_group: @@ -1380,35 +1293,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def count(self): return len(self.input_fields) - def update_studio_values(self, parent_values): - old_inputs = tuple(self.input_fields) - - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - self.studio_value = value - - if value is not NOT_SET: - for item_key, item_value in value.items(): - self.add_row(key=item_key, value=item_value) - - elif self.default_value is not NOT_SET: - for item_key, item_value in self.default_value.items(): - self.add_row(key=item_key, value=item_value) - - for old_input in old_inputs: - self.remove_row(old_input) - - if self.count() == 0: - self.add_row(is_empty=True) - - self.start_value = self.item_value() - - self._is_modified = self.studio_value != self.start_value - def set_value(self, value): previous_inputs = tuple(self.input_fields) for item_key, item_value in value.items(): @@ -1417,6 +1301,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): for input_field in previous_inputs: self.remove_row(input_field) + if self.count() == 0: + self.add_row(is_empty=True) + def _on_value_change(self, item=None): fields_by_keys = collections.defaultdict(list) for input_field in self.input_fields: @@ -2066,7 +1953,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.default_value = NOT_SET self.studio_value = NOT_SET self.override_value = NOT_SET - self.start_value = NOT_SET self.input_fields = [] @@ -2143,24 +2029,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.setFocusProxy(self.input_fields[0]) self.content_layout.addWidget(proxy_widget) - def update_studio_values(self, parent_values): - value = NOT_SET - if self._as_widget: - value = parent_values - elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) - - if not self.multiplatform: - self.input_fields[0].update_studio_values(parent_values) - - elif self.multiplatform: - for input_field in self.input_fields: - input_field.update_studio_values(value) - - self.studio_value = value - self.start_value = self.item_value() - self._is_modified = self.studio_value != self.start_value - def apply_overrides(self, parent_values): self._is_modified = False self._state = None From 46944e87c996d2ceb987f6eafbaf9b2dda705405 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 14:25:14 +0200 Subject: [PATCH 441/580] simplified state stylesheets --- .../config_setting/style/style.css | 68 +++++-------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index fe3bba366a..fef1278de1 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -53,21 +53,11 @@ QLabel[state="overriden"]:hover {color: #ffa64d;} QLabel[state="invalid"] {color: #ad2e2e; font-weight: bold;} QLabel[state="invalid"]:hover {color: #ad2e2e; font-weight: bold;} -QWidget[input-state="modified"] { - border-color: #137cbd; -} -QWidget[input-state="overriden-modified"] { - border-color: #137cbd; -} - -QWidget[input-state="overriden"] { - border-color: #ff8c1a; -} - -QWidget[input-state="invalid"] { - border-color: #ad2e2e; -} +QWidget[input-state="modified"] {border-color: #137cbd;} +QWidget[input-state="overriden-modified"] {border-color: #137cbd;} +QWidget[input-state="overriden"] {border-color: #ff8c1a;} +QWidget[input-state="invalid"] {border-color: #ad2e2e;} QPushButton { border: 1px solid #aaaaaa; @@ -105,19 +95,10 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } -#DictKey[state="modified"] { - border-color: #137cbd; -} - -#DictKey[state="overriden"] { - border-color: #00f; -} -#DictKey[state="overriden-modified"] { - border-color: #0f0; -} -#DictKey[state="invalid"] { - border-color: #ad2e2e; -} +#DictKey[state="modified"] {border-color: #137cbd;} +#DictKey[state="overriden"] {border-color: #00f;} +#DictKey[state="overriden-modified"] {border-color: #0f0;} +#DictKey[state="invalid"] {border-color: #ad2e2e;} #DictLabel { font-weight: bold; @@ -144,33 +125,18 @@ QPushButton[btn-type="expand-toggle"] { border-color: #62839d; } -#SideLineWidget[state="child-modified"]{ - border-color: #106aa2; -} -#SideLineWidget[state="child-modified"]:hover{ - border-color: #137cbd; -} -#SideLineWidget[state="child-invalid"]{ - border-color: #ad2e2e; -} -#SideLineWidget[state="child-invalid"]:hover{ - border-color: #c93636; -} +#SideLineWidget[state="child-modified"] {border-color: #106aa2;} +#SideLineWidget[state="child-modified"]:hover {border-color: #137cbd;} -#SideLineWidget[state="child-overriden"]{ - border-color: #e67300; -} -#SideLineWidget[state="child-overriden"]:hover { - border-color: #ff8c1a; -} +#SideLineWidget[state="child-invalid"] {border-color: #ad2e2e;} +#SideLineWidget[state="child-invalid"]:hover {border-color: #c93636;} -#SideLineWidget[state="child-overriden-modified"] { - border-color: #106aa2; -} -#SideLineWidget[state="child-overriden-modified"]:hover { - border-color: #137cbd; -} +#SideLineWidget[state="child-overriden"] {border-color: #e67300;} +#SideLineWidget[state="child-overriden"]:hover {border-color: #ff8c1a;} + +#SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} +#SideLineWidget[state="child-overriden-modified"]:hover {border-color: #137cbd;} QScrollBar:horizontal { height: 15px; From 5830b637d7b17c0bb0b18e5f9b59db9376bf50a8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 14:25:29 +0200 Subject: [PATCH 442/580] normla label is little bit darker --- pype/tools/config_setting/config_setting/style/style.css | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index fef1278de1..61581b9124 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -38,11 +38,15 @@ QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:d QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { border: 1px solid #ffffff; } -QLabel, QToolButton { +QToolButton { background: transparent; } -QLabel:hover {color: #ffffff;} +QLabel { + background: transparent; + color: #808080; +} +QLabel:hover {color: #999999;} QLabel[state="modified"] {color: #137cbd;} QLabel[state="modified"]:hover {color: #1798e8;} From ac116aaa02637ddf0efad6b27229eed8ad9288f2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 14:25:45 +0200 Subject: [PATCH 443/580] added child_has_studio_override to abstract methods --- .../config_setting/config_setting/widgets/widgets.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 9e814a81e5..5547f66597 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -302,6 +302,15 @@ class AbstractConfigObject: "{} does not have implemented setter method `ignore_value_changes`" ).format(self)) + @property + def child_has_studio_override(self): + """Any children item is modified.""" + raise NotImplementedError( + "{} does not have implemented `child_has_studio_override`".format( + self + ) + ) + @property def child_modified(self): """Any children item is modified.""" From 82a29d9c2734e1a23cebe4efcabcbb9fc6a9b945 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 14:25:58 +0200 Subject: [PATCH 444/580] implemented child_has_studio_override for inputs --- .../config_setting/widgets/inputs.py | 108 +++++++++++++++--- 1 file changed, 93 insertions(+), 15 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index fa07419fde..a9cbc502e9 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -94,9 +94,13 @@ class ConfigObject(AbstractConfigObject): return {self.key: self.item_value()} @classmethod - def style_state(cls, is_invalid, is_overriden, is_modified): + def style_state( + cls, has_studio_override, is_invalid, is_overriden, is_modified + ): items = [] - if is_invalid: + if has_studio_override: + items.append("studio") + elif is_invalid: items.append("invalid") else: if is_overriden: @@ -261,10 +265,13 @@ class InputObject(ConfigObject): if self.has_studio_override: self.set_value(self.studio_value) else: - self.set_value(self.defaul_value) + self.set_value(self.default_value) if not self.is_overidable: - self._is_modified = self.studio_value != self.item_value() + if self.has_studio_override: + self._is_modified = self.studio_value != self.item_value() + else: + self._is_modified = self.default_value != self.item_value() self._is_overriden = False return @@ -274,6 +281,10 @@ class InputObject(ConfigObject): def set_as_overriden(self): self._is_overriden = True + @property + def child_has_studio_override(self): + return self.has_studio_override + @property def child_modified(self): return self.is_modified @@ -367,7 +378,10 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -456,7 +470,10 @@ class NumberWidget(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -548,7 +565,10 @@ class TextWidget(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -637,7 +657,10 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -788,7 +811,10 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -876,6 +902,10 @@ class ListItem(QtWidgets.QWidget, ConfigObject): return self.value_input.item_value() return NOT_SET + @property + def child_has_studio_override(self): + return self.value_input.child_has_studio_override + @property def child_modified(self): return self.value_input.child_modified @@ -1060,7 +1090,10 @@ class ListWidget(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -1345,7 +1378,10 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def update_style(self): state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -1633,10 +1669,14 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self.update_style() def update_style(self, is_overriden=None): + child_has_studio_override = self.child_has_studio_override child_modified = self.child_modified child_invalid = self.child_invalid child_state = self.style_state( - child_invalid, self.child_overriden, child_modified + child_has_studio_override, + child_invalid, + self.child_overriden, + child_modified ) if child_state: child_state = "child-{}".format(child_state) @@ -1649,7 +1689,10 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self._child_state = child_state state = self.style_state( - child_invalid, self.is_overriden, self.is_modified + child_has_studio_override, + child_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -1665,6 +1708,13 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): return self._is_modified or self.child_modified return False + @property + def child_has_studio_override(self): + for input_field in self.input_fields: + if input_field.child_has_studio_override: + return True + return False + @property def child_modified(self): for input_field in self.input_fields: @@ -1768,6 +1818,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): def update_style(self, *args, **kwargs): return + @property + def child_has_studio_override(self): + for input_field in self.input_fields: + if input_field.child_has_studio_override: + return True + return False + @property def child_modified(self): for input_field in self.input_fields: @@ -2085,10 +2142,14 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.value_changed.emit(self) def update_style(self, is_overriden=None): + child_has_studio_override = self.has_studio_override child_modified = self.child_modified child_invalid = self.child_invalid child_state = self.style_state( - child_invalid, self.child_overriden, child_modified + child_has_studio_override, + child_invalid, + self.child_overriden, + child_modified ) if child_state: child_state = "child-{}".format(child_state) @@ -2100,7 +2161,10 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): if not self._as_widget: state = self.style_state( - child_invalid, self.is_overriden, self.is_modified + child_has_studio_override, + child_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -2128,6 +2192,13 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): def set_as_overriden(self): self._is_overriden = True + @property + def child_has_studio_override(self): + for input_field in self.input_fields: + if input_field.child_has_studio_override: + return True + return False + @property def child_modified(self): for input_field in self.input_fields: @@ -2286,6 +2357,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): if self.any_parent_is_group: self.hierarchical_style_update() + @property + def child_has_studio_override(self): + for input_field in self.input_fields: + if input_field.child_has_studio_override: + return True + return False + @property def child_modified(self): for input_field in self.input_fields: From 84108c5fda60808b0b2ea4f8424eccfa1b16aa6a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 14:46:44 +0200 Subject: [PATCH 445/580] fixed state values and added styles for studio overrides --- .../config_setting/config_setting/style/style.css | 10 ++++++++-- .../config_setting/config_setting/widgets/inputs.py | 8 +++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 61581b9124..73c1854bee 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -48,6 +48,8 @@ QLabel { } QLabel:hover {color: #999999;} +QLabel[state="studio"] {color: #bfccd6;} +QLabel[state="studio"]:hover {color: #ffffff;} QLabel[state="modified"] {color: #137cbd;} QLabel[state="modified"]:hover {color: #1798e8;} QLabel[state="overriden-modified"] {color: #137cbd;} @@ -58,6 +60,7 @@ QLabel[state="invalid"] {color: #ad2e2e; font-weight: bold;} QLabel[state="invalid"]:hover {color: #ad2e2e; font-weight: bold;} +QWidget[input-state="studio"] {border-color: #bfccd6;} QWidget[input-state="modified"] {border-color: #137cbd;} QWidget[input-state="overriden-modified"] {border-color: #137cbd;} QWidget[input-state="overriden"] {border-color: #ff8c1a;} @@ -99,6 +102,7 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } +#DictKey[state="studio"] {border-color: #bfccd6;} #DictKey[state="modified"] {border-color: #137cbd;} #DictKey[state="overriden"] {border-color: #00f;} #DictKey[state="overriden-modified"] {border-color: #0f0;} @@ -118,7 +122,7 @@ QPushButton[btn-type="expand-toggle"] { #SideLineWidget { background-color: #31424e; border-style: solid; - border-color: #455c6e; + border-color: #808080; border-left-width: 3px; border-bottom-width: 0px; border-right-width: 0px; @@ -126,9 +130,11 @@ QPushButton[btn-type="expand-toggle"] { } #SideLineWidget:hover { - border-color: #62839d; + border-color: #999999; } +#SideLineWidget[state="child-studio"] {border-color: #455c6e;} +#SideLineWidget[state="child-studio"]:hover {border-color: #62839d;} #SideLineWidget[state="child-modified"] {border-color: #106aa2;} #SideLineWidget[state="child-modified"]:hover {border-color: #137cbd;} diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index a9cbc502e9..b0aaa5ed3d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -98,15 +98,17 @@ class ConfigObject(AbstractConfigObject): cls, has_studio_override, is_invalid, is_overriden, is_modified ): items = [] - if has_studio_override: - items.append("studio") - elif is_invalid: + if is_invalid: items.append("invalid") else: if is_overriden: items.append("overriden") if is_modified: items.append("modified") + + if not items and has_studio_override: + items.append("studio") + return "-".join(items) or cls.default_state def _discard_changes(self): From 3af3e46f1018307697ac8f49b7c49b33e7f94109 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 15:35:38 +0200 Subject: [PATCH 446/580] config split into lib and config file --- pype/configurations/config.py | 222 +++------------------------------- pype/configurations/lib.py | 208 +++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 206 deletions(-) create mode 100644 pype/configurations/lib.py diff --git a/pype/configurations/config.py b/pype/configurations/config.py index de310645ac..e19a27f33c 100644 --- a/pype/configurations/config.py +++ b/pype/configurations/config.py @@ -1,214 +1,24 @@ -import os -import json -import logging -import copy - -log = logging.getLogger(__name__) - -# Metadata keys for work with studio and project overrides -OVERRIDEN_KEY = "__overriden_keys__" -# NOTE key popping not implemented yet -POP_KEY = "__pop_key__" - -# Paths to studio and project overrides -STUDIO_OVERRIDES_PATH = os.environ["PYPE_CONFIG"] - -SYSTEM_CONFIGURATIONS_DIR = "system_configurations" -SYSTEM_CONFIGURATIONS_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, SYSTEM_CONFIGURATIONS_DIR -) -PROJECT_CONFIGURATIONS_DIR = "project_configurations" -PROJECT_CONFIGURATIONS_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, PROJECT_CONFIGURATIONS_DIR +from .lib import ( + apply_overrides, + default_configuration, + studio_system_configurations, + studio_project_configurations, + project_configurations_overrides ) -# Variable where cache of default configurations are stored -_DEFAULT_CONFIGURATIONS = None -# TODO remove this as is maybe deprecated -first_run = False +def system_configurations(): + default_values = default_configuration()["system_configurations"] + studio_values = studio_system_configurations() + return apply_overrides(default_values, studio_values) -def default_configuration(): - global _DEFAULT_CONFIGURATIONS - if _DEFAULT_CONFIGURATIONS is None: - current_dir = os.path.dirname(__file__) - defaults_path = os.path.join(current_dir, "defaults") - _DEFAULT_CONFIGURATIONS = load_jsons_from_dir(defaults_path) - return _DEFAULT_CONFIGURATIONS +def project_configurations(project_name): + default_values = default_configuration() + studio_values = studio_project_configurations() + studio_overrides = apply_overrides(default_values, studio_values) -def load_json(fpath): - # Load json data - with open(fpath, "r") as opened_file: - lines = opened_file.read().splitlines() + project_overrides = project_configurations_overrides(project_name) - # prepare json string - standard_json = "" - for line in lines: - # Remove all whitespace on both sides - line = line.strip() - - # Skip blank lines - if len(line) == 0: - continue - - standard_json += line - - # Check if has extra commas - extra_comma = False - if ",]" in standard_json or ",}" in standard_json: - extra_comma = True - standard_json = standard_json.replace(",]", "]") - standard_json = standard_json.replace(",}", "}") - - global first_run - if extra_comma and first_run: - log.error("Extra comma in json file: \"{}\"".format(fpath)) - - # return empty dict if file is empty - if standard_json == "": - if first_run: - log.error("Empty json file: \"{}\"".format(fpath)) - return {} - - # Try to parse string - try: - return json.loads(standard_json) - - except json.decoder.JSONDecodeError: - # Return empty dict if it is first time that decode error happened - if not first_run: - return {} - - # Repreduce the exact same exception but traceback contains better - # information about position of error in the loaded json - try: - with open(fpath, "r") as opened_file: - json.load(opened_file) - - except json.decoder.JSONDecodeError: - log.warning( - "File has invalid json format \"{}\"".format(fpath), - exc_info=True - ) - - return {} - - -def subkey_merge(_dict, value, keys): - key = keys.pop(0) - if not keys: - _dict[key] = value - return _dict - - if key not in _dict: - _dict[key] = {} - _dict[key] = subkey_merge(_dict[key], value, keys) - - return _dict - - -def load_jsons_from_dir(path, *args, **kwargs): - output = {} - - path = os.path.normpath(path) - if not os.path.exists(path): - # TODO warning - return output - - sub_keys = list(kwargs.pop("subkeys", args)) - for sub_key in tuple(sub_keys): - _path = os.path.join(path, sub_key) - if not os.path.exists(_path): - break - - path = _path - sub_keys.pop(0) - - base_len = len(path) + 1 - for base, _directories, filenames in os.walk(path): - base_items_str = base[base_len:] - if not base_items_str: - base_items = [] - else: - base_items = base_items_str.split(os.path.sep) - - for filename in filenames: - basename, ext = os.path.splitext(filename) - if ext == ".json": - full_path = os.path.join(base, filename) - value = load_json(full_path) - dict_keys = base_items + [basename] - output = subkey_merge(output, value, dict_keys) - - for sub_key in sub_keys: - output = output[sub_key] - return output - - -def system_configurations(*args, **kwargs): - return load_jsons_from_dir(SYSTEM_CONFIGURATIONS_PATH, *args, **kwargs) - - -def global_project_configurations(**kwargs): - return load_jsons_from_dir(PROJECT_CONFIGURATIONS_PATH, **kwargs) - - -def path_to_project_overrides(project_name): - project_configs_path = os.environ["PYPE_PROJECT_CONFIGS"] - dirpath = os.path.join(project_configs_path, project_name) - return os.path.join(dirpath, PROJECT_CONFIGURATIONS_DIR + ".json") - - -def project_configurations_overrides(project_name, **kwargs): - if not project_name: - return {} - - path_to_json = path_to_project_overrides(project_name) - if not os.path.exists(path_to_json): - return {} - return load_json(path_to_json) - - -def merge_overrides(global_dict, override_dict): - if OVERRIDEN_KEY in override_dict: - overriden_keys = set(override_dict.pop(OVERRIDEN_KEY)) - else: - overriden_keys = set() - - for key, value in override_dict.items(): - if value == POP_KEY: - global_dict.pop(key) - - elif ( - key in overriden_keys - or key not in global_dict - ): - global_dict[key] = value - - elif isinstance(value, dict) and isinstance(global_dict[key], dict): - global_dict[key] = merge_overrides(global_dict[key], value) - - else: - global_dict[key] = value - return global_dict - - -def apply_overrides(global_presets, project_overrides): - global_presets = copy.deepcopy(global_presets) - if not project_overrides: - return global_presets - return merge_overrides(global_presets, project_overrides) - - -def project_presets(project_name=None, **kwargs): - global_presets = global_project_configurations(**kwargs) - - if not project_name: - project_name = os.environ.get("AVALON_PROJECT") - project_overrides = project_configurations_overrides( - project_name, **kwargs - ) - - return apply_overrides(global_presets, project_overrides) + return apply_overrides(studio_overrides, project_overrides) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py new file mode 100644 index 0000000000..4cd7203626 --- /dev/null +++ b/pype/configurations/lib.py @@ -0,0 +1,208 @@ +import os +import json +import logging +import copy + +log = logging.getLogger(__name__) + +# Metadata keys for work with studio and project overrides +OVERRIDEN_KEY = "__overriden_keys__" +# NOTE key popping not implemented yet +POP_KEY = "__pop_key__" + +# Folder where studio overrides are stored +STUDIO_OVERRIDES_PATH = os.environ["PYPE_CONFIG"] + +# File where studio's system overrides are stored +SYSTEM_CONFIGURATIONS_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, "system_configurations.json" +) + +# File where studio's default project overrides are stored +PROJECT_CONFIGURATIONS_FILENAME = "project_configurations.json" +PROJECT_CONFIGURATIONS_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, PROJECT_CONFIGURATIONS_FILENAME +) + +# Folder where studio's per project overrides are stored +STUDIO_PROJECT_OVERRIDES_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, "project_overrides" +) + +# Variable where cache of default configurations are stored +_DEFAULT_CONFIGURATIONS = None + + +def default_configuration(): + global _DEFAULT_CONFIGURATIONS + if _DEFAULT_CONFIGURATIONS is None: + current_dir = os.path.dirname(__file__) + defaults_path = os.path.join(current_dir, "defaults") + _DEFAULT_CONFIGURATIONS = load_jsons_from_dir(defaults_path) + return _DEFAULT_CONFIGURATIONS + + +def load_json(fpath): + # Load json data + with open(fpath, "r") as opened_file: + lines = opened_file.read().splitlines() + + # prepare json string + standard_json = "" + for line in lines: + # Remove all whitespace on both sides + line = line.strip() + + # Skip blank lines + if len(line) == 0: + continue + + standard_json += line + + # Check if has extra commas + extra_comma = False + if ",]" in standard_json or ",}" in standard_json: + extra_comma = True + standard_json = standard_json.replace(",]", "]") + standard_json = standard_json.replace(",}", "}") + + if extra_comma: + log.error("Extra comma in json file: \"{}\"".format(fpath)) + + # return empty dict if file is empty + if standard_json == "": + return {} + + # Try to parse string + try: + return json.loads(standard_json) + + except json.decoder.JSONDecodeError: + # Return empty dict if it is first time that decode error happened + return {} + + # Repreduce the exact same exception but traceback contains better + # information about position of error in the loaded json + try: + with open(fpath, "r") as opened_file: + json.load(opened_file) + + except json.decoder.JSONDecodeError: + log.warning( + "File has invalid json format \"{}\"".format(fpath), + exc_info=True + ) + + return {} + + +def subkey_merge(_dict, value, keys): + key = keys.pop(0) + if not keys: + _dict[key] = value + return _dict + + if key not in _dict: + _dict[key] = {} + _dict[key] = subkey_merge(_dict[key], value, keys) + + return _dict + + +def load_jsons_from_dir(path, *args, **kwargs): + output = {} + + path = os.path.normpath(path) + if not os.path.exists(path): + # TODO warning + return output + + sub_keys = list(kwargs.pop("subkeys", args)) + for sub_key in tuple(sub_keys): + _path = os.path.join(path, sub_key) + if not os.path.exists(_path): + break + + path = _path + sub_keys.pop(0) + + base_len = len(path) + 1 + for base, _directories, filenames in os.walk(path): + base_items_str = base[base_len:] + if not base_items_str: + base_items = [] + else: + base_items = base_items_str.split(os.path.sep) + + for filename in filenames: + basename, ext = os.path.splitext(filename) + if ext == ".json": + full_path = os.path.join(base, filename) + value = load_json(full_path) + dict_keys = base_items + [basename] + output = subkey_merge(output, value, dict_keys) + + for sub_key in sub_keys: + output = output[sub_key] + return output + + +def studio_system_configurations(): + if os.path.exists(SYSTEM_CONFIGURATIONS_PATH): + return load_json(SYSTEM_CONFIGURATIONS_PATH) + return {} + + +def studio_project_configurations(): + if os.path.exists(PROJECT_CONFIGURATIONS_PATH): + return load_json(PROJECT_CONFIGURATIONS_PATH) + return {} + + +def path_to_project_overrides(project_name): + return os.path.join( + STUDIO_PROJECT_OVERRIDES_PATH, + project_name, + PROJECT_CONFIGURATIONS_FILENAME + ) + + +def project_configurations_overrides(project_name): + if not project_name: + return {} + + path_to_json = path_to_project_overrides(project_name) + if not os.path.exists(path_to_json): + return {} + return load_json(path_to_json) + + +def merge_overrides(global_dict, override_dict): + if OVERRIDEN_KEY in override_dict: + overriden_keys = set(override_dict.pop(OVERRIDEN_KEY)) + else: + overriden_keys = set() + + for key, value in override_dict.items(): + if value == POP_KEY: + global_dict.pop(key) + + elif ( + key in overriden_keys + or key not in global_dict + ): + global_dict[key] = value + + elif isinstance(value, dict) and isinstance(global_dict[key], dict): + global_dict[key] = merge_overrides(global_dict[key], value) + + else: + global_dict[key] = value + return global_dict + + +def apply_overrides(global_presets, project_overrides): + global_presets = copy.deepcopy(global_presets) + if not project_overrides: + return global_presets + return merge_overrides(global_presets, project_overrides) From b6b439c369f164a9f4ed48bc232c283c0cf32564 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 15:36:36 +0200 Subject: [PATCH 447/580] config_value method renamed to studio_value --- .../config_setting/widgets/anatomy_inputs.py | 16 +++++++------- .../config_setting/widgets/base.py | 6 ++--- .../config_setting/widgets/inputs.py | 22 +++++++++---------- .../config_setting/widgets/widgets.py | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 43146f7442..18a58b1dc6 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -165,15 +165,15 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.discard_changes() def overrides(self): - return self.config_value(), True + return self.studio_value(), True def item_value(self): output = {} - output.update(self.root_widget.config_value()) - output.update(self.templates_widget.config_value()) + output.update(self.root_widget.studio_value()) + output.update(self.templates_widget.studio_value()) return output - def config_value(self): + def studio_value(self): return {self.key: self.item_value()} @@ -479,7 +479,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: return self.singleroot_widget.item_value() - def config_value(self): + def studio_value(self): return {self.key: self.item_value()} @@ -587,13 +587,13 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def overrides(self): if not self.child_overriden: return NOT_SET, False - return self.config_value(), True + return self.studio_value(), True def item_value(self): return self.value_input.item_value() - def config_value(self): - return self.value_input.config_value() + def studio_value(self): + return self.value_input.studio_value() TypeToKlass.types["anatomy"] = AnatomyWidget diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 55ca6096de..981713d5ae 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -125,7 +125,7 @@ class SystemWidget(QtWidgets.QWidget): all_values = {} for item in self.input_fields: - all_values.update(item.config_value()) + all_values.update(item.studio_value()) for key in reversed(self.keys): _all_values = {key: all_values} @@ -499,7 +499,7 @@ class ProjectWidget(QtWidgets.QWidget): def _save_defaults(self): output = {} for item in self.input_fields: - output.update(item.config_value()) + output.update(item.studio_value()) for key in reversed(self.keys): _output = {key: output} @@ -507,7 +507,7 @@ class ProjectWidget(QtWidgets.QWidget): all_values = {} for item in self.input_fields: - all_values.update(item.config_value()) + all_values.update(item.studio_value()) for key in reversed(self.keys): _all_values = {key: all_values} diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b0aaa5ed3d..d1b71b2848 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -89,7 +89,7 @@ class ConfigObject(AbstractConfigObject): """Setter for global parent item to apply changes for all inputs.""" self._parent.ignore_value_changes = value - def config_value(self): + def studio_value(self): """Output for saving changes or overrides.""" return {self.key: self.item_value()} @@ -217,7 +217,7 @@ class InputObject(ConfigObject): def overrides(self): if not self.is_overriden: return NOT_SET, False - return self.config_value(), self.is_group + return self.studio_value(), self.is_group def hierarchical_style_update(self): self.update_style() @@ -899,7 +899,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def on_remove_clicked(self): self._parent.remove_row(self) - def config_value(self): + def studio_value(self): if self.value_input.isEnabled(): return self.value_input.item_value() return NOT_SET @@ -1106,7 +1106,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): def item_value(self): output = [] for item in self.input_fields: - value = item.config_value() + value = item.studio_value() if value is not NOT_SET: output.append(value) return output @@ -1245,7 +1245,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def row(self): return self._parent.input_fields.index(self) - def config_value(self): + def studio_value(self): key = self.key_input.text() value = self.value_input.item_value() return {key: value} @@ -1405,7 +1405,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def item_value(self): output = {} for item in self.input_fields: - output.update(item.config_value()) + output.update(item.studio_value()) return output def add_row(self, row=None, key=None, value=None, is_empty=False): @@ -1749,7 +1749,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) + output.update(input_field.studio_value()) return output def overrides(self): @@ -1859,7 +1859,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) + output.update(input_field.studio_value()) return output def _on_value_change(self, item=None): @@ -2236,7 +2236,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): output = {} for input_field in self.input_fields: - output.update(input_field.config_value()) + output.update(input_field.studio_value()) return output def overrides(self): @@ -2402,10 +2402,10 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts - output.update(input_field.config_value()) + output.update(input_field.studio_value()) return output - def config_value(self): + def studio_value(self): return self.item_value() def overrides(self): diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 5547f66597..1e57bf73df 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -344,7 +344,7 @@ class AbstractConfigObject: "Method `item_value` not implemented!" ) - def config_value(self): + def studio_value(self): """Output for saving changes or overrides.""" return {self.key: self.item_value()} From 778f645057f22e076c9b4e6cad4320b724069cb6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:07:05 +0200 Subject: [PATCH 448/580] renamed method studio_value back to config_value --- .../config_setting/widgets/anatomy_inputs.py | 16 +++++++------- .../config_setting/widgets/base.py | 6 ++--- .../config_setting/widgets/inputs.py | 22 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 18a58b1dc6..43146f7442 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -165,15 +165,15 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.discard_changes() def overrides(self): - return self.studio_value(), True + return self.config_value(), True def item_value(self): output = {} - output.update(self.root_widget.studio_value()) - output.update(self.templates_widget.studio_value()) + output.update(self.root_widget.config_value()) + output.update(self.templates_widget.config_value()) return output - def studio_value(self): + def config_value(self): return {self.key: self.item_value()} @@ -479,7 +479,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: return self.singleroot_widget.item_value() - def studio_value(self): + def config_value(self): return {self.key: self.item_value()} @@ -587,13 +587,13 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def overrides(self): if not self.child_overriden: return NOT_SET, False - return self.studio_value(), True + return self.config_value(), True def item_value(self): return self.value_input.item_value() - def studio_value(self): - return self.value_input.studio_value() + def config_value(self): + return self.value_input.config_value() TypeToKlass.types["anatomy"] = AnatomyWidget diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 981713d5ae..55ca6096de 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -125,7 +125,7 @@ class SystemWidget(QtWidgets.QWidget): all_values = {} for item in self.input_fields: - all_values.update(item.studio_value()) + all_values.update(item.config_value()) for key in reversed(self.keys): _all_values = {key: all_values} @@ -499,7 +499,7 @@ class ProjectWidget(QtWidgets.QWidget): def _save_defaults(self): output = {} for item in self.input_fields: - output.update(item.studio_value()) + output.update(item.config_value()) for key in reversed(self.keys): _output = {key: output} @@ -507,7 +507,7 @@ class ProjectWidget(QtWidgets.QWidget): all_values = {} for item in self.input_fields: - all_values.update(item.studio_value()) + all_values.update(item.config_value()) for key in reversed(self.keys): _all_values = {key: all_values} diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index d1b71b2848..b0aaa5ed3d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -89,7 +89,7 @@ class ConfigObject(AbstractConfigObject): """Setter for global parent item to apply changes for all inputs.""" self._parent.ignore_value_changes = value - def studio_value(self): + def config_value(self): """Output for saving changes or overrides.""" return {self.key: self.item_value()} @@ -217,7 +217,7 @@ class InputObject(ConfigObject): def overrides(self): if not self.is_overriden: return NOT_SET, False - return self.studio_value(), self.is_group + return self.config_value(), self.is_group def hierarchical_style_update(self): self.update_style() @@ -899,7 +899,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def on_remove_clicked(self): self._parent.remove_row(self) - def studio_value(self): + def config_value(self): if self.value_input.isEnabled(): return self.value_input.item_value() return NOT_SET @@ -1106,7 +1106,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): def item_value(self): output = [] for item in self.input_fields: - value = item.studio_value() + value = item.config_value() if value is not NOT_SET: output.append(value) return output @@ -1245,7 +1245,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def row(self): return self._parent.input_fields.index(self) - def studio_value(self): + def config_value(self): key = self.key_input.text() value = self.value_input.item_value() return {key: value} @@ -1405,7 +1405,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): def item_value(self): output = {} for item in self.input_fields: - output.update(item.studio_value()) + output.update(item.config_value()) return output def add_row(self, row=None, key=None, value=None, is_empty=False): @@ -1749,7 +1749,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts - output.update(input_field.studio_value()) + output.update(input_field.config_value()) return output def overrides(self): @@ -1859,7 +1859,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts - output.update(input_field.studio_value()) + output.update(input_field.config_value()) return output def _on_value_change(self, item=None): @@ -2236,7 +2236,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): output = {} for input_field in self.input_fields: - output.update(input_field.studio_value()) + output.update(input_field.config_value()) return output def overrides(self): @@ -2402,10 +2402,10 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): for input_field in self.input_fields: # TODO maybe merge instead of update should be used # NOTE merge is custom function which merges 2 dicts - output.update(input_field.studio_value()) + output.update(input_field.config_value()) return output - def studio_value(self): + def config_value(self): return self.item_value() def overrides(self): From c483705a91e6cd9c4cf82634afdfc9428053022b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:16:22 +0200 Subject: [PATCH 449/580] any_parent_is_group is abstract attribute --- .../config_setting/widgets/inputs.py | 18 +++++++++++------- .../config_setting/widgets/widgets.py | 6 ++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index b0aaa5ed3d..9e712fd087 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -25,6 +25,7 @@ class ConfigObject(AbstractConfigObject): _is_group = False _is_nullable = False + _any_parent_is_group = None _log = None @property @@ -36,6 +37,10 @@ class ConfigObject(AbstractConfigObject): @property def has_studio_override(self): return self._has_studio_override + def any_parent_is_group(self): + if self._any_parent_is_group is None: + return super(ConfigObject, self).any_parent_is_group + return self._any_parent_is_group @property def is_modified(self): @@ -752,7 +757,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group + self._any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) @@ -843,7 +848,6 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def __init__(self, object_type, input_modifiers, config_parent, parent): self._parent = config_parent - super(ListItem, self).__init__(parent) layout = QtWidgets.QHBoxLayout(self) @@ -1280,7 +1284,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group + self._any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) @@ -1500,7 +1504,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): any_parent_is_group = parent.is_group if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group + self._any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) self._is_nullable = input_data.get("is_nullable", False) @@ -1789,7 +1793,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group + self._any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) @@ -1997,7 +2001,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): any_parent_is_group = parent.is_group if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group + self._any_parent_is_group = any_parent_is_group # This is partial input and dictionary input if not any_parent_is_group and not as_widget: @@ -2274,7 +2278,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): if not any_parent_is_group: any_parent_is_group = parent.any_parent_is_group - self.any_parent_is_group = any_parent_is_group + self._any_parent_is_group = any_parent_is_group self._is_group = False diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index 1e57bf73df..d803624850 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -248,6 +248,12 @@ class AbstractConfigObject: "{} does not have implemented `is_overriden`".format(self) ) + @property + def any_parent_is_group(self): + raise NotImplementedError( + "{} does not have implemented `any_parent_is_group`".format(self) + ) + @property def was_overriden(self): """Initial state after applying overrides.""" From daebec1faec9fca76812ab8f9285849a25b66f19 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:16:33 +0200 Subject: [PATCH 450/580] fixe override key import --- pype/tools/config_setting/config_setting/widgets/lib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index 69c3259b3b..6b3aa53c8f 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -1,9 +1,8 @@ import os import json import copy -from pype.api import config +from pype.configurations.lib import OVERRIDEN_KEY from queue import Queue -OVERRIDEN_KEY = config.OVERRIDEN_KEY # Singleton database of available inputs From ce90e8a1835cbef57ead0739bf980367b7b9d884 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:16:44 +0200 Subject: [PATCH 451/580] has_studio_override fix --- pype/tools/config_setting/config_setting/widgets/inputs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 9e712fd087..e7f3f71620 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -36,7 +36,8 @@ class ConfigObject(AbstractConfigObject): @property def has_studio_override(self): - return self._has_studio_override + return self._has_studio_override or self._parent.has_studio_override + def any_parent_is_group(self): if self._any_parent_is_group is None: return super(ConfigObject, self).any_parent_is_group @@ -290,7 +291,7 @@ class InputObject(ConfigObject): @property def child_has_studio_override(self): - return self.has_studio_override + return self._has_studio_override @property def child_modified(self): From 39cde9bd82e6d3852f7d92550a10e2884ba05e95 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:34:46 +0200 Subject: [PATCH 452/580] update saving of studio overrides --- .../config_setting/widgets/base.py | 146 +++++------------- 1 file changed, 40 insertions(+), 106 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 55ca6096de..9abe05946e 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -1,7 +1,15 @@ import os import json from Qt import QtWidgets, QtCore, QtGui -from pype.api import config +from pype.configurations.lib import ( + SYSTEM_CONFIGURATIONS_PATH, + PROJECT_CONFIGURATIONS_PATH, + default_configuration, + studio_system_configurations, + project_configurations_overrides, + path_to_project_overrides, + studio_project_configurations +) from .widgets import UnsavedChangesDialog from . import lib from avalon import io @@ -123,60 +131,31 @@ class SystemWidget(QtWidgets.QWidget): first_invalid_item.setFocus(True) return - all_values = {} - for item in self.input_fields: - all_values.update(item.config_value()) + _data = {} + for input_field in self.input_fields: + value, is_group = input_field.studio_overrides() + if value is not lib.NOT_SET: + _data.update(value) - for key in reversed(self.keys): - _all_values = {key: all_values} - all_values = _all_values + values = _data["system"] - # Skip first key - all_values = all_values["system"] + dirpath = os.path.dirname(SYSTEM_CONFIGURATIONS_PATH) + if not os.path.exists(dirpath): + os.makedirs(dirpath) - # Load studio data with metadata - current_configurations = config.system_configurations() - - keys_to_file = lib.file_keys_from_schema(self.schema) - for key_sequence in keys_to_file: - # Skip first key - key_sequence = key_sequence[1:] - subpath = "/".join(key_sequence) + ".json" - origin_values = current_configurations - for key in key_sequence: - if not origin_values or key not in origin_values: - origin_values = {} - break - origin_values = origin_values[key] - - if not origin_values: - origin_values = {} - - new_values = all_values - for key in key_sequence: - new_values = new_values[key] - origin_values.update(new_values) - raise NotImplementedError("Output from global values has changed") - output_path = os.path.join( - config.STUDIO_PRESETS_PATH, subpath - ) - dirpath = os.path.dirname(output_path) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to: ", output_path) - with open(output_path, "w") as file_stream: - json.dump(origin_values, file_stream, indent=4) + print("Saving data to:", SYSTEM_CONFIGURATIONS_PATH) + with open(SYSTEM_CONFIGURATIONS_PATH, "w") as file_stream: + json.dump(values, file_stream, indent=4) self._update_values() def _update_values(self): - default_values = config.default_configuration() + default_values = default_configuration() default_values = {"system": default_values["system_configurations"]} for input_field in self.input_fields: input_field.update_default_values(default_values) - system_values = {"system": config.system_configurations()} + system_values = {"system": studio_system_configurations()} for input_field in self.input_fields: input_field.update_studio_values(system_values) @@ -429,7 +408,7 @@ class ProjectWidget(QtWidgets.QWidget): _overrides = lib.NOT_SET self.is_overidable = False else: - _overrides = config.project_configurations_overrides(project_name) + _overrides = project_configurations_overrides(project_name) self.is_overidable = True overrides = {"project": lib.convert_overrides_to_gui_data(_overrides)} @@ -475,94 +454,49 @@ class ProjectWidget(QtWidgets.QWidget): value, is_group = item.overrides() if value is not lib.NOT_SET: _data.update(value) - if is_group: - raise Exception( - "Top item can't be overriden in Project widget." - ) data = _data.get("project") or {} output_data = lib.convert_gui_data_to_overrides(data) - overrides_json_path = config.path_to_project_overrides( + overrides_json_path = path_to_project_overrides( self.project_name ) dirpath = os.path.dirname(overrides_json_path) if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving data to: ", overrides_json_path) + print("Saving data to:", overrides_json_path) with open(overrides_json_path, "w") as file_stream: json.dump(output_data, file_stream, indent=4) self._on_project_change() def _save_defaults(self): - output = {} - for item in self.input_fields: - output.update(item.config_value()) + _data = {} + for input_field in self.input_fields: + value, is_group = input_field.studio_overrides() + if value is not lib.NOT_SET: + _data.update(value) - for key in reversed(self.keys): - _output = {key: output} - output = _output + output = _data["project"] - all_values = {} - for item in self.input_fields: - all_values.update(item.config_value()) + dirpath = os.path.dirname(PROJECT_CONFIGURATIONS_PATH) + if not os.path.exists(dirpath): + os.makedirs(dirpath) - for key in reversed(self.keys): - _all_values = {key: all_values} - all_values = _all_values - - # Skip first key - all_values = all_values["project"] - - # Load studio data with metadata - current_configurations = config.global_project_configurations() - - keys_to_file = lib.file_keys_from_schema(self.schema) - for key_sequence in keys_to_file: - # Skip first key - key_sequence = key_sequence[1:] - subpath = "/".join(key_sequence) + ".json" - origin_values = current_configurations - for key in key_sequence: - if not origin_values or key not in origin_values: - origin_values = {} - break - origin_values = origin_values[key] - - if not origin_values: - origin_values = {} - - new_values = all_values - for key in key_sequence: - new_values = new_values[key] - if isinstance(new_values, dict): - origin_values.update(new_values) - else: - origin_values = new_values - - raise NotImplementedError("Output from global values has changed") - output_path = os.path.join( - config.PROJECT_PRESETS_PATH, subpath - ) - dirpath = os.path.dirname(output_path) - if not os.path.exists(dirpath): - os.makedirs(dirpath) - - print("Saving data to: ", output_path) - with open(output_path, "w") as file_stream: - json.dump(origin_values, file_stream, indent=4) + print("Saving data to:", PROJECT_CONFIGURATIONS_PATH) + with open(PROJECT_CONFIGURATIONS_PATH, "w") as file_stream: + json.dump(output, file_stream, indent=4) self._update_values() def _update_values(self): - default_values = config.default_configuration() + default_values = default_configuration() default_values = {"project": default_values["project_configurations"]} for input_field in self.input_fields: input_field.update_default_values(default_values) - studio_values = {"project": config.global_project_configurations()} + studio_values = {"project": studio_project_configurations()} for input_field in self.input_fields: input_field.update_studio_values(studio_values) From 9cda39766cb7e8361b5f1c9db41bb973ab9acac3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:35:01 +0200 Subject: [PATCH 453/580] inputs has studio_overrides methods now --- .../config_setting/widgets/inputs.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index e7f3f71620..6e229fb9ea 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -220,6 +220,11 @@ class InputObject(ConfigObject): self._is_modified = False + def studio_overrides(self): + if not self.has_studio_override: + return NOT_SET, False + return self.config_value(), self.is_group + def overrides(self): if not self.is_overriden: return NOT_SET, False @@ -1757,6 +1762,22 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): output.update(input_field.config_value()) return output + def studio_overrides(self): + if not self.has_studio_override and not self.child_has_studio_override: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(value.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return {self.key: values}, self.is_group + def overrides(self): if not self.is_overriden and not self.child_overriden: return NOT_SET, False @@ -1953,6 +1974,22 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): ) self._was_overriden = bool(self._is_overriden) + def studio_overrides(self): + if not self.has_studio_override and not self.child_has_studio_override: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(value.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return {self.key: values}, self.is_group + def overrides(self): if not self.is_overriden and not self.child_overriden: return NOT_SET, False @@ -2244,6 +2281,15 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): output.update(input_field.config_value()) return output + def studio_overrides(self): + if not self.has_studio_override and not self.child_has_studio_override: + return NOT_SET, False + + value = self.item_value() + if not self.multiplatform: + value = {self.key: value} + return value, self.is_group + def overrides(self): if not self.is_overriden and not self.child_overriden: return NOT_SET, False @@ -2413,6 +2459,22 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): def config_value(self): return self.item_value() + def studio_overrides(self): + if not self.has_studio_override and not self.child_has_studio_override: + return NOT_SET, False + + values = {} + groups = [] + for input_field in self.input_fields: + value, is_group = input_field.overrides() + if value is not NOT_SET: + values.update(value) + if is_group: + groups.extend(value.keys()) + if groups: + values[METADATA_KEY] = {"groups": groups} + return values, self.is_group + def overrides(self): if not self.is_overriden and not self.child_overriden: return NOT_SET, False From 9521ea3f08ee69b532c1991ac82d644404483b7c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:40:40 +0200 Subject: [PATCH 454/580] removed attribute methods from base widgets --- .../config_setting/widgets/base.py | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 9abe05946e..172450684b 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -17,9 +17,10 @@ from avalon import io class SystemWidget(QtWidgets.QWidget): is_overidable = False - _is_overriden = False - _is_group = False - _any_parent_is_group = False + has_studio_override = False + is_overriden = False + is_group = False + any_parent_is_group = False def __init__(self, parent=None): super(SystemWidget, self).__init__(parent) @@ -67,18 +68,6 @@ class SystemWidget(QtWidgets.QWidget): def any_parent_overriden(self): return False - @property - def is_overriden(self): - return self._is_overriden - - @property - def is_group(self): - return self._is_group - - @property - def any_parent_is_group(self): - return self._any_parent_is_group - @property def ignore_value_changes(self): return self._ignore_value_changes @@ -297,9 +286,10 @@ class ProjectListWidget(QtWidgets.QWidget): class ProjectWidget(QtWidgets.QWidget): - _is_overriden = False - _is_group = False - _any_parent_is_group = False + has_studio_override = False + is_overriden = False + is_group = False + any_parent_is_group = False def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) @@ -362,18 +352,6 @@ class ProjectWidget(QtWidgets.QWidget): def any_parent_overriden(self): return False - @property - def is_overriden(self): - return self._is_overriden - - @property - def is_group(self): - return self._is_group - - @property - def any_parent_is_group(self): - return self._any_parent_is_group - @property def ignore_value_changes(self): return self._ignore_value_changes From 9693a6a37b886e1ae3646f52903d493532542b85 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 16:40:58 +0200 Subject: [PATCH 455/580] any parent is group is attribute --- pype/tools/config_setting/config_setting/widgets/inputs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 6e229fb9ea..3a3d517cc1 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -38,6 +38,7 @@ class ConfigObject(AbstractConfigObject): def has_studio_override(self): return self._has_studio_override or self._parent.has_studio_override + @property def any_parent_is_group(self): if self._any_parent_is_group is None: return super(ConfigObject, self).any_parent_is_group From ffa233994e58994192e2715b1acbedea4f3c45ca Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 9 Sep 2020 16:57:19 +0200 Subject: [PATCH 456/580] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index 9e1a271244..95a6d3a792 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.11.8" +__version__ = "2.12.0" From d51a5701590c08fcb928f784480d73da29468489 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 9 Sep 2020 17:27:16 +0200 Subject: [PATCH 457/580] configure changelog generator --- .github_changelog_generator | 7 + HISTORY.md | 435 ++++++++++++++++++++++++++++++++++++ changelog.md | 120 ---------- 3 files changed, 442 insertions(+), 120 deletions(-) create mode 100644 .github_changelog_generator create mode 100644 HISTORY.md delete mode 100644 changelog.md diff --git a/.github_changelog_generator b/.github_changelog_generator new file mode 100644 index 0000000000..93ab39f4d0 --- /dev/null +++ b/.github_changelog_generator @@ -0,0 +1,7 @@ +pr-wo-labels=False +exclude-labels=duplicate,question,invalid,wontfix,weekly-digest +author=False +unreleased=False +since-tag=2.11.0 +release-branch=master +enhancement-label=New / Enhancements diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000000..4b5463c924 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,435 @@ +# Pype changelog # +Welcome to pype changelog + + +## 2.11.0 ## + +_**release date:** 27 July 2020_ + +**new:** +- _(blender)_ namespace support [\#341](https://github.com/pypeclub/pype/pull/341) +- _(blender)_ start end frames [\#330](https://github.com/pypeclub/pype/pull/330) +- _(blender)_ camera asset [\#322](https://github.com/pypeclub/pype/pull/322) +- _(pype)_ toggle instances per family in pyblish GUI [\#320](https://github.com/pypeclub/pype/pull/320) +- _(pype)_ current release version is now shown in the tray menu [#379](https://github.com/pypeclub/pype/pull/379) + + +**improved:** +- _(resolve)_ tagging for publish [\#239](https://github.com/pypeclub/pype/issues/239) +- _(pype)_ Support publishing a subset of shots with standalone editorial [\#336](https://github.com/pypeclub/pype/pull/336) +- _(harmony)_ Basic support for palettes [\#324](https://github.com/pypeclub/pype/pull/324) +- _(photoshop)_ Flag outdated containers on startup and publish. [\#309](https://github.com/pypeclub/pype/pull/309) +- _(harmony)_ Flag Outdated containers [\#302](https://github.com/pypeclub/pype/pull/302) +- _(photoshop)_ Publish review [\#298](https://github.com/pypeclub/pype/pull/298) +- _(pype)_ Optional Last workfile launch [\#365](https://github.com/pypeclub/pype/pull/365) + + +**fixed:** +- _(premiere)_ workflow fixes [\#346](https://github.com/pypeclub/pype/pull/346) +- _(pype)_ pype-setup does not work with space in path [\#327](https://github.com/pypeclub/pype/issues/327) +- _(ftrack)_ Ftrack delete action cause circular error [\#206](https://github.com/pypeclub/pype/issues/206) +- _(nuke)_ Priority was forced to 50 [\#345](https://github.com/pypeclub/pype/pull/345) +- _(nuke)_ Fix ValidateNukeWriteKnobs [\#340](https://github.com/pypeclub/pype/pull/340) +- _(maya)_ If camera attributes are connected, we can ignore them. [\#339](https://github.com/pypeclub/pype/pull/339) +- _(pype)_ stop appending of tools environment to existing env [\#337](https://github.com/pypeclub/pype/pull/337) +- _(ftrack)_ Ftrack timeout needs to look at AVALON\_TIMEOUT [\#325](https://github.com/pypeclub/pype/pull/325) +- _(harmony)_ Only zip files are supported. [\#310](https://github.com/pypeclub/pype/pull/310) +- _(pype)_ hotfix/Fix event server mongo uri [\#305](https://github.com/pypeclub/pype/pull/305) +- _(photoshop)_ Subset was not named or validated correctly. [\#304](https://github.com/pypeclub/pype/pull/304) + + + + +## 2.10.0 ## + +_**release date:** 17 June 2020_ + +**new:** +- _(harmony)_ **Toon Boom Harmony** has been greatly extended to support rigging, scene build, animation and rendering workflows. [#270](https://github.com/pypeclub/pype/issues/270) [#271](https://github.com/pypeclub/pype/issues/271) [#190](https://github.com/pypeclub/pype/issues/190) [#191](https://github.com/pypeclub/pype/issues/191) [#172](https://github.com/pypeclub/pype/issues/172) [#168](https://github.com/pypeclub/pype/issues/168) +- _(pype)_ Added support for rudimentary **edl publishing** into individual shots. [#265](https://github.com/pypeclub/pype/issues/265) +- _(celaction)_ Simple **Celaction** integration has been added with support for workfiles and rendering. [#255](https://github.com/pypeclub/pype/issues/255) +- _(maya)_ Support for multiple job types when submitting to the farm. We can now render Maya or Standalone render jobs for Vray and Arnold (limited support for arnold) [#204](https://github.com/pypeclub/pype/issues/204) +- _(photoshop)_ Added initial support for Photoshop [#232](https://github.com/pypeclub/pype/issues/232) + +**improved:** +- _(blender)_ Updated support for rigs and added support Layout family [#233](https://github.com/pypeclub/pype/issues/233) [#226](https://github.com/pypeclub/pype/issues/226) +- _(premiere)_ It is now possible to choose different storage root for workfiles of different task types. [#255](https://github.com/pypeclub/pype/issues/255) +- _(maya)_ Support for unmerged AOVs in Redshift multipart EXRs [#197](https://github.com/pypeclub/pype/issues/197) +- _(pype)_ Pype repository has been refactored in preparation for 3.0 release [#169](https://github.com/pypeclub/pype/issues/169) +- _(deadline)_ All file dependencies are now passed to deadline from maya to prevent premature start of rendering if caches or textures haven't been coppied over yet. [#195](https://github.com/pypeclub/pype/issues/195) +- _(nuke)_ Script validation can now be made optional. [#194](https://github.com/pypeclub/pype/issues/194) +- _(pype)_ Publishing can now be stopped at any time. [#194](https://github.com/pypeclub/pype/issues/194) + +**fix:** +- _(pype)_ Pyblish-lite has been integrated into pype repository, plus various publishing GUI fixes. [#274](https://github.com/pypeclub/pype/issues/274) [#275](https://github.com/pypeclub/pype/issues/275) [#268](https://github.com/pypeclub/pype/issues/268) [#227](https://github.com/pypeclub/pype/issues/227) [#238](https://github.com/pypeclub/pype/issues/238) +- _(maya)_ Alembic extractor was getting wrong frame range type in certain scenarios [#254](https://github.com/pypeclub/pype/issues/254) +- _(maya)_ Attaching a render to subset in maya was not passing validation in certain scenarios [#256](https://github.com/pypeclub/pype/issues/256) +- _(ftrack)_ Various small fixes to ftrack sync [#263](https://github.com/pypeclub/pype/issues/263) [#259](https://github.com/pypeclub/pype/issues/259) +- _(maya)_ Look extraction is now able to skp invalid connections in shaders [#207](https://github.com/pypeclub/pype/issues/207) + + + + +## 2.9.0 ## + +_**release date:** 25 May 2020_ + +**new:** +- _(pype)_ Support for **Multiroot projects**. You can now store project data on multiple physical or virtual storages and target individual publishes to these locations. For instance render can be stored on a faster storage than the rest of the project. [#145](https://github.com/pypeclub/pype/issues/145), [#38](https://github.com/pypeclub/pype/issues/38) +- _(harmony)_ Basic implementation of **Toon Boom Harmony** has been added. [#142](https://github.com/pypeclub/pype/issues/142) +- _(pype)_ OSX support is in public beta now. There are issues to be expected, but the main implementation should be functional. [#141](https://github.com/pypeclub/pype/issues/141) + + +**improved:** + +- _(pype)_ **Review extractor** has been completely rebuilt. It now supports granular filtering so you can create **multiple outputs** for different tasks, families or hosts. [#103](https://github.com/pypeclub/pype/issues/103), [#166](https://github.com/pypeclub/pype/issues/166), [#165](https://github.com/pypeclub/pype/issues/165) +- _(pype)_ **Burnin** generation had been extended to **support same multi-output filtering** as review extractor [#103](https://github.com/pypeclub/pype/issues/103) +- _(pype)_ Publishing file templates can now be specified in config for each individual family [#114](https://github.com/pypeclub/pype/issues/114) +- _(pype)_ Studio specific plugins can now be appended to pype standard publishing plugins. [#112](https://github.com/pypeclub/pype/issues/112) +- _(nukestudio)_ Reviewable clips no longer need to be previously cut, exported and re-imported to timeline. **Pype can now dynamically cut reviewable quicktimes** from continuous offline footage during publishing. [#23](https://github.com/pypeclub/pype/issues/23) +- _(deadline)_ Deadline can now correctly differentiate between staging and production pype. [#154](https://github.com/pypeclub/pype/issues/154) +- _(deadline)_ `PYPE_PYTHON_EXE` env variable can now be used to direct publishing to explicit python installation. [#120](https://github.com/pypeclub/pype/issues/120) +- _(nuke)_ Nuke now check for new version of loaded data on file open. [#140](https://github.com/pypeclub/pype/issues/140) +- _(nuke)_ frame range and limit checkboxes are now exposed on write node. [#119](https://github.com/pypeclub/pype/issues/119) + + + +**fix:** + +- _(nukestudio)_ Project Location was using backslashes which was breaking nukestudio native exporting in certains configurations [#82](https://github.com/pypeclub/pype/issues/82) +- _(nukestudio)_ Duplicity in hierarchy tags was prone to throwing publishing error [#130](https://github.com/pypeclub/pype/issues/130), [#144](https://github.com/pypeclub/pype/issues/144) +- _(ftrack)_ multiple stability improvements [#157](https://github.com/pypeclub/pype/issues/157), [#159](https://github.com/pypeclub/pype/issues/159), [#128](https://github.com/pypeclub/pype/issues/128), [#118](https://github.com/pypeclub/pype/issues/118), [#127](https://github.com/pypeclub/pype/issues/127) +- _(deadline)_ multipart EXRs were stopping review publishing on the farm. They are still not supported for automatic review generation, but the publish will go through correctly without the quicktime. [#155](https://github.com/pypeclub/pype/issues/155) +- _(deadline)_ If deadline is non-responsive it will no longer freeze host when publishing [#149](https://github.com/pypeclub/pype/issues/149) +- _(deadline)_ Sometimes deadline was trying to launch render before all the source data was coppied over. [#137](https://github.com/pypeclub/pype/issues/137) _(harmony)_ Basic implementation of **Toon Boom Harmony** has been added. [#142](https://github.com/pypeclub/pype/issues/142) +- _(nuke)_ Filepath knob wasn't updated properly. [#131](https://github.com/pypeclub/pype/issues/131) +- _(maya)_ When extracting animation, the "Write Color Set" options on the instance were not respected. [#108](https://github.com/pypeclub/pype/issues/108) +- _(maya)_ Attribute overrides for AOV only worked for the legacy render layers. Now it works for new render setup as well [#132](https://github.com/pypeclub/pype/issues/132) +- _(maya)_ Stability and usability improvements in yeti workflow [#104](https://github.com/pypeclub/pype/issues/104) + + + + +## 2.8.0 ## + +_**release date:** 20 April 2020_ + +**new:** + +- _(pype)_ Option to generate slates from json templates. [PYPE-628] [#26](https://github.com/pypeclub/pype/issues/26) +- _(pype)_ It is now possible to automate loading of published subsets into any scene. Documentation will follow :). [PYPE-611] [#24](https://github.com/pypeclub/pype/issues/24) + +**fix:** + +- _(maya)_ Some Redshift render tokens could break publishing. [PYPE-778] [#33](https://github.com/pypeclub/pype/issues/33) +- _(maya)_ Publish was not preserving maya file extension. [#39](https://github.com/pypeclub/pype/issues/39) +- _(maya)_ Rig output validator was failing on nodes without shapes. [#40](https://github.com/pypeclub/pype/issues/40) +- _(maya)_ Yeti caches can now be properly versioned up in the scene inventory. [#40](https://github.com/pypeclub/pype/issues/40) +- _(nuke)_ Build first workfiles was not accepting jpeg sequences. [#34](https://github.com/pypeclub/pype/issues/34) +- _(deadline)_ Trying to generate ffmpeg review from multipart EXRs no longer crashes publishing. [PYPE-781] +- _(deadline)_ Render publishing is more stable in multiplatform environments. [PYPE-775] + + + + +## 2.7.0 ## + +_**release date:** 30 March 2020_ + +**new:** + +- _(maya)_ Artist can now choose to load multiple references of the same subset at once [PYPE-646, PYPS-81] +- _(nuke)_ Option to use named OCIO colorspaces for review colour baking. [PYPS-82] +- _(pype)_ Pype can now work with `master` versions for publishing and loading. These are non-versioned publishes that are overwritten with the latest version during publish. These are now supported in all the GUIs, but their publishing is deactivated by default. [PYPE-653] +- _(blender)_ Added support for basic blender workflow. We currently support `rig`, `model` and `animation` families. [PYPE-768] +- _(pype)_ Source timecode can now be used in burn-ins. [PYPE-777] +- _(pype)_ Review outputs profiles can now specify delivery resolution different than project setting [PYPE-759] +- _(nuke)_ Bookmark to current context is now added automatically to all nuke browser windows. [PYPE-712] + +**change:** + +- _(maya)_ It is now possible to publish camera without. baking. Keep in mind that unbaked cameras can't be guaranteed to work in other hosts. [PYPE-595] +- _(maya)_ All the renders from maya are now grouped in the loader by their Layer name. [PYPE-482] +- _(nuke/hiero)_ Any publishes from nuke and hiero can now be versioned independently of the workfile. [PYPE-728] + + +**fix:** + +- _(nuke)_ Mixed slashes caused issues in ocio config path. +- _(pype)_ Intent field in pyblish GUI was passing label instead of value to ftrack. [PYPE-733] +- _(nuke)_ Publishing of pre-renders was inconsistent. [PYPE-766] +- _(maya)_ Handles and frame ranges were inconsistent in various places during publishing. +- _(nuke)_ Nuke was crashing if it ran into certain missing knobs. For example DPX output missing `autocrop` [PYPE-774] +- _(deadline)_ Project overrides were not working properly with farm render publishing. +- _(hiero)_ Problems with single frame plates publishing. +- _(maya)_ Redshift RenderPass token were breaking render publishing. [PYPE-778] +- _(nuke)_ Build first workfile was not accepting jpeg sequences. +- _(maya)_ Multipart (Multilayer) EXRs were breaking review publishing due to FFMPEG incompatiblity [PYPE-781] + + + +## 2.6.0 ## + +_**release date:** 9 March 2020_ + +**change:** +- _(maya)_ render publishing has been simplified and made more robust. Render setup layers are now automatically added to publishing subsets and `render globals` family has been replaced with simple `render` [PYPE-570] +- _(avalon)_ change context and workfiles apps, have been merged into one, that allows both actions to be performed at the same time. [PYPE-747] +- _(pype)_ thumbnails are now automatically propagate to asset from the last published subset in the loader +- _(ftrack)_ publishing comment and intent are now being published to ftrack note as well as describtion. [PYPE-727] +- _(pype)_ when overriding existing version new old representations are now overriden, instead of the new ones just being appended. (to allow this behaviour, the version validator need to be disabled. [PYPE-690]) +- _(pype)_ burnin preset has been significantly simplified. It now doesn't require passing function to each field, but only need the actual text template. to use this, all the current burnin PRESETS MUST BE UPDATED for all the projects. +- _(ftrack)_ credentials are now stored on a per server basis, so it's possible to switch between ftrack servers without having to log in and out. [PYPE-723] + + +**new:** +- _(pype)_ production and development deployments now have different colour of the tray icon. Orange for Dev and Green for production [PYPE-718] +- _(maya)_ renders can now be attached to a publishable subset rather than creating their own subset. For example it is possible to create a reviewable `look` or `model` render and have it correctly attached as a representation of the subsets [PYPE-451] +- _(maya)_ after saving current scene into a new context (as a new shot for instance), all the scene publishing subsets data gets re-generated automatically to match the new context [PYPE-532] +- _(pype)_ we now support project specific publish, load and create plugins [PYPE-740] +- _(ftrack)_ new action that allow archiving/deleting old published versions. User can keep how many of the latest version to keep when the action is ran. [PYPE-748, PYPE-715] +- _(ftrack)_ it is now possible to monitor and restart ftrack event server using ftrack action. [PYPE-658] +- _(pype)_ validator that prevent accidental overwrites of previously published versions. [PYPE-680] +- _(avalon)_ avalon core updated to version 5.6.0 +- _(maya)_ added validator to make sure that relative paths are used when publishing arnold standins. +- _(nukestudio)_ it is now possible to extract and publish audio family from clip in nuke studio [PYPE-682] + +**fix**: +- _(maya)_ maya set framerange button was ignoring handles [PYPE-719] +- _(ftrack)_ sync to avalon was sometime crashing when ran on empty project +- _(nukestudio)_ publishing same shots after they've been previously archived/deleted would result in a crash. [PYPE-737] +- _(nuke)_ slate workflow was breaking in certain scenarios. [PYPE-730] +- _(pype)_ rendering publish workflow has been significantly improved to prevent error resulting from implicit render collection. [PYPE-665, PYPE-746] +- _(pype)_ launching application on a non-synced project resulted in obscure [PYPE-528] +- _(pype)_ missing keys in burnins no longer result in an error. [PYPE-706] +- _(ftrack)_ create folder structure action was sometimes failing for project managers due to wrong permissions. +- _(Nukestudio)_ using `source` in the start frame tag could result in wrong frame range calculation +- _(ftrack)_ sync to avalon action and event have been improved by catching more edge cases and provessing them properly. + + + +## 2.5.0 ## + +_**release date:** 11 Feb 2020_ + +**change:** +- _(pype)_ added many logs for easier debugging +- _(pype)_ review presets can now be separated between 2d and 3d renders [PYPE-693] +- _(pype)_ anatomy module has been greatly improved to allow for more dynamic pulblishing and faster debugging [PYPE-685] +- _(pype)_ avalon schemas have been moved from `pype-config` to `pype` repository, for simplification. [PYPE-670] +- _(ftrack)_ updated to latest ftrack API +- _(ftrack)_ publishing comments now appear in ftrack also as a note on version with customisable category [PYPE-645] +- _(ftrack)_ delete asset/subset action had been improved. It is now able to remove multiple entities and descendants of the selected entities [PYPE-361, PYPS-72] +- _(workfiles)_ added date field to workfiles app [PYPE-603] +- _(maya)_ old deprecated loader have been removed in favour of a single unified reference loader (old scenes will upgrade automatically to the new loader upon opening) [PYPE-633, PYPE-697] +- _(avalon)_ core updated to 5.5.15 [PYPE-671] +- _(nuke)_ library loader is now available in nuke [PYPE-698] + + +**new:** +- _(pype)_ added pype render wrapper to allow rendering on mixed platform farms. [PYPE-634] +- _(pype)_ added `pype launch` command. It let's admin run applications with dynamically built environment based on the given context. [PYPE-634] +- _(pype)_ added support for extracting review sequences with burnins [PYPE-657] +- _(publish)_ users can now set intent next to a comment when publishing. This will then be reflected on an attribute in ftrack. [PYPE-632] +- _(burnin)_ timecode can now be added to burnin +- _(burnin)_ datetime keys can now be added to burnin and anatomy [PYPE-651] +- _(burnin)_ anatomy templates can now be used in burnins. [PYPE=626] +- _(nuke)_ new validator for render resolution +- _(nuke)_ support for attach slate to nuke renders [PYPE-630] +- _(nuke)_ png sequences were added to loaders +- _(maya)_ added maya 2020 compatibility [PYPE-677] +- _(maya)_ ability to publish and load .ASS standin sequences [PYPS-54] +- _(pype)_ thumbnails can now be published and are visible in the loader. `AVALON_THUMBNAIL_ROOT` environment variable needs to be set for this to work [PYPE-573, PYPE-132] +- _(blender)_ base implementation of blender was added with publishing and loading of .blend files [PYPE-612] +- _(ftrack)_ new action for preparing deliveries [PYPE-639] + + +**fix**: +- _(burnin)_ more robust way of finding ffmpeg for burnins. +- _(pype)_ improved UNC paths remapping when sending to farm. +- _(pype)_ float frames sometimes made their way to representation context in database, breaking loaders [PYPE-668] +- _(pype)_ `pype install --force` was failing sometimes [PYPE-600] +- _(pype)_ padding in published files got calculated wrongly sometimes. It is now instead being always read from project anatomy. [PYPE-667] +- _(publish)_ comment publishing was failing in certain situations +- _(ftrack)_ multiple edge case scenario fixes in auto sync and sync-to-avalon action +- _(ftrack)_ sync to avalon now works on empty projects +- _(ftrack)_ thumbnail update event was failing when deleting entities [PYPE-561] +- _(nuke)_ loader applies proper colorspaces from Presets +- _(nuke)_ publishing handles didn't always work correctly [PYPE-686] +- _(maya)_ assembly publishing and loading wasn't working correctly + + + + + +## 2.4.0 ## + +_**release date:** 9 Dec 2019_ + +**change:** +- _(ftrack)_ version to status ftrack event can now be configured from Presets + - based on preset `presets/ftracc/ftrack_config.json["status_version_to_task"]` +- _(ftrack)_ sync to avalon event has been completely re-written. It now supports most of the project management situations on ftrack including moving, renaming and deleting entities, updating attributes and working with tasks. +- _(ftrack)_ sync to avalon action has been also re-writen. It is now much faster (up to 100 times depending on a project structure), has much better logging and reporting on encountered problems, and is able to handle much more complex situations. +- _(ftrack)_ sync to avalon trigger by checking `auto-sync` toggle on ftrack [PYPE-504] +- _(pype)_ various new features in the REST api +- _(pype)_ new visual identity used across pype +- _(pype)_ started moving all requirements to pip installation rather than vendorising them in pype repository. Due to a few yet unreleased packages, this means that pype can temporarily be only installed in the offline mode. + +**new:** +- _(nuke)_ support for publishing gizmos and loading them as viewer processes +- _(nuke)_ support for publishing nuke nodes from backdrops and loading them back +- _(pype)_ burnins can now work with start and end frames as keys + - use keys `{frame_start}`, `{frame_end}` and `{current_frame}` in burnin preset to use them. [PYPS-44,PYPS-73, PYPE-602] +- _(pype)_ option to filter logs by user and level in loggin GUI +- _(pype)_ image family added to standalone publisher [PYPE-574] +- _(pype)_ matchmove family added to standalone publisher [PYPE-574] +- _(nuke)_ validator for comparing arbitrary knobs with values from presets +- _(maya)_ option to force maya to copy textures in the new look publish rather than hardlinking them +- _(pype)_ comments from pyblish GUI are now being added to ftrack version +- _(maya)_ validator for checking outdated containers in the scene +- _(maya)_ option to publish and load arnold standin sequence [PYPE-579, PYPS-54] + +**fix**: +- _(pype)_ burnins were not respecting codec of the input video +- _(nuke)_ lot's of various nuke and nuke studio fixes across the board [PYPS-45] +- _(pype)_ workfiles app is not launching with the start of the app by default [PYPE-569] +- _(ftrack)_ ftrack integration during publishing was failing under certain situations [PYPS-66] +- _(pype)_ minor fixes in REST api +- _(ftrack)_ status change event was crashing when the target status was missing [PYPS-68] +- _(ftrack)_ actions will try to reconnect if they fail for some reason +- _(maya)_ problems with fps mapping when using float FPS values +- _(deadline)_ overall improvements to deadline publishing +- _(setup)_ environment variables are now remapped on the fly based on the platform pype is running on. This fixes many issues in mixed platform environments. + + + +## 2.3.6 # + +_**release date:** 27 Nov 2019_ + +**hotfix**: +- _(ftrack)_ was hiding important debug logo +- _(nuke)_ crashes during workfile publishing +- _(ftrack)_ event server crashes because of signal problems +- _(muster)_ problems with muster render submissions +- _(ftrack)_ thumbnail update event syntax errors + + +## 2.3.0 ## +_release date: 6 Oct 2019_ + +**new**: +- _(maya)_ support for yeti rigs and yeti caches +- _(maya)_ validator for comparing arbitrary attributes against ftrack +- _(pype)_ burnins can now show current date and time +- _(muster)_ pools can now be set in render globals in maya +- _(pype)_ Rest API has been implemented in beta stage +- _(nuke)_ LUT loader has been added +- _(pype)_ rudimentary user module has been added as preparation for user management +- _(pype)_ a simple logging GUI has been added to pype tray +- _(nuke)_ nuke can now bake input process into mov +- _(maya)_ imported models now have selection handle displayed by defaulting +- _(avalon)_ it's is now possible to load multiple assets at once using loader +- _(maya)_ added ability to automatically connect yeti rig to a mesh upon loading + +**changed**: +- _(ftrack)_ event server now runs two parallel processes and is able to keep queue of events to process. +- _(nuke)_ task name is now added to all rendered subsets +- _(pype)_ adding more families to standalone publisher +- _(pype)_ standalone publisher now uses pyblish-lite +- _(pype)_ standalone publisher can now create review quicktimes +- _(ftrack)_ queries to ftrack were sped up +- _(ftrack)_ multiple ftrack action have been deprecated +- _(avalon)_ avalon upstream has been updated to 5.5.0 +- _(nukestudio)_ published transforms can now be animated +- + +**fix**: +- _(maya)_ fps popup button didn't work in some cases +- _(maya)_ geometry instances and references in maya were losing shader assignments +- _(muster)_ muster rendering templates were not working correctly +- _(maya)_ arnold tx texture conversion wasn't respecting colorspace set by the artist +- _(pype)_ problems with avalon db sync +- _(maya)_ ftrack was rounding FPS making it inconsistent +- _(pype)_ wrong icon names in Creator +- _(maya)_ scene inventory wasn't showing anything if representation was removed from database after it's been loaded to the scene +- _(nukestudio)_ multiple bugs squashed +- _(loader)_ loader was taking long time to show all the loading action when first launcher in maya + +## 2.2.0 ## +_release date: 8 Sept 2019_ + +**new**: +- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts +- _(nuke)_ option to choose deadline chunk size on write nodes +- _(nukestudio)_ added option to publish soft effects (subTrackItems) from NukeStudio as subsets including LUT files. these can then be loaded in nuke or NukeStudio +- _(nuke)_ option to build nuke script from previously published latest versions of plate and render subsets. +- _(nuke)_ nuke writes now have deadline tab. +- _(ftrack)_ Prepare Project action can now be used for creating the base folder structure on disk and in ftrack, setting up all the initial project attributes and it automatically prepares `pype_project_config` folder for the given project. +- _(clockify)_ Added support for time tracking in clockify. This currently in addition to ftrack time logs, but does not completely replace them. +- _(pype)_ any attributes in Creator and Loader plugins can now be customised using pype preset system + +**changed**: +- nukestudio now uses workio API for workfiles +- _(maya)_ "FIX FPS" prompt in maya now appears in the middle of the screen +- _(muster)_ can now be configured with custom templates +- _(pype)_ global publishing plugins can now be configured using presets as well as host specific ones + + +**fix**: +- wrong version retrieval from path in certain scenarios +- nuke reset resolution wasn't working in certain scenarios + +## 2.1.0 ## +_release date: 6 Aug 2019_ + +A large cleanup release. Most of the change are under the hood. + +**new**: +- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts +- _(pype)_ Added configurable option to add burnins to any generated quicktimes +- _(ftrack)_ Action that identifies what machines pype is running on. +- _(system)_ unify subprocess calls +- _(maya)_ add audio to review quicktimes +- _(nuke)_ add crop before write node to prevent overscan problems in ffmpeg +- **Nuke Studio** publishing and workfiles support +- **Muster** render manager support +- _(nuke)_ Framerange, FPS and Resolution are set automatically at startup +- _(maya)_ Ability to load published sequences as image planes +- _(system)_ Ftrack event that sets asset folder permissions based on task assignees in ftrack. +- _(maya)_ Pyblish plugin that allow validation of maya attributes +- _(system)_ added better startup logging to tray debug, including basic connection information +- _(avalon)_ option to group published subsets to groups in the loader +- _(avalon)_ loader family filters are working now + +**changed**: +- change multiple key attributes to unify their behaviour across the pipeline + - `frameRate` to `fps` + - `startFrame` to `frameStart` + - `endFrame` to `frameEnd` + - `fstart` to `frameStart` + - `fend` to `frameEnd` + - `handle_start` to `handleStart` + - `handle_end` to `handleEnd` + - `resolution_width` to `resolutionWidth` + - `resolution_height` to `resolutionHeight` + - `pixel_aspect` to `pixelAspect` + +- _(nuke)_ write nodes are now created inside group with only some attributes editable by the artist +- rendered frames are now deleted from temporary location after their publishing is finished. +- _(ftrack)_ RV action can now be launched from any entity +- after publishing only refresh button is now available in pyblish UI +- added context instance pyblish-lite so that artist knows if context plugin fails +- _(avalon)_ allow opening selected files using enter key +- _(avalon)_ core updated to v5.2.9 with our forked changes on top + +**fix**: +- faster hierarchy retrieval from db +- _(nuke)_ A lot of stability enhancements +- _(nuke studio)_ A lot of stability enhancements +- _(nuke)_ now only renders a single write node on farm +- _(ftrack)_ pype would crash when launcher project level task +- work directory was sometimes not being created correctly +- major pype.lib cleanup. Removing of unused functions, merging those that were doing the same and general house cleaning. +- _(avalon)_ subsets in maya 2019 weren't behaving correctly in the outliner diff --git a/changelog.md b/changelog.md deleted file mode 100644 index bdee041615..0000000000 --- a/changelog.md +++ /dev/null @@ -1,120 +0,0 @@ -# Pype changelog # -Welcome to pype changelog - -## 2.3.0 ## -_release date: 6 Oct 2019_ - -**new**: -- _(maya)_ support for yeti rigs and yeti caches -- _(maya)_ validator for comparing arbitrary attributes against ftrack -- _(pype)_ burnins can now show current date and time -- _(muster)_ pools can now be set in render globals in maya -- _(pype)_ Rest API has been implemented in beta stage -- _(nuke)_ LUT loader has been added -- _(pype)_ rudimentary user module has been added as preparation for user management -- _(pype)_ a simple logging GUI has been added to pype tray -- _(nuke)_ nuke can now bake input process into mov -- _(maya)_ imported models now have selection handle displayed by defaulting -- _(avalon)_ it's is now possible to load multiple assets at once using loader -- _(maya)_ added ability to automatically connect yeti rig to a mesh upon loading - -**changed**: -- _(ftrack)_ event server now runs two parallel processes and is able to keep queue of events to process. -- _(nuke)_ task name is now added to all rendered subsets -- _(pype)_ adding more families to standalone publisher -- _(pype)_ standalone publisher now uses pyblish-lite -- _(pype)_ standalone publisher can now create review quicktimes -- _(ftrack)_ queries to ftrack were sped up -- _(ftrack)_ multiple ftrack action have been deprecated -- _(avalon)_ avalon upstream has been updated to 5.5.0 -- _(nukestudio)_ published transforms can now be animated -- - -**fix**: -- _(maya)_ fps popup button didn't work in some cases -- _(maya)_ geometry instances and references in maya were losing shader assignments -- _(muster)_ muster rendering templates were not working correctly -- _(maya)_ arnold tx texture conversion wasn't respecting colorspace set by the artist -- _(pype)_ problems with avalon db sync -- _(maya)_ ftrack was rounding FPS making it inconsistent -- _(pype)_ wrong icon names in Creator -- _(maya)_ scene inventory wasn't showing anything if representation was removed from database after it's been loaded to the scene -- _(nukestudio)_ multiple bugs squashed -- _(loader)_ loader was taking long time to show all the loading action when first launcher in maya - -## 2.2.0 ## -_release date: 8 Sept 2019_ - -**new**: -- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts -- _(nuke)_ option to choose deadline chunk size on write nodes -- _(nukestudio)_ added option to publish soft effects (subTrackItems) from NukeStudio as subsets including LUT files. these can then be loaded in nuke or NukeStudio -- _(nuke)_ option to build nuke script from previously published latest versions of plate and render subsets. -- _(nuke)_ nuke writes now have deadline tab. -- _(ftrack)_ Prepare Project action can now be used for creating the base folder structure on disk and in ftrack, setting up all the initial project attributes and it automatically prepares `pype_project_config` folder for the given project. -- _(clockify)_ Added support for time tracking in clockify. This currently in addition to ftrack time logs, but does not completely replace them. -- _(pype)_ any attributes in Creator and Loader plugins can now be customised using pype preset system - -**changed**: -- nukestudio now uses workio API for workfiles -- _(maya)_ "FIX FPS" prompt in maya now appears in the middle of the screen -- _(muster)_ can now be configured with custom templates -- _(pype)_ global publishing plugins can now be configured using presets as well as host specific ones - - -**fix**: -- wrong version retrieval from path in certain scenarios -- nuke reset resolution wasn't working in certain scenarios - -## 2.1.0 ## -_release date: 6 Aug 2019_ - -A large cleanup release. Most of the change are under the hood. - -**new**: -- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts -- _(pype)_ Added configurable option to add burnins to any generated quicktimes -- _(ftrack)_ Action that identifies what machines pype is running on. -- _(system)_ unify subprocess calls -- _(maya)_ add audio to review quicktimes -- _(nuke)_ add crop before write node to prevent overscan problems in ffmpeg -- **Nuke Studio** publishing and workfiles support -- **Muster** render manager support -- _(nuke)_ Framerange, FPS and Resolution are set automatically at startup -- _(maya)_ Ability to load published sequences as image planes -- _(system)_ Ftrack event that sets asset folder permissions based on task assignees in ftrack. -- _(maya)_ Pyblish plugin that allow validation of maya attributes -- _(system)_ added better startup logging to tray debug, including basic connection information -- _(avalon)_ option to group published subsets to groups in the loader -- _(avalon)_ loader family filters are working now - -**changed**: -- change multiple key attributes to unify their behaviour across the pipeline - - `frameRate` to `fps` - - `startFrame` to `frameStart` - - `endFrame` to `frameEnd` - - `fstart` to `frameStart` - - `fend` to `frameEnd` - - `handle_start` to `handleStart` - - `handle_end` to `handleEnd` - - `resolution_width` to `resolutionWidth` - - `resolution_height` to `resolutionHeight` - - `pixel_aspect` to `pixelAspect` - -- _(nuke)_ write nodes are now created inside group with only some attributes editable by the artist -- rendered frames are now deleted from temporary location after their publishing is finished. -- _(ftrack)_ RV action can now be launched from any entity -- after publishing only refresh button is now available in pyblish UI -- added context instance pyblish-lite so that artist knows if context plugin fails -- _(avalon)_ allow opening selected files using enter key -- _(avalon)_ core updated to v5.2.9 with our forked changes on top - -**fix**: -- faster hierarchy retrieval from db -- _(nuke)_ A lot of stability enhancements -- _(nuke studio)_ A lot of stability enhancements -- _(nuke)_ now only renders a single write node on farm -- _(ftrack)_ pype would crash when launcher project level task -- work directory was sometimes not being created correctly -- major pype.lib cleanup. Removing of unused functions, merging those that were doing the same and general house cleaning. -- _(avalon)_ subsets in maya 2019 weren't behaving correctly in the outliner From 93f7391e5a899a14adb1c8a0c964a26a9e565c23 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 17:49:19 +0200 Subject: [PATCH 458/580] convert data from gui data t o config data --- pype/tools/config_setting/config_setting/widgets/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 172450684b..02116b6044 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -126,7 +126,7 @@ class SystemWidget(QtWidgets.QWidget): if value is not lib.NOT_SET: _data.update(value) - values = _data["system"] + values = lib.convert_gui_data_to_overrides(_data.get("system", {})) dirpath = os.path.dirname(SYSTEM_CONFIGURATIONS_PATH) if not os.path.exists(dirpath): @@ -456,7 +456,7 @@ class ProjectWidget(QtWidgets.QWidget): if value is not lib.NOT_SET: _data.update(value) - output = _data["project"] + output = lib.convert_gui_data_to_overrides(_data.get("project", {})) dirpath = os.path.dirname(PROJECT_CONFIGURATIONS_PATH) if not os.path.exists(dirpath): From 037a573f7ca7f774d3855bbf16250844dd517827 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 17:51:22 +0200 Subject: [PATCH 459/580] a lot of changes to be able to get studio overrides --- .../config_setting/widgets/inputs.py | 223 ++++++++---------- 1 file changed, 93 insertions(+), 130 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3a3d517cc1..cf42d47ab5 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -16,15 +16,20 @@ class ConfigObject(AbstractConfigObject): default_state = "" - _has_studio_override = False _as_widget = False - _is_overriden = False - _is_modified = False - _was_overriden = False - _is_invalid = False _is_group = False + # TODO not implemented yet _is_nullable = False + _has_studio_override = False + _had_studio_override = False + + _is_overriden = False + _was_overriden = False + + _is_modified = False + _is_invalid = False + _any_parent_is_group = None _log = None @@ -38,6 +43,10 @@ class ConfigObject(AbstractConfigObject): def has_studio_override(self): return self._has_studio_override or self._parent.has_studio_override + @property + def had_studio_override(self): + return self._had_studio_override + @property def any_parent_is_group(self): if self._any_parent_is_group is None: @@ -47,7 +56,11 @@ class ConfigObject(AbstractConfigObject): @property def is_modified(self): """Has object any changes that require saving.""" - return self._is_modified or (self.was_overriden != self.is_overriden) + return ( + self._is_modified + or (self.was_overriden != self.is_overriden) + or (self.has_studio_override != self.had_studio_override) + ) @property def is_overriden(self): @@ -200,8 +213,9 @@ class InputObject(ConfigObject): ) self.default_value = value - if not self.has_studio_override: - self.set_value(value) + self._has_studio_override = False + self._had_studio_override = False + self.set_value(value) def update_studio_values(self, parent_values): value = NOT_SET @@ -219,8 +233,31 @@ class InputObject(ConfigObject): self.set_value(self.default_value) self._has_studio_override = False + self._had_studio_override = bool(self._has_studio_override) self._is_modified = False + def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + + if self.is_overidable: + self._is_overriden = True + else: + self._has_studio_override = True + + if self._is_invalid: + self._is_modified = True + elif self._is_overriden: + self._is_modified = self.item_value() != self.override_value + elif self._has_studio_override: + self._is_modified = self.item_value() != self.studio_value + else: + self._is_modified = self.item_value() != self.default_value + + self.update_style() + + self.value_changed.emit(self) + def studio_overrides(self): if not self.has_studio_override: return NOT_SET, False @@ -372,24 +409,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): # value as `value` the `_on_value_change` is not triggered self.checkbox.setChecked(value) - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_overidable: - self._is_overriden = True - - if self._is_invalid: - self._is_modified = True - elif self._is_overriden: - self._is_modified = self.item_value() != self.override_value - else: - self._is_modified = self.item_value() != self.studio_value - - self.update_style() - - self.value_changed.emit(self) - def update_style(self): state = self.style_state( self.has_studio_override, @@ -464,24 +483,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.input_field.setValue(value) - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_overidable: - self._is_overriden = True - - if self._is_invalid: - self._is_modified = True - elif self._is_overriden: - self._is_modified = self.item_value() != self.override_value - else: - self._is_modified = self.item_value() != self.studio_value - - self.update_style() - - self.value_changed.emit(self) - def update_style(self): state = self.style_state( self.has_studio_override, @@ -559,24 +560,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.text_input.setText(value) - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_overidable: - self._is_overriden = True - - if self._is_invalid: - self._is_modified = True - elif self._is_overriden: - self._is_modified = self.item_value() != self.override_value - else: - self._is_modified = self.item_value() != self.studio_value - - self.update_style() - - self.value_changed.emit(self) - def update_style(self): state = self.style_state( self.has_studio_override, @@ -651,24 +634,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.path_input.clear_end_path() super(PathInput, self).focusOutEvent(event) - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_overidable: - self._is_overriden = True - - if self._is_invalid: - self._is_modified = True - elif self.is_overriden: - self._is_modified = self.item_value() != self.override_value - else: - self._is_modified = self.item_value() != self.studio_value - - self.update_style() - - self.value_changed.emit(self) - def update_style(self): state = self.style_state( self.has_studio_override, @@ -804,24 +769,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.text_input.set_value(value) - def _on_value_change(self, item=None): + def _on_value_change(self, *args, **kwargs): self._is_invalid = self.text_input.has_invalid_value() - if self.ignore_value_changes: - return - - if self.is_overidable: - self._is_overriden = True - - if self._is_invalid: - self._is_modified = True - elif self._is_overriden: - self._is_modified = self.item_value() != self.override_value - else: - self._is_modified = self.item_value() != self.studio_value - - self.update_style() - - self.value_changed.emit(self) + return super(RawJsonWidget, self)._on_value_change(*args, **kwargs) def update_style(self): state = self.style_state( @@ -1006,24 +956,6 @@ class ListWidget(QtWidgets.QWidget, InputObject): if self.count() == 0: self.add_row(is_empty=True) - def _on_value_change(self, item=None): - if self.ignore_value_changes: - return - - if self.is_overidable: - self._is_overriden = True - - if self._is_invalid: - self._is_modified = True - elif self._is_overriden: - self._is_modified = self.item_value() != self.override_value - else: - self._is_modified = self.item_value() != self.studio_value - - self.update_style() - - self.value_changed.emit(self) - def add_row(self, row=None, value=None, is_empty=False): # Create new item item_widget = ListItem( @@ -1351,6 +1283,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.add_row(is_empty=True) def _on_value_change(self, item=None): + if self.ignore_value_changes: + return + fields_by_keys = collections.defaultdict(list) for input_field in self.input_fields: key = input_field.key_value() @@ -1367,18 +1302,19 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): field.is_key_duplicated = True field.update_style() - if self.ignore_value_changes: - return - if self.is_overidable: self._is_overriden = True + else: + self._has_studio_override = True - if self.is_invalid: + if self._is_invalid: self._is_modified = True elif self._is_overriden: self._is_modified = self.item_value() != self.override_value - else: + elif self._has_studio_override: self._is_modified = self.item_value() != self.studio_value + else: + self._is_modified = self.item_value() != self.default_value self.update_style() @@ -1633,6 +1569,12 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): if parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) + if value is NOT_SET: + self._has_studio_override = False + else: + self._has_studio_override = True + self._had_studio_override = bool(self._has_studio_override) + for item in self.input_fields: item.update_studio_values(value) @@ -1669,6 +1611,8 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): if self.is_group: if self.is_overidable: self._is_overriden = True + else: + self._has_studio_override = True self.hierarchical_style_update() @@ -1702,7 +1646,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): self._child_state = child_state state = self.style_state( - child_has_studio_override, + self.had_studio_override, child_invalid, self.is_overriden, self.is_modified @@ -1724,7 +1668,10 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): @property def child_has_studio_override(self): for input_field in self.input_fields: - if input_field.child_has_studio_override: + if ( + input_field.has_studio_override + or input_field.child_has_studio_override + ): return True return False @@ -1770,7 +1717,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): values = {} groups = [] for input_field in self.input_fields: - value, is_group = input_field.overrides() + value, is_group = input_field.studio_overrides() if value is not NOT_SET: values.update(value) if is_group: @@ -1850,7 +1797,10 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): @property def child_has_studio_override(self): for input_field in self.input_fields: - if input_field.child_has_studio_override: + if ( + input_field.has_studio_override + or input_field.child_has_studio_override + ): return True return False @@ -1896,6 +1846,8 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): if self.is_group: if self.is_overidable: self._is_overriden = True + else: + self._has_studio_override = True self.hierarchical_style_update() self.value_changed.emit(self) @@ -1982,7 +1934,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): values = {} groups = [] for input_field in self.input_fields: - value, is_group = input_field.overrides() + value, is_group = input_field.studio_overrides() if value is not NOT_SET: values.update(value) if is_group: @@ -2174,20 +2126,24 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): if self.is_overidable: self._is_overriden = True + else: + self._has_studio_override = True if self._is_invalid: self._is_modified = True elif self._is_overriden: self._is_modified = self.item_value() != self.override_value - else: + elif self._has_studio_override: self._is_modified = self.item_value() != self.studio_value + else: + self._is_modified = self.item_value() != self.default_value self.hierarchical_style_update() self.value_changed.emit(self) def update_style(self, is_overriden=None): - child_has_studio_override = self.has_studio_override + child_has_studio_override = self.child_has_studio_override child_modified = self.child_modified child_invalid = self.child_invalid child_state = self.style_state( @@ -2240,7 +2196,10 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): @property def child_has_studio_override(self): for input_field in self.input_fields: - if input_field.child_has_studio_override: + if ( + input_field.has_studio_override + or input_field.child_has_studio_override + ): return True return False @@ -2407,6 +2366,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): def _on_value_change(self, item=None): if self.ignore_value_changes: return + self.value_changed.emit(self) if self.any_parent_is_group: self.hierarchical_style_update() @@ -2414,7 +2374,10 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): @property def child_has_studio_override(self): for input_field in self.input_fields: - if input_field.child_has_studio_override: + if ( + input_field.has_studio_override + or input_field.child_has_studio_override + ): return True return False @@ -2467,7 +2430,7 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): values = {} groups = [] for input_field in self.input_fields: - value, is_group = input_field.overrides() + value, is_group = input_field.studio_overrides() if value is not NOT_SET: values.update(value) if is_group: From 6bdee49e2fd0d66e2b32b31eb56bcac3699d26f6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 17:52:52 +0200 Subject: [PATCH 460/580] underscored attributes are kept --- .../config_setting/widgets/base.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 02116b6044..cfbed884d9 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -17,10 +17,10 @@ from avalon import io class SystemWidget(QtWidgets.QWidget): is_overidable = False - has_studio_override = False - is_overriden = False - is_group = False - any_parent_is_group = False + has_studio_override = _has_studio_override = False + is_overriden = _is_overriden = False + is_group = _is_group = False + any_parent_is_group = _any_parent_is_group = False def __init__(self, parent=None): super(SystemWidget, self).__init__(parent) @@ -286,10 +286,10 @@ class ProjectListWidget(QtWidgets.QWidget): class ProjectWidget(QtWidgets.QWidget): - has_studio_override = False - is_overriden = False - is_group = False - any_parent_is_group = False + has_studio_override = _has_studio_override = False + is_overriden = _is_overriden = False + is_group = _is_group = False + any_parent_is_group = _any_parent_is_group = False def __init__(self, parent=None): super(ProjectWidget, self).__init__(parent) From b3f6c8296510e37f5940f945210496c64f6689b1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 18:00:41 +0200 Subject: [PATCH 461/580] ignore value changes during loading of studio overrides --- .../config_setting/widgets/base.py | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index cfbed884d9..a143e584dd 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -139,8 +139,11 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() def _update_values(self): - default_values = default_configuration() - default_values = {"system": default_values["system_configurations"]} + self.ignore_value_changes = True + + default_values = { + "system": default_configuration()["system_configurations"] + } for input_field in self.input_fields: input_field.update_default_values(default_values) @@ -148,8 +151,7 @@ class SystemWidget(QtWidgets.QWidget): for input_field in self.input_fields: input_field.update_studio_values(system_values) - for input_field in self.input_fields: - input_field.hierarchical_style_update() + self.ignore_value_changes = False def add_children_gui(self, child_configuration): item_type = child_configuration["type"] @@ -469,8 +471,11 @@ class ProjectWidget(QtWidgets.QWidget): self._update_values() def _update_values(self): - default_values = default_configuration() - default_values = {"project": default_values["project_configurations"]} + self.ignore_value_changes = True + + default_values = { + "project": default_configuration()["project_configurations"] + } for input_field in self.input_fields: input_field.update_default_values(default_values) @@ -478,5 +483,4 @@ class ProjectWidget(QtWidgets.QWidget): for input_field in self.input_fields: input_field.update_studio_values(studio_values) - for input_field in self.input_fields: - input_field.hierarchical_style_update() + self.ignore_value_changes = False From a4babc31da11cab5e9841c5187e03d409db99640 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 18:00:59 +0200 Subject: [PATCH 462/580] few minor changes --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index cf42d47ab5..ff4448992d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -762,10 +762,10 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.text_input.textChanged.connect(self._on_value_change) def update_studio_values(self, parent_values): - super(RawJsonWidget, self).update_studio_values(parent_values) - self._is_invalid = self.text_input.has_invalid_value() + super(RawJsonWidget, self).update_studio_values(parent_values) + def set_value(self, value): self.text_input.set_value(value) @@ -1765,6 +1765,8 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): self._any_parent_is_group = any_parent_is_group self._is_group = input_data.get("is_group", False) + if self._is_group: + raise TypeError("DictInvisible can't be marked as group input.") self.setAttribute(QtCore.Qt.WA_TranslucentBackground) From 0506d513954a29950a517a194d8203c7da4da84b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 18:38:54 +0200 Subject: [PATCH 463/580] fix dict studio override --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ff4448992d..4a71f0380c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1569,10 +1569,10 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): if parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) - if value is NOT_SET: - self._has_studio_override = False - else: + self._has_studio_override = False + if self.is_group and value is not NOT_SET: self._has_studio_override = True + self._had_studio_override = bool(self._has_studio_override) for item in self.input_fields: From d372f9077eff211a34c8849a85ee422679da5554 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 10 Sep 2020 09:54:58 +0200 Subject: [PATCH 464/580] changelog update --- .github_changelog_generator | 2 +- CHANGELOG.md | 565 ++++++++++++++++++++++++++++++++++++ HISTORY.md | 3 - 3 files changed, 566 insertions(+), 4 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.github_changelog_generator b/.github_changelog_generator index 93ab39f4d0..cd09ebcbfa 100644 --- a/.github_changelog_generator +++ b/.github_changelog_generator @@ -4,4 +4,4 @@ author=False unreleased=False since-tag=2.11.0 release-branch=master -enhancement-label=New / Enhancements +enhancement-label=**Enhancements:** diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..ba86b85eec --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,565 @@ +# Changelog + +## [2.12.0](https://github.com/pypeclub/pype/tree/2.12.0) (2020-09-09) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.8...2.12.0) + +**Enhancements:** + +- Less mongo connections [\#509](https://github.com/pypeclub/pype/pull/509) +- Nuke: adding image loader [\#499](https://github.com/pypeclub/pype/pull/499) +- Move launcher window to top if launcher action is clicked [\#450](https://github.com/pypeclub/pype/pull/450) +- Maya: better tile rendering support in Pype [\#446](https://github.com/pypeclub/pype/pull/446) +- Implementation of non QML launcher [\#443](https://github.com/pypeclub/pype/pull/443) +- Optional skip review on renders. [\#441](https://github.com/pypeclub/pype/pull/441) +- Ftrack: Option to push status from task to latest version [\#440](https://github.com/pypeclub/pype/pull/440) +- Properly containerize image plane loads. [\#434](https://github.com/pypeclub/pype/pull/434) +- Option to keep the review files. [\#426](https://github.com/pypeclub/pype/pull/426) +- Isolate view on instance members. [\#425](https://github.com/pypeclub/pype/pull/425) +- ftrack group is bcw compatible [\#418](https://github.com/pypeclub/pype/pull/418) +- Maya: Publishing of tile renderings on Deadline [\#398](https://github.com/pypeclub/pype/pull/398) +- Feature/little bit better logging gui [\#383](https://github.com/pypeclub/pype/pull/383) + +**Fixed bugs:** + +- Maya: Fix tile order for Draft Tile Assembler [\#511](https://github.com/pypeclub/pype/pull/511) +- Remove extra dash [\#501](https://github.com/pypeclub/pype/pull/501) +- Fix: strip dot from repre names in single frame renders [\#498](https://github.com/pypeclub/pype/pull/498) +- Better handling of destination during integrating [\#485](https://github.com/pypeclub/pype/pull/485) +- Fix: allow thumbnail creation for single frame renders [\#460](https://github.com/pypeclub/pype/pull/460) +- added missing argument to launch\_application in ftrack app handler [\#453](https://github.com/pypeclub/pype/pull/453) +- Burnins: Copy bit rate of input video to match quality. [\#448](https://github.com/pypeclub/pype/pull/448) +- Standalone publisher is now independent from tray [\#442](https://github.com/pypeclub/pype/pull/442) +- Bugfix/empty enumerator attributes [\#436](https://github.com/pypeclub/pype/pull/436) +- Fixed wrong order of "other" category collapssing in publisher [\#435](https://github.com/pypeclub/pype/pull/435) +- Multiple reviews where being overwritten to one. [\#424](https://github.com/pypeclub/pype/pull/424) +- Cleanup plugin fail on instances without staging dir [\#420](https://github.com/pypeclub/pype/pull/420) +- deprecated -intra parameter in ffmpeg to new `-g` [\#417](https://github.com/pypeclub/pype/pull/417) +- Delivery action can now work with entered path [\#397](https://github.com/pypeclub/pype/pull/397) + +**Merged pull requests:** + +- Review on instance.data [\#473](https://github.com/pypeclub/pype/pull/473) + +## [2.11.8](https://github.com/pypeclub/pype/tree/2.11.8) (2020-08-27) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.7...2.11.8) + +**Enhancements:** + +- DWAA support for Maya [\#382](https://github.com/pypeclub/pype/issues/382) +- Isolate View on Playblast [\#367](https://github.com/pypeclub/pype/issues/367) +- Maya: Tile rendering [\#297](https://github.com/pypeclub/pype/issues/297) +- single pype instance running [\#47](https://github.com/pypeclub/pype/issues/47) +- PYPE-649: projects don't guarantee backwards compatible environment [\#8](https://github.com/pypeclub/pype/issues/8) +- PYPE-663: separate venv for each deployed version [\#7](https://github.com/pypeclub/pype/issues/7) + +**Fixed bugs:** + +- pyblish pype - other group is collapsed before plugins are done [\#431](https://github.com/pypeclub/pype/issues/431) +- Alpha white edges in harmony on PNGs [\#412](https://github.com/pypeclub/pype/issues/412) +- harmony image loader picks wrong representations [\#404](https://github.com/pypeclub/pype/issues/404) +- Clockify crash when response contain symbol not allowed by UTF-8 [\#81](https://github.com/pypeclub/pype/issues/81) + +## [2.11.7](https://github.com/pypeclub/pype/tree/2.11.7) (2020-08-21) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.6...2.11.7) + +**Fixed bugs:** + +- Clean Up Baked Movie [\#369](https://github.com/pypeclub/pype/issues/369) +- celaction last workfile [\#459](https://github.com/pypeclub/pype/pull/459) + +## [2.11.6](https://github.com/pypeclub/pype/tree/2.11.6) (2020-08-18) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.5...2.11.6) + +**Enhancements:** + +- publisher app [\#56](https://github.com/pypeclub/pype/issues/56) + +## [2.11.5](https://github.com/pypeclub/pype/tree/2.11.5) (2020-08-13) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.4...2.11.5) + +**Enhancements:** + +- Switch from master to equivalent [\#220](https://github.com/pypeclub/pype/issues/220) +- Standalone publisher now only groups sequence if the extension is known [\#439](https://github.com/pypeclub/pype/pull/439) + +**Fixed bugs:** + +- Logs have been disable for editorial by default to speed up publishing [\#433](https://github.com/pypeclub/pype/pull/433) +- additional fixes for celaction [\#430](https://github.com/pypeclub/pype/pull/430) +- Harmony: invalid variable scope in validate scene settings [\#428](https://github.com/pypeclub/pype/pull/428) +- new representation name for audio was not accepted [\#427](https://github.com/pypeclub/pype/pull/427) + +## [2.11.4](https://github.com/pypeclub/pype/tree/2.11.4) (2020-08-10) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.3...2.11.4) + +**Enhancements:** + +- WebSocket server [\#135](https://github.com/pypeclub/pype/issues/135) +- standalonepublisher: editorial family features expansion \[master branch\] [\#411](https://github.com/pypeclub/pype/pull/411) + +## [2.11.3](https://github.com/pypeclub/pype/tree/2.11.3) (2020-08-04) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.2...2.11.3) + +**Fixed bugs:** + +- Harmony: publishing performance issues [\#408](https://github.com/pypeclub/pype/pull/408) + +## [2.11.2](https://github.com/pypeclub/pype/tree/2.11.2) (2020-07-31) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.1...2.11.2) + +**Fixed bugs:** + +- Ftrack to Avalon bug [\#406](https://github.com/pypeclub/pype/issues/406) + +## [2.11.1](https://github.com/pypeclub/pype/tree/2.11.1) (2020-07-29) + +[Full Changelog](https://github.com/pypeclub/pype/compare/2.11.0...2.11.1) + +**Merged pull requests:** + +- Celaction: metadata json folder fixes on path [\#393](https://github.com/pypeclub/pype/pull/393) +- CelAction - version up method taken fro pype.lib [\#391](https://github.com/pypeclub/pype/pull/391) + + +## 2.11.0 ## + +_**release date:** 27 July 2020_ + +**new:** +- _(blender)_ namespace support [\#341](https://github.com/pypeclub/pype/pull/341) +- _(blender)_ start end frames [\#330](https://github.com/pypeclub/pype/pull/330) +- _(blender)_ camera asset [\#322](https://github.com/pypeclub/pype/pull/322) +- _(pype)_ toggle instances per family in pyblish GUI [\#320](https://github.com/pypeclub/pype/pull/320) +- _(pype)_ current release version is now shown in the tray menu [#379](https://github.com/pypeclub/pype/pull/379) + + +**improved:** +- _(resolve)_ tagging for publish [\#239](https://github.com/pypeclub/pype/issues/239) +- _(pype)_ Support publishing a subset of shots with standalone editorial [\#336](https://github.com/pypeclub/pype/pull/336) +- _(harmony)_ Basic support for palettes [\#324](https://github.com/pypeclub/pype/pull/324) +- _(photoshop)_ Flag outdated containers on startup and publish. [\#309](https://github.com/pypeclub/pype/pull/309) +- _(harmony)_ Flag Outdated containers [\#302](https://github.com/pypeclub/pype/pull/302) +- _(photoshop)_ Publish review [\#298](https://github.com/pypeclub/pype/pull/298) +- _(pype)_ Optional Last workfile launch [\#365](https://github.com/pypeclub/pype/pull/365) + + +**fixed:** +- _(premiere)_ workflow fixes [\#346](https://github.com/pypeclub/pype/pull/346) +- _(pype)_ pype-setup does not work with space in path [\#327](https://github.com/pypeclub/pype/issues/327) +- _(ftrack)_ Ftrack delete action cause circular error [\#206](https://github.com/pypeclub/pype/issues/206) +- _(nuke)_ Priority was forced to 50 [\#345](https://github.com/pypeclub/pype/pull/345) +- _(nuke)_ Fix ValidateNukeWriteKnobs [\#340](https://github.com/pypeclub/pype/pull/340) +- _(maya)_ If camera attributes are connected, we can ignore them. [\#339](https://github.com/pypeclub/pype/pull/339) +- _(pype)_ stop appending of tools environment to existing env [\#337](https://github.com/pypeclub/pype/pull/337) +- _(ftrack)_ Ftrack timeout needs to look at AVALON\_TIMEOUT [\#325](https://github.com/pypeclub/pype/pull/325) +- _(harmony)_ Only zip files are supported. [\#310](https://github.com/pypeclub/pype/pull/310) +- _(pype)_ hotfix/Fix event server mongo uri [\#305](https://github.com/pypeclub/pype/pull/305) +- _(photoshop)_ Subset was not named or validated correctly. [\#304](https://github.com/pypeclub/pype/pull/304) + + + + +## 2.10.0 ## + +_**release date:** 17 June 2020_ + +**new:** +- _(harmony)_ **Toon Boom Harmony** has been greatly extended to support rigging, scene build, animation and rendering workflows. [#270](https://github.com/pypeclub/pype/issues/270) [#271](https://github.com/pypeclub/pype/issues/271) [#190](https://github.com/pypeclub/pype/issues/190) [#191](https://github.com/pypeclub/pype/issues/191) [#172](https://github.com/pypeclub/pype/issues/172) [#168](https://github.com/pypeclub/pype/issues/168) +- _(pype)_ Added support for rudimentary **edl publishing** into individual shots. [#265](https://github.com/pypeclub/pype/issues/265) +- _(celaction)_ Simple **Celaction** integration has been added with support for workfiles and rendering. [#255](https://github.com/pypeclub/pype/issues/255) +- _(maya)_ Support for multiple job types when submitting to the farm. We can now render Maya or Standalone render jobs for Vray and Arnold (limited support for arnold) [#204](https://github.com/pypeclub/pype/issues/204) +- _(photoshop)_ Added initial support for Photoshop [#232](https://github.com/pypeclub/pype/issues/232) + +**improved:** +- _(blender)_ Updated support for rigs and added support Layout family [#233](https://github.com/pypeclub/pype/issues/233) [#226](https://github.com/pypeclub/pype/issues/226) +- _(premiere)_ It is now possible to choose different storage root for workfiles of different task types. [#255](https://github.com/pypeclub/pype/issues/255) +- _(maya)_ Support for unmerged AOVs in Redshift multipart EXRs [#197](https://github.com/pypeclub/pype/issues/197) +- _(pype)_ Pype repository has been refactored in preparation for 3.0 release [#169](https://github.com/pypeclub/pype/issues/169) +- _(deadline)_ All file dependencies are now passed to deadline from maya to prevent premature start of rendering if caches or textures haven't been coppied over yet. [#195](https://github.com/pypeclub/pype/issues/195) +- _(nuke)_ Script validation can now be made optional. [#194](https://github.com/pypeclub/pype/issues/194) +- _(pype)_ Publishing can now be stopped at any time. [#194](https://github.com/pypeclub/pype/issues/194) + +**fix:** +- _(pype)_ Pyblish-lite has been integrated into pype repository, plus various publishing GUI fixes. [#274](https://github.com/pypeclub/pype/issues/274) [#275](https://github.com/pypeclub/pype/issues/275) [#268](https://github.com/pypeclub/pype/issues/268) [#227](https://github.com/pypeclub/pype/issues/227) [#238](https://github.com/pypeclub/pype/issues/238) +- _(maya)_ Alembic extractor was getting wrong frame range type in certain scenarios [#254](https://github.com/pypeclub/pype/issues/254) +- _(maya)_ Attaching a render to subset in maya was not passing validation in certain scenarios [#256](https://github.com/pypeclub/pype/issues/256) +- _(ftrack)_ Various small fixes to ftrack sync [#263](https://github.com/pypeclub/pype/issues/263) [#259](https://github.com/pypeclub/pype/issues/259) +- _(maya)_ Look extraction is now able to skp invalid connections in shaders [#207](https://github.com/pypeclub/pype/issues/207) + + + + +## 2.9.0 ## + +_**release date:** 25 May 2020_ + +**new:** +- _(pype)_ Support for **Multiroot projects**. You can now store project data on multiple physical or virtual storages and target individual publishes to these locations. For instance render can be stored on a faster storage than the rest of the project. [#145](https://github.com/pypeclub/pype/issues/145), [#38](https://github.com/pypeclub/pype/issues/38) +- _(harmony)_ Basic implementation of **Toon Boom Harmony** has been added. [#142](https://github.com/pypeclub/pype/issues/142) +- _(pype)_ OSX support is in public beta now. There are issues to be expected, but the main implementation should be functional. [#141](https://github.com/pypeclub/pype/issues/141) + + +**improved:** + +- _(pype)_ **Review extractor** has been completely rebuilt. It now supports granular filtering so you can create **multiple outputs** for different tasks, families or hosts. [#103](https://github.com/pypeclub/pype/issues/103), [#166](https://github.com/pypeclub/pype/issues/166), [#165](https://github.com/pypeclub/pype/issues/165) +- _(pype)_ **Burnin** generation had been extended to **support same multi-output filtering** as review extractor [#103](https://github.com/pypeclub/pype/issues/103) +- _(pype)_ Publishing file templates can now be specified in config for each individual family [#114](https://github.com/pypeclub/pype/issues/114) +- _(pype)_ Studio specific plugins can now be appended to pype standard publishing plugins. [#112](https://github.com/pypeclub/pype/issues/112) +- _(nukestudio)_ Reviewable clips no longer need to be previously cut, exported and re-imported to timeline. **Pype can now dynamically cut reviewable quicktimes** from continuous offline footage during publishing. [#23](https://github.com/pypeclub/pype/issues/23) +- _(deadline)_ Deadline can now correctly differentiate between staging and production pype. [#154](https://github.com/pypeclub/pype/issues/154) +- _(deadline)_ `PYPE_PYTHON_EXE` env variable can now be used to direct publishing to explicit python installation. [#120](https://github.com/pypeclub/pype/issues/120) +- _(nuke)_ Nuke now check for new version of loaded data on file open. [#140](https://github.com/pypeclub/pype/issues/140) +- _(nuke)_ frame range and limit checkboxes are now exposed on write node. [#119](https://github.com/pypeclub/pype/issues/119) + + + +**fix:** + +- _(nukestudio)_ Project Location was using backslashes which was breaking nukestudio native exporting in certains configurations [#82](https://github.com/pypeclub/pype/issues/82) +- _(nukestudio)_ Duplicity in hierarchy tags was prone to throwing publishing error [#130](https://github.com/pypeclub/pype/issues/130), [#144](https://github.com/pypeclub/pype/issues/144) +- _(ftrack)_ multiple stability improvements [#157](https://github.com/pypeclub/pype/issues/157), [#159](https://github.com/pypeclub/pype/issues/159), [#128](https://github.com/pypeclub/pype/issues/128), [#118](https://github.com/pypeclub/pype/issues/118), [#127](https://github.com/pypeclub/pype/issues/127) +- _(deadline)_ multipart EXRs were stopping review publishing on the farm. They are still not supported for automatic review generation, but the publish will go through correctly without the quicktime. [#155](https://github.com/pypeclub/pype/issues/155) +- _(deadline)_ If deadline is non-responsive it will no longer freeze host when publishing [#149](https://github.com/pypeclub/pype/issues/149) +- _(deadline)_ Sometimes deadline was trying to launch render before all the source data was coppied over. [#137](https://github.com/pypeclub/pype/issues/137) _(harmony)_ Basic implementation of **Toon Boom Harmony** has been added. [#142](https://github.com/pypeclub/pype/issues/142) +- _(nuke)_ Filepath knob wasn't updated properly. [#131](https://github.com/pypeclub/pype/issues/131) +- _(maya)_ When extracting animation, the "Write Color Set" options on the instance were not respected. [#108](https://github.com/pypeclub/pype/issues/108) +- _(maya)_ Attribute overrides for AOV only worked for the legacy render layers. Now it works for new render setup as well [#132](https://github.com/pypeclub/pype/issues/132) +- _(maya)_ Stability and usability improvements in yeti workflow [#104](https://github.com/pypeclub/pype/issues/104) + + + + +## 2.8.0 ## + +_**release date:** 20 April 2020_ + +**new:** + +- _(pype)_ Option to generate slates from json templates. [PYPE-628] [#26](https://github.com/pypeclub/pype/issues/26) +- _(pype)_ It is now possible to automate loading of published subsets into any scene. Documentation will follow :). [PYPE-611] [#24](https://github.com/pypeclub/pype/issues/24) + +**fix:** + +- _(maya)_ Some Redshift render tokens could break publishing. [PYPE-778] [#33](https://github.com/pypeclub/pype/issues/33) +- _(maya)_ Publish was not preserving maya file extension. [#39](https://github.com/pypeclub/pype/issues/39) +- _(maya)_ Rig output validator was failing on nodes without shapes. [#40](https://github.com/pypeclub/pype/issues/40) +- _(maya)_ Yeti caches can now be properly versioned up in the scene inventory. [#40](https://github.com/pypeclub/pype/issues/40) +- _(nuke)_ Build first workfiles was not accepting jpeg sequences. [#34](https://github.com/pypeclub/pype/issues/34) +- _(deadline)_ Trying to generate ffmpeg review from multipart EXRs no longer crashes publishing. [PYPE-781] +- _(deadline)_ Render publishing is more stable in multiplatform environments. [PYPE-775] + + + + +## 2.7.0 ## + +_**release date:** 30 March 2020_ + +**new:** + +- _(maya)_ Artist can now choose to load multiple references of the same subset at once [PYPE-646, PYPS-81] +- _(nuke)_ Option to use named OCIO colorspaces for review colour baking. [PYPS-82] +- _(pype)_ Pype can now work with `master` versions for publishing and loading. These are non-versioned publishes that are overwritten with the latest version during publish. These are now supported in all the GUIs, but their publishing is deactivated by default. [PYPE-653] +- _(blender)_ Added support for basic blender workflow. We currently support `rig`, `model` and `animation` families. [PYPE-768] +- _(pype)_ Source timecode can now be used in burn-ins. [PYPE-777] +- _(pype)_ Review outputs profiles can now specify delivery resolution different than project setting [PYPE-759] +- _(nuke)_ Bookmark to current context is now added automatically to all nuke browser windows. [PYPE-712] + +**change:** + +- _(maya)_ It is now possible to publish camera without. baking. Keep in mind that unbaked cameras can't be guaranteed to work in other hosts. [PYPE-595] +- _(maya)_ All the renders from maya are now grouped in the loader by their Layer name. [PYPE-482] +- _(nuke/hiero)_ Any publishes from nuke and hiero can now be versioned independently of the workfile. [PYPE-728] + + +**fix:** + +- _(nuke)_ Mixed slashes caused issues in ocio config path. +- _(pype)_ Intent field in pyblish GUI was passing label instead of value to ftrack. [PYPE-733] +- _(nuke)_ Publishing of pre-renders was inconsistent. [PYPE-766] +- _(maya)_ Handles and frame ranges were inconsistent in various places during publishing. +- _(nuke)_ Nuke was crashing if it ran into certain missing knobs. For example DPX output missing `autocrop` [PYPE-774] +- _(deadline)_ Project overrides were not working properly with farm render publishing. +- _(hiero)_ Problems with single frame plates publishing. +- _(maya)_ Redshift RenderPass token were breaking render publishing. [PYPE-778] +- _(nuke)_ Build first workfile was not accepting jpeg sequences. +- _(maya)_ Multipart (Multilayer) EXRs were breaking review publishing due to FFMPEG incompatiblity [PYPE-781] + + + +## 2.6.0 ## + +_**release date:** 9 March 2020_ + +**change:** +- _(maya)_ render publishing has been simplified and made more robust. Render setup layers are now automatically added to publishing subsets and `render globals` family has been replaced with simple `render` [PYPE-570] +- _(avalon)_ change context and workfiles apps, have been merged into one, that allows both actions to be performed at the same time. [PYPE-747] +- _(pype)_ thumbnails are now automatically propagate to asset from the last published subset in the loader +- _(ftrack)_ publishing comment and intent are now being published to ftrack note as well as describtion. [PYPE-727] +- _(pype)_ when overriding existing version new old representations are now overriden, instead of the new ones just being appended. (to allow this behaviour, the version validator need to be disabled. [PYPE-690]) +- _(pype)_ burnin preset has been significantly simplified. It now doesn't require passing function to each field, but only need the actual text template. to use this, all the current burnin PRESETS MUST BE UPDATED for all the projects. +- _(ftrack)_ credentials are now stored on a per server basis, so it's possible to switch between ftrack servers without having to log in and out. [PYPE-723] + + +**new:** +- _(pype)_ production and development deployments now have different colour of the tray icon. Orange for Dev and Green for production [PYPE-718] +- _(maya)_ renders can now be attached to a publishable subset rather than creating their own subset. For example it is possible to create a reviewable `look` or `model` render and have it correctly attached as a representation of the subsets [PYPE-451] +- _(maya)_ after saving current scene into a new context (as a new shot for instance), all the scene publishing subsets data gets re-generated automatically to match the new context [PYPE-532] +- _(pype)_ we now support project specific publish, load and create plugins [PYPE-740] +- _(ftrack)_ new action that allow archiving/deleting old published versions. User can keep how many of the latest version to keep when the action is ran. [PYPE-748, PYPE-715] +- _(ftrack)_ it is now possible to monitor and restart ftrack event server using ftrack action. [PYPE-658] +- _(pype)_ validator that prevent accidental overwrites of previously published versions. [PYPE-680] +- _(avalon)_ avalon core updated to version 5.6.0 +- _(maya)_ added validator to make sure that relative paths are used when publishing arnold standins. +- _(nukestudio)_ it is now possible to extract and publish audio family from clip in nuke studio [PYPE-682] + +**fix**: +- _(maya)_ maya set framerange button was ignoring handles [PYPE-719] +- _(ftrack)_ sync to avalon was sometime crashing when ran on empty project +- _(nukestudio)_ publishing same shots after they've been previously archived/deleted would result in a crash. [PYPE-737] +- _(nuke)_ slate workflow was breaking in certain scenarios. [PYPE-730] +- _(pype)_ rendering publish workflow has been significantly improved to prevent error resulting from implicit render collection. [PYPE-665, PYPE-746] +- _(pype)_ launching application on a non-synced project resulted in obscure [PYPE-528] +- _(pype)_ missing keys in burnins no longer result in an error. [PYPE-706] +- _(ftrack)_ create folder structure action was sometimes failing for project managers due to wrong permissions. +- _(Nukestudio)_ using `source` in the start frame tag could result in wrong frame range calculation +- _(ftrack)_ sync to avalon action and event have been improved by catching more edge cases and provessing them properly. + + + +## 2.5.0 ## + +_**release date:** 11 Feb 2020_ + +**change:** +- _(pype)_ added many logs for easier debugging +- _(pype)_ review presets can now be separated between 2d and 3d renders [PYPE-693] +- _(pype)_ anatomy module has been greatly improved to allow for more dynamic pulblishing and faster debugging [PYPE-685] +- _(pype)_ avalon schemas have been moved from `pype-config` to `pype` repository, for simplification. [PYPE-670] +- _(ftrack)_ updated to latest ftrack API +- _(ftrack)_ publishing comments now appear in ftrack also as a note on version with customisable category [PYPE-645] +- _(ftrack)_ delete asset/subset action had been improved. It is now able to remove multiple entities and descendants of the selected entities [PYPE-361, PYPS-72] +- _(workfiles)_ added date field to workfiles app [PYPE-603] +- _(maya)_ old deprecated loader have been removed in favour of a single unified reference loader (old scenes will upgrade automatically to the new loader upon opening) [PYPE-633, PYPE-697] +- _(avalon)_ core updated to 5.5.15 [PYPE-671] +- _(nuke)_ library loader is now available in nuke [PYPE-698] + + +**new:** +- _(pype)_ added pype render wrapper to allow rendering on mixed platform farms. [PYPE-634] +- _(pype)_ added `pype launch` command. It let's admin run applications with dynamically built environment based on the given context. [PYPE-634] +- _(pype)_ added support for extracting review sequences with burnins [PYPE-657] +- _(publish)_ users can now set intent next to a comment when publishing. This will then be reflected on an attribute in ftrack. [PYPE-632] +- _(burnin)_ timecode can now be added to burnin +- _(burnin)_ datetime keys can now be added to burnin and anatomy [PYPE-651] +- _(burnin)_ anatomy templates can now be used in burnins. [PYPE=626] +- _(nuke)_ new validator for render resolution +- _(nuke)_ support for attach slate to nuke renders [PYPE-630] +- _(nuke)_ png sequences were added to loaders +- _(maya)_ added maya 2020 compatibility [PYPE-677] +- _(maya)_ ability to publish and load .ASS standin sequences [PYPS-54] +- _(pype)_ thumbnails can now be published and are visible in the loader. `AVALON_THUMBNAIL_ROOT` environment variable needs to be set for this to work [PYPE-573, PYPE-132] +- _(blender)_ base implementation of blender was added with publishing and loading of .blend files [PYPE-612] +- _(ftrack)_ new action for preparing deliveries [PYPE-639] + + +**fix**: +- _(burnin)_ more robust way of finding ffmpeg for burnins. +- _(pype)_ improved UNC paths remapping when sending to farm. +- _(pype)_ float frames sometimes made their way to representation context in database, breaking loaders [PYPE-668] +- _(pype)_ `pype install --force` was failing sometimes [PYPE-600] +- _(pype)_ padding in published files got calculated wrongly sometimes. It is now instead being always read from project anatomy. [PYPE-667] +- _(publish)_ comment publishing was failing in certain situations +- _(ftrack)_ multiple edge case scenario fixes in auto sync and sync-to-avalon action +- _(ftrack)_ sync to avalon now works on empty projects +- _(ftrack)_ thumbnail update event was failing when deleting entities [PYPE-561] +- _(nuke)_ loader applies proper colorspaces from Presets +- _(nuke)_ publishing handles didn't always work correctly [PYPE-686] +- _(maya)_ assembly publishing and loading wasn't working correctly + + + + + +## 2.4.0 ## + +_**release date:** 9 Dec 2019_ + +**change:** +- _(ftrack)_ version to status ftrack event can now be configured from Presets + - based on preset `presets/ftracc/ftrack_config.json["status_version_to_task"]` +- _(ftrack)_ sync to avalon event has been completely re-written. It now supports most of the project management situations on ftrack including moving, renaming and deleting entities, updating attributes and working with tasks. +- _(ftrack)_ sync to avalon action has been also re-writen. It is now much faster (up to 100 times depending on a project structure), has much better logging and reporting on encountered problems, and is able to handle much more complex situations. +- _(ftrack)_ sync to avalon trigger by checking `auto-sync` toggle on ftrack [PYPE-504] +- _(pype)_ various new features in the REST api +- _(pype)_ new visual identity used across pype +- _(pype)_ started moving all requirements to pip installation rather than vendorising them in pype repository. Due to a few yet unreleased packages, this means that pype can temporarily be only installed in the offline mode. + +**new:** +- _(nuke)_ support for publishing gizmos and loading them as viewer processes +- _(nuke)_ support for publishing nuke nodes from backdrops and loading them back +- _(pype)_ burnins can now work with start and end frames as keys + - use keys `{frame_start}`, `{frame_end}` and `{current_frame}` in burnin preset to use them. [PYPS-44,PYPS-73, PYPE-602] +- _(pype)_ option to filter logs by user and level in loggin GUI +- _(pype)_ image family added to standalone publisher [PYPE-574] +- _(pype)_ matchmove family added to standalone publisher [PYPE-574] +- _(nuke)_ validator for comparing arbitrary knobs with values from presets +- _(maya)_ option to force maya to copy textures in the new look publish rather than hardlinking them +- _(pype)_ comments from pyblish GUI are now being added to ftrack version +- _(maya)_ validator for checking outdated containers in the scene +- _(maya)_ option to publish and load arnold standin sequence [PYPE-579, PYPS-54] + +**fix**: +- _(pype)_ burnins were not respecting codec of the input video +- _(nuke)_ lot's of various nuke and nuke studio fixes across the board [PYPS-45] +- _(pype)_ workfiles app is not launching with the start of the app by default [PYPE-569] +- _(ftrack)_ ftrack integration during publishing was failing under certain situations [PYPS-66] +- _(pype)_ minor fixes in REST api +- _(ftrack)_ status change event was crashing when the target status was missing [PYPS-68] +- _(ftrack)_ actions will try to reconnect if they fail for some reason +- _(maya)_ problems with fps mapping when using float FPS values +- _(deadline)_ overall improvements to deadline publishing +- _(setup)_ environment variables are now remapped on the fly based on the platform pype is running on. This fixes many issues in mixed platform environments. + + + +## 2.3.6 # + +_**release date:** 27 Nov 2019_ + +**hotfix**: +- _(ftrack)_ was hiding important debug logo +- _(nuke)_ crashes during workfile publishing +- _(ftrack)_ event server crashes because of signal problems +- _(muster)_ problems with muster render submissions +- _(ftrack)_ thumbnail update event syntax errors + + +## 2.3.0 ## +_release date: 6 Oct 2019_ + +**new**: +- _(maya)_ support for yeti rigs and yeti caches +- _(maya)_ validator for comparing arbitrary attributes against ftrack +- _(pype)_ burnins can now show current date and time +- _(muster)_ pools can now be set in render globals in maya +- _(pype)_ Rest API has been implemented in beta stage +- _(nuke)_ LUT loader has been added +- _(pype)_ rudimentary user module has been added as preparation for user management +- _(pype)_ a simple logging GUI has been added to pype tray +- _(nuke)_ nuke can now bake input process into mov +- _(maya)_ imported models now have selection handle displayed by defaulting +- _(avalon)_ it's is now possible to load multiple assets at once using loader +- _(maya)_ added ability to automatically connect yeti rig to a mesh upon loading + +**changed**: +- _(ftrack)_ event server now runs two parallel processes and is able to keep queue of events to process. +- _(nuke)_ task name is now added to all rendered subsets +- _(pype)_ adding more families to standalone publisher +- _(pype)_ standalone publisher now uses pyblish-lite +- _(pype)_ standalone publisher can now create review quicktimes +- _(ftrack)_ queries to ftrack were sped up +- _(ftrack)_ multiple ftrack action have been deprecated +- _(avalon)_ avalon upstream has been updated to 5.5.0 +- _(nukestudio)_ published transforms can now be animated +- + +**fix**: +- _(maya)_ fps popup button didn't work in some cases +- _(maya)_ geometry instances and references in maya were losing shader assignments +- _(muster)_ muster rendering templates were not working correctly +- _(maya)_ arnold tx texture conversion wasn't respecting colorspace set by the artist +- _(pype)_ problems with avalon db sync +- _(maya)_ ftrack was rounding FPS making it inconsistent +- _(pype)_ wrong icon names in Creator +- _(maya)_ scene inventory wasn't showing anything if representation was removed from database after it's been loaded to the scene +- _(nukestudio)_ multiple bugs squashed +- _(loader)_ loader was taking long time to show all the loading action when first launcher in maya + +## 2.2.0 ## +_release date: 8 Sept 2019_ + +**new**: +- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts +- _(nuke)_ option to choose deadline chunk size on write nodes +- _(nukestudio)_ added option to publish soft effects (subTrackItems) from NukeStudio as subsets including LUT files. these can then be loaded in nuke or NukeStudio +- _(nuke)_ option to build nuke script from previously published latest versions of plate and render subsets. +- _(nuke)_ nuke writes now have deadline tab. +- _(ftrack)_ Prepare Project action can now be used for creating the base folder structure on disk and in ftrack, setting up all the initial project attributes and it automatically prepares `pype_project_config` folder for the given project. +- _(clockify)_ Added support for time tracking in clockify. This currently in addition to ftrack time logs, but does not completely replace them. +- _(pype)_ any attributes in Creator and Loader plugins can now be customised using pype preset system + +**changed**: +- nukestudio now uses workio API for workfiles +- _(maya)_ "FIX FPS" prompt in maya now appears in the middle of the screen +- _(muster)_ can now be configured with custom templates +- _(pype)_ global publishing plugins can now be configured using presets as well as host specific ones + + +**fix**: +- wrong version retrieval from path in certain scenarios +- nuke reset resolution wasn't working in certain scenarios + +## 2.1.0 ## +_release date: 6 Aug 2019_ + +A large cleanup release. Most of the change are under the hood. + +**new**: +- _(pype)_ add customisable workflow for creating quicktimes from renders or playblasts +- _(pype)_ Added configurable option to add burnins to any generated quicktimes +- _(ftrack)_ Action that identifies what machines pype is running on. +- _(system)_ unify subprocess calls +- _(maya)_ add audio to review quicktimes +- _(nuke)_ add crop before write node to prevent overscan problems in ffmpeg +- **Nuke Studio** publishing and workfiles support +- **Muster** render manager support +- _(nuke)_ Framerange, FPS and Resolution are set automatically at startup +- _(maya)_ Ability to load published sequences as image planes +- _(system)_ Ftrack event that sets asset folder permissions based on task assignees in ftrack. +- _(maya)_ Pyblish plugin that allow validation of maya attributes +- _(system)_ added better startup logging to tray debug, including basic connection information +- _(avalon)_ option to group published subsets to groups in the loader +- _(avalon)_ loader family filters are working now + +**changed**: +- change multiple key attributes to unify their behaviour across the pipeline + - `frameRate` to `fps` + - `startFrame` to `frameStart` + - `endFrame` to `frameEnd` + - `fstart` to `frameStart` + - `fend` to `frameEnd` + - `handle_start` to `handleStart` + - `handle_end` to `handleEnd` + - `resolution_width` to `resolutionWidth` + - `resolution_height` to `resolutionHeight` + - `pixel_aspect` to `pixelAspect` + +- _(nuke)_ write nodes are now created inside group with only some attributes editable by the artist +- rendered frames are now deleted from temporary location after their publishing is finished. +- _(ftrack)_ RV action can now be launched from any entity +- after publishing only refresh button is now available in pyblish UI +- added context instance pyblish-lite so that artist knows if context plugin fails +- _(avalon)_ allow opening selected files using enter key +- _(avalon)_ core updated to v5.2.9 with our forked changes on top + +**fix**: +- faster hierarchy retrieval from db +- _(nuke)_ A lot of stability enhancements +- _(nuke studio)_ A lot of stability enhancements +- _(nuke)_ now only renders a single write node on farm +- _(ftrack)_ pype would crash when launcher project level task +- work directory was sometimes not being created correctly +- major pype.lib cleanup. Removing of unused functions, merging those that were doing the same and general house cleaning. +- _(avalon)_ subsets in maya 2019 weren't behaving correctly in the outliner + + +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/HISTORY.md b/HISTORY.md index 4b5463c924..d60bd7b0c7 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,3 @@ -# Pype changelog # -Welcome to pype changelog - ## 2.11.0 ## From 431a52689ebdd91e7c1047a815da3a1c277b5f1a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 10:25:34 +0200 Subject: [PATCH 465/580] discard changes fix --- .../config_setting/config_setting/widgets/inputs.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4a71f0380c..afdcc207cf 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -306,14 +306,12 @@ class InputObject(ConfigObject): def discard_changes(self): self._is_overriden = self._was_overriden - if ( - self.is_overidable - and self._was_overriden - and self.override_value is not NOT_SET - ): - self.set_value(self.override_value) + self._has_studio_override = self._had_studio_override + if self.is_overidable: + if self._was_overriden and self.override_value is not NOT_SET: + self.set_value(self.override_value) else: - if self.has_studio_override: + if self._had_studio_override: self.set_value(self.studio_value) else: self.set_value(self.default_value) From 729b474f20332f3d5ebc7132b9b0675ade7c1662 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 10:39:15 +0200 Subject: [PATCH 466/580] restart states on value updates --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index afdcc207cf..c9c40f251c 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -201,6 +201,7 @@ class ConfigObject(AbstractConfigObject): class InputObject(ConfigObject): def update_default_values(self, parent_values): + self._state = None value = NOT_SET if self._as_widget: value = parent_values @@ -218,6 +219,7 @@ class InputObject(ConfigObject): self.set_value(value) def update_studio_values(self, parent_values): + self._state = None value = NOT_SET if self._as_widget: value = parent_values From 50aea9f15061129cb0fcdeb3cb6d0db252b11229 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 10:40:01 +0200 Subject: [PATCH 467/580] apply_overrides works for widget inputs --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c9c40f251c..945ad0f255 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -285,7 +285,9 @@ class InputObject(ConfigObject): self._is_modified = False self._state = None - if parent_values is NOT_SET or self.key not in parent_values: + if self._as_widget: + override_value = parent_values + elif parent_values is NOT_SET or self.key not in parent_values: override_value = NOT_SET else: override_value = parent_values[self.key] From 6ed724d040bf85fa0dadbcc64699caa65fc124ec Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 10:56:08 +0200 Subject: [PATCH 468/580] state for disabled widgets is different --- .../config_setting/widgets/inputs.py | 107 +++++++++++------- 1 file changed, 65 insertions(+), 42 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 945ad0f255..eea33d3ef6 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -412,12 +412,15 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.checkbox.setChecked(value) def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) if self._state == state: return @@ -486,12 +489,15 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.input_field.setValue(value) def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) if self._state == state: return @@ -563,12 +569,15 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.text_input.setText(value) def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) if self._state == state: return @@ -637,12 +646,16 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): super(PathInput, self).focusOutEvent(event) def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + if self._state == state: return @@ -776,12 +789,16 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): return super(RawJsonWidget, self)._on_value_change(*args, **kwargs) def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + if self._state == state: return @@ -1036,12 +1053,15 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.update_style() def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) if self._state == state: return @@ -1328,12 +1348,15 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.update_style() def update_style(self): - state = self.style_state( - self.has_studio_override, - self.is_invalid, - self.is_overriden, - self.is_modified - ) + if self._as_widget and not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) if self._state == state: return From c55d2ee91f589522662e21b8e34c66efa91f5d20 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 10:56:38 +0200 Subject: [PATCH 469/580] list items has apply_overrides and update_studio_values --- .../config_setting/config_setting/widgets/inputs.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index eea33d3ef6..ae55679d73 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -902,6 +902,12 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def mouseReleaseEvent(self, event): return QtWidgets.QWidget.mouseReleaseEvent(self, event) + def update_studio_values(self, value): + self.value_input.update_studio_values(value) + + def apply_overrides(self, value): + self.value_input.apply_overrides(value) + class ListWidget(QtWidgets.QWidget, InputObject): value_changed = QtCore.Signal(object) @@ -1002,7 +1008,11 @@ class ListWidget(QtWidgets.QWidget, InputObject): # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` if value is not None: - item_widget.value_input.update_studio_values(value) + if self._is_overriden: + item_widget.apply_overrides(value) + else: + item_widget.update_studio_values(value) + self.hierarchical_style_update() else: self._on_value_change() self.updateGeometry() From 1164d0b9880716c231d05df679be21e7966d15e9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:33:47 +0200 Subject: [PATCH 470/580] moved setting attributes much earlier --- pype/tools/config_setting/config_setting/widgets/inputs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ae55679d73..7096f70ecd 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -228,14 +228,15 @@ class InputObject(ConfigObject): self.studio_value = value if value is not NOT_SET: - self.set_value(value) self._has_studio_override = True + self._had_studio_override = True + self.set_value(value) else: - self.set_value(self.default_value) self._has_studio_override = False + self._had_studio_override = False + self.set_value(self.default_value) - self._had_studio_override = bool(self._has_studio_override) self._is_modified = False def _on_value_change(self, item=None): From c210b317042ae2dbab6e12b3fb027dde6c363330 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:34:05 +0200 Subject: [PATCH 471/580] is_modified cares if is_overridable or not --- .../config_setting/config_setting/widgets/inputs.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 7096f70ecd..8aebb6dd5f 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -56,11 +56,13 @@ class ConfigObject(AbstractConfigObject): @property def is_modified(self): """Has object any changes that require saving.""" - return ( - self._is_modified - or (self.was_overriden != self.is_overriden) - or (self.has_studio_override != self.had_studio_override) - ) + if self._is_modified: + return True + + if self.is_overidable: + return self.was_overriden != self.is_overriden + else: + return self.has_studio_override != self.had_studio_override @property def is_overriden(self): From adc086ba0f14ffc8f41c9404f70349e59874dfe2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:34:29 +0200 Subject: [PATCH 472/580] method apply_overrides moved --- .../config_setting/widgets/inputs.py | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8aebb6dd5f..a7e09abb6d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -239,7 +239,32 @@ class InputObject(ConfigObject): self._had_studio_override = False self.set_value(self.default_value) + def apply_overrides(self, parent_values): self._is_modified = False + self._state = None + self._had_studio_override = bool(self._has_studio_override) + if self._as_widget: + override_value = parent_values + elif parent_values is NOT_SET or self.key not in parent_values: + override_value = NOT_SET + else: + override_value = parent_values[self.key] + + self.override_value = override_value + + if override_value is NOT_SET: + self._is_overriden = False + self._was_overriden = False + if self.has_studio_override: + value = self.studio_value + else: + value = self.default_value + else: + self._is_overriden = True + self._was_overriden = True + value = override_value + + self.set_value(value) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -284,33 +309,6 @@ class InputObject(ConfigObject): self._is_overriden = False self._is_modified = False - def apply_overrides(self, parent_values): - self._is_modified = False - self._state = None - - if self._as_widget: - override_value = parent_values - elif parent_values is NOT_SET or self.key not in parent_values: - override_value = NOT_SET - else: - override_value = parent_values[self.key] - - self.override_value = override_value - - if override_value is NOT_SET: - self._is_overriden = False - self._was_overriden = False - if self.has_studio_override: - value = self.studio_value - else: - value = self.default_value - else: - self._is_overriden = True - self._was_overriden = True - value = override_value - - self.set_value(value) - def discard_changes(self): self._is_overriden = self._was_overriden self._has_studio_override = self._had_studio_override From 2e9ef743536ed41be674e8cb2aaa7e4499d15947 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:36:43 +0200 Subject: [PATCH 473/580] as widget input does not care about overrides --- .../config_setting/widgets/inputs.py | 85 ++++++++++++++++--- 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index a7e09abb6d..81218855c9 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -413,8 +413,16 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): self.checkbox.setChecked(value) def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -490,8 +498,16 @@ class NumberWidget(QtWidgets.QWidget, InputObject): self.input_field.setValue(value) def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -570,8 +586,16 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.text_input.setText(value) def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -579,6 +603,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.is_overriden, self.is_modified ) + if self._state == state: return @@ -647,8 +672,16 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): super(PathInput, self).focusOutEvent(event) def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -790,8 +823,16 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): return super(RawJsonWidget, self)._on_value_change(*args, **kwargs) def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -1064,8 +1105,16 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.update_style() def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -1359,8 +1408,16 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.update_style() def update_style(self): - if self._as_widget and not self.isEnabled(): - state = self.style_state(False, False, False, False) + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, From 78dc9b1c3bedcc049d1904c0ca2b91ab5dbbfc08 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:37:34 +0200 Subject: [PATCH 474/580] list has updating default values --- .../config_setting/config_setting/widgets/inputs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 81218855c9..3f59f751e5 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -204,6 +204,8 @@ class ConfigObject(AbstractConfigObject): class InputObject(ConfigObject): def update_default_values(self, parent_values): self._state = None + self._is_modified = False + value = NOT_SET if self._as_widget: value = parent_values @@ -222,6 +224,8 @@ class InputObject(ConfigObject): def update_studio_values(self, parent_values): self._state = None + self._is_modified = False + value = NOT_SET if self._as_widget: value = parent_values @@ -944,6 +948,9 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def mouseReleaseEvent(self, event): return QtWidgets.QWidget.mouseReleaseEvent(self, event) + def update_default_values(self, value): + self.value_input.update_default_values(value) + def update_studio_values(self, value): self.value_input.update_studio_values(value) @@ -1050,7 +1057,9 @@ class ListWidget(QtWidgets.QWidget, InputObject): # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` if value is not None: - if self._is_overriden: + if not self._has_studio_override: + item_widget.update_default_values(value) + elif self._is_overriden: item_widget.apply_overrides(value) else: item_widget.update_studio_values(value) From 442e5ccfd3099524f9c204d200905278e531202d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:41:43 +0200 Subject: [PATCH 475/580] fixed any_parent_is_group attribute in anatomy inputs --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 43146f7442..525e1bcd88 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -46,7 +46,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self._child_state = None self._state = None - self.any_parent_is_group = False + self._any_parent_is_group = False self.root_widget = RootsWidget(self) self.templates_widget = TemplatesWidget(self) @@ -190,7 +190,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._multiroot_state = None self._is_group = True - self.any_parent_is_group = False + self._any_parent_is_group = False self.global_is_multiroot = False self.was_multiroot = NOT_SET @@ -492,7 +492,7 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): self._state = None self._is_group = True - self.any_parent_is_group = False + self._any_parent_is_group = False self.key = "templates" body_widget = ExpandingWidget("Templates", self) From e8459167a8aaa4626e7d5c0e21ae8ad881584524 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 11:41:51 +0200 Subject: [PATCH 476/580] abstracted updating methods --- .../config_setting/widgets/widgets.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index d803624850..d7631e6fea 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -234,6 +234,21 @@ class AbstractConfigObject: ) return super(AbstractConfigObject, self).__getattribute__(name) + def update_default_values(self, parent_values): + raise NotImplementedError( + "{} does not have implemented `update_default_values`".format(self) + ) + + def update_studio_values(self, parent_values): + raise NotImplementedError( + "{} does not have implemented `update_studio_values`".format(self) + ) + + def apply_overrides(self, parent_values): + raise NotImplementedError( + "{} does not have implemented `apply_overrides`".format(self) + ) + @property def is_modified(self): """Has object any changes that require saving.""" From 36fff023017c835927b5b0af256aa9a6b5d465cb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 12:00:43 +0200 Subject: [PATCH 477/580] PathWIdget has update values methods --- .../config_setting/widgets/inputs.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 3f59f751e5..8e5e8c2a5d 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2187,6 +2187,49 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.setFocusProxy(self.input_fields[0]) self.content_layout.addWidget(proxy_widget) + def update_default_values(self, parent_values): + self._state = None + self._child_state = None + self._is_modified = False + + value = NOT_SET + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + if value is NOT_SET: + raise ValueError( + "Default value is not set. This is implementation BUG." + ) + + self.default_value = value + self._has_studio_override = False + self._had_studio_override = False + self.set_value(value) + + def update_studio_values(self, parent_values): + self._state = None + self._child_state = None + self._is_modified = False + + value = NOT_SET + if self._as_widget: + value = parent_values + elif parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) + + self.studio_value = value + if value is not NOT_SET: + self._has_studio_override = True + self._had_studio_override = True + self.set_value(value) + + else: + self._has_studio_override = False + self._had_studio_override = False + self.set_value(self.default_value) + def apply_overrides(self, parent_values): self._is_modified = False self._state = None From 42dcad9655e03655e0724a2e36f6eb8ce203ef9c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 12:00:59 +0200 Subject: [PATCH 478/580] fixed update defaults in anatomy widget --- .../config_setting/widgets/anatomy_inputs.py | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 525e1bcd88..4756ac25a4 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -75,7 +75,15 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.value_changed.connect(self._on_value_change) - def update_default_values(self, value): + def update_default_values(self, parent_values): + self._state = None + self._child_state = None + + if isinstance(parent_values, dict): + value = parent_values.get(self.key, NOT_SET) + else: + value = NOT_SET + self.root_widget.update_default_values(value) self.templates_widget.update_default_values(value) @@ -280,11 +288,17 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(is_multiroot) if is_multiroot: - self.singleroot_widget.update_studio_values(NOT_SET) - self.multiroot_widget.update_studio_values(value) + for _value in value.values(): + singleroot_value = _value + break + + multiroot_value = value else: - self.singleroot_widget.update_studio_values(value) - self.multiroot_widget.update_studio_values(NOT_SET) + singleroot_value = value + multiroot_value = {"": value} + + self.singleroot_widget.update_default_values(singleroot_value) + self.multiroot_widget.update_default_values(multiroot_value) def update_studio_values(self, parent_values): self._state = None From c31267906fc7fe5ac7427b5012e7a650936120fd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 12:08:17 +0200 Subject: [PATCH 479/580] added studio overrides to anatomy inputs --- .../config_setting/widgets/anatomy_inputs.py | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 4756ac25a4..141feee61d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -123,10 +123,14 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.value_changed.emit(self) def update_style(self, is_overriden=None): + child_has_studio_override = self.child_has_studio_override child_modified = self.child_modified child_invalid = self.child_invalid child_state = self.style_state( - child_invalid, self.child_overriden, child_modified + child_has_studio_override, + child_invalid, + self.child_overriden, + child_modified ) if child_state: child_state = "child-{}".format(child_state) @@ -143,6 +147,13 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.hierarchical_style_update() self.update_style() + @property + def child_has_studio_override(self): + return ( + self.root_widget.child_has_studio_override + or self.templates_widget.child_has_studio_override + ) + @property def child_modified(self): return ( @@ -320,6 +331,13 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.was_multiroot = is_multiroot self.set_multiroot(is_multiroot) + if value is NOT_SET: + self._has_studio_override = False + self._had_studio_override = False + else: + self._has_studio_override = True + self._had_studio_override = True + if is_multiroot: self.singleroot_widget.update_studio_values(NOT_SET) self.multiroot_widget.update_studio_values(value) @@ -368,6 +386,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def update_style(self): multiroot_state = self.style_state( + self.has_studio_override, False, self.is_overriden, self.was_multiroot != self.is_multiroot @@ -378,7 +397,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._multiroot_state = multiroot_state state = self.style_state( - self.is_invalid, self.is_overriden, self.is_modified + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified ) if self._state == state: return @@ -433,6 +455,13 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._on_value_change() + @property + def child_has_studio_override(self): + if self.is_multiroot: + return self.multiroot_widget.child_has_studio_override + else: + return self.singleroot_widget.child_has_studio_override + @property def child_modified(self): if self.is_multiroot: @@ -549,7 +578,10 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def update_style(self): state = self.style_state( - self.child_invalid, self.child_overriden, self.child_modified + self.has_studio_override, + self.child_invalid, + self.child_overriden, + self.child_modified ) if self._state == state: return @@ -577,6 +609,10 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def is_overriden(self): return self._is_overriden + @property + def child_has_studio_override(self): + return self.value_input.child_has_studio_override + @property def child_modified(self): return self.value_input.child_modified From c618cd0b4421a32412fee2806a93db72673cb1cc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 16:01:23 +0200 Subject: [PATCH 480/580] modified pathwidget --- .../config_setting/widgets/inputs.py | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 8e5e8c2a5d..c32d45246b 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1197,7 +1197,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.key_input.textChanged.connect(self._on_value_change) self.value_input.value_changed.connect(self._on_value_change) - self.origin_key = self.key_value() + self.origin_key = NOT_SET def key_value(self): return self.key_input.text() @@ -1214,6 +1214,11 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): self.update_style() self.value_changed.emit(self) + def update_default_values(self, key, value): + self.origin_key = key + self.key_input.setText(key) + self.value_input.update_default_values(value) + def update_studio_values(self, key, value): self.origin_key = key self.key_input.setText(key) @@ -1488,7 +1493,9 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): # Set value if entered value is not None # else (when add button clicked) trigger `_on_value_change` if value is not None and key is not None: - if self._is_overriden: + if not self._has_studio_override: + item_widget.update_default_values(key, value) + elif self._is_overriden: item_widget.apply_overrides(key, value) else: item_widget.update_studio_values(key, value) @@ -2206,7 +2213,12 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.default_value = value self._has_studio_override = False self._had_studio_override = False - self.set_value(value) + + if not self.multiplatform: + self.input_fields[0].update_studio_values(value) + else: + for input_field in self.input_fields: + input_field.update_studio_values(value) def update_studio_values(self, parent_values): self._state = None @@ -2223,12 +2235,16 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): if value is not NOT_SET: self._has_studio_override = True self._had_studio_override = True - self.set_value(value) - else: self._has_studio_override = False self._had_studio_override = False - self.set_value(self.default_value) + value = self.default_value + + if not self.multiplatform: + self.input_fields[0].update_studio_values(value) + else: + for input_field in self.input_fields: + input_field.update_studio_values(value) def apply_overrides(self, parent_values): self._is_modified = False From 3e5b0cf82f0a547d0f2668d455e5357d02b4eafa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 16:01:41 +0200 Subject: [PATCH 481/580] fixed saving in bases --- .../config_setting/widgets/base.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index a143e584dd..a8bdd9b1a4 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -429,14 +429,15 @@ class ProjectWidget(QtWidgets.QWidget): self._save_overrides() def _save_overrides(self): - _data = {} + data = {} for item in self.input_fields: value, is_group = item.overrides() if value is not lib.NOT_SET: - _data.update(value) + data.update(value) - data = _data.get("project") or {} - output_data = lib.convert_gui_data_to_overrides(data) + output_data = lib.convert_gui_data_to_overrides( + data.get("project") or {} + ) overrides_json_path = path_to_project_overrides( self.project_name @@ -452,21 +453,27 @@ class ProjectWidget(QtWidgets.QWidget): self._on_project_change() def _save_defaults(self): - _data = {} + data = {} for input_field in self.input_fields: value, is_group = input_field.studio_overrides() if value is not lib.NOT_SET: - _data.update(value) + data.update(value) - output = lib.convert_gui_data_to_overrides(_data.get("project", {})) + output_data = lib.convert_gui_data_to_overrides( + data.get("project", {}) + ) dirpath = os.path.dirname(PROJECT_CONFIGURATIONS_PATH) if not os.path.exists(dirpath): os.makedirs(dirpath) print("Saving data to:", PROJECT_CONFIGURATIONS_PATH) - with open(PROJECT_CONFIGURATIONS_PATH, "w") as file_stream: - json.dump(output, file_stream, indent=4) + try: + with open(PROJECT_CONFIGURATIONS_PATH, "w") as file_stream: + json.dump(output_data, file_stream, indent=4) + except Exception as exc: + print(output_data) + raise self._update_values() From 25f3d91b6d6a60eeee3b0eaad0c3258a093b4ec0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 16:01:53 +0200 Subject: [PATCH 482/580] fixed anatomy inputs filling --- .../config_setting/widgets/anatomy_inputs.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 141feee61d..e5f0dd5990 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -1,7 +1,7 @@ from Qt import QtWidgets, QtCore from .widgets import ExpandingWidget from .inputs import ConfigObject, ModifiableDict, PathWidget, RawJsonWidget -from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET +from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET, METADATA_KEY class AnatomyWidget(QtWidgets.QWidget, ConfigObject): @@ -192,6 +192,17 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): output.update(self.templates_widget.config_value()) return output + def studio_overrides(self): + if ( + self.root_widget.child_has_studio_override + or self.templates_widget.child_has_studio_override + ): + groups = [self.root_widget.key, self.templates_widget.key] + value = self.config_value() + value[self.key][METADATA_KEY] = {"groups": groups} + return value, True + return NOT_SET, False + def config_value(self): return {self.key: self.item_value()} @@ -339,11 +350,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._had_studio_override = True if is_multiroot: - self.singleroot_widget.update_studio_values(NOT_SET) self.multiroot_widget.update_studio_values(value) else: self.singleroot_widget.update_studio_values(value) - self.multiroot_widget.update_studio_values(NOT_SET) def apply_overrides(self, parent_values): # Make sure this is set to False @@ -371,13 +380,11 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if is_multiroot: self._is_overriden = parent_values is not NOT_SET self._was_overriden = bool(self._is_overriden) - self.singleroot_widget.apply_overrides(NOT_SET) self.multiroot_widget.apply_overrides(parent_values) else: self._is_overriden = value is not NOT_SET self._was_overriden = bool(self._is_overriden) self.singleroot_widget.apply_overrides(value) - self.multiroot_widget.apply_overrides(NOT_SET) def hierarchical_style_update(self): self.singleroot_widget.hierarchical_style_update() From f2372c27b9e873b0008a8d0484888ba73ff5f4b2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 17:02:04 +0200 Subject: [PATCH 483/580] fixed roots input statuses --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index e5f0dd5990..bf2477bd7c 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -292,6 +292,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def update_default_values(self, parent_values): self._state = None self._multiroot_state = None + self._is_modified = False if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) @@ -309,6 +310,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.was_multiroot = is_multiroot self.set_multiroot(is_multiroot) + self._has_studio_override = False + self._had_studio_override = False if is_multiroot: for _value in value.values(): singleroot_value = _value @@ -325,6 +328,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def update_studio_values(self, parent_values): self._state = None self._multiroot_state = None + self._is_modified = False if isinstance(parent_values, dict): value = parent_values.get(self.key, NOT_SET) @@ -597,7 +601,7 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): child_state = "child-{}".format(state) else: child_state = "" - print(child_state) + self.body_widget.side_line_widget.setProperty("state", child_state) self.body_widget.side_line_widget.style().polish( self.body_widget.side_line_widget From 5aa922026d338c487a13c0e12642e47741319511 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 17:18:39 +0200 Subject: [PATCH 484/580] templates widget has value_changed signal --- .../config_setting/widgets/anatomy_inputs.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index bf2477bd7c..404fe589d3 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -74,6 +74,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.label_widget = body_widget.label_widget self.root_widget.value_changed.connect(self._on_value_change) + self.templates_widget.value_changed.connect(self._on_value_change) def update_default_values(self, parent_values): self._state = None @@ -538,6 +539,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): class TemplatesWidget(QtWidgets.QWidget, ConfigObject): + value_changed = QtCore.Signal(object) + def __init__(self, parent): super(TemplatesWidget, self).__init__(parent) @@ -571,6 +574,13 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): layout.addWidget(body_widget) + self.value_input.value_changed.connect(self._on_value_change) + + def _on_value_change(self, item): + self.update_style() + + self.value_changed.emit(self) + def update_default_values(self, values): self._state = None self.value_input.update_default_values(values) @@ -620,6 +630,10 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def is_overriden(self): return self._is_overriden + @property + def has_studio_override(self): + return self.value_input.has_studio_override + @property def child_has_studio_override(self): return self.value_input.child_has_studio_override From 5928990cb3159395bd7521a0335e256fd3d21a32 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 17:18:51 +0200 Subject: [PATCH 485/580] just small modification --- pype/tools/config_setting/config_setting/widgets/inputs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c32d45246b..05fd9e8aab 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -816,8 +816,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def update_studio_values(self, parent_values): self._is_invalid = self.text_input.has_invalid_value() - - super(RawJsonWidget, self).update_studio_values(parent_values) + return super(RawJsonWidget, self).update_studio_values(parent_values) def set_value(self, value): self.text_input.set_value(value) From d020503f53e01983b4184ed2c5fc6b5418f50e29 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 17:53:41 +0200 Subject: [PATCH 486/580] ModifiableDict has fixed invalid state --- .../config_setting/config_setting/widgets/inputs.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 05fd9e8aab..5763738351 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1337,6 +1337,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if as_widget: main_layout.addWidget(content_widget) + body_widget = None else: body_widget = ExpandingWidget(input_data["label"], self) main_layout.addWidget(body_widget) @@ -1353,6 +1354,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if expanded: body_widget.toggle_content() + self.body_widget = body_widget self.content_widget = content_widget self.content_layout = content_layout @@ -1427,7 +1429,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): else: state = self.style_state( False, - self._is_invalid, + self.is_invalid, False, self._is_modified ) @@ -1446,8 +1448,11 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): else: child_state = "" - self.setProperty("state", child_state) - self.style().polish(self) + if self.body_widget: + self.body_widget.side_line_widget.setProperty("state", child_state) + self.body_widget.side_line_widget.style().polish( + self.body_widget.side_line_widget + ) if not self._as_widget: self.label_widget.setProperty("state", state) From 139c1b50cf417cd2ac313f9bb77f74422ff57f32 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 18:02:07 +0200 Subject: [PATCH 487/580] fixed style updates for root widget --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 404fe589d3..efba588692 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -410,7 +410,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): state = self.style_state( self.has_studio_override, - self.is_invalid, + self.child_invalid, self.is_overriden, self.is_modified ) @@ -453,6 +453,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): or self.child_modified ) + self.update_style() + self.value_changed.emit(self) def set_multiroot(self, is_multiroot=None): From a2d3072fd6c5b52b6ea10e6f8484b7e6a1ff2643 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 10 Sep 2020 18:02:55 +0200 Subject: [PATCH 488/580] extract render was duplicating extract review --- .../publish/integrate_ftrack_instances.py | 10 +++- .../plugins/harmony/publish/extract_render.py | 59 +++---------------- 2 files changed, 17 insertions(+), 52 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py index 9ef82cbc4b..2646dc90cc 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py @@ -88,8 +88,14 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): instance.data["frameEnd"] - instance.data["frameStart"] ) - if not comp.get('fps'): - comp['fps'] = instance.context.data['fps'] + fps = comp.get('fps') + if fps is None: + fps = instance.data.get( + "fps", instance.context.data['fps'] + ) + + comp['fps'] = fps + location = self.get_ftrack_location( 'ftrack.server', ft_session ) diff --git a/pype/plugins/harmony/publish/extract_render.py b/pype/plugins/harmony/publish/extract_render.py index 45b52e0307..6486c13d70 100644 --- a/pype/plugins/harmony/publish/extract_render.py +++ b/pype/plugins/harmony/publish/extract_render.py @@ -4,6 +4,7 @@ import subprocess import pyblish.api from avalon import harmony +import pype.lib import clique @@ -43,6 +44,8 @@ class ExtractRender(pyblish.api.InstancePlugin): frame_start = result[4] frame_end = result[5] audio_path = result[6] + instance.data["audio"] = [{"filename": audio_path}] + instance.data["fps"] = frame_rate # Set output path to temp folder. path = tempfile.mkdtemp() @@ -87,17 +90,13 @@ class ExtractRender(pyblish.api.InstancePlugin): if len(list(col)) > 1: collection = col else: - # assert len(collections) == 1, ( - # "There should only be one image sequence in {}. Found: {}".format( - # path, len(collections) - # ) - # ) collection = collections[0] # Generate thumbnail. thumbnail_path = os.path.join(path, "thumbnail.png") + ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") args = [ - "ffmpeg", "-y", + ffmpeg_path, "-y", "-i", os.path.join(path, list(collections[0])[0]), "-vf", "scale=300:-1", "-vframes", "1", @@ -117,57 +116,17 @@ class ExtractRender(pyblish.api.InstancePlugin): self.log.debug(output.decode("utf-8")) - # Generate mov. - mov_path = os.path.join(path, instance.data["name"] + ".mov") - if os.path.isfile(audio_path): - args = [ - "ffmpeg", "-y", - "-i", audio_path, - "-i", - os.path.join(path, collection.head + "%04d" + collection.tail), - mov_path - ] - else: - args = [ - "ffmpeg", "-y", - "-i", - os.path.join(path, collection.head + "%04d" + collection.tail), - mov_path - ] - - process = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - stdin=subprocess.PIPE - ) - - output = process.communicate()[0] - - if process.returncode != 0: - raise ValueError(output.decode("utf-8")) - - self.log.debug(output.decode("utf-8")) - # Generate representations. extension = collection.tail[1:] representation = { "name": extension, "ext": extension, "files": list(collection), - "stagingDir": path - } - movie = { - "name": "mov", - "ext": "mov", - "files": os.path.basename(mov_path), "stagingDir": path, - "frameStart": frame_start, - "frameEnd": frame_end, - "fps": frame_rate, - "preview": True, - "tags": ["review", "ftrackreview"] + "tags": ["review"], + "fps": frame_rate } + thumbnail = { "name": "thumbnail", "ext": "png", @@ -175,7 +134,7 @@ class ExtractRender(pyblish.api.InstancePlugin): "stagingDir": path, "tags": ["thumbnail"] } - instance.data["representations"] = [representation, movie, thumbnail] + instance.data["representations"] = [representation, thumbnail] # Required for extract_review plugin (L222 onwards). instance.data["frameStart"] = frame_start From 81b328977d4ef701671c5567b657c1c92ac51015 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 10 Sep 2020 20:54:11 +0200 Subject: [PATCH 489/580] allow burnin in harmony --- pype/plugins/global/publish/extract_burnin.py | 3 ++- pype/plugins/harmony/publish/extract_render.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index dedfd98979..4443cfe223 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -25,7 +25,8 @@ class ExtractBurnin(pype.api.Extractor): "shell", "nukestudio", "premiere", - "standalonepublisher" + "standalonepublisher", + "harmony" ] optional = True diff --git a/pype/plugins/harmony/publish/extract_render.py b/pype/plugins/harmony/publish/extract_render.py index 6486c13d70..70dceb9ca2 100644 --- a/pype/plugins/harmony/publish/extract_render.py +++ b/pype/plugins/harmony/publish/extract_render.py @@ -44,7 +44,8 @@ class ExtractRender(pyblish.api.InstancePlugin): frame_start = result[4] frame_end = result[5] audio_path = result[6] - instance.data["audio"] = [{"filename": audio_path}] + if audio_path: + instance.data["audio"] = [{"filename": audio_path}] instance.data["fps"] = frame_rate # Set output path to temp folder. From c8a6837d8927c0b251a5c3c63ecbf90d2d935c53 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 21:30:25 +0200 Subject: [PATCH 490/580] removed activate_project and replaced with setting Session attribute --- pype/tools/standalonepublish/widgets/widget_asset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/standalonepublish/widgets/widget_asset.py b/pype/tools/standalonepublish/widgets/widget_asset.py index c468c9627b..6f041a535f 100644 --- a/pype/tools/standalonepublish/widgets/widget_asset.py +++ b/pype/tools/standalonepublish/widgets/widget_asset.py @@ -240,7 +240,7 @@ class AssetWidget(QtWidgets.QWidget): self.combo_projects.clear() if len(projects) > 0: self.combo_projects.addItems(projects) - self.dbcon.activate_project(projects[0]) + self.dbcon.Session["AVALON_PROJECT"] = projects[0] def on_project_change(self): projects = list() @@ -248,7 +248,7 @@ class AssetWidget(QtWidgets.QWidget): projects.append(project['name']) project_name = self.combo_projects.currentText() if project_name in projects: - self.dbcon.activate_project(project_name) + self.dbcon.Session["AVALON_PROJECT"] = project_name self.refresh() def _refresh_model(self): From b161dda7adea6a43b2e58f99a29823dddd7ea255 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 11:27:13 +0200 Subject: [PATCH 491/580] fix config loading --- pype/configurations/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/configurations/config.py b/pype/configurations/config.py index e19a27f33c..ed7104427f 100644 --- a/pype/configurations/config.py +++ b/pype/configurations/config.py @@ -14,7 +14,7 @@ def system_configurations(): def project_configurations(project_name): - default_values = default_configuration() + default_values = default_configuration()["project_configurations"] studio_values = studio_project_configurations() studio_overrides = apply_overrides(default_values, studio_values) From 2f87b60f2e2dd967a465682f9420a030564bcb99 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 11:27:44 +0200 Subject: [PATCH 492/580] add develop button to save as default --- pype/tools/config_setting/__main__.py | 3 ++- .../config_setting/widgets/base.py | 23 +++++++++++++++++-- .../config_setting/widgets/window.py | 6 ++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/__main__.py b/pype/tools/config_setting/__main__.py index aa6f707443..0e4ab1c0aa 100644 --- a/pype/tools/config_setting/__main__.py +++ b/pype/tools/config_setting/__main__.py @@ -11,7 +11,8 @@ if __name__ == "__main__": app.setStyleSheet(stylesheet) app.setWindowIcon(QtGui.QIcon(config_setting.style.app_icon_path())) - widget = config_setting.MainWidget() + develop = "-dev" in sys.argv + widget = config_setting.MainWidget(develop) widget.show() sys.exit(app.exec_()) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index a8bdd9b1a4..52d6b73c98 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -22,9 +22,10 @@ class SystemWidget(QtWidgets.QWidget): is_group = _is_group = False any_parent_is_group = _any_parent_is_group = False - def __init__(self, parent=None): + def __init__(self, develop, parent=None): super(SystemWidget, self).__init__(parent) + self.develop = develop self._ignore_value_changes = False self.input_fields = [] @@ -48,6 +49,11 @@ class SystemWidget(QtWidgets.QWidget): footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) + if self.develop: + save_as_default_btn = QtWidgets.QPushButton("Save as Default") + footer_layout.addWidget(save_as_default_btn, 0) + save_as_default_btn.clicked.connect(self._save_as_defaults) + save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() footer_layout.addWidget(spacer_widget, 1) @@ -138,6 +144,9 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() + def _save_as_defaults(self): + print("_save_as_defaults") + def _update_values(self): self.ignore_value_changes = True @@ -293,9 +302,11 @@ class ProjectWidget(QtWidgets.QWidget): is_group = _is_group = False any_parent_is_group = _any_parent_is_group = False - def __init__(self, parent=None): + def __init__(self, develop, parent=None): super(ProjectWidget, self).__init__(parent) + self.develop = develop + self.is_overidable = False self._ignore_value_changes = False self.project_name = None @@ -320,6 +331,11 @@ class ProjectWidget(QtWidgets.QWidget): footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) + if self.develop: + save_as_default_btn = QtWidgets.QPushButton("Save as Default") + footer_layout.addWidget(save_as_default_btn, 0) + save_as_default_btn.clicked.connect(self._save_as_defaults) + save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() footer_layout.addWidget(spacer_widget, 1) @@ -398,6 +414,9 @@ class ProjectWidget(QtWidgets.QWidget): item.apply_overrides(overrides) self.ignore_value_changes = False + def _save_as_defaults(self): + print("_save_as_defaults") + def _save(self): has_invalid = False for item in self.input_fields: diff --git a/pype/tools/config_setting/config_setting/widgets/window.py b/pype/tools/config_setting/config_setting/widgets/window.py index 7ad46b1a06..f8da9a196e 100644 --- a/pype/tools/config_setting/config_setting/widgets/window.py +++ b/pype/tools/config_setting/config_setting/widgets/window.py @@ -6,15 +6,15 @@ class MainWidget(QtWidgets.QWidget): widget_width = 1000 widget_height = 600 - def __init__(self, parent=None): + def __init__(self, develop, parent=None): super(MainWidget, self).__init__(parent) self.resize(self.widget_width, self.widget_height) header_tab_widget = QtWidgets.QTabWidget(parent=self) - studio_widget = SystemWidget() - project_widget = ProjectWidget() + studio_widget = SystemWidget(develop) + project_widget = ProjectWidget(develop) header_tab_widget.addTab(studio_widget, "System") header_tab_widget.addTab(project_widget, "Project") From 6539dc325c2bd9ba43265d2adc3358dbc2b5d7f2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 11:49:06 +0200 Subject: [PATCH 493/580] removed ftrack project config --- .../1_ftrack_projects_gui_schema.json | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json deleted file mode 100644 index e9937e64b8..0000000000 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_ftrack_projects_gui_schema.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "key": "ftrack", - "type": "dict", - "expandable": true, - "label": "Ftrack", - "children": [ - { - "key": "status_update", - "type": "dict", - "expandable": true, - "label": "Status updates", - "is_group": true, - "children": [ - { - "key": "Ready", - "type": "text", - "label": "Ready" - }, { - "key": "Ready2", - "type": "text", - "label": "Ready2" - } - ] - }, { - "key": "status_version_to_task", - "type": "dict", - "expandable": true, - "label": "Version status to Task status", - "is_group": true, - "children": [ - { - "key": "in progress", - "type": "text", - "label": "In Progress" - } - ] - } - ] -} From e9b9198f4384d7c068959dcaea153652dc5bee01 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 11:52:46 +0200 Subject: [PATCH 494/580] added is_file attribute back --- .../projects_schema/0_project_gui_schema.json | 13 +++- .../projects_schema/1_plugins_gui_schema.json | 15 ++++- .../system_schema/0_system_gui_schema.json | 3 +- .../1_applications_gui_schema.json | 1 + .../system_schema/1_intents_gui_schema.json | 1 + .../system_schema/1_tools_gui_schema.json | 1 + .../system_schema/1_tray_items.json | 1 + .../config_setting/widgets/lib.py | 67 +++++++++++++++++++ 8 files changed, 98 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json index 86504eefd2..52565640bc 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json @@ -4,7 +4,18 @@ "children": [ { "type": "anatomy", - "key": "anatomy" + "key": "anatomy", + "children": [ + { + "type": "anatomy_roots", + "key": "roots", + "is_file": true + }, { + "type": "anatomy_templates", + "key": "templates", + "is_file": true + } + ] }, { "type": "schema", "children": [ diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 597f51d6fd..5dad665b2d 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -15,6 +15,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [ { "type": "dict", @@ -74,6 +75,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [ { "type": "dict", @@ -113,6 +115,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [ { "type": "dict", @@ -276,6 +279,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [ { "type": "dict", @@ -350,7 +354,8 @@ }, { "type": "raw-json", "key": "workfile_build", - "label": "Workfile Build logic" + "label": "Workfile Build logic", + "is_file": true } ] }, { @@ -364,6 +369,7 @@ "expandable": true, "key": "create", "label": "Create plugins", + "is_file": true, "children": [ { "type": "dict", @@ -398,6 +404,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [ { "type": "dict", @@ -510,7 +517,8 @@ }, { "type": "raw-json", "key": "workfile_build", - "label": "Workfile Build logic" + "label": "Workfile Build logic", + "is_file": true } ] }, { @@ -524,6 +532,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [ { "type": "dict", @@ -573,6 +582,7 @@ "expandable": true, "key": "create", "label": "Creator plugins", + "is_file": true, "children": [ { "type": "dict", @@ -611,6 +621,7 @@ "expandable": true, "key": "publish", "label": "Publish plugins", + "is_file": true, "children": [] } ] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json index 0b51267f4e..bdc0158511 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json @@ -27,7 +27,8 @@ }, "is_group": true, "key": "templates_mapping", - "label": "Muster - Templates mapping" + "label": "Muster - Templates mapping", + "is_file": true }] } ] diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json index af128b138f..5ee769eed8 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json @@ -4,6 +4,7 @@ "label": "Applications", "expandable": true, "is_group": true, + "is_file": true, "children": [ { "type": "dict-form", diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json index 11b45c8409..a4b5e16fa1 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json @@ -4,6 +4,7 @@ "label": "Intent Setting", "expandable": true, "is_group": true, + "is_file": true, "children": [ { "type": "dict-modifiable", diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json index a16f00547e..bf35326d1c 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json @@ -4,6 +4,7 @@ "label": "Tools", "expandable": true, "is_group": true, + "is_file": true, "children": [ { "type": "dict-form", diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json index afa509254e..7507050900 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json @@ -4,6 +4,7 @@ "label": "Modules", "expandable": true, "is_group": true, + "is_file": true, "children": [ { "key": "item_usage", diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/config_setting/config_setting/widgets/lib.py index 6b3aa53c8f..daba87de15 100644 --- a/pype/tools/config_setting/config_setting/widgets/lib.py +++ b/pype/tools/config_setting/config_setting/widgets/lib.py @@ -80,6 +80,19 @@ def _fill_inner_schemas(schema_data, schema_collection): return schema_data +class SchemaMissingFileInfo(Exception): + def __init__(self, invalid): + full_path_keys = [] + for item in invalid: + full_path_keys.append("\"{}\"".format("/".join(item))) + + msg = ( + "Schema has missing definition of output file (\"is_file\" key)" + " for keys. [{}]" + ).format(", ".join(full_path_keys)) + super(SchemaMissingFileInfo, self).__init__(msg) + + class SchemeGroupHierarchyBug(Exception): def __init__(self, invalid): full_path_keys = [] @@ -108,6 +121,59 @@ class SchemaDuplicatedKeys(Exception): super(SchemaDuplicatedKeys, self).__init__(msg) +def file_keys_from_schema(schema_data): + output = [] + keys = [] + key = schema_data.get("key") + if key: + keys.append(key) + + for child in schema_data["children"]: + if child.get("is_file"): + _keys = copy.deepcopy(keys) + _keys.append(child["key"]) + output.append(_keys) + continue + + for result in file_keys_from_schema(child): + _keys = copy.deepcopy(keys) + _keys.extend(result) + output.append(_keys) + return output + + +def validate_all_has_ending_file(schema_data, is_top=True): + if schema_data.get("is_file"): + return None + + children = schema_data.get("children") + if not children: + return [[schema_data["key"]]] + + invalid = [] + keyless = "key" not in schema_data + for child in children: + result = validate_all_has_ending_file(child, False) + if result is None: + continue + + if keyless: + invalid.extend(result) + else: + for item in result: + new_invalid = [schema_data["key"]] + new_invalid.extend(item) + invalid.append(new_invalid) + + if not invalid: + return None + + if not is_top: + return invalid + + raise SchemaMissingFileInfo(invalid) + + def validate_is_group_is_unique_in_hierarchy( schema_data, any_parent_is_group=False, keys=None ): @@ -203,6 +269,7 @@ def validate_keys_are_unique(schema_data, keys=None): def validate_schema(schema_data): + validate_all_has_ending_file(schema_data) validate_is_group_is_unique_in_hierarchy(schema_data) validate_keys_are_unique(schema_data) From b8c15fd5144a22bf675bae4b074205e8b5ef53f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 12:01:16 +0200 Subject: [PATCH 495/580] added develop_mode attribute to inputs --- .../config_setting/config_setting/widgets/base.py | 12 ++++++------ .../config_setting/config_setting/widgets/inputs.py | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 52d6b73c98..58e53b8c58 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -22,10 +22,10 @@ class SystemWidget(QtWidgets.QWidget): is_group = _is_group = False any_parent_is_group = _any_parent_is_group = False - def __init__(self, develop, parent=None): + def __init__(self, develop_mode, parent=None): super(SystemWidget, self).__init__(parent) - self.develop = develop + self.develop_mode = develop_mode self._ignore_value_changes = False self.input_fields = [] @@ -49,7 +49,7 @@ class SystemWidget(QtWidgets.QWidget): footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) - if self.develop: + if self.develop_mode: save_as_default_btn = QtWidgets.QPushButton("Save as Default") footer_layout.addWidget(save_as_default_btn, 0) save_as_default_btn.clicked.connect(self._save_as_defaults) @@ -302,10 +302,10 @@ class ProjectWidget(QtWidgets.QWidget): is_group = _is_group = False any_parent_is_group = _any_parent_is_group = False - def __init__(self, develop, parent=None): + def __init__(self, develop_mode, parent=None): super(ProjectWidget, self).__init__(parent) - self.develop = develop + self.develop_mode = develop_mode self.is_overidable = False self._ignore_value_changes = False @@ -331,7 +331,7 @@ class ProjectWidget(QtWidgets.QWidget): footer_widget = QtWidgets.QWidget() footer_layout = QtWidgets.QHBoxLayout(footer_widget) - if self.develop: + if self.develop_mode: save_as_default_btn = QtWidgets.QPushButton("Save as Default") footer_layout.addWidget(save_as_default_btn, 0) save_as_default_btn.clicked.connect(self._save_as_defaults) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 5763738351..5f56f39518 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -33,6 +33,10 @@ class ConfigObject(AbstractConfigObject): _any_parent_is_group = None _log = None + @property + def develop_mode(self): + return self._parent.develop_mode + @property def log(self): if self._log is None: From 68ba48bcf294c1a48958150b010e0d098444db03 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 13:29:15 +0200 Subject: [PATCH 496/580] in develop mode empty defaults won't crash the gui --- .../config_setting/widgets/inputs.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 5f56f39518..ea774d90de 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -12,6 +12,7 @@ from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET class ConfigObject(AbstractConfigObject): + default_input_value = NOT_SET allow_actions = True default_state = "" @@ -217,11 +218,20 @@ class InputObject(ConfigObject): value = parent_values.get(self.key, NOT_SET) if value is NOT_SET: - raise ValueError( - "Default value is not set. This is implementation BUG." - ) + if self.develop_mode: + value = self.default_input_value + if value is NOT_SET: + raise NotImplementedError(( + "{} Does not have implemented" + " attribute `default_input_value`" + ).format(self)) - self.default_value = value + else: + raise ValueError( + "Default value is not set. This is implementation BUG." + ) + + self._default_value = value self._has_studio_override = False self._had_studio_override = False self.set_value(value) @@ -370,6 +380,7 @@ class InputObject(ConfigObject): class BooleanWidget(QtWidgets.QWidget, InputObject): + default_input_value = True value_changed = QtCore.Signal(object) def __init__( @@ -455,6 +466,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): class NumberWidget(QtWidgets.QWidget, InputObject): + default_input_value = 0 value_changed = QtCore.Signal(object) input_modifiers = ("minimum", "maximum", "decimal") @@ -541,6 +553,7 @@ class NumberWidget(QtWidgets.QWidget, InputObject): class TextWidget(QtWidgets.QWidget, InputObject): + default_input_value = "" value_changed = QtCore.Signal(object) def __init__( @@ -633,6 +646,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): class PathInputWidget(QtWidgets.QWidget, InputObject): + default_input_value = "" value_changed = QtCore.Signal(object) def __init__( @@ -768,6 +782,7 @@ class RawJsonInput(QtWidgets.QPlainTextEdit): class RawJsonWidget(QtWidgets.QWidget, InputObject): + default_input_value = "{}" value_changed = QtCore.Signal(object) def __init__( @@ -872,9 +887,9 @@ class ListItem(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) def __init__(self, object_type, input_modifiers, config_parent, parent): - self._parent = config_parent super(ListItem, self).__init__(parent) + self._parent = config_parent layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) @@ -962,6 +977,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): class ListWidget(QtWidgets.QWidget, InputObject): + default_input_value = [] value_changed = QtCore.Signal(object) def __init__( @@ -1297,6 +1313,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): class ModifiableDict(QtWidgets.QWidget, InputObject): + default_input_value = {} # Should be used only for dictionary with one datatype as value # TODO this is actually input field (do not care if is group or not) value_changed = QtCore.Signal(object) From 72221cfafd75ae167f907608faed624a497728d7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 13:39:17 +0200 Subject: [PATCH 497/580] it is possible to know that defaults are not set --- .../config_setting/widgets/inputs.py | 218 +++++++----------- 1 file changed, 77 insertions(+), 141 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index ea774d90de..32befd6ef8 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -14,25 +14,58 @@ from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET class ConfigObject(AbstractConfigObject): default_input_value = NOT_SET allow_actions = True - default_state = "" - _as_widget = False - _is_group = False - # TODO not implemented yet - _is_nullable = False + def set_default_attributes(self): + # Default input attributes + self._has_studio_override = False + self._had_studio_override = False - _has_studio_override = False - _had_studio_override = False + self._is_overriden = False + self._was_overriden = False - _is_overriden = False - _was_overriden = False + self._is_modified = False + self._is_invalid = False - _is_modified = False - _is_invalid = False + self._is_nullable = False + self._as_widget = False + self._is_group = False - _any_parent_is_group = None - _log = None + self._any_parent_is_group = None + + # Parent input + self._parent = None + + # States of inputs + self._state = None + self._child_state = None + + # Attributes where values are stored + self.default_value = NOT_SET + self.studio_value = NOT_SET + self.override_value = NOT_SET + + # Log object + self._log = None + + # Only for develop mode + self.defaults_not_set = False + + def initial_attributes(self, input_data, parent, as_widget): + self.set_default_attributes() + + self._parent = parent + self._as_widget = as_widget + + self._is_group = input_data.get("is_group", False) + # TODO not implemented yet + self._is_nullable = input_data.get("is_nullable", False) + + any_parent_is_group = parent.is_group + if not any_parent_is_group: + any_parent_is_group = parent.any_parent_is_group + + self._any_parent_is_group = any_parent_is_group @property def develop_mode(self): @@ -61,7 +94,7 @@ class ConfigObject(AbstractConfigObject): @property def is_modified(self): """Has object any changes that require saving.""" - if self._is_modified: + if self._is_modified or self.defaults_not_set: return True if self.is_overidable: @@ -220,6 +253,7 @@ class InputObject(ConfigObject): if value is NOT_SET: if self.develop_mode: value = self.default_input_value + self.defaults_not_set = True if value is NOT_SET: raise NotImplementedError(( "{} Does not have implemented" @@ -231,7 +265,7 @@ class InputObject(ConfigObject): "Default value is not set. This is implementation BUG." ) - self._default_value = value + self.default_value = value self._has_studio_override = False self._had_studio_override = False self.set_value(value) @@ -391,22 +425,13 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): parent_widget = parent super(BooleanWidget, self).__init__(parent_widget) - self._parent = parent - self._as_widget = as_widget - self._state = None - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET + self.initial_attributes(input_data, parent, as_widget) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not as_widget: + if not self._as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] @@ -478,16 +503,7 @@ class NumberWidget(QtWidgets.QWidget, InputObject): parent_widget = parent super(NumberWidget, self).__init__(parent_widget) - self._parent = parent - self._as_widget = as_widget - self._state = None - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET + self.initial_attributes(input_data, parent, as_widget) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -564,19 +580,10 @@ class TextWidget(QtWidgets.QWidget, InputObject): parent_widget = parent super(TextWidget, self).__init__(parent_widget) - self._parent = parent - self._as_widget = as_widget - self._state = None - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) + self.initial_attributes(input_data, parent, as_widget) self.multiline = input_data.get("multiline", False) - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET - layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) @@ -657,16 +664,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): parent_widget = parent super(PathInputWidget, self).__init__(parent_widget) - self._parent = parent - self._as_widget = as_widget - self._state = None - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET + self.initial_attributes(input_data, parent, as_widget) layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -793,22 +791,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): parent_widget = parent super(RawJsonWidget, self).__init__(parent_widget) - self._parent = parent - self._as_widget = as_widget - self._state = None - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self._any_parent_is_group = any_parent_is_group - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) - - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET + self.initial_attributes(input_data, parent, as_widget) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -889,7 +872,10 @@ class ListItem(QtWidgets.QWidget, ConfigObject): def __init__(self, object_type, input_modifiers, config_parent, parent): super(ListItem, self).__init__(parent) + self.set_default_attributes() self._parent = config_parent + self._any_parent_is_group = True + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) @@ -989,20 +975,11 @@ class ListWidget(QtWidgets.QWidget, InputObject): super(ListWidget, self).__init__(parent_widget) self.setObjectName("ListWidget") - self._parent = parent - self._state = None - self._as_widget = as_widget - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) + self.initial_attributes(input_data, parent, as_widget) self.object_type = input_data["object_type"] self.input_modifiers = input_data.get("input_modifiers") or {} - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET - self.key = input_data["key"] self.input_fields = [] @@ -1327,22 +1304,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): super(ModifiableDict, self).__init__(parent_widget) self.setObjectName("ModifiableDict") - self._parent = parent - self._state = None - self._as_widget = as_widget - - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self._any_parent_is_group = any_parent_is_group - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) + self.initial_attributes(input_data, parent, as_widget) self.input_fields = [] @@ -1573,18 +1535,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): super(DictWidget, self).__init__(parent_widget) self.setObjectName("DictWidget") - self._state = None - self._child_state = None - - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - self._any_parent_is_group = any_parent_is_group - - self._is_group = input_data.get("is_group", False) - self._is_nullable = input_data.get("is_nullable", False) + self.initial_attributes(input_data, parent, as_widget) if input_data.get("highlight_content", False): content_state = "hightlighted" @@ -1891,14 +1842,8 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): super(DictInvisible, self).__init__(parent_widget) self.setObjectName("DictInvisible") - self._parent = parent + self.initial_attributes(input_data, parent, as_widget) - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self._any_parent_is_group = any_parent_is_group - self._is_group = input_data.get("is_group", False) if self._is_group: raise TypeError("DictInvisible can't be marked as group input.") @@ -2098,7 +2043,6 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): class PathWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) - platforms = ("windows", "darwin", "linux") platform_labels_mapping = { "windows": "Windows", @@ -2120,30 +2064,17 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): parent_widget = parent super(PathWidget, self).__init__(parent_widget) - self._parent = parent - self._state = None - self._child_state = None - self._as_widget = as_widget - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - self._any_parent_is_group = any_parent_is_group + self.initial_attributes(input_data, parent, as_widget) # This is partial input and dictionary input - if not any_parent_is_group and not as_widget: + if not self.any_parent_is_group and not self._as_widget: self._is_group = True else: self._is_group = False - self._is_nullable = input_data.get("is_nullable", False) self.multiplatform = input_data.get("multiplatform", False) self.multipath = input_data.get("multipath", False) - self.default_value = NOT_SET - self.studio_value = NOT_SET - self.override_value = NOT_SET - self.input_fields = [] if not self.multiplatform and not self.multipath: @@ -2153,7 +2084,7 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not as_widget: + if not self._as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] @@ -2171,6 +2102,16 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self.create_gui() + @property + def default_input_value(self): + if self.multiplatform: + return { + platform: "" + for platform in self.platforms + } + else: + return "" + def create_gui(self): if not self.multiplatform and not self.multipath: input_data = {"key": self.key} @@ -2467,14 +2408,9 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): parent_widget = parent super(DictFormWidget, self).__init__(parent_widget) - self._parent = parent - - any_parent_is_group = parent.is_group - if not any_parent_is_group: - any_parent_is_group = parent.any_parent_is_group - - self._any_parent_is_group = any_parent_is_group + self.initial_attributes(input_data, parent, as_widget) + self._as_widget = False self._is_group = False self.input_fields = [] From 3cd46bb0f2e7045a406e25c19e23ca9cb00a6a5f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 13:42:59 +0200 Subject: [PATCH 498/580] configurations lib has constant path to defaults --- pype/configurations/lib.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index 4cd7203626..b555ea0167 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -29,6 +29,9 @@ STUDIO_PROJECT_OVERRIDES_PATH = os.path.join( STUDIO_OVERRIDES_PATH, "project_overrides" ) +# Path to default configurations +DEFAULTS_DIR = os.path.join(os.path.dirname(__file__), "defaults") + # Variable where cache of default configurations are stored _DEFAULT_CONFIGURATIONS = None @@ -36,9 +39,7 @@ _DEFAULT_CONFIGURATIONS = None def default_configuration(): global _DEFAULT_CONFIGURATIONS if _DEFAULT_CONFIGURATIONS is None: - current_dir = os.path.dirname(__file__) - defaults_path = os.path.join(current_dir, "defaults") - _DEFAULT_CONFIGURATIONS = load_jsons_from_dir(defaults_path) + _DEFAULT_CONFIGURATIONS = load_jsons_from_dir(DEFAULTS_DIR) return _DEFAULT_CONFIGURATIONS From 714bd5794327785596964ee05d521a7e5b70c2d3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 13:59:54 +0200 Subject: [PATCH 499/580] added specific keys as constants --- pype/configurations/lib.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index b555ea0167..c0b783e3fb 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -14,12 +14,14 @@ POP_KEY = "__pop_key__" STUDIO_OVERRIDES_PATH = os.environ["PYPE_CONFIG"] # File where studio's system overrides are stored +SYSTEM_CONFIGURATIONS_KEY = "system_configurations" SYSTEM_CONFIGURATIONS_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, "system_configurations.json" + STUDIO_OVERRIDES_PATH, SYSTEM_CONFIGURATIONS_KEY + ".json" ) # File where studio's default project overrides are stored -PROJECT_CONFIGURATIONS_FILENAME = "project_configurations.json" +PROJECT_CONFIGURATIONS_KEY = "project_configurations" +PROJECT_CONFIGURATIONS_FILENAME = PROJECT_CONFIGURATIONS_KEY + ".json" PROJECT_CONFIGURATIONS_PATH = os.path.join( STUDIO_OVERRIDES_PATH, PROJECT_CONFIGURATIONS_FILENAME ) From ebfa87a3ac2cc57108a87cdec9b11da3f342928d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 14:05:12 +0200 Subject: [PATCH 500/580] removed standalone publisher as not complete yet --- .../projects_schema/1_plugins_gui_schema.json | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index 5dad665b2d..df0de07a4d 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -610,21 +610,6 @@ ] } ] - }, { - "type": "dict", - "expandable": true, - "key": "standalonepublisher", - "label": "StandalonePublisher", - "children": [ - { - "type": "dict", - "expandable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [] - } - ] } ] } From ce198d1c4a3460174c16637eb8b6c04e04083351 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 14:09:26 +0200 Subject: [PATCH 501/580] added possibility to reset defaults --- pype/configurations/lib.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index c0b783e3fb..b8832ceacb 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -38,6 +38,11 @@ DEFAULTS_DIR = os.path.join(os.path.dirname(__file__), "defaults") _DEFAULT_CONFIGURATIONS = None +def reset_default_configurations(): + global _DEFAULT_CONFIGURATIONS + _DEFAULT_CONFIGURATIONS = None + + def default_configuration(): global _DEFAULT_CONFIGURATIONS if _DEFAULT_CONFIGURATIONS is None: From a4a4b5244f07b08099748217c86a4e15057d85e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 14:34:26 +0200 Subject: [PATCH 502/580] added ability to save as defaults --- .../global/applications.json | 31 +++--- .../projects_schema/1_plugins_gui_schema.json | 4 + .../config_setting/widgets/base.py | 94 ++++++++++++++++++- 3 files changed, 109 insertions(+), 20 deletions(-) diff --git a/pype/configurations/defaults/system_configurations/global/applications.json b/pype/configurations/defaults/system_configurations/global/applications.json index 8e27f11002..3a74a85468 100644 --- a/pype/configurations/defaults/system_configurations/global/applications.json +++ b/pype/configurations/defaults/system_configurations/global/applications.json @@ -6,34 +6,29 @@ "celaction_local": true, "celaction_remote": true, "harmony_17": true, - "houdini_16": true, - "houdini_17": true, - "houdini_18": true, - "maya_2016": true, "maya_2017": true, "maya_2018": true, "maya_2019": true, "maya_2020": true, - "nukestudio_10.0": true, - "nukestudio_11.0": true, - "nukestudio_11.2": true, - "nukestudio_11.3": true, - "nukestudio_12.0": true, - "nukex_10.0": true, - "nukex_11.0": true, - "nukex_11.2": true, - "nukex_11.3": true, - "nukex_12.0": true, "nuke_10.0": true, - "nuke_11.0": true, "nuke_11.2": true, "nuke_11.3": true, "nuke_12.0": true, - "photoshop_2020": true, + "nukex_10.0": true, + "nukex_11.2": true, + "nukex_11.3": true, + "nukex_12.0": true, + "nukestudio_10.0": true, + "nukestudio_11.2": true, + "nukestudio_11.3": true, + "nukestudio_12.0": true, + "houdini_16": true, + "houdini_16.5": false, + "houdini_17": true, + "houdini_18": true, "premiere_2019": true, "premiere_2020": true, "resolve_16": true, "storyboardpro_7": true, - "unreal_4.24": true, - "houdini_16.5": false + "unreal_4.24": true } \ No newline at end of file diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json index df0de07a4d..c279a6b04a 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json @@ -140,6 +140,10 @@ "is_group": true, "children": [ { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { "type": "dict-invisible", "key": "ffmpeg_args", "children": [ diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 58e53b8c58..d7078e4ab6 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -2,8 +2,12 @@ import os import json from Qt import QtWidgets, QtCore, QtGui from pype.configurations.lib import ( + SYSTEM_CONFIGURATIONS_KEY, SYSTEM_CONFIGURATIONS_PATH, + PROJECT_CONFIGURATIONS_KEY, PROJECT_CONFIGURATIONS_PATH, + DEFAULTS_DIR, + reset_default_configurations, default_configuration, studio_system_configurations, project_configurations_overrides, @@ -145,7 +149,50 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() def _save_as_defaults(self): - print("_save_as_defaults") + output = {} + for item in self.input_fields: + output.update(item.config_value()) + + for key in reversed(self.keys): + _output = {key: output} + output = _output + + all_values = {} + for item in self.input_fields: + all_values.update(item.config_value()) + + for key in reversed(self.keys): + _all_values = {key: all_values} + all_values = _all_values + + # Skip first key + all_values = all_values["system"] + + prject_defaults_dir = os.path.join( + DEFAULTS_DIR, SYSTEM_CONFIGURATIONS_KEY + ) + keys_to_file = lib.file_keys_from_schema(self.schema) + for key_sequence in keys_to_file: + # Skip first key + key_sequence = key_sequence[1:] + subpath = "/".join(key_sequence) + ".json" + + new_values = all_values + for key in key_sequence: + new_values = new_values[key] + + output_path = os.path.join(prject_defaults_dir, subpath) + dirpath = os.path.dirname(output_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving data to: ", subpath) + with open(output_path, "w") as file_stream: + json.dump(new_values, file_stream, indent=4) + + reset_default_configurations() + + self._update_values() def _update_values(self): self.ignore_value_changes = True @@ -415,7 +462,50 @@ class ProjectWidget(QtWidgets.QWidget): self.ignore_value_changes = False def _save_as_defaults(self): - print("_save_as_defaults") + output = {} + for item in self.input_fields: + output.update(item.config_value()) + + for key in reversed(self.keys): + _output = {key: output} + output = _output + + all_values = {} + for item in self.input_fields: + all_values.update(item.config_value()) + + for key in reversed(self.keys): + _all_values = {key: all_values} + all_values = _all_values + + # Skip first key + all_values = all_values["project"] + + prject_defaults_dir = os.path.join( + DEFAULTS_DIR, PROJECT_CONFIGURATIONS_KEY + ) + keys_to_file = lib.file_keys_from_schema(self.schema) + for key_sequence in keys_to_file: + # Skip first key + key_sequence = key_sequence[1:] + subpath = "/".join(key_sequence) + ".json" + + new_values = all_values + for key in key_sequence: + new_values = new_values[key] + + output_path = os.path.join(prject_defaults_dir, subpath) + dirpath = os.path.dirname(output_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving data to: ", subpath) + with open(output_path, "w") as file_stream: + json.dump(new_values, file_stream, indent=4) + + reset_default_configurations() + + self._update_values() def _save(self): has_invalid = False From 438d456bb55b52158a51859ea347455aefa612a2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 15:21:12 +0200 Subject: [PATCH 503/580] fix dictionary item initialization --- pype/tools/config_setting/config_setting/widgets/inputs.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 32befd6ef8..bc63e27f5a 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -873,6 +873,7 @@ class ListItem(QtWidgets.QWidget, ConfigObject): super(ListItem, self).__init__(parent) self.set_default_attributes() + self._parent = config_parent self._any_parent_is_group = True @@ -1149,6 +1150,7 @@ class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): def __init__(self, object_type, input_modifiers, config_parent, parent): super(ModifiableDictItem, self).__init__(parent) + self.set_default_attributes() self._parent = config_parent self.is_single = False From ea8ffca0fadbc8122e2a1b55e4712c61bfb5a33b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 15:21:34 +0200 Subject: [PATCH 504/580] modified anatomy widgets to match new initialization --- .../config_setting/widgets/anatomy_inputs.py | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index efba588692..4ae7d8d290 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -40,14 +40,11 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): ) super(AnatomyWidget, self).__init__(parent) self.setObjectName("AnatomyWidget") - self._parent = parent + + self.initial_attributes(input_data, parent, as_widget) + self.key = "anatomy" - self._child_state = None - self._state = None - - self._any_parent_is_group = False - self.root_widget = RootsWidget(self) self.templates_widget = TemplatesWidget(self) @@ -214,15 +211,13 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def __init__(self, parent): super(RootsWidget, self).__init__(parent) self.setObjectName("RootsWidget") - self._parent = parent + + input_data = {"is_group": True} + self.initial_attributes(input_data, parent, False) + self.key = "roots" - self._state = None self._multiroot_state = None - - self._is_group = True - self._any_parent_is_group = False - self.global_is_multiroot = False self.was_multiroot = NOT_SET @@ -546,12 +541,9 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def __init__(self, parent): super(TemplatesWidget, self).__init__(parent) - self._parent = parent + input_data = {"is_group": True} + self.initial_attributes(input_data, parent, False) - self._state = None - - self._is_group = True - self._any_parent_is_group = False self.key = "templates" body_widget = ExpandingWidget("Templates", self) @@ -634,7 +626,7 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): @property def has_studio_override(self): - return self.value_input.has_studio_override + return self.value_input._has_studio_override @property def child_has_studio_override(self): From f346b80e4d29b25b9406709d26a8bcf74ebceb29 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 15:27:56 +0200 Subject: [PATCH 505/580] set as overriden kinda works on roots widget --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 4ae7d8d290..2c4548df4e 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -173,6 +173,10 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): or self.templates_widget.child_invalid ) + def set_as_overriden(self): + self.root_widget.set_as_overriden() + self.templates_widget.set_as_overriden() + def remove_overrides(self): self.root_widget.remove_overrides() self.templates_widget.remove_overrides() @@ -521,7 +525,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._is_modified = self.child_modified def set_as_overriden(self): - self._is_overriden = self._was_overriden + self._is_overriden = True self.singleroot_widget.set_as_overriden() self.multiroot_widget.set_as_overriden() From 12fff9477a0d4038a3a54d7c6af144144ad675a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 15:31:01 +0200 Subject: [PATCH 506/580] multiroot label does not care about overrides --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 2c4548df4e..7dd89838d4 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -399,7 +399,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): multiroot_state = self.style_state( self.has_studio_override, False, - self.is_overriden, + False, self.was_multiroot != self.is_multiroot ) if multiroot_state != self._multiroot_state: From c76f9f604c96b82eb26c3fb2b1fd556431803f64 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 15:52:01 +0200 Subject: [PATCH 507/580] anatomy overrides can be unset --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 7dd89838d4..a62b32664e 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -186,7 +186,9 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.templates_widget.discard_changes() def overrides(self): - return self.config_value(), True + if self.child_overriden: + return self.config_value(), True + return NOT_SET, False def item_value(self): output = {} From 47f1429214b73aa6db634e3660b7666471a87bb7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 15:52:41 +0200 Subject: [PATCH 508/580] fixed different cases of set_overrides and removing overrides --- .../config_setting/widgets/anatomy_inputs.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index a62b32664e..306149f9b3 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -510,8 +510,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(self.global_is_multiroot) - self.singleroot_widget.remove_overrides() - self.multiroot_widget.remove_overrides() + if self.is_multiroot: + self.multiroot_widget.remove_overrides() + else: + self.singleroot_widget.remove_overrides() def discard_changes(self): self._is_overriden = self._was_overriden @@ -521,8 +523,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: self.set_multiroot(self.global_is_multiroot) - self.singleroot_widget.discard_changes() - self.multiroot_widget.discard_changes() + if self.is_multiroot: + self.multiroot_widget.discard_changes() + else: + self.singleroot_widget.discard_changes() self._is_modified = self.child_modified From 3759920d3873158ccf0c7b5c1ab1844734b0b869 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 16:31:40 +0200 Subject: [PATCH 509/580] modified api to not break old way of loading presets --- pype/api.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/api.py b/pype/api.py index ee0d1ef4a2..c5cd28d4de 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,8 +1,12 @@ -from .configurations import config +from .configurations.config import ( + system_configurations, + project_configurations +) from pypeapp import ( Logger, Anatomy, project_overrides_dir_path, + config, execute ) @@ -49,6 +53,9 @@ from .lib import ( from .lib import _subprocess as subprocess __all__ = [ + "system_configurations", + "project_configurations", + "Logger", "Anatomy", "project_overrides_dir_path", From 201d0aca14a58c419d13fcf298719ccedfb72721 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:17:54 +0200 Subject: [PATCH 510/580] moved anatomy to separate folder --- .../colorspace.json | 0 .../anatomy => project_anatomy}/dataflow.json | 0 .../anatomy => project_anatomy}/roots.json | 0 .../templates.json | 0 .../project_configurations/anatomy/README.md | 0 .../anatomy/colorspace/aces103-cg.json | 46 --------------- .../anatomy/dataflow/aces-exr.json | 58 ------------------- .../anatomy/default.yaml | 29 ---------- 8 files changed, 133 deletions(-) rename pype/configurations/defaults/{project_configurations/anatomy => project_anatomy}/colorspace.json (100%) rename pype/configurations/defaults/{project_configurations/anatomy => project_anatomy}/dataflow.json (100%) rename pype/configurations/defaults/{project_configurations/anatomy => project_anatomy}/roots.json (100%) rename pype/configurations/defaults/{project_configurations/anatomy => project_anatomy}/templates.json (100%) delete mode 100644 pype/configurations/defaults/project_configurations/anatomy/README.md delete mode 100644 pype/configurations/defaults/project_configurations/anatomy/colorspace/aces103-cg.json delete mode 100644 pype/configurations/defaults/project_configurations/anatomy/dataflow/aces-exr.json delete mode 100644 pype/configurations/defaults/project_configurations/anatomy/default.yaml diff --git a/pype/configurations/defaults/project_configurations/anatomy/colorspace.json b/pype/configurations/defaults/project_anatomy/colorspace.json similarity index 100% rename from pype/configurations/defaults/project_configurations/anatomy/colorspace.json rename to pype/configurations/defaults/project_anatomy/colorspace.json diff --git a/pype/configurations/defaults/project_configurations/anatomy/dataflow.json b/pype/configurations/defaults/project_anatomy/dataflow.json similarity index 100% rename from pype/configurations/defaults/project_configurations/anatomy/dataflow.json rename to pype/configurations/defaults/project_anatomy/dataflow.json diff --git a/pype/configurations/defaults/project_configurations/anatomy/roots.json b/pype/configurations/defaults/project_anatomy/roots.json similarity index 100% rename from pype/configurations/defaults/project_configurations/anatomy/roots.json rename to pype/configurations/defaults/project_anatomy/roots.json diff --git a/pype/configurations/defaults/project_configurations/anatomy/templates.json b/pype/configurations/defaults/project_anatomy/templates.json similarity index 100% rename from pype/configurations/defaults/project_configurations/anatomy/templates.json rename to pype/configurations/defaults/project_anatomy/templates.json diff --git a/pype/configurations/defaults/project_configurations/anatomy/README.md b/pype/configurations/defaults/project_configurations/anatomy/README.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pype/configurations/defaults/project_configurations/anatomy/colorspace/aces103-cg.json b/pype/configurations/defaults/project_configurations/anatomy/colorspace/aces103-cg.json deleted file mode 100644 index dd3fca4c2d..0000000000 --- a/pype/configurations/defaults/project_configurations/anatomy/colorspace/aces103-cg.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "resolve": { - - }, - "nukestudio": { - - }, - "nuke": { - "root": { - "colorManagement": "OCIO", - "OCIO_config": "aces_1.0.3", - "workingSpaceLUT": "ACES - ACEScg", - "defaultViewerLUT": "OCIO LUTs", - "monitorLut": "ACES/sRGB", - "int8Lut": "Utility - sRGB - Texture", - "int16Lut": "Utility - sRGB - Texture", - "logLut": "Input - ADX - ADX10", - "floatLut": "ACES - ACES2065-1" - }, - "viewer": { - "viewerProcess": "sRGB (ACES)" - }, - "write": { - "render": { - "colorspace": "ACES - ACES2065-1" - }, - "prerender": { - "colorspace": "ACES - ACES2065-1" - }, - "still": { - "colorspace": "Utility - Curve - sRGB" - } - }, - "read": { - "[^-a-zA-Z0-9](beauty)[^-a-zA-Z0-9]": "lin_srgb", - "[^-a-zA-Z0-9](P|N|Z|crypto)[^-a-zA-Z0-9]": "raw", - "[^-a-zA-Z0-9](plateRef)[^-a-zA-Z0-9]": "crv_srgb" - } - }, - "maya": { - - }, - "houdini": { - - } -} diff --git a/pype/configurations/defaults/project_configurations/anatomy/dataflow/aces-exr.json b/pype/configurations/defaults/project_configurations/anatomy/dataflow/aces-exr.json deleted file mode 100644 index 75846c0bd6..0000000000 --- a/pype/configurations/defaults/project_configurations/anatomy/dataflow/aces-exr.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "nuke": { - "nodes": { - "connected": true, - "modifymetadata": { - "_id": "connect_metadata", - "_previous": "ENDING", - "metadata.set.pype_studio_name": "{PYPE_STUDIO_NAME}", - "metadata.set.avalon_project_name": "{AVALON_PROJECT}", - "metadata.set.avalon_project_code": "{PYPE_STUDIO_CODE}", - "metadata.set.avalon_asset_name": "{AVALON_ASSET}" - }, - "crop": { - "_id": "connect_crop", - "_previous": "connect_metadata", - "box": [ - "{metadata.crop.x}", - "{metadata.crop.y}", - "{metadata.crop.right}", - "{metadata.crop.top}" - ] - }, - "write": { - "render": { - "_id": "output_write", - "_previous": "connect_crop", - "file_type": "exr", - "datatype": "16 bit half", - "compression": "Zip (1 scanline)", - "create_directories": true, - "autocrop": true, - "tile_color": "0xff0000ff", - "channels": "rgb" - }, - "prerender": { - "_id": "output_write", - "_previous": "connect_crop", - "file_type": "exr", - "datatype": "16 bit half", - "compression": "Zip (1 scanline)", - "create_directories": true, - "autocrop": false, - "tile_color": "0xc9892aff", - "channels": "rgba" - }, - "still": { - "_previous": "connect_crop", - "channels": "rgba", - "file_type": "tiff", - "datatype": "16 bit", - "compression": "LZW", - "create_directories": true, - "tile_color": "0x4145afff" - } - } - } - } -} diff --git a/pype/configurations/defaults/project_configurations/anatomy/default.yaml b/pype/configurations/defaults/project_configurations/anatomy/default.yaml deleted file mode 100644 index 381aa05d4a..0000000000 --- a/pype/configurations/defaults/project_configurations/anatomy/default.yaml +++ /dev/null @@ -1,29 +0,0 @@ - -version_padding: 3 -version: "v{version:0>{@version_padding}}" -frame_padding: 4 -frame: "{frame:0>{@frame_padding}}" - -work: - folder: "{root}/{project[name]}/{hierarchy}/{asset}/work/{task}" - file: "{project[code]}_{asset}_{task}_{@version}<_{comment}>.{ext}" - path: "{@folder}/{@file}" - -render: - folder: "{root}/{project[name]}/{hierarchy}/{asset}/publish/render/{subset}/{@version}" - file: "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}" - path: "{@folder}/{@file}" - -texture: - path: "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}" - -publish: - folder: "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}" - file: "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}" - path: "{@folder}/{@file}" - thumbnail: "{thumbnail_root}/{project[name]}/{_id}_{thumbnail_type}{ext}" - -master: - folder: "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/master" - file: "{project[code]}_{asset}_{subset}_master<_{output}><.{frame}>.{representation}" - path: "{@folder}/{@file}" From 5971468b93a22627ed08c28313642bfd7c88323d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:21:42 +0200 Subject: [PATCH 511/580] anatomy data are more schema based --- .../config_setting/widgets/anatomy_inputs.py | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 306149f9b3..ed73ad6468 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -43,10 +43,19 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.initial_attributes(input_data, parent, as_widget) - self.key = "anatomy" + self.key = input_data["key"] - self.root_widget = RootsWidget(self) - self.templates_widget = TemplatesWidget(self) + children_data = input_data["children"] + roots_input_data = {} + templates_input_data = {} + for child in children_data: + if child["type"] == "anatomy_roots": + roots_input_data = child + elif child["type"] == "anatomy_templates": + templates_input_data = child + + self.root_widget = RootsWidget(roots_input_data, self) + self.templates_widget = TemplatesWidget(templates_input_data, self) self.setAttribute(QtCore.Qt.WA_StyledBackground) @@ -214,14 +223,14 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): class RootsWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) - def __init__(self, parent): + def __init__(self, input_data, parent): super(RootsWidget, self).__init__(parent) self.setObjectName("RootsWidget") input_data = {"is_group": True} self.initial_attributes(input_data, parent, False) - self.key = "roots" + self.key = input_data["key"] self._multiroot_state = None self.global_is_multiroot = False @@ -548,13 +557,13 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): class TemplatesWidget(QtWidgets.QWidget, ConfigObject): value_changed = QtCore.Signal(object) - def __init__(self, parent): + def __init__(self, input_data, parent): super(TemplatesWidget, self).__init__(parent) input_data = {"is_group": True} self.initial_attributes(input_data, parent, False) - self.key = "templates" + self.key = input_data["key"] body_widget = ExpandingWidget("Templates", self) content_widget = QtWidgets.QWidget(body_widget) From 4bd3c8716bfdd5e4e7d55521d719a1569bc973f1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:21:53 +0200 Subject: [PATCH 512/580] wrapped project data more inside --- .../projects_schema/0_project_gui_schema.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json index 52565640bc..3d7cac68fd 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json @@ -4,7 +4,7 @@ "children": [ { "type": "anatomy", - "key": "anatomy", + "key": "project_anatomy", "children": [ { "type": "anatomy_roots", @@ -17,9 +17,15 @@ } ] }, { - "type": "schema", + "type": "dict-invisible", + "key": "project_configurations", "children": [ - "1_plugins_gui_schema" + { + "type": "schema", + "children": [ + "1_plugins_gui_schema" + ] + } ] } ] From e359256b6ebcc100be3e8a83ebce3356a342abf4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:22:39 +0200 Subject: [PATCH 513/580] configurations has also functions for getting anatomy --- pype/configurations/lib.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index b8832ceacb..abd848f95c 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -26,6 +26,12 @@ PROJECT_CONFIGURATIONS_PATH = os.path.join( STUDIO_OVERRIDES_PATH, PROJECT_CONFIGURATIONS_FILENAME ) +PROJECT_ANATOMY_KEY = "project_anatomy" +PROJECT_ANATOMY_FILENAME = PROJECT_ANATOMY_KEY + ".json" +PROJECT_ANATOMY_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, PROJECT_ANATOMY_FILENAME +) + # Folder where studio's per project overrides are stored STUDIO_PROJECT_OVERRIDES_PATH = os.path.join( STUDIO_OVERRIDES_PATH, "project_overrides" @@ -167,6 +173,12 @@ def studio_project_configurations(): return {} +def studio_project_anatomy(): + if os.path.exists(PROJECT_ANATOMY_PATH): + return load_json(PROJECT_ANATOMY_PATH) + return {} + + def path_to_project_overrides(project_name): return os.path.join( STUDIO_PROJECT_OVERRIDES_PATH, @@ -175,6 +187,14 @@ def path_to_project_overrides(project_name): ) +def path_to_project_anatomy(project_name): + return os.path.join( + STUDIO_PROJECT_OVERRIDES_PATH, + project_name, + PROJECT_ANATOMY_FILENAME + ) + + def project_configurations_overrides(project_name): if not project_name: return {} @@ -185,6 +205,16 @@ def project_configurations_overrides(project_name): return load_json(path_to_json) +def project_anatomy_overrides(project_name): + if not project_name: + return {} + + path_to_json = path_to_project_anatomy(project_name) + if not os.path.exists(path_to_json): + return {} + return load_json(path_to_json) + + def merge_overrides(global_dict, override_dict): if OVERRIDEN_KEY in override_dict: overriden_keys = set(override_dict.pop(OVERRIDEN_KEY)) From f5736a7e9ab1e7b7ea537df526c63aea6509f503 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:23:02 +0200 Subject: [PATCH 514/580] anatomy loading/saving is in project widget separated --- .../config_setting/widgets/base.py | 100 +++++++++++++----- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index d7078e4ab6..6d25357fc9 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -6,13 +6,23 @@ from pype.configurations.lib import ( SYSTEM_CONFIGURATIONS_PATH, PROJECT_CONFIGURATIONS_KEY, PROJECT_CONFIGURATIONS_PATH, + PROJECT_ANATOMY_KEY, + PROJECT_ANATOMY_PATH, + DEFAULTS_DIR, + reset_default_configurations, default_configuration, + studio_system_configurations, + studio_project_configurations, + studio_project_anatomy, + project_configurations_overrides, + project_anatomy_overrides, + path_to_project_overrides, - studio_project_configurations + path_to_project_anatomy ) from .widgets import UnsavedChangesDialog from . import lib @@ -448,13 +458,22 @@ class ProjectWidget(QtWidgets.QWidget): def _on_project_change(self): project_name = self.project_list_widget.project_name() if project_name is None: - _overrides = lib.NOT_SET + _project_overrides = lib.NOT_SET + _project_anatomy = lib.NOT_SET self.is_overidable = False else: - _overrides = project_configurations_overrides(project_name) + _project_overrides = project_configurations_overrides(project_name) + _project_anatomy = project_anatomy_overrides(project_name) self.is_overidable = True - overrides = {"project": lib.convert_overrides_to_gui_data(_overrides)} + overrides = {"project": { + PROJECT_CONFIGURATIONS_KEY: lib.convert_overrides_to_gui_data( + _project_overrides + ), + PROJECT_ANATOMY_KEY: lib.convert_overrides_to_gui_data( + _project_anatomy + ) + }} self.project_name = project_name self.ignore_value_changes = True for item in self.input_fields: @@ -481,9 +500,6 @@ class ProjectWidget(QtWidgets.QWidget): # Skip first key all_values = all_values["project"] - prject_defaults_dir = os.path.join( - DEFAULTS_DIR, PROJECT_CONFIGURATIONS_KEY - ) keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: # Skip first key @@ -494,7 +510,7 @@ class ProjectWidget(QtWidgets.QWidget): for key in key_sequence: new_values = new_values[key] - output_path = os.path.join(prject_defaults_dir, subpath) + output_path = os.path.join(DEFAULTS_DIR, subpath) dirpath = os.path.dirname(output_path) if not os.path.exists(dirpath): os.makedirs(dirpath) @@ -533,7 +549,7 @@ class ProjectWidget(QtWidgets.QWidget): return if self.project_name is None: - self._save_defaults() + self._save_studio_overrides() else: self._save_overrides() @@ -548,20 +564,40 @@ class ProjectWidget(QtWidgets.QWidget): data.get("project") or {} ) - overrides_json_path = path_to_project_overrides( + # Saving overrides data + project_overrides_data = output_data.get( + PROJECT_CONFIGURATIONS_KEY, {} + ) + project_overrides_json_path = path_to_project_overrides( self.project_name ) - dirpath = os.path.dirname(overrides_json_path) + dirpath = os.path.dirname(project_overrides_json_path) if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving data to:", overrides_json_path) - with open(overrides_json_path, "w") as file_stream: - json.dump(output_data, file_stream, indent=4) + print("Saving data to:", project_overrides_json_path) + with open(project_overrides_json_path, "w") as file_stream: + json.dump(project_overrides_data, file_stream, indent=4) + # Saving anatomy data + project_anatomy_data = output_data.get( + PROJECT_ANATOMY_KEY, {} + ) + project_anatomy_json_path = path_to_project_anatomy( + self.project_name + ) + dirpath = os.path.dirname(project_anatomy_json_path) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving data to:", project_anatomy_json_path) + with open(project_anatomy_json_path, "w") as file_stream: + json.dump(project_anatomy_data, file_stream, indent=4) + + # Refill values with overrides self._on_project_change() - def _save_defaults(self): + def _save_studio_overrides(self): data = {} for input_field in self.input_fields: value, is_group = input_field.studio_overrides() @@ -572,30 +608,44 @@ class ProjectWidget(QtWidgets.QWidget): data.get("project", {}) ) + # Project overrides data + project_overrides_data = output_data.get( + PROJECT_CONFIGURATIONS_KEY, {} + ) dirpath = os.path.dirname(PROJECT_CONFIGURATIONS_PATH) if not os.path.exists(dirpath): os.makedirs(dirpath) print("Saving data to:", PROJECT_CONFIGURATIONS_PATH) - try: - with open(PROJECT_CONFIGURATIONS_PATH, "w") as file_stream: - json.dump(output_data, file_stream, indent=4) - except Exception as exc: - print(output_data) - raise + with open(PROJECT_CONFIGURATIONS_PATH, "w") as file_stream: + json.dump(project_overrides_data, file_stream, indent=4) + # Project Anatomy data + project_anatomy_data = output_data.get( + PROJECT_ANATOMY_KEY, {} + ) + dirpath = os.path.dirname(PROJECT_ANATOMY_PATH) + if not os.path.exists(dirpath): + os.makedirs(dirpath) + + print("Saving data to:", PROJECT_ANATOMY_PATH) + with open(PROJECT_ANATOMY_PATH, "w") as file_stream: + json.dump(project_anatomy_data, file_stream, indent=4) + + # Update saved values self._update_values() def _update_values(self): self.ignore_value_changes = True - default_values = { - "project": default_configuration()["project_configurations"] - } + default_values = {"project": default_configuration()} for input_field in self.input_fields: input_field.update_default_values(default_values) - studio_values = {"project": studio_project_configurations()} + studio_values = {"project": { + PROJECT_CONFIGURATIONS_KEY: studio_project_configurations(), + PROJECT_ANATOMY_KEY: studio_project_anatomy() + }} for input_field in self.input_fields: input_field.update_studio_values(studio_values) From 5eb25c7ae3ebdfe7fe66729c2f27a840f6a00dcd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:23:28 +0200 Subject: [PATCH 515/580] overrides are not saved to path from PYPE_CONFIG but to PYPE_PROJECT_CONFIGS --- pype/configurations/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index abd848f95c..9ef782ca6a 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -11,7 +11,7 @@ OVERRIDEN_KEY = "__overriden_keys__" POP_KEY = "__pop_key__" # Folder where studio overrides are stored -STUDIO_OVERRIDES_PATH = os.environ["PYPE_CONFIG"] +STUDIO_OVERRIDES_PATH = os.environ["PYPE_PROJECT_CONFIGS"] # File where studio's system overrides are stored SYSTEM_CONFIGURATIONS_KEY = "system_configurations" From 4d05ebaa71d4cc6a2f0194e610e94e01e07f12fc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 17:26:29 +0200 Subject: [PATCH 516/580] fixed roots and templates input data --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index ed73ad6468..b034bc1763 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -227,7 +227,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): super(RootsWidget, self).__init__(parent) self.setObjectName("RootsWidget") - input_data = {"is_group": True} + input_data["is_group"] = True self.initial_attributes(input_data, parent, False) self.key = input_data["key"] @@ -560,7 +560,7 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def __init__(self, input_data, parent): super(TemplatesWidget, self).__init__(parent) - input_data = {"is_group": True} + input_data["is_group"] = True self.initial_attributes(input_data, parent, False) self.key = input_data["key"] From 8a1c164f51efa34dfb5e7a964effdfbea09fcce4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 18:07:53 +0200 Subject: [PATCH 517/580] changed how the margins of main window are --- pype/tools/config_setting/config_setting/widgets/base.py | 4 ++-- pype/tools/config_setting/config_setting/widgets/window.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index 6d25357fc9..a0a470fc97 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -74,7 +74,7 @@ class SystemWidget(QtWidgets.QWidget): footer_layout.addWidget(save_btn, 0) layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(5, 0, 5, 0) + layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setLayout(layout) @@ -400,7 +400,7 @@ class ProjectWidget(QtWidgets.QWidget): configurations_widget = QtWidgets.QWidget() configurations_layout = QtWidgets.QVBoxLayout(configurations_widget) - configurations_layout.setContentsMargins(5, 0, 5, 0) + configurations_layout.setContentsMargins(0, 0, 0, 0) configurations_layout.setSpacing(0) configurations_layout.addWidget(scroll_widget, 1) diff --git a/pype/tools/config_setting/config_setting/widgets/window.py b/pype/tools/config_setting/config_setting/widgets/window.py index f8da9a196e..5c7a35fa52 100644 --- a/pype/tools/config_setting/config_setting/widgets/window.py +++ b/pype/tools/config_setting/config_setting/widgets/window.py @@ -8,18 +8,19 @@ class MainWidget(QtWidgets.QWidget): def __init__(self, develop, parent=None): super(MainWidget, self).__init__(parent) + self.setObjectName("MainWidget") self.resize(self.widget_width, self.widget_height) header_tab_widget = QtWidgets.QTabWidget(parent=self) - studio_widget = SystemWidget(develop) - project_widget = ProjectWidget(develop) + studio_widget = SystemWidget(develop, header_tab_widget) + project_widget = ProjectWidget(develop, header_tab_widget) header_tab_widget.addTab(studio_widget, "System") header_tab_widget.addTab(project_widget, "Project") layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) + layout.setContentsMargins(5, 5, 5, 5) layout.setSpacing(0) layout.addWidget(header_tab_widget) From 375188a5587ca6b36719df56af104fefb356855d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 18:08:06 +0200 Subject: [PATCH 518/580] modified tab style --- .../config_setting/style/style.css | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 73c1854bee..5b6821a85d 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -90,7 +90,7 @@ QPushButton[btn-type="expand-toggle"] { } #GroupWidget { - border: 1px solid #aaaaaa; + border-bottom: 1px solid #1d272f; } #ProjectListWidget QListView { @@ -148,6 +148,53 @@ QPushButton[btn-type="expand-toggle"] { #SideLineWidget[state="child-overriden-modified"] {border-color: #106aa2;} #SideLineWidget[state="child-overriden-modified"]:hover {border-color: #137cbd;} +#MainWidget { + background: #141a1f; +} + +QTabWidget::pane { + border-top-style: none; +} + +QTabBar { + background: transparent; +} + +QTabBar::tab { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + padding: 5px; +} + +QTabBar::tab:selected { + background: #293742; + border-color: #9B9B9B; + border-bottom-color: #C2C7CB; +} + +QTabBar::tab:!selected { + margin-top: 2px; + background: #1d272f; +} + +QTabBar::tab:!selected:hover { + background: #3b4f5e; +} + + + +QTabBar::tab:first:selected { + margin-left: 0; +} + +QTabBar::tab:last:selected { + margin-right: 0; +} + +QTabBar::tab:only-one { + margin: 0; +} + QScrollBar:horizontal { height: 15px; margin: 3px 15px 3px 15px; From 529570c906ec6f7465206039e5bf7d47310fb74c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 18:44:57 +0200 Subject: [PATCH 519/580] small changes --- .../defaults/project_anatomy/templates.json | 7 +------ .../project_configurations/plugins/global/publish.json | 3 +-- pype/tools/config_setting/config_setting/style/style.css | 8 ++++---- pype/tools/config_setting/config_setting/widgets/base.py | 2 +- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/pype/configurations/defaults/project_anatomy/templates.json b/pype/configurations/defaults/project_anatomy/templates.json index 23e9f308f2..0fff0265b3 100644 --- a/pype/configurations/defaults/project_anatomy/templates.json +++ b/pype/configurations/defaults/project_anatomy/templates.json @@ -3,33 +3,28 @@ "version": "v{version:0>{@version_padding}}", "frame_padding": 4, "frame": "{frame:0>{@frame_padding}}", - "work": { "folder": "{root}/{project[name]}/{hierarchy}/{asset}/work/{task}", "file": "{project[code]}_{asset}_{task}_{@version}<_{comment}>.{ext}", "path": "{@folder}/{@file}" }, - "render": { "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/render/{subset}/{@version}", "file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}", "path": "{@folder}/{@file}" }, - "texture": { "path": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}" }, - "publish": { "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/{@version}", "file": "{project[code]}_{asset}_{subset}_{@version}<_{output}><.{@frame}>.{representation}", "path": "{@folder}/{@file}", "thumbnail": "{thumbnail_root}/{project[name]}/{_id}_{thumbnail_type}{ext}" }, - "master": { "folder": "{root}/{project[name]}/{hierarchy}/{asset}/publish/{family}/{subset}/master", "file": "{project[code]}_{asset}_{subset}_master<_{output}><.{frame}>.{representation}", "path": "{@folder}/{@file}" } -} +} \ No newline at end of file diff --git a/pype/configurations/defaults/project_configurations/plugins/global/publish.json b/pype/configurations/defaults/project_configurations/plugins/global/publish.json index d531f1aa47..b946ac4b32 100644 --- a/pype/configurations/defaults/project_configurations/plugins/global/publish.json +++ b/pype/configurations/defaults/project_configurations/plugins/global/publish.json @@ -75,7 +75,6 @@ ] }, "IntegrateAssetNew": { - "enabled": true, "template_name_profiles": { "publish": { "families": [], @@ -96,4 +95,4 @@ "deadline_pool": "", "deadline_group": "" } -} +} \ No newline at end of file diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/config_setting/config_setting/style/style.css index 5b6821a85d..f6dd354935 100644 --- a/pype/tools/config_setting/config_setting/style/style.css +++ b/pype/tools/config_setting/config_setting/style/style.css @@ -44,9 +44,9 @@ QToolButton { QLabel { background: transparent; - color: #808080; + color: #7390a5; } -QLabel:hover {color: #999999;} +QLabel:hover {color: #839caf;} QLabel[state="studio"] {color: #bfccd6;} QLabel[state="studio"]:hover {color: #ffffff;} @@ -122,7 +122,7 @@ QPushButton[btn-type="expand-toggle"] { #SideLineWidget { background-color: #31424e; border-style: solid; - border-color: #808080; + border-color: #3b4f5e; border-left-width: 3px; border-bottom-width: 0px; border-right-width: 0px; @@ -130,7 +130,7 @@ QPushButton[btn-type="expand-toggle"] { } #SideLineWidget:hover { - border-color: #999999; + border-color: #58768d; } #SideLineWidget[state="child-studio"] {border-color: #455c6e;} diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/config_setting/config_setting/widgets/base.py index a0a470fc97..16192aadf3 100644 --- a/pype/tools/config_setting/config_setting/widgets/base.py +++ b/pype/tools/config_setting/config_setting/widgets/base.py @@ -250,7 +250,7 @@ class ProjectListWidget(QtWidgets.QWidget): self.setObjectName("ProjectListWidget") label_widget = QtWidgets.QLabel("Projects") - + label_widget.setProperty("state", "studio") project_list = ProjectListView(self) project_list.setModel(QtGui.QStandardItemModel()) From e9737d9b3a644a1958c66e18dec34101bb647b7d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:01:27 +0200 Subject: [PATCH 520/580] fix default_values for pathwidget --- pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index bc63e27f5a..4a9dd28df1 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2183,10 +2183,10 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): self._had_studio_override = False if not self.multiplatform: - self.input_fields[0].update_studio_values(value) + self.input_fields[0].update_default_values(value) else: for input_field in self.input_fields: - input_field.update_studio_values(value) + input_field.update_default_values(value) def update_studio_values(self, parent_values): self._state = None From 80c091c7fd36dafcc439b15c6e9774322d0418a4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:01:51 +0200 Subject: [PATCH 521/580] project overrides are not stored in subfolder --- pype/configurations/lib.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index 9ef782ca6a..7e24d25483 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -32,11 +32,6 @@ PROJECT_ANATOMY_PATH = os.path.join( STUDIO_OVERRIDES_PATH, PROJECT_ANATOMY_FILENAME ) -# Folder where studio's per project overrides are stored -STUDIO_PROJECT_OVERRIDES_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, "project_overrides" -) - # Path to default configurations DEFAULTS_DIR = os.path.join(os.path.dirname(__file__), "defaults") @@ -181,7 +176,7 @@ def studio_project_anatomy(): def path_to_project_overrides(project_name): return os.path.join( - STUDIO_PROJECT_OVERRIDES_PATH, + STUDIO_OVERRIDES_PATH, project_name, PROJECT_CONFIGURATIONS_FILENAME ) @@ -189,7 +184,7 @@ def path_to_project_overrides(project_name): def path_to_project_anatomy(project_name): return os.path.join( - STUDIO_PROJECT_OVERRIDES_PATH, + STUDIO_OVERRIDES_PATH, project_name, PROJECT_ANATOMY_FILENAME ) From 098c1bed80f30bcc0dc797b4a43f7e42fa99ff1c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:06:59 +0200 Subject: [PATCH 522/580] fix roots fillings --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index b034bc1763..573f48409d 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -393,9 +393,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.set_multiroot(is_multiroot) if is_multiroot: - self._is_overriden = parent_values is not NOT_SET + self._is_overriden = value is not NOT_SET self._was_overriden = bool(self._is_overriden) - self.multiroot_widget.apply_overrides(parent_values) + self.multiroot_widget.apply_overrides(value) else: self._is_overriden = value is not NOT_SET self._was_overriden = bool(self._is_overriden) From 026358a2ea3b866bda7060a068667fd3711d5f10 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:07:19 +0200 Subject: [PATCH 523/580] change order of filling values logic --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 4a9dd28df1..1280b39904 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -1054,10 +1054,10 @@ class ListWidget(QtWidgets.QWidget, InputObject): # Set text if entered text is not None # else (when add button clicked) trigger `_on_value_change` if value is not None: - if not self._has_studio_override: - item_widget.update_default_values(value) - elif self._is_overriden: + if self._is_overriden: item_widget.apply_overrides(value) + elif not self._has_studio_override: + item_widget.update_default_values(value) else: item_widget.update_studio_values(value) self.hierarchical_style_update() From 35bee377dd6b8c19ee31c62d4ca56510239e08e0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:07:39 +0200 Subject: [PATCH 524/580] change logic of roots changes for default, studio and overrides --- .../config_setting/widgets/anatomy_inputs.py | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 573f48409d..ec6da20c72 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -233,7 +233,8 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.key = input_data["key"] self._multiroot_state = None - self.global_is_multiroot = False + self.default_is_multiroot = False + self.studio_is_multiroot = False self.was_multiroot = NOT_SET checkbox_widget = QtWidgets.QWidget(self) @@ -317,7 +318,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): is_multiroot = True break - self.global_is_multiroot = is_multiroot + self.default_is_multiroot = is_multiroot self.was_multiroot = is_multiroot self.set_multiroot(is_multiroot) @@ -346,24 +347,25 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: value = NOT_SET - is_multiroot = False - if isinstance(value, dict): - for _value in value.values(): - if isinstance(_value, dict): - is_multiroot = True - break - - self.global_is_multiroot = is_multiroot - self.was_multiroot = is_multiroot - self.set_multiroot(is_multiroot) - if value is NOT_SET: + is_multiroot = self.default_is_multiroot + self.studio_is_multiroot = NOT_SET self._has_studio_override = False self._had_studio_override = False else: + is_multiroot = False + if isinstance(value, dict): + for _value in value.values(): + if isinstance(_value, dict): + is_multiroot = True + break + self.studio_is_multiroot = is_multiroot self._has_studio_override = True self._had_studio_override = True + self.was_multiroot = is_multiroot + self.set_multiroot(is_multiroot) + if is_multiroot: self.multiroot_widget.update_studio_values(value) else: @@ -380,7 +382,9 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): value = parent_values.get(self.key, value) if value is NOT_SET: - is_multiroot = self.global_is_multiroot + is_multiroot = self.studio_is_multiroot + if is_multiroot is NOT_SET: + is_multiroot = self.default_is_multiroot else: is_multiroot = False if isinstance(value, dict): @@ -517,7 +521,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._is_overriden = False self._is_modified = False - self.set_multiroot(self.global_is_multiroot) + if self.studio_is_multiroot is NOT_SET: + self.set_multiroot(self.default_is_multiroot) + else: + self.set_multiroot(self.studio_is_multiroot) if self.is_multiroot: self.multiroot_widget.remove_overrides() @@ -530,7 +537,10 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): if self._is_overriden: self.set_multiroot(self.was_multiroot) else: - self.set_multiroot(self.global_is_multiroot) + if self.studio_is_multiroot is NOT_SET: + self.set_multiroot(self.default_is_multiroot) + else: + self.set_multiroot(self.studio_is_multiroot) if self.is_multiroot: self.multiroot_widget.discard_changes() From 3351264c7c1028eac98e665f4747687ff6617e32 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:21:28 +0200 Subject: [PATCH 525/580] a little bit better changing from multi to single root --- .../config_setting/widgets/anatomy_inputs.py | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index ec6da20c72..ed104128a0 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -447,7 +447,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self._state = state def _on_multiroot_checkbox(self): - self.set_multiroot(self.is_multiroot) + self.set_multiroot() def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -471,9 +471,37 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): self.value_changed.emit(self) + def _from_single_to_multi(self): + single_value = self.singleroot_widget.item_value() + mutli_value = self.multiroot_widget.item_value() + first_key = None + for key in mutli_value.keys(): + first_key = key + break + + if first_key is None: + first_key = "" + + mutli_value[first_key] = single_value + + self.multiroot_widget.set_value(mutli_value) + + def _from_multi_to_single(self): + mutli_value = self.multiroot_widget.item_value() + first_key = None + for value in mutli_value.values(): + single_value = value + break + + self.singleroot_widget.set_value(single_value) + def set_multiroot(self, is_multiroot=None): if is_multiroot is None: - is_multiroot = not self.is_multiroot + is_multiroot = self.is_multiroot + if is_multiroot: + self._from_single_to_multi() + else: + self._from_multi_to_single() if is_multiroot != self.is_multiroot: self.multiroot_checkbox.setChecked(is_multiroot) From 93c391a9d4f084b2db79fccb9c13d3f7d331f904 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:27:01 +0200 Subject: [PATCH 526/580] changed labels of actions --- .../config_setting/config_setting/widgets/anatomy_inputs.py | 1 - pype/tools/config_setting/config_setting/widgets/inputs.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index ed104128a0..75ee12ee02 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -488,7 +488,6 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): def _from_multi_to_single(self): mutli_value = self.multiroot_widget.item_value() - first_key = None for value in mutli_value.values(): single_value = value break diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 1280b39904..c7f817a48e 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -201,7 +201,7 @@ class ConfigObject(AbstractConfigObject): and not self.is_overriden and not self.any_parent_is_group ): - action = QtWidgets.QAction("Set as overriden") + action = QtWidgets.QAction("Set project override") actions_mapping[action] = self._set_as_overriden menu.addAction(action) @@ -210,7 +210,7 @@ class ConfigObject(AbstractConfigObject): and (self.is_overriden or self.child_overriden) ): # TODO better label - action = QtWidgets.QAction("Remove override") + action = QtWidgets.QAction("Remove project override") actions_mapping[action] = self._remove_overrides menu.addAction(action) From 17362076a5b56f1e065b81a2029dec33503ab4ef Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:37:21 +0200 Subject: [PATCH 527/580] Added possibility to reset to pype's default values --- .../config_setting/widgets/anatomy_inputs.py | 15 +++++ .../config_setting/widgets/inputs.py | 64 +++++++++++++++---- .../config_setting/widgets/widgets.py | 12 ++++ 3 files changed, 79 insertions(+), 12 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py index 75ee12ee02..09544a2455 100644 --- a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py @@ -190,6 +190,10 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): self.root_widget.remove_overrides() self.templates_widget.remove_overrides() + def reset_to_pype_default(self): + self.root_widget.reset_to_pype_default() + self.templates_widget.reset_to_pype_default() + def discard_changes(self): self.root_widget.discard_changes() self.templates_widget.discard_changes() @@ -558,6 +562,14 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): else: self.singleroot_widget.remove_overrides() + def reset_to_pype_default(self): + self.set_multiroot(self.default_is_multiroot) + if self.is_multiroot: + self.multiroot_widget.reset_to_pype_default() + else: + self.singleroot_widget.reset_to_pype_default() + self._has_studio_override = False + def discard_changes(self): self._is_overriden = self._was_overriden self._is_modified = False @@ -703,6 +715,9 @@ class TemplatesWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self.value_input.remove_overrides() + def reset_to_pype_default(self): + self.value_input.reset_to_pype_default() + def discard_changes(self): self.value_input.discard_changes() diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index c7f817a48e..fe2e8032b1 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -176,6 +176,11 @@ class ConfigObject(AbstractConfigObject): self.discard_changes() self.ignore_value_changes = False + def _reset_to_pype_default(self): + self.ignore_value_changes = True + self.reset_to_pype_default() + self.ignore_value_changes = False + def _remove_overrides(self): self.ignore_value_changes = True self.remove_overrides() @@ -205,6 +210,17 @@ class ConfigObject(AbstractConfigObject): actions_mapping[action] = self._set_as_overriden menu.addAction(action) + if ( + not self.is_overidable + and ( + self.has_studio_override + or self.child_has_studio_override + ) + ): + action = QtWidgets.QAction("Reset to pype default") + actions_mapping[action] = self._reset_to_pype_default + menu.addAction(action) + if ( not self.any_parent_overriden() and (self.is_overriden or self.child_overriden) @@ -361,6 +377,10 @@ class InputObject(ConfigObject): self._is_overriden = False self._is_modified = False + def reset_to_pype_default(self): + self.set_value(self.default_value) + self._has_studio_override = False + def discard_changes(self): self._is_overriden = self._was_overriden self._has_studio_override = self._had_studio_override @@ -1618,15 +1638,20 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - for item in self.input_fields: - item.remove_overrides() + for input_field in self.input_fields: + input_field.remove_overrides() + + def reset_to_pype_default(self): + for input_field in self.input_fields: + input_field.reset_to_pype_default() + self._has_studio_override = False def discard_changes(self): self._is_overriden = self._was_overriden self._is_modified = False - for item in self.input_fields: - item.discard_changes() + for input_field in self.input_fields: + input_field.discard_changes() self._is_modified = self.child_modified @@ -1943,15 +1968,20 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - for item in self.input_fields: - item.remove_overrides() + for input_field in self.input_fields: + input_field.remove_overrides() + + def reset_to_pype_default(self): + for input_field in self.input_fields: + input_field.reset_to_pype_default() + self._has_studio_override = False def discard_changes(self): self._is_modified = False self._is_overriden = self._was_overriden - for item in self.input_fields: - item.discard_changes() + for input_field in self.input_fields: + input_field.discard_changes() self._is_modified = self.child_modified @@ -2309,8 +2339,13 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - for item in self.input_fields: - item.remove_overrides() + for input_field in self.input_fields: + input_field.remove_overrides() + + def reset_to_pype_default(self): + for input_field in self.input_fields: + input_field.reset_to_pype_default() + self._has_studio_override = False def discard_changes(self): self._is_modified = False @@ -2467,8 +2502,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - for item in self.input_fields: - item.remove_overrides() + for input_field in self.input_fields: + input_field.remove_overrides() + + def reset_to_pype_default(self): + for input_field in self.input_fields: + input_field.reset_to_pype_default() + self._has_studio_override = False def set_as_overriden(self): if self.is_overriden: diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index d7631e6fea..e8286fd919 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -400,6 +400,18 @@ class AbstractConfigObject: ) ) + def _reset_to_pype_default(self): + self.ignore_value_changes = True + self.reset_to_pype_default() + self.ignore_value_changes = False + + def reset_to_pype_default(self): + raise NotImplementedError( + "{} Method `reset_to_pype_default` not implemented!".format( + repr(self) + ) + ) + def _remove_overrides(self): self.ignore_value_changes = True self.remove_overrides() From 4996c5617041f872d487c67c38700886d3e5ad2a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:38:32 +0200 Subject: [PATCH 528/580] removed duplicated methods --- .../config_setting/widgets/inputs.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index fe2e8032b1..55b0c999d0 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -171,25 +171,6 @@ class ConfigObject(AbstractConfigObject): return "-".join(items) or cls.default_state - def _discard_changes(self): - self.ignore_value_changes = True - self.discard_changes() - self.ignore_value_changes = False - - def _reset_to_pype_default(self): - self.ignore_value_changes = True - self.reset_to_pype_default() - self.ignore_value_changes = False - - def _remove_overrides(self): - self.ignore_value_changes = True - self.remove_overrides() - self.ignore_value_changes = False - - def _set_as_overriden(self): - self.ignore_value_changes = True - self.set_as_overriden() - self.ignore_value_changes = False def mouseReleaseEvent(self, event): if self.allow_actions and event.button() == QtCore.Qt.RightButton: From 57ac12b5140def9432d16de21fc82b28a048b3fd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 19:43:44 +0200 Subject: [PATCH 529/580] added set studio defaults action --- .../config_setting/widgets/inputs.py | 43 ++++++++++++++++++- .../config_setting/widgets/widgets.py | 12 ++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 55b0c999d0..fba799e5c0 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -171,7 +171,6 @@ class ConfigObject(AbstractConfigObject): return "-".join(items) or cls.default_state - def mouseReleaseEvent(self, event): if self.allow_actions and event.button() == QtCore.Qt.RightButton: menu = QtWidgets.QMenu() @@ -202,6 +201,17 @@ class ConfigObject(AbstractConfigObject): actions_mapping[action] = self._reset_to_pype_default menu.addAction(action) + if ( + not self.is_overidable + and ( + (self.is_group and not self._had_studio_override) + or self.any_parent_is_group + ) + ): + action = QtWidgets.QAction("Set sudio default") + actions_mapping[action] = self._set_studio_default + menu.addAction(action) + if ( not self.any_parent_overriden() and (self.is_overriden or self.child_overriden) @@ -362,6 +372,9 @@ class InputObject(ConfigObject): self.set_value(self.default_value) self._has_studio_override = False + def set_studio_default(self): + self._has_studio_override = True + def discard_changes(self): self._is_overriden = self._was_overriden self._has_studio_override = self._had_studio_override @@ -1627,6 +1640,13 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): input_field.reset_to_pype_default() self._has_studio_override = False + def set_studio_default(self): + for input_field in self.input_fields: + input_field.set_studio_default() + + if self.is_group: + self._has_studio_override = True + def discard_changes(self): self._is_overriden = self._was_overriden self._is_modified = False @@ -1957,6 +1977,13 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): input_field.reset_to_pype_default() self._has_studio_override = False + def set_studio_default(self): + for input_field in self.input_fields: + input_field.set_studio_default() + + if self.is_group: + self._has_studio_override = True + def discard_changes(self): self._is_modified = False self._is_overriden = self._was_overriden @@ -2328,6 +2355,13 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): input_field.reset_to_pype_default() self._has_studio_override = False + def set_studio_default(self): + for input_field in self.input_fields: + input_field.set_studio_default() + + if self.is_group: + self._has_studio_override = True + def discard_changes(self): self._is_modified = False self._is_overriden = self._was_overriden @@ -2491,6 +2525,13 @@ class DictFormWidget(QtWidgets.QWidget, ConfigObject): input_field.reset_to_pype_default() self._has_studio_override = False + def set_studio_default(self): + for input_field in self.input_fields: + input_field.set_studio_default() + + if self.is_group: + self._has_studio_override = True + def set_as_overriden(self): if self.is_overriden: return diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/config_setting/config_setting/widgets/widgets.py index e8286fd919..aa1f17a7f4 100644 --- a/pype/tools/config_setting/config_setting/widgets/widgets.py +++ b/pype/tools/config_setting/config_setting/widgets/widgets.py @@ -400,6 +400,18 @@ class AbstractConfigObject: ) ) + def _set_studio_default(self): + self.ignore_value_changes = True + self.set_studio_default() + self.ignore_value_changes = False + + def set_studio_default(self): + raise NotImplementedError( + "{} Method `set_studio_default` not implemented!".format( + repr(self) + ) + ) + def _reset_to_pype_default(self): self.ignore_value_changes = True self.reset_to_pype_default() From 689438f63adfa1f264071c9e9f266a733a272ba6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 10:11:09 +0200 Subject: [PATCH 530/580] removed separators from PathWidget --- pype/tools/config_setting/config_setting/widgets/inputs.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index fba799e5c0..61a5aac435 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -2089,12 +2089,6 @@ class PathWidget(QtWidgets.QWidget, ConfigObject): "darwin": "MacOS", "linux": "Linux" } - # TODO be able to save and load with separators - platform_separators = { - "windows": ";", - "darwin": ":", - "linux": ":" - } def __init__( self, input_data, parent, From ffa4bd4f073997f3092750f6259a35f68c05f2a3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 10:32:20 +0200 Subject: [PATCH 531/580] ListWidget has items next to label instead of under --- .../config_setting/config_setting/widgets/inputs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/config_setting/config_setting/widgets/inputs.py index 61a5aac435..fa809cd2d2 100644 --- a/pype/tools/config_setting/config_setting/widgets/inputs.py +++ b/pype/tools/config_setting/config_setting/widgets/inputs.py @@ -999,14 +999,14 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.input_fields = [] - layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 5) + layout.setSpacing(5) if not label_widget: - label = input_data["label"] - label_widget = QtWidgets.QLabel(label) + label_widget = QtWidgets.QLabel(input_data["label"], self) layout.addWidget(label_widget) + self.label_widget = label_widget inputs_widget = QtWidgets.QWidget(self) @@ -1014,7 +1014,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): layout.addWidget(inputs_widget) inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) - inputs_layout.setContentsMargins(0, 5, 0, 5) + inputs_layout.setContentsMargins(0, 0, 0, 0) inputs_layout.setSpacing(3) self.inputs_widget = inputs_widget From dff5da3a5ef2e3f2c0d7a9f5b684be8c536b899b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 11:42:33 +0200 Subject: [PATCH 532/580] removed label from dict-invisible --- .../config_gui_schema/system_schema/0_system_gui_schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json index bdc0158511..b16545111c 100644 --- a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json +++ b/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json @@ -5,7 +5,6 @@ { "type": "dict-invisible", "key": "global", - "label": "Global", "children": [{ "type": "schema", "children": [ From 8f10391b53ae23640c9ffcb016419a57ffa49320 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 12:21:55 +0200 Subject: [PATCH 533/580] renamed config_setting to settings --- pype/tools/helpguide.txt | 153 ++++++++++++++++++ .../{config_setting => settings}/__init__.py | 2 +- .../{config_setting => settings}/__main__.py | 8 +- .../settings}/__init__.py | 0 .../projects_schema/0_project_gui_schema.json | 0 .../projects_schema/1_plugins_gui_schema.json | 0 .../system_schema/0_system_gui_schema.json | 0 .../1_applications_gui_schema.json | 0 .../system_schema/1_intents_gui_schema.json | 0 .../system_schema/1_tools_gui_schema.json | 0 .../system_schema/1_tray_items.json | 0 .../settings}/style/__init__.py | 0 .../settings}/style/pype_icon.png | Bin .../settings}/style/style.css | 0 .../settings}/widgets/__init__.py | 0 .../settings}/widgets/anatomy_inputs.py | 0 .../settings}/widgets/base.py | 0 .../settings}/widgets/inputs.py | 0 .../settings}/widgets/lib.py | 0 .../settings}/widgets/tests.py | 0 .../settings}/widgets/widgets.py | 0 .../settings}/widgets/window.py | 0 22 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 pype/tools/helpguide.txt rename pype/tools/{config_setting => settings}/__init__.py (50%) rename pype/tools/{config_setting => settings}/__main__.py (53%) rename pype/tools/{config_setting/config_setting => settings/settings}/__init__.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/projects_schema/0_project_gui_schema.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/projects_schema/1_plugins_gui_schema.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/system_schema/0_system_gui_schema.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/system_schema/1_applications_gui_schema.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/system_schema/1_intents_gui_schema.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/system_schema/1_tools_gui_schema.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/config_gui_schema/system_schema/1_tray_items.json (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/style/__init__.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/style/pype_icon.png (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/style/style.css (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/__init__.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/anatomy_inputs.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/base.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/inputs.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/lib.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/tests.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/widgets.py (100%) rename pype/tools/{config_setting/config_setting => settings/settings}/widgets/window.py (100%) diff --git a/pype/tools/helpguide.txt b/pype/tools/helpguide.txt new file mode 100644 index 0000000000..b0c9471e3e --- /dev/null +++ b/pype/tools/helpguide.txt @@ -0,0 +1,153 @@ +## Basic rules +- configurations does not define GUI, but GUI defines configurations! +- output is always json (yaml is not needed for anatomy templates anymore) +- GUI schema has multiple input types, all inputs are represented by a dictionary +- each input may have "input modifiers" (keys in dictionary) that are required or optional + - only required modifier for all input items is key `"type"` which says what type of item it is +- there are special keys across all inputs + - `"is_file"` - this key is for storing pype defaults in `pype` repo + - reasons of existence: developing new schemas does not require to create defaults manually + - key is validated, must be once in hierarchy else it won't be possible to store pype defaults + - `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides + - key is validated, can be only once in hierarchy but is not required + +## Basic Dictionary inputs +- these inputs wraps another inputs into {key: value} relation + +## dict-invisible +- this input gives ability to wrap another inputs but keep them in same widget without visible divider + - this is used as first input widget +- has required keys `"key"` and `"children"` + - "children" says what children inputs are underneath + - "key" is key under which will be stored value from it's children +- output is dictionary `{the "key": children values}` + +``` +{ + "type": "dict-invisible", + "key": "global", + "children": [{ + ... + }] +} +``` + +## dict +- this is another dictionary input wrapping more inputs but visually makes them different + +``` +{ + "key": "applications", + "type": "dict", + "label": "Applications", + "expandable": true, + "is_group": true, + "is_file": true, +} +``` + +## Inputs for setting any kind of value (`Pure` inputs) +- all these input must have defined `"key"` under which will be stored and `"label"` which will be shown next to input + - unless they are used in different types of inputs (later) "as widgets" in that case `"key"` and `"label"` are not required as there is not place where to set them + +### boolean +- simple checkbox, nothing more to set +``` +{ + "type": "boolean", + "key": "my_boolean_key", + "label": "Do you want to use Pype?" +} +``` + +### number +- number input, can be used for both integer and float + - key `"decimal"` defines how many decimal places will be used, 0 is for integer input (Default: `0`) + - key `"minimum"` as minimum allowed number to enter (Default: `-99999`) + - key `"maxium"` as maximum allowed number to enter (Default: `99999`) +``` +{ + "type": "number", + "key": "fps", + "label": "Frame rate (FPS)" + "decimal": 2, + "minimum": 1, + "maximum": 300000 +} +``` + +### text +- simple text input + - key `"multiline"` allows to enter multiple lines of text (Default: `False`) + +``` +{ + "type": "text", + "key": "deadline_pool", + "label": "Deadline pool" +} +``` + +### raw-json +- a little bit enhanced text input for raw json +- has validations of json format + - empty value is invalid value, always must be at least `{}` of `[]` + +``` +{ + "type": "raw-json", + "key": "profiles", + "label": "Extract Review profiles" +} +``` + +## Inputs for setting value using Pure inputs +- these inputs also have required `"key"` and `"label"` +- they use Pure inputs "as widgets" + +### list +- output is list +- items can be added and removed +- items in list must be the same type + - type of items is defined with key `"object_type"` where Pure input name is entered (e.g. `number`) + - because Pure inputs may have modifiers (`number` input has `minimum`, `maximum` and `decimals`) you can set these in key `"input_modifiers"` + +``` +{ + "type": "list", + "object_type": "number", + "key": "exclude_ports", + "label": "Exclude ports", + "input_modifiers": { + "minimum": 1, + "maximum": 65535 + } +} +``` + +### dict-modifiable +- one of dictionary inputs, this is only used as value input +- items in this input can be removed and added same way as in `list` input +- value items in dictionary must be the same type + - type of items is defined with key `"object_type"` where Pure input name is entered (e.g. `number`) + - because Pure inputs may have modifiers (`number` input has `minimum`, `maximum` and `decimals`) you can set these in key `"input_modifiers"` +- this input can be expandable + - that can be set with key `"expandable"` as `True`/`False` (Default: `True`) + - with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`) + +``` +{ + "type": "dict-modifiable", + "object_type": "number", + "input_modifiers": { + "minimum": 0, + "maximum": 300 + }, + "is_group": true, + "key": "templates_mapping", + "label": "Muster - Templates mapping", + "is_file": true +} +``` + +Currently there are `system configurations` and `project configurations`. Both has `root` schema where all begins. diff --git a/pype/tools/config_setting/__init__.py b/pype/tools/settings/__init__.py similarity index 50% rename from pype/tools/config_setting/__init__.py rename to pype/tools/settings/__init__.py index c3bd49449d..7df121f06e 100644 --- a/pype/tools/config_setting/__init__.py +++ b/pype/tools/settings/__init__.py @@ -1,4 +1,4 @@ -from config_setting import style, MainWidget +from settings import style, MainWidget __all__ = ( diff --git a/pype/tools/config_setting/__main__.py b/pype/tools/settings/__main__.py similarity index 53% rename from pype/tools/config_setting/__main__.py rename to pype/tools/settings/__main__.py index 0e4ab1c0aa..044c2ef495 100644 --- a/pype/tools/config_setting/__main__.py +++ b/pype/tools/settings/__main__.py @@ -1,18 +1,18 @@ import sys -import config_setting +import settings from Qt import QtWidgets, QtGui if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) - stylesheet = config_setting.style.load_stylesheet() + stylesheet = settings.style.load_stylesheet() app.setStyleSheet(stylesheet) - app.setWindowIcon(QtGui.QIcon(config_setting.style.app_icon_path())) + app.setWindowIcon(QtGui.QIcon(settings.style.app_icon_path())) develop = "-dev" in sys.argv - widget = config_setting.MainWidget(develop) + widget = settings.MainWidget(develop) widget.show() sys.exit(app.exec_()) diff --git a/pype/tools/config_setting/config_setting/__init__.py b/pype/tools/settings/settings/__init__.py similarity index 100% rename from pype/tools/config_setting/config_setting/__init__.py rename to pype/tools/settings/settings/__init__.py diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/config_gui_schema/projects_schema/0_project_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/0_project_gui_schema.json rename to pype/tools/settings/settings/config_gui_schema/projects_schema/0_project_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/config_gui_schema/projects_schema/1_plugins_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/projects_schema/1_plugins_gui_schema.json rename to pype/tools/settings/settings/config_gui_schema/projects_schema/1_plugins_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json b/pype/tools/settings/settings/config_gui_schema/system_schema/0_system_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/system_schema/0_system_gui_schema.json rename to pype/tools/settings/settings/config_gui_schema/system_schema/0_system_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json b/pype/tools/settings/settings/config_gui_schema/system_schema/1_applications_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_applications_gui_schema.json rename to pype/tools/settings/settings/config_gui_schema/system_schema/1_applications_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json b/pype/tools/settings/settings/config_gui_schema/system_schema/1_intents_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_intents_gui_schema.json rename to pype/tools/settings/settings/config_gui_schema/system_schema/1_intents_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json b/pype/tools/settings/settings/config_gui_schema/system_schema/1_tools_gui_schema.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tools_gui_schema.json rename to pype/tools/settings/settings/config_gui_schema/system_schema/1_tools_gui_schema.json diff --git a/pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json b/pype/tools/settings/settings/config_gui_schema/system_schema/1_tray_items.json similarity index 100% rename from pype/tools/config_setting/config_setting/config_gui_schema/system_schema/1_tray_items.json rename to pype/tools/settings/settings/config_gui_schema/system_schema/1_tray_items.json diff --git a/pype/tools/config_setting/config_setting/style/__init__.py b/pype/tools/settings/settings/style/__init__.py similarity index 100% rename from pype/tools/config_setting/config_setting/style/__init__.py rename to pype/tools/settings/settings/style/__init__.py diff --git a/pype/tools/config_setting/config_setting/style/pype_icon.png b/pype/tools/settings/settings/style/pype_icon.png similarity index 100% rename from pype/tools/config_setting/config_setting/style/pype_icon.png rename to pype/tools/settings/settings/style/pype_icon.png diff --git a/pype/tools/config_setting/config_setting/style/style.css b/pype/tools/settings/settings/style/style.css similarity index 100% rename from pype/tools/config_setting/config_setting/style/style.css rename to pype/tools/settings/settings/style/style.css diff --git a/pype/tools/config_setting/config_setting/widgets/__init__.py b/pype/tools/settings/settings/widgets/__init__.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/__init__.py rename to pype/tools/settings/settings/widgets/__init__.py diff --git a/pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py b/pype/tools/settings/settings/widgets/anatomy_inputs.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/anatomy_inputs.py rename to pype/tools/settings/settings/widgets/anatomy_inputs.py diff --git a/pype/tools/config_setting/config_setting/widgets/base.py b/pype/tools/settings/settings/widgets/base.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/base.py rename to pype/tools/settings/settings/widgets/base.py diff --git a/pype/tools/config_setting/config_setting/widgets/inputs.py b/pype/tools/settings/settings/widgets/inputs.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/inputs.py rename to pype/tools/settings/settings/widgets/inputs.py diff --git a/pype/tools/config_setting/config_setting/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/lib.py rename to pype/tools/settings/settings/widgets/lib.py diff --git a/pype/tools/config_setting/config_setting/widgets/tests.py b/pype/tools/settings/settings/widgets/tests.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/tests.py rename to pype/tools/settings/settings/widgets/tests.py diff --git a/pype/tools/config_setting/config_setting/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/widgets.py rename to pype/tools/settings/settings/widgets/widgets.py diff --git a/pype/tools/config_setting/config_setting/widgets/window.py b/pype/tools/settings/settings/widgets/window.py similarity index 100% rename from pype/tools/config_setting/config_setting/widgets/window.py rename to pype/tools/settings/settings/widgets/window.py From 9e016906458aeaa15634f9f9e1ca03f843e1a4ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 12:27:15 +0200 Subject: [PATCH 534/580] folder config_gui_schema renamed to gui_schemas --- .../projects_schema/0_project_gui_schema.json | 0 .../projects_schema/1_plugins_gui_schema.json | 0 .../system_schema/0_system_gui_schema.json | 0 .../system_schema/1_applications_gui_schema.json | 0 .../system_schema/1_intents_gui_schema.json | 0 .../system_schema/1_tools_gui_schema.json | 0 .../system_schema/1_tray_items.json | 0 pype/tools/settings/settings/widgets/lib.py | 2 +- 8 files changed, 1 insertion(+), 1 deletion(-) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/projects_schema/0_project_gui_schema.json (100%) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/projects_schema/1_plugins_gui_schema.json (100%) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/system_schema/0_system_gui_schema.json (100%) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/system_schema/1_applications_gui_schema.json (100%) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/system_schema/1_intents_gui_schema.json (100%) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/system_schema/1_tools_gui_schema.json (100%) rename pype/tools/settings/settings/{config_gui_schema => gui_schemas}/system_schema/1_tray_items.json (100%) diff --git a/pype/tools/settings/settings/config_gui_schema/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/projects_schema/0_project_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json diff --git a/pype/tools/settings/settings/config_gui_schema/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/projects_schema/1_plugins_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json diff --git a/pype/tools/settings/settings/config_gui_schema/system_schema/0_system_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/system_schema/0_system_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json diff --git a/pype/tools/settings/settings/config_gui_schema/system_schema/1_applications_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_applications_gui_schema.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/system_schema/1_applications_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/system_schema/1_applications_gui_schema.json diff --git a/pype/tools/settings/settings/config_gui_schema/system_schema/1_intents_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_intents_gui_schema.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/system_schema/1_intents_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/system_schema/1_intents_gui_schema.json diff --git a/pype/tools/settings/settings/config_gui_schema/system_schema/1_tools_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_tools_gui_schema.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/system_schema/1_tools_gui_schema.json rename to pype/tools/settings/settings/gui_schemas/system_schema/1_tools_gui_schema.json diff --git a/pype/tools/settings/settings/config_gui_schema/system_schema/1_tray_items.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json similarity index 100% rename from pype/tools/settings/settings/config_gui_schema/system_schema/1_tray_items.json rename to pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index daba87de15..9f54b090cb 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -278,7 +278,7 @@ def gui_schema(subfolder, main_schema_name): subfolder, main_schema_name dirpath = os.path.join( os.path.dirname(os.path.dirname(__file__)), - "config_gui_schema", + "gui_schemas", subfolder ) From 1c8d2c3a3065da76e13d2c65480f320faf6645d5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 12:53:20 +0200 Subject: [PATCH 535/580] removed temp file --- pype/tools/helpguide.txt | 153 --------------------------------------- 1 file changed, 153 deletions(-) delete mode 100644 pype/tools/helpguide.txt diff --git a/pype/tools/helpguide.txt b/pype/tools/helpguide.txt deleted file mode 100644 index b0c9471e3e..0000000000 --- a/pype/tools/helpguide.txt +++ /dev/null @@ -1,153 +0,0 @@ -## Basic rules -- configurations does not define GUI, but GUI defines configurations! -- output is always json (yaml is not needed for anatomy templates anymore) -- GUI schema has multiple input types, all inputs are represented by a dictionary -- each input may have "input modifiers" (keys in dictionary) that are required or optional - - only required modifier for all input items is key `"type"` which says what type of item it is -- there are special keys across all inputs - - `"is_file"` - this key is for storing pype defaults in `pype` repo - - reasons of existence: developing new schemas does not require to create defaults manually - - key is validated, must be once in hierarchy else it won't be possible to store pype defaults - - `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides - - key is validated, can be only once in hierarchy but is not required - -## Basic Dictionary inputs -- these inputs wraps another inputs into {key: value} relation - -## dict-invisible -- this input gives ability to wrap another inputs but keep them in same widget without visible divider - - this is used as first input widget -- has required keys `"key"` and `"children"` - - "children" says what children inputs are underneath - - "key" is key under which will be stored value from it's children -- output is dictionary `{the "key": children values}` - -``` -{ - "type": "dict-invisible", - "key": "global", - "children": [{ - ... - }] -} -``` - -## dict -- this is another dictionary input wrapping more inputs but visually makes them different - -``` -{ - "key": "applications", - "type": "dict", - "label": "Applications", - "expandable": true, - "is_group": true, - "is_file": true, -} -``` - -## Inputs for setting any kind of value (`Pure` inputs) -- all these input must have defined `"key"` under which will be stored and `"label"` which will be shown next to input - - unless they are used in different types of inputs (later) "as widgets" in that case `"key"` and `"label"` are not required as there is not place where to set them - -### boolean -- simple checkbox, nothing more to set -``` -{ - "type": "boolean", - "key": "my_boolean_key", - "label": "Do you want to use Pype?" -} -``` - -### number -- number input, can be used for both integer and float - - key `"decimal"` defines how many decimal places will be used, 0 is for integer input (Default: `0`) - - key `"minimum"` as minimum allowed number to enter (Default: `-99999`) - - key `"maxium"` as maximum allowed number to enter (Default: `99999`) -``` -{ - "type": "number", - "key": "fps", - "label": "Frame rate (FPS)" - "decimal": 2, - "minimum": 1, - "maximum": 300000 -} -``` - -### text -- simple text input - - key `"multiline"` allows to enter multiple lines of text (Default: `False`) - -``` -{ - "type": "text", - "key": "deadline_pool", - "label": "Deadline pool" -} -``` - -### raw-json -- a little bit enhanced text input for raw json -- has validations of json format - - empty value is invalid value, always must be at least `{}` of `[]` - -``` -{ - "type": "raw-json", - "key": "profiles", - "label": "Extract Review profiles" -} -``` - -## Inputs for setting value using Pure inputs -- these inputs also have required `"key"` and `"label"` -- they use Pure inputs "as widgets" - -### list -- output is list -- items can be added and removed -- items in list must be the same type - - type of items is defined with key `"object_type"` where Pure input name is entered (e.g. `number`) - - because Pure inputs may have modifiers (`number` input has `minimum`, `maximum` and `decimals`) you can set these in key `"input_modifiers"` - -``` -{ - "type": "list", - "object_type": "number", - "key": "exclude_ports", - "label": "Exclude ports", - "input_modifiers": { - "minimum": 1, - "maximum": 65535 - } -} -``` - -### dict-modifiable -- one of dictionary inputs, this is only used as value input -- items in this input can be removed and added same way as in `list` input -- value items in dictionary must be the same type - - type of items is defined with key `"object_type"` where Pure input name is entered (e.g. `number`) - - because Pure inputs may have modifiers (`number` input has `minimum`, `maximum` and `decimals`) you can set these in key `"input_modifiers"` -- this input can be expandable - - that can be set with key `"expandable"` as `True`/`False` (Default: `True`) - - with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`) - -``` -{ - "type": "dict-modifiable", - "object_type": "number", - "input_modifiers": { - "minimum": 0, - "maximum": 300 - }, - "is_group": true, - "key": "templates_mapping", - "label": "Muster - Templates mapping", - "is_file": true -} -``` - -Currently there are `system configurations` and `project configurations`. Both has `root` schema where all begins. From 2f2eb3689bf726cf5ecc4613ad6eafe0e1309d9c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:13:43 +0200 Subject: [PATCH 536/580] extracted config.py to __init__.py --- pype/configurations/__init__.py | 9 +++++++++ pype/configurations/config.py | 24 ------------------------ pype/configurations/lib.py | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 pype/configurations/__init__.py delete mode 100644 pype/configurations/config.py diff --git a/pype/configurations/__init__.py b/pype/configurations/__init__.py new file mode 100644 index 0000000000..e3fc53fcfd --- /dev/null +++ b/pype/configurations/__init__.py @@ -0,0 +1,9 @@ +from .lib import ( + system_configurations, + project_configurations +) + +__all__ = ( + "system_configurations", + "project_configurations" +) diff --git a/pype/configurations/config.py b/pype/configurations/config.py deleted file mode 100644 index ed7104427f..0000000000 --- a/pype/configurations/config.py +++ /dev/null @@ -1,24 +0,0 @@ -from .lib import ( - apply_overrides, - default_configuration, - studio_system_configurations, - studio_project_configurations, - project_configurations_overrides -) - - -def system_configurations(): - default_values = default_configuration()["system_configurations"] - studio_values = studio_system_configurations() - return apply_overrides(default_values, studio_values) - - -def project_configurations(project_name): - default_values = default_configuration()["project_configurations"] - studio_values = studio_project_configurations() - - studio_overrides = apply_overrides(default_values, studio_values) - - project_overrides = project_configurations_overrides(project_name) - - return apply_overrides(studio_overrides, project_overrides) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index 7e24d25483..6fb90261e1 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -239,3 +239,20 @@ def apply_overrides(global_presets, project_overrides): if not project_overrides: return global_presets return merge_overrides(global_presets, project_overrides) + + +def system_configurations(): + default_values = default_configuration()["system_configurations"] + studio_values = studio_system_configurations() + return apply_overrides(default_values, studio_values) + + +def project_configurations(project_name): + default_values = default_configuration()["project_configurations"] + studio_values = studio_project_configurations() + + studio_overrides = apply_overrides(default_values, studio_values) + + project_overrides = project_configurations_overrides(project_name) + + return apply_overrides(studio_overrides, project_overrides) From 9b466e93728e324462961cfb210bb059c5b4c279 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:15:40 +0200 Subject: [PATCH 537/580] renamed configuration constants to settings constant names --- pype/configurations/lib.py | 38 ++++++++++---------- pype/tools/settings/settings/widgets/base.py | 26 +++++++------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/pype/configurations/lib.py b/pype/configurations/lib.py index 6fb90261e1..101b579b14 100644 --- a/pype/configurations/lib.py +++ b/pype/configurations/lib.py @@ -14,16 +14,16 @@ POP_KEY = "__pop_key__" STUDIO_OVERRIDES_PATH = os.environ["PYPE_PROJECT_CONFIGS"] # File where studio's system overrides are stored -SYSTEM_CONFIGURATIONS_KEY = "system_configurations" -SYSTEM_CONFIGURATIONS_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, SYSTEM_CONFIGURATIONS_KEY + ".json" +SYSTEM_SETTINGS_KEY = "system_configurations" +SYSTEM_SETTINGS_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, SYSTEM_SETTINGS_KEY + ".json" ) # File where studio's default project overrides are stored -PROJECT_CONFIGURATIONS_KEY = "project_configurations" -PROJECT_CONFIGURATIONS_FILENAME = PROJECT_CONFIGURATIONS_KEY + ".json" -PROJECT_CONFIGURATIONS_PATH = os.path.join( - STUDIO_OVERRIDES_PATH, PROJECT_CONFIGURATIONS_FILENAME +PROJECT_SETTINGS_KEY = "project_configurations" +PROJECT_SETTINGS_FILENAME = PROJECT_SETTINGS_KEY + ".json" +PROJECT_SETTINGS_PATH = os.path.join( + STUDIO_OVERRIDES_PATH, PROJECT_SETTINGS_FILENAME ) PROJECT_ANATOMY_KEY = "project_anatomy" @@ -36,19 +36,19 @@ PROJECT_ANATOMY_PATH = os.path.join( DEFAULTS_DIR = os.path.join(os.path.dirname(__file__), "defaults") # Variable where cache of default configurations are stored -_DEFAULT_CONFIGURATIONS = None +_DEFAULT_SETTINGS = None def reset_default_configurations(): - global _DEFAULT_CONFIGURATIONS - _DEFAULT_CONFIGURATIONS = None + global _DEFAULT_SETTINGS + _DEFAULT_SETTINGS = None def default_configuration(): - global _DEFAULT_CONFIGURATIONS - if _DEFAULT_CONFIGURATIONS is None: - _DEFAULT_CONFIGURATIONS = load_jsons_from_dir(DEFAULTS_DIR) - return _DEFAULT_CONFIGURATIONS + global _DEFAULT_SETTINGS + if _DEFAULT_SETTINGS is None: + _DEFAULT_SETTINGS = load_jsons_from_dir(DEFAULTS_DIR) + return _DEFAULT_SETTINGS def load_json(fpath): @@ -157,14 +157,14 @@ def load_jsons_from_dir(path, *args, **kwargs): def studio_system_configurations(): - if os.path.exists(SYSTEM_CONFIGURATIONS_PATH): - return load_json(SYSTEM_CONFIGURATIONS_PATH) + if os.path.exists(SYSTEM_SETTINGS_PATH): + return load_json(SYSTEM_SETTINGS_PATH) return {} def studio_project_configurations(): - if os.path.exists(PROJECT_CONFIGURATIONS_PATH): - return load_json(PROJECT_CONFIGURATIONS_PATH) + if os.path.exists(PROJECT_SETTINGS_PATH): + return load_json(PROJECT_SETTINGS_PATH) return {} @@ -178,7 +178,7 @@ def path_to_project_overrides(project_name): return os.path.join( STUDIO_OVERRIDES_PATH, project_name, - PROJECT_CONFIGURATIONS_FILENAME + PROJECT_SETTINGS_FILENAME ) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 16192aadf3..e1d167a9f2 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -3,9 +3,9 @@ import json from Qt import QtWidgets, QtCore, QtGui from pype.configurations.lib import ( SYSTEM_CONFIGURATIONS_KEY, - SYSTEM_CONFIGURATIONS_PATH, - PROJECT_CONFIGURATIONS_KEY, - PROJECT_CONFIGURATIONS_PATH, + SYSTEM_SETTINGS_PATH, + PROJECT_SETTINGS_KEY, + PROJECT_SETTINGS_PATH, PROJECT_ANATOMY_KEY, PROJECT_ANATOMY_PATH, @@ -148,12 +148,12 @@ class SystemWidget(QtWidgets.QWidget): values = lib.convert_gui_data_to_overrides(_data.get("system", {})) - dirpath = os.path.dirname(SYSTEM_CONFIGURATIONS_PATH) + dirpath = os.path.dirname(SYSTEM_SETTINGS_PATH) if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving data to:", SYSTEM_CONFIGURATIONS_PATH) - with open(SYSTEM_CONFIGURATIONS_PATH, "w") as file_stream: + print("Saving data to:", SYSTEM_SETTINGS_PATH) + with open(SYSTEM_SETTINGS_PATH, "w") as file_stream: json.dump(values, file_stream, indent=4) self._update_values() @@ -467,7 +467,7 @@ class ProjectWidget(QtWidgets.QWidget): self.is_overidable = True overrides = {"project": { - PROJECT_CONFIGURATIONS_KEY: lib.convert_overrides_to_gui_data( + PROJECT_SETTINGS_KEY: lib.convert_overrides_to_gui_data( _project_overrides ), PROJECT_ANATOMY_KEY: lib.convert_overrides_to_gui_data( @@ -566,7 +566,7 @@ class ProjectWidget(QtWidgets.QWidget): # Saving overrides data project_overrides_data = output_data.get( - PROJECT_CONFIGURATIONS_KEY, {} + PROJECT_SETTINGS_KEY, {} ) project_overrides_json_path = path_to_project_overrides( self.project_name @@ -610,14 +610,14 @@ class ProjectWidget(QtWidgets.QWidget): # Project overrides data project_overrides_data = output_data.get( - PROJECT_CONFIGURATIONS_KEY, {} + PROJECT_SETTINGS_KEY, {} ) - dirpath = os.path.dirname(PROJECT_CONFIGURATIONS_PATH) + dirpath = os.path.dirname(PROJECT_SETTINGS_PATH) if not os.path.exists(dirpath): os.makedirs(dirpath) - print("Saving data to:", PROJECT_CONFIGURATIONS_PATH) - with open(PROJECT_CONFIGURATIONS_PATH, "w") as file_stream: + print("Saving data to:", PROJECT_SETTINGS_PATH) + with open(PROJECT_SETTINGS_PATH, "w") as file_stream: json.dump(project_overrides_data, file_stream, indent=4) # Project Anatomy data @@ -643,7 +643,7 @@ class ProjectWidget(QtWidgets.QWidget): input_field.update_default_values(default_values) studio_values = {"project": { - PROJECT_CONFIGURATIONS_KEY: studio_project_configurations(), + PROJECT_SETTINGS_KEY: studio_project_configurations(), PROJECT_ANATOMY_KEY: studio_project_anatomy() }} for input_field in self.input_fields: From b4860169c58fb8f3a964bb3915668f99fc3d31dc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:17:50 +0200 Subject: [PATCH 538/580] renamed most of variables with configuration in name to settings --- .../settings/widgets/anatomy_inputs.py | 8 ++++---- .../tools/settings/settings/widgets/inputs.py | 20 +++++++++---------- .../settings/settings/widgets/widgets.py | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_inputs.py b/pype/tools/settings/settings/widgets/anatomy_inputs.py index 09544a2455..0e7e094be5 100644 --- a/pype/tools/settings/settings/widgets/anatomy_inputs.py +++ b/pype/tools/settings/settings/widgets/anatomy_inputs.py @@ -1,10 +1,10 @@ from Qt import QtWidgets, QtCore from .widgets import ExpandingWidget -from .inputs import ConfigObject, ModifiableDict, PathWidget, RawJsonWidget +from .inputs import SettingObject, ModifiableDict, PathWidget, RawJsonWidget from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET, METADATA_KEY -class AnatomyWidget(QtWidgets.QWidget, ConfigObject): +class AnatomyWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) template_keys = ( "project[name]", @@ -224,7 +224,7 @@ class AnatomyWidget(QtWidgets.QWidget, ConfigObject): return {self.key: self.item_value()} -class RootsWidget(QtWidgets.QWidget, ConfigObject): +class RootsWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) def __init__(self, input_data, parent): @@ -603,7 +603,7 @@ class RootsWidget(QtWidgets.QWidget, ConfigObject): return {self.key: self.item_value()} -class TemplatesWidget(QtWidgets.QWidget, ConfigObject): +class TemplatesWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) def __init__(self, input_data, parent): diff --git a/pype/tools/settings/settings/widgets/inputs.py b/pype/tools/settings/settings/widgets/inputs.py index fa809cd2d2..aa72f1c81f 100644 --- a/pype/tools/settings/settings/widgets/inputs.py +++ b/pype/tools/settings/settings/widgets/inputs.py @@ -3,7 +3,7 @@ import logging import collections from Qt import QtWidgets, QtCore, QtGui from .widgets import ( - AbstractConfigObject, + AbstractSettingObject, ExpandingWidget, NumberSpinBox, PathInput @@ -11,7 +11,7 @@ from .widgets import ( from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET -class ConfigObject(AbstractConfigObject): +class SettingObject(AbstractSettingObject): default_input_value = NOT_SET allow_actions = True default_state = "" @@ -88,7 +88,7 @@ class ConfigObject(AbstractConfigObject): @property def any_parent_is_group(self): if self._any_parent_is_group is None: - return super(ConfigObject, self).any_parent_is_group + return super(SettingObject, self).any_parent_is_group return self._any_parent_is_group @property @@ -246,7 +246,7 @@ class ConfigObject(AbstractConfigObject): return item.mouseReleaseEvent(self, event) -class InputObject(ConfigObject): +class InputObject(SettingObject): def update_default_values(self, parent_values): self._state = None self._is_modified = False @@ -879,7 +879,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): return self.text_input.json_value() -class ListItem(QtWidgets.QWidget, ConfigObject): +class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1157,7 +1157,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): return output -class ModifiableDictItem(QtWidgets.QWidget, ConfigObject): +class ModifiableDictItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -1534,7 +1534,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): # Dictionaries -class DictWidget(QtWidgets.QWidget, ConfigObject): +class DictWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) def __init__( @@ -1856,7 +1856,7 @@ class DictWidget(QtWidgets.QWidget, ConfigObject): return {self.key: values}, self.is_group -class DictInvisible(QtWidgets.QWidget, ConfigObject): +class DictInvisible(QtWidgets.QWidget, SettingObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) allow_actions = False @@ -2081,7 +2081,7 @@ class DictInvisible(QtWidgets.QWidget, ConfigObject): return {self.key: values}, self.is_group -class PathWidget(QtWidgets.QWidget, ConfigObject): +class PathWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) platforms = ("windows", "darwin", "linux") platform_labels_mapping = { @@ -2442,7 +2442,7 @@ class FormLabel(QtWidgets.QLabel): self.item = None -class DictFormWidget(QtWidgets.QWidget, ConfigObject): +class DictFormWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) allow_actions = False diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index aa1f17a7f4..bb42df6026 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -224,7 +224,7 @@ class UnsavedChangesDialog(QtWidgets.QDialog): self.done(2) -class AbstractConfigObject: +class AbstractSettingObject: abstract_attributes = ("_parent", ) def __getattr__(self, name): @@ -232,7 +232,7 @@ class AbstractConfigObject: raise NotImplementedError( "Attribute `{}` is not implemented. {}".format(name, self) ) - return super(AbstractConfigObject, self).__getattribute__(name) + return super(AbstractSettingObject, self).__getattribute__(name) def update_default_values(self, parent_values): raise NotImplementedError( From 111e11b9b15b244659b92baeecf9949648cb0eb3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:20:13 +0200 Subject: [PATCH 539/580] renamed configurations folder in pype co settings --- pype/api.py | 2 +- pype/{configurations => settings}/__init__.py | 0 .../defaults/project_anatomy/colorspace.json | 0 .../defaults/project_anatomy/dataflow.json | 0 .../defaults/project_anatomy/roots.json | 0 .../defaults/project_anatomy/templates.json | 0 .../defaults/project_configurations/ftrack/ftrack_config.json | 0 .../project_configurations/ftrack/ftrack_custom_attributes.json | 0 .../project_configurations/ftrack/partnership_ftrack_cred.json | 0 .../defaults/project_configurations/ftrack/plugins/server.json | 0 .../defaults/project_configurations/ftrack/plugins/user.json | 0 .../project_configurations/ftrack/project_defaults.json | 0 .../defaults/project_configurations/global/creator.json | 0 .../project_configurations/global/project_folder_structure.json | 0 .../defaults/project_configurations/global/sw_folders.json | 0 .../defaults/project_configurations/global/workfiles.json | 0 .../defaults/project_configurations/maya/capture.json | 0 .../project_configurations/muster/templates_mapping.json | 0 .../project_configurations/plugins/celaction/publish.json | 0 .../defaults/project_configurations/plugins/config.json | 0 .../defaults/project_configurations/plugins/ftrack/publish.json | 0 .../defaults/project_configurations/plugins/global/create.json | 0 .../defaults/project_configurations/plugins/global/filter.json | 0 .../defaults/project_configurations/plugins/global/load.json | 0 .../defaults/project_configurations/plugins/global/publish.json | 0 .../defaults/project_configurations/plugins/maya/create.json | 0 .../defaults/project_configurations/plugins/maya/filter.json | 0 .../defaults/project_configurations/plugins/maya/load.json | 0 .../defaults/project_configurations/plugins/maya/publish.json | 0 .../project_configurations/plugins/maya/workfile_build.json | 0 .../defaults/project_configurations/plugins/nuke/create.json | 0 .../defaults/project_configurations/plugins/nuke/load.json | 0 .../defaults/project_configurations/plugins/nuke/publish.json | 0 .../project_configurations/plugins/nuke/workfile_build.json | 0 .../project_configurations/plugins/nukestudio/filter.json | 0 .../project_configurations/plugins/nukestudio/publish.json | 0 .../defaults/project_configurations/plugins/resolve/create.json | 0 .../plugins/standalonepublisher/publish.json | 0 .../defaults/project_configurations/plugins/test/create.json | 0 .../defaults/project_configurations/plugins/test/publish.json | 0 .../defaults/project_configurations/premiere/asset_default.json | 0 .../defaults/project_configurations/premiere/rules_tasks.json | 0 .../project_configurations/standalonepublisher/families.json | 0 .../project_configurations/tools/slates/example_HD.json | 0 .../defaults/project_configurations/unreal/project_setup.json | 0 .../defaults/system_configurations/environments/avalon.json | 0 .../defaults/system_configurations/environments/blender.json | 0 .../defaults/system_configurations/environments/celaction.json | 0 .../defaults/system_configurations/environments/deadline.json | 0 .../defaults/system_configurations/environments/ftrack.json | 0 .../defaults/system_configurations/environments/global.json | 0 .../defaults/system_configurations/environments/harmony.json | 0 .../defaults/system_configurations/environments/houdini.json | 0 .../defaults/system_configurations/environments/maya.json | 0 .../defaults/system_configurations/environments/maya_2018.json | 0 .../defaults/system_configurations/environments/maya_2020.json | 0 .../defaults/system_configurations/environments/mayabatch.json | 0 .../system_configurations/environments/mayabatch_2019.json | 0 .../defaults/system_configurations/environments/mtoa_3.1.1.json | 0 .../defaults/system_configurations/environments/muster.json | 0 .../defaults/system_configurations/environments/nuke.json | 0 .../defaults/system_configurations/environments/nukestudio.json | 0 .../system_configurations/environments/nukestudio_10.0.json | 0 .../defaults/system_configurations/environments/nukex.json | 0 .../defaults/system_configurations/environments/nukex_10.0.json | 0 .../defaults/system_configurations/environments/photoshop.json | 0 .../defaults/system_configurations/environments/premiere.json | 0 .../defaults/system_configurations/environments/resolve.json | 0 .../system_configurations/environments/storyboardpro.json | 0 .../system_configurations/environments/unreal_4.24.json | 0 .../defaults/system_configurations/environments/vray_4300.json | 0 .../defaults/system_configurations/global/applications.json | 0 .../defaults/system_configurations/global/intent.json | 0 .../defaults/system_configurations/global/tools.json | 0 .../defaults/system_configurations/global/tray_modules.json | 0 .../defaults/system_configurations/launchers/blender_2.80.toml | 0 .../defaults/system_configurations/launchers/blender_2.81.toml | 0 .../defaults/system_configurations/launchers/blender_2.82.toml | 0 .../defaults/system_configurations/launchers/blender_2.83.toml | 0 .../system_configurations/launchers/celaction_local.toml | 0 .../system_configurations/launchers/celaction_publish.toml | 0 .../system_configurations/launchers/darwin/blender_2.82 | 0 .../defaults/system_configurations/launchers/darwin/harmony_17 | 0 .../system_configurations/launchers/darwin/harmony_17_launch | 0 .../defaults/system_configurations/launchers/darwin/python3 | 0 .../defaults/system_configurations/launchers/harmony_17.toml | 0 .../defaults/system_configurations/launchers/houdini_16.toml | 0 .../defaults/system_configurations/launchers/houdini_17.toml | 0 .../defaults/system_configurations/launchers/houdini_18.toml | 0 .../defaults/system_configurations/launchers/linux/maya2016 | 0 .../defaults/system_configurations/launchers/linux/maya2017 | 0 .../defaults/system_configurations/launchers/linux/maya2018 | 0 .../defaults/system_configurations/launchers/linux/maya2019 | 0 .../defaults/system_configurations/launchers/linux/maya2020 | 0 .../defaults/system_configurations/launchers/linux/nuke11.3 | 0 .../defaults/system_configurations/launchers/linux/nuke12.0 | 0 .../system_configurations/launchers/linux/nukestudio11.3 | 0 .../system_configurations/launchers/linux/nukestudio12.0 | 0 .../defaults/system_configurations/launchers/linux/nukex11.3 | 0 .../defaults/system_configurations/launchers/linux/nukex12.0 | 0 .../defaults/system_configurations/launchers/maya_2016.toml | 0 .../defaults/system_configurations/launchers/maya_2017.toml | 0 .../defaults/system_configurations/launchers/maya_2018.toml | 0 .../defaults/system_configurations/launchers/maya_2019.toml | 0 .../defaults/system_configurations/launchers/maya_2020.toml | 0 .../system_configurations/launchers/mayabatch_2019.toml | 0 .../system_configurations/launchers/mayabatch_2020.toml | 0 .../defaults/system_configurations/launchers/mayapy2016.toml | 0 .../defaults/system_configurations/launchers/mayapy2017.toml | 0 .../defaults/system_configurations/launchers/mayapy2018.toml | 0 .../defaults/system_configurations/launchers/mayapy2019.toml | 0 .../defaults/system_configurations/launchers/mayapy2020.toml | 0 .../defaults/system_configurations/launchers/myapp.toml | 0 .../defaults/system_configurations/launchers/nuke_10.0.toml | 0 .../defaults/system_configurations/launchers/nuke_11.0.toml | 0 .../defaults/system_configurations/launchers/nuke_11.2.toml | 0 .../defaults/system_configurations/launchers/nuke_11.3.toml | 0 .../defaults/system_configurations/launchers/nuke_12.0.toml | 0 .../system_configurations/launchers/nukestudio_10.0.toml | 0 .../system_configurations/launchers/nukestudio_11.0.toml | 0 .../system_configurations/launchers/nukestudio_11.2.toml | 0 .../system_configurations/launchers/nukestudio_11.3.toml | 0 .../system_configurations/launchers/nukestudio_12.0.toml | 0 .../defaults/system_configurations/launchers/nukex_10.0.toml | 0 .../defaults/system_configurations/launchers/nukex_11.0.toml | 0 .../defaults/system_configurations/launchers/nukex_11.2.toml | 0 .../defaults/system_configurations/launchers/nukex_11.3.toml | 0 .../defaults/system_configurations/launchers/nukex_12.0.toml | 0 .../system_configurations/launchers/photoshop_2020.toml | 0 .../defaults/system_configurations/launchers/premiere_2019.toml | 0 .../defaults/system_configurations/launchers/premiere_2020.toml | 0 .../defaults/system_configurations/launchers/python_2.toml | 0 .../defaults/system_configurations/launchers/python_3.toml | 0 .../defaults/system_configurations/launchers/resolve_16.toml | 0 .../defaults/system_configurations/launchers/shell.toml | 0 .../system_configurations/launchers/storyboardpro_7.toml | 0 .../defaults/system_configurations/launchers/unreal_4.24.toml | 0 .../system_configurations/launchers/windows/blender_2.80.bat | 0 .../system_configurations/launchers/windows/blender_2.81.bat | 0 .../system_configurations/launchers/windows/blender_2.82.bat | 0 .../system_configurations/launchers/windows/blender_2.83.bat | 0 .../system_configurations/launchers/windows/celaction_local.bat | 0 .../launchers/windows/celaction_publish.bat | 0 .../system_configurations/launchers/windows/harmony_17.bat | 0 .../system_configurations/launchers/windows/houdini_16.bat | 0 .../system_configurations/launchers/windows/houdini_17.bat | 0 .../system_configurations/launchers/windows/houdini_18.bat | 0 .../system_configurations/launchers/windows/maya2016.bat | 0 .../system_configurations/launchers/windows/maya2017.bat | 0 .../system_configurations/launchers/windows/maya2018.bat | 0 .../system_configurations/launchers/windows/maya2019.bat | 0 .../system_configurations/launchers/windows/maya2020.bat | 0 .../system_configurations/launchers/windows/mayabatch2019.bat | 0 .../system_configurations/launchers/windows/mayabatch2020.bat | 0 .../system_configurations/launchers/windows/mayapy2016.bat | 0 .../system_configurations/launchers/windows/mayapy2017.bat | 0 .../system_configurations/launchers/windows/mayapy2018.bat | 0 .../system_configurations/launchers/windows/mayapy2019.bat | 0 .../system_configurations/launchers/windows/mayapy2020.bat | 0 .../system_configurations/launchers/windows/nuke10.0.bat | 0 .../system_configurations/launchers/windows/nuke11.0.bat | 0 .../system_configurations/launchers/windows/nuke11.2.bat | 0 .../system_configurations/launchers/windows/nuke11.3.bat | 0 .../system_configurations/launchers/windows/nuke12.0.bat | 0 .../system_configurations/launchers/windows/nukestudio10.0.bat | 0 .../system_configurations/launchers/windows/nukestudio11.0.bat | 0 .../system_configurations/launchers/windows/nukestudio11.2.bat | 0 .../system_configurations/launchers/windows/nukestudio11.3.bat | 0 .../system_configurations/launchers/windows/nukestudio12.0.bat | 0 .../system_configurations/launchers/windows/nukex10.0.bat | 0 .../system_configurations/launchers/windows/nukex11.0.bat | 0 .../system_configurations/launchers/windows/nukex11.2.bat | 0 .../system_configurations/launchers/windows/nukex11.3.bat | 0 .../system_configurations/launchers/windows/nukex12.0.bat | 0 .../system_configurations/launchers/windows/photoshop_2020.bat | 0 .../launchers/windows/premiere_pro_2019.bat | 0 .../launchers/windows/premiere_pro_2020.bat | 0 .../system_configurations/launchers/windows/python3.bat | 0 .../system_configurations/launchers/windows/resolve_16.bat | 0 .../defaults/system_configurations/launchers/windows/shell.bat | 0 .../system_configurations/launchers/windows/storyboardpro_7.bat | 0 .../defaults/system_configurations/launchers/windows/unreal.bat | 0 .../system_configurations/muster/templates_mapping.json | 0 .../system_configurations/standalone_publish/families.json | 0 pype/{configurations => settings}/lib.py | 0 185 files changed, 1 insertion(+), 1 deletion(-) rename pype/{configurations => settings}/__init__.py (100%) rename pype/{configurations => settings}/defaults/project_anatomy/colorspace.json (100%) rename pype/{configurations => settings}/defaults/project_anatomy/dataflow.json (100%) rename pype/{configurations => settings}/defaults/project_anatomy/roots.json (100%) rename pype/{configurations => settings}/defaults/project_anatomy/templates.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/ftrack/ftrack_config.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/ftrack/ftrack_custom_attributes.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/ftrack/partnership_ftrack_cred.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/ftrack/plugins/server.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/ftrack/plugins/user.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/ftrack/project_defaults.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/global/creator.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/global/project_folder_structure.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/global/sw_folders.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/global/workfiles.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/maya/capture.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/muster/templates_mapping.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/celaction/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/config.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/ftrack/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/global/create.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/global/filter.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/global/load.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/global/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/maya/create.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/maya/filter.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/maya/load.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/maya/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/maya/workfile_build.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/nuke/create.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/nuke/load.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/nuke/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/nuke/workfile_build.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/nukestudio/filter.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/nukestudio/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/resolve/create.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/standalonepublisher/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/test/create.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/plugins/test/publish.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/premiere/asset_default.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/premiere/rules_tasks.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/standalonepublisher/families.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/tools/slates/example_HD.json (100%) rename pype/{configurations => settings}/defaults/project_configurations/unreal/project_setup.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/avalon.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/blender.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/celaction.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/deadline.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/ftrack.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/global.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/harmony.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/houdini.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/maya.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/maya_2018.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/maya_2020.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/mayabatch.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/mayabatch_2019.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/mtoa_3.1.1.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/muster.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/nuke.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/nukestudio.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/nukestudio_10.0.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/nukex.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/nukex_10.0.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/photoshop.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/premiere.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/resolve.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/storyboardpro.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/unreal_4.24.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/environments/vray_4300.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/global/applications.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/global/intent.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/global/tools.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/global/tray_modules.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/blender_2.80.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/blender_2.81.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/blender_2.82.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/blender_2.83.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/celaction_local.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/celaction_publish.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/darwin/blender_2.82 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/darwin/harmony_17 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/darwin/harmony_17_launch (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/darwin/python3 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/harmony_17.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/houdini_16.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/houdini_17.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/houdini_18.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/maya2016 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/maya2017 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/maya2018 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/maya2019 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/maya2020 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/nuke11.3 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/nuke12.0 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/nukestudio11.3 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/nukestudio12.0 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/nukex11.3 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/linux/nukex12.0 (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/maya_2016.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/maya_2017.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/maya_2018.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/maya_2019.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/maya_2020.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayabatch_2019.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayabatch_2020.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayapy2016.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayapy2017.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayapy2018.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayapy2019.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/mayapy2020.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/myapp.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nuke_10.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nuke_11.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nuke_11.2.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nuke_11.3.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nuke_12.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukestudio_10.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukestudio_11.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukestudio_11.2.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukestudio_11.3.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukestudio_12.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukex_10.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukex_11.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukex_11.2.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukex_11.3.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/nukex_12.0.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/photoshop_2020.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/premiere_2019.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/premiere_2020.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/python_2.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/python_3.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/resolve_16.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/shell.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/storyboardpro_7.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/unreal_4.24.toml (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/blender_2.80.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/blender_2.81.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/blender_2.82.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/blender_2.83.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/celaction_local.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/celaction_publish.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/harmony_17.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/houdini_16.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/houdini_17.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/houdini_18.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/maya2016.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/maya2017.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/maya2018.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/maya2019.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/maya2020.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayabatch2019.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayabatch2020.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayapy2016.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayapy2017.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayapy2018.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayapy2019.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/mayapy2020.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nuke10.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nuke11.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nuke11.2.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nuke11.3.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nuke12.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukestudio10.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukestudio11.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukestudio11.2.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukestudio11.3.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukestudio12.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukex10.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukex11.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukex11.2.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukex11.3.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/nukex12.0.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/photoshop_2020.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/python3.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/resolve_16.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/shell.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/storyboardpro_7.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/launchers/windows/unreal.bat (100%) rename pype/{configurations => settings}/defaults/system_configurations/muster/templates_mapping.json (100%) rename pype/{configurations => settings}/defaults/system_configurations/standalone_publish/families.json (100%) rename pype/{configurations => settings}/lib.py (100%) diff --git a/pype/api.py b/pype/api.py index c5cd28d4de..0b3439c4c2 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,4 +1,4 @@ -from .configurations.config import ( +from .settings import ( system_configurations, project_configurations ) diff --git a/pype/configurations/__init__.py b/pype/settings/__init__.py similarity index 100% rename from pype/configurations/__init__.py rename to pype/settings/__init__.py diff --git a/pype/configurations/defaults/project_anatomy/colorspace.json b/pype/settings/defaults/project_anatomy/colorspace.json similarity index 100% rename from pype/configurations/defaults/project_anatomy/colorspace.json rename to pype/settings/defaults/project_anatomy/colorspace.json diff --git a/pype/configurations/defaults/project_anatomy/dataflow.json b/pype/settings/defaults/project_anatomy/dataflow.json similarity index 100% rename from pype/configurations/defaults/project_anatomy/dataflow.json rename to pype/settings/defaults/project_anatomy/dataflow.json diff --git a/pype/configurations/defaults/project_anatomy/roots.json b/pype/settings/defaults/project_anatomy/roots.json similarity index 100% rename from pype/configurations/defaults/project_anatomy/roots.json rename to pype/settings/defaults/project_anatomy/roots.json diff --git a/pype/configurations/defaults/project_anatomy/templates.json b/pype/settings/defaults/project_anatomy/templates.json similarity index 100% rename from pype/configurations/defaults/project_anatomy/templates.json rename to pype/settings/defaults/project_anatomy/templates.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/ftrack_config.json b/pype/settings/defaults/project_configurations/ftrack/ftrack_config.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/ftrack_config.json rename to pype/settings/defaults/project_configurations/ftrack/ftrack_config.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/ftrack_custom_attributes.json b/pype/settings/defaults/project_configurations/ftrack/ftrack_custom_attributes.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/ftrack_custom_attributes.json rename to pype/settings/defaults/project_configurations/ftrack/ftrack_custom_attributes.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/partnership_ftrack_cred.json b/pype/settings/defaults/project_configurations/ftrack/partnership_ftrack_cred.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/partnership_ftrack_cred.json rename to pype/settings/defaults/project_configurations/ftrack/partnership_ftrack_cred.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/plugins/server.json b/pype/settings/defaults/project_configurations/ftrack/plugins/server.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/plugins/server.json rename to pype/settings/defaults/project_configurations/ftrack/plugins/server.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/plugins/user.json b/pype/settings/defaults/project_configurations/ftrack/plugins/user.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/plugins/user.json rename to pype/settings/defaults/project_configurations/ftrack/plugins/user.json diff --git a/pype/configurations/defaults/project_configurations/ftrack/project_defaults.json b/pype/settings/defaults/project_configurations/ftrack/project_defaults.json similarity index 100% rename from pype/configurations/defaults/project_configurations/ftrack/project_defaults.json rename to pype/settings/defaults/project_configurations/ftrack/project_defaults.json diff --git a/pype/configurations/defaults/project_configurations/global/creator.json b/pype/settings/defaults/project_configurations/global/creator.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/creator.json rename to pype/settings/defaults/project_configurations/global/creator.json diff --git a/pype/configurations/defaults/project_configurations/global/project_folder_structure.json b/pype/settings/defaults/project_configurations/global/project_folder_structure.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/project_folder_structure.json rename to pype/settings/defaults/project_configurations/global/project_folder_structure.json diff --git a/pype/configurations/defaults/project_configurations/global/sw_folders.json b/pype/settings/defaults/project_configurations/global/sw_folders.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/sw_folders.json rename to pype/settings/defaults/project_configurations/global/sw_folders.json diff --git a/pype/configurations/defaults/project_configurations/global/workfiles.json b/pype/settings/defaults/project_configurations/global/workfiles.json similarity index 100% rename from pype/configurations/defaults/project_configurations/global/workfiles.json rename to pype/settings/defaults/project_configurations/global/workfiles.json diff --git a/pype/configurations/defaults/project_configurations/maya/capture.json b/pype/settings/defaults/project_configurations/maya/capture.json similarity index 100% rename from pype/configurations/defaults/project_configurations/maya/capture.json rename to pype/settings/defaults/project_configurations/maya/capture.json diff --git a/pype/configurations/defaults/project_configurations/muster/templates_mapping.json b/pype/settings/defaults/project_configurations/muster/templates_mapping.json similarity index 100% rename from pype/configurations/defaults/project_configurations/muster/templates_mapping.json rename to pype/settings/defaults/project_configurations/muster/templates_mapping.json diff --git a/pype/configurations/defaults/project_configurations/plugins/celaction/publish.json b/pype/settings/defaults/project_configurations/plugins/celaction/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/celaction/publish.json rename to pype/settings/defaults/project_configurations/plugins/celaction/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/config.json b/pype/settings/defaults/project_configurations/plugins/config.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/config.json rename to pype/settings/defaults/project_configurations/plugins/config.json diff --git a/pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json b/pype/settings/defaults/project_configurations/plugins/ftrack/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/ftrack/publish.json rename to pype/settings/defaults/project_configurations/plugins/ftrack/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/create.json b/pype/settings/defaults/project_configurations/plugins/global/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/create.json rename to pype/settings/defaults/project_configurations/plugins/global/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/filter.json b/pype/settings/defaults/project_configurations/plugins/global/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/filter.json rename to pype/settings/defaults/project_configurations/plugins/global/filter.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/load.json b/pype/settings/defaults/project_configurations/plugins/global/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/load.json rename to pype/settings/defaults/project_configurations/plugins/global/load.json diff --git a/pype/configurations/defaults/project_configurations/plugins/global/publish.json b/pype/settings/defaults/project_configurations/plugins/global/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/global/publish.json rename to pype/settings/defaults/project_configurations/plugins/global/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/create.json b/pype/settings/defaults/project_configurations/plugins/maya/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/create.json rename to pype/settings/defaults/project_configurations/plugins/maya/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/filter.json b/pype/settings/defaults/project_configurations/plugins/maya/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/filter.json rename to pype/settings/defaults/project_configurations/plugins/maya/filter.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/load.json b/pype/settings/defaults/project_configurations/plugins/maya/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/load.json rename to pype/settings/defaults/project_configurations/plugins/maya/load.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/publish.json b/pype/settings/defaults/project_configurations/plugins/maya/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/publish.json rename to pype/settings/defaults/project_configurations/plugins/maya/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json b/pype/settings/defaults/project_configurations/plugins/maya/workfile_build.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/maya/workfile_build.json rename to pype/settings/defaults/project_configurations/plugins/maya/workfile_build.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/create.json b/pype/settings/defaults/project_configurations/plugins/nuke/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/create.json rename to pype/settings/defaults/project_configurations/plugins/nuke/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/load.json b/pype/settings/defaults/project_configurations/plugins/nuke/load.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/load.json rename to pype/settings/defaults/project_configurations/plugins/nuke/load.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/publish.json b/pype/settings/defaults/project_configurations/plugins/nuke/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/publish.json rename to pype/settings/defaults/project_configurations/plugins/nuke/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json b/pype/settings/defaults/project_configurations/plugins/nuke/workfile_build.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nuke/workfile_build.json rename to pype/settings/defaults/project_configurations/plugins/nuke/workfile_build.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json b/pype/settings/defaults/project_configurations/plugins/nukestudio/filter.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nukestudio/filter.json rename to pype/settings/defaults/project_configurations/plugins/nukestudio/filter.json diff --git a/pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json b/pype/settings/defaults/project_configurations/plugins/nukestudio/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/nukestudio/publish.json rename to pype/settings/defaults/project_configurations/plugins/nukestudio/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/resolve/create.json b/pype/settings/defaults/project_configurations/plugins/resolve/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/resolve/create.json rename to pype/settings/defaults/project_configurations/plugins/resolve/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json b/pype/settings/defaults/project_configurations/plugins/standalonepublisher/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/standalonepublisher/publish.json rename to pype/settings/defaults/project_configurations/plugins/standalonepublisher/publish.json diff --git a/pype/configurations/defaults/project_configurations/plugins/test/create.json b/pype/settings/defaults/project_configurations/plugins/test/create.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/test/create.json rename to pype/settings/defaults/project_configurations/plugins/test/create.json diff --git a/pype/configurations/defaults/project_configurations/plugins/test/publish.json b/pype/settings/defaults/project_configurations/plugins/test/publish.json similarity index 100% rename from pype/configurations/defaults/project_configurations/plugins/test/publish.json rename to pype/settings/defaults/project_configurations/plugins/test/publish.json diff --git a/pype/configurations/defaults/project_configurations/premiere/asset_default.json b/pype/settings/defaults/project_configurations/premiere/asset_default.json similarity index 100% rename from pype/configurations/defaults/project_configurations/premiere/asset_default.json rename to pype/settings/defaults/project_configurations/premiere/asset_default.json diff --git a/pype/configurations/defaults/project_configurations/premiere/rules_tasks.json b/pype/settings/defaults/project_configurations/premiere/rules_tasks.json similarity index 100% rename from pype/configurations/defaults/project_configurations/premiere/rules_tasks.json rename to pype/settings/defaults/project_configurations/premiere/rules_tasks.json diff --git a/pype/configurations/defaults/project_configurations/standalonepublisher/families.json b/pype/settings/defaults/project_configurations/standalonepublisher/families.json similarity index 100% rename from pype/configurations/defaults/project_configurations/standalonepublisher/families.json rename to pype/settings/defaults/project_configurations/standalonepublisher/families.json diff --git a/pype/configurations/defaults/project_configurations/tools/slates/example_HD.json b/pype/settings/defaults/project_configurations/tools/slates/example_HD.json similarity index 100% rename from pype/configurations/defaults/project_configurations/tools/slates/example_HD.json rename to pype/settings/defaults/project_configurations/tools/slates/example_HD.json diff --git a/pype/configurations/defaults/project_configurations/unreal/project_setup.json b/pype/settings/defaults/project_configurations/unreal/project_setup.json similarity index 100% rename from pype/configurations/defaults/project_configurations/unreal/project_setup.json rename to pype/settings/defaults/project_configurations/unreal/project_setup.json diff --git a/pype/configurations/defaults/system_configurations/environments/avalon.json b/pype/settings/defaults/system_configurations/environments/avalon.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/avalon.json rename to pype/settings/defaults/system_configurations/environments/avalon.json diff --git a/pype/configurations/defaults/system_configurations/environments/blender.json b/pype/settings/defaults/system_configurations/environments/blender.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/blender.json rename to pype/settings/defaults/system_configurations/environments/blender.json diff --git a/pype/configurations/defaults/system_configurations/environments/celaction.json b/pype/settings/defaults/system_configurations/environments/celaction.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/celaction.json rename to pype/settings/defaults/system_configurations/environments/celaction.json diff --git a/pype/configurations/defaults/system_configurations/environments/deadline.json b/pype/settings/defaults/system_configurations/environments/deadline.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/deadline.json rename to pype/settings/defaults/system_configurations/environments/deadline.json diff --git a/pype/configurations/defaults/system_configurations/environments/ftrack.json b/pype/settings/defaults/system_configurations/environments/ftrack.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/ftrack.json rename to pype/settings/defaults/system_configurations/environments/ftrack.json diff --git a/pype/configurations/defaults/system_configurations/environments/global.json b/pype/settings/defaults/system_configurations/environments/global.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/global.json rename to pype/settings/defaults/system_configurations/environments/global.json diff --git a/pype/configurations/defaults/system_configurations/environments/harmony.json b/pype/settings/defaults/system_configurations/environments/harmony.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/harmony.json rename to pype/settings/defaults/system_configurations/environments/harmony.json diff --git a/pype/configurations/defaults/system_configurations/environments/houdini.json b/pype/settings/defaults/system_configurations/environments/houdini.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/houdini.json rename to pype/settings/defaults/system_configurations/environments/houdini.json diff --git a/pype/configurations/defaults/system_configurations/environments/maya.json b/pype/settings/defaults/system_configurations/environments/maya.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/maya.json rename to pype/settings/defaults/system_configurations/environments/maya.json diff --git a/pype/configurations/defaults/system_configurations/environments/maya_2018.json b/pype/settings/defaults/system_configurations/environments/maya_2018.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/maya_2018.json rename to pype/settings/defaults/system_configurations/environments/maya_2018.json diff --git a/pype/configurations/defaults/system_configurations/environments/maya_2020.json b/pype/settings/defaults/system_configurations/environments/maya_2020.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/maya_2020.json rename to pype/settings/defaults/system_configurations/environments/maya_2020.json diff --git a/pype/configurations/defaults/system_configurations/environments/mayabatch.json b/pype/settings/defaults/system_configurations/environments/mayabatch.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/mayabatch.json rename to pype/settings/defaults/system_configurations/environments/mayabatch.json diff --git a/pype/configurations/defaults/system_configurations/environments/mayabatch_2019.json b/pype/settings/defaults/system_configurations/environments/mayabatch_2019.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/mayabatch_2019.json rename to pype/settings/defaults/system_configurations/environments/mayabatch_2019.json diff --git a/pype/configurations/defaults/system_configurations/environments/mtoa_3.1.1.json b/pype/settings/defaults/system_configurations/environments/mtoa_3.1.1.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/mtoa_3.1.1.json rename to pype/settings/defaults/system_configurations/environments/mtoa_3.1.1.json diff --git a/pype/configurations/defaults/system_configurations/environments/muster.json b/pype/settings/defaults/system_configurations/environments/muster.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/muster.json rename to pype/settings/defaults/system_configurations/environments/muster.json diff --git a/pype/configurations/defaults/system_configurations/environments/nuke.json b/pype/settings/defaults/system_configurations/environments/nuke.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/nuke.json rename to pype/settings/defaults/system_configurations/environments/nuke.json diff --git a/pype/configurations/defaults/system_configurations/environments/nukestudio.json b/pype/settings/defaults/system_configurations/environments/nukestudio.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/nukestudio.json rename to pype/settings/defaults/system_configurations/environments/nukestudio.json diff --git a/pype/configurations/defaults/system_configurations/environments/nukestudio_10.0.json b/pype/settings/defaults/system_configurations/environments/nukestudio_10.0.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/nukestudio_10.0.json rename to pype/settings/defaults/system_configurations/environments/nukestudio_10.0.json diff --git a/pype/configurations/defaults/system_configurations/environments/nukex.json b/pype/settings/defaults/system_configurations/environments/nukex.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/nukex.json rename to pype/settings/defaults/system_configurations/environments/nukex.json diff --git a/pype/configurations/defaults/system_configurations/environments/nukex_10.0.json b/pype/settings/defaults/system_configurations/environments/nukex_10.0.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/nukex_10.0.json rename to pype/settings/defaults/system_configurations/environments/nukex_10.0.json diff --git a/pype/configurations/defaults/system_configurations/environments/photoshop.json b/pype/settings/defaults/system_configurations/environments/photoshop.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/photoshop.json rename to pype/settings/defaults/system_configurations/environments/photoshop.json diff --git a/pype/configurations/defaults/system_configurations/environments/premiere.json b/pype/settings/defaults/system_configurations/environments/premiere.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/premiere.json rename to pype/settings/defaults/system_configurations/environments/premiere.json diff --git a/pype/configurations/defaults/system_configurations/environments/resolve.json b/pype/settings/defaults/system_configurations/environments/resolve.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/resolve.json rename to pype/settings/defaults/system_configurations/environments/resolve.json diff --git a/pype/configurations/defaults/system_configurations/environments/storyboardpro.json b/pype/settings/defaults/system_configurations/environments/storyboardpro.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/storyboardpro.json rename to pype/settings/defaults/system_configurations/environments/storyboardpro.json diff --git a/pype/configurations/defaults/system_configurations/environments/unreal_4.24.json b/pype/settings/defaults/system_configurations/environments/unreal_4.24.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/unreal_4.24.json rename to pype/settings/defaults/system_configurations/environments/unreal_4.24.json diff --git a/pype/configurations/defaults/system_configurations/environments/vray_4300.json b/pype/settings/defaults/system_configurations/environments/vray_4300.json similarity index 100% rename from pype/configurations/defaults/system_configurations/environments/vray_4300.json rename to pype/settings/defaults/system_configurations/environments/vray_4300.json diff --git a/pype/configurations/defaults/system_configurations/global/applications.json b/pype/settings/defaults/system_configurations/global/applications.json similarity index 100% rename from pype/configurations/defaults/system_configurations/global/applications.json rename to pype/settings/defaults/system_configurations/global/applications.json diff --git a/pype/configurations/defaults/system_configurations/global/intent.json b/pype/settings/defaults/system_configurations/global/intent.json similarity index 100% rename from pype/configurations/defaults/system_configurations/global/intent.json rename to pype/settings/defaults/system_configurations/global/intent.json diff --git a/pype/configurations/defaults/system_configurations/global/tools.json b/pype/settings/defaults/system_configurations/global/tools.json similarity index 100% rename from pype/configurations/defaults/system_configurations/global/tools.json rename to pype/settings/defaults/system_configurations/global/tools.json diff --git a/pype/configurations/defaults/system_configurations/global/tray_modules.json b/pype/settings/defaults/system_configurations/global/tray_modules.json similarity index 100% rename from pype/configurations/defaults/system_configurations/global/tray_modules.json rename to pype/settings/defaults/system_configurations/global/tray_modules.json diff --git a/pype/configurations/defaults/system_configurations/launchers/blender_2.80.toml b/pype/settings/defaults/system_configurations/launchers/blender_2.80.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/blender_2.80.toml rename to pype/settings/defaults/system_configurations/launchers/blender_2.80.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/blender_2.81.toml b/pype/settings/defaults/system_configurations/launchers/blender_2.81.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/blender_2.81.toml rename to pype/settings/defaults/system_configurations/launchers/blender_2.81.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/blender_2.82.toml b/pype/settings/defaults/system_configurations/launchers/blender_2.82.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/blender_2.82.toml rename to pype/settings/defaults/system_configurations/launchers/blender_2.82.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/blender_2.83.toml b/pype/settings/defaults/system_configurations/launchers/blender_2.83.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/blender_2.83.toml rename to pype/settings/defaults/system_configurations/launchers/blender_2.83.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/celaction_local.toml b/pype/settings/defaults/system_configurations/launchers/celaction_local.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/celaction_local.toml rename to pype/settings/defaults/system_configurations/launchers/celaction_local.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/celaction_publish.toml b/pype/settings/defaults/system_configurations/launchers/celaction_publish.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/celaction_publish.toml rename to pype/settings/defaults/system_configurations/launchers/celaction_publish.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/darwin/blender_2.82 b/pype/settings/defaults/system_configurations/launchers/darwin/blender_2.82 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/darwin/blender_2.82 rename to pype/settings/defaults/system_configurations/launchers/darwin/blender_2.82 diff --git a/pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17 b/pype/settings/defaults/system_configurations/launchers/darwin/harmony_17 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17 rename to pype/settings/defaults/system_configurations/launchers/darwin/harmony_17 diff --git a/pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17_launch b/pype/settings/defaults/system_configurations/launchers/darwin/harmony_17_launch similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/darwin/harmony_17_launch rename to pype/settings/defaults/system_configurations/launchers/darwin/harmony_17_launch diff --git a/pype/configurations/defaults/system_configurations/launchers/darwin/python3 b/pype/settings/defaults/system_configurations/launchers/darwin/python3 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/darwin/python3 rename to pype/settings/defaults/system_configurations/launchers/darwin/python3 diff --git a/pype/configurations/defaults/system_configurations/launchers/harmony_17.toml b/pype/settings/defaults/system_configurations/launchers/harmony_17.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/harmony_17.toml rename to pype/settings/defaults/system_configurations/launchers/harmony_17.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/houdini_16.toml b/pype/settings/defaults/system_configurations/launchers/houdini_16.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/houdini_16.toml rename to pype/settings/defaults/system_configurations/launchers/houdini_16.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/houdini_17.toml b/pype/settings/defaults/system_configurations/launchers/houdini_17.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/houdini_17.toml rename to pype/settings/defaults/system_configurations/launchers/houdini_17.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/houdini_18.toml b/pype/settings/defaults/system_configurations/launchers/houdini_18.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/houdini_18.toml rename to pype/settings/defaults/system_configurations/launchers/houdini_18.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/maya2016 b/pype/settings/defaults/system_configurations/launchers/linux/maya2016 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/maya2016 rename to pype/settings/defaults/system_configurations/launchers/linux/maya2016 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/maya2017 b/pype/settings/defaults/system_configurations/launchers/linux/maya2017 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/maya2017 rename to pype/settings/defaults/system_configurations/launchers/linux/maya2017 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/maya2018 b/pype/settings/defaults/system_configurations/launchers/linux/maya2018 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/maya2018 rename to pype/settings/defaults/system_configurations/launchers/linux/maya2018 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/maya2019 b/pype/settings/defaults/system_configurations/launchers/linux/maya2019 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/maya2019 rename to pype/settings/defaults/system_configurations/launchers/linux/maya2019 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/maya2020 b/pype/settings/defaults/system_configurations/launchers/linux/maya2020 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/maya2020 rename to pype/settings/defaults/system_configurations/launchers/linux/maya2020 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/nuke11.3 b/pype/settings/defaults/system_configurations/launchers/linux/nuke11.3 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/nuke11.3 rename to pype/settings/defaults/system_configurations/launchers/linux/nuke11.3 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/nuke12.0 b/pype/settings/defaults/system_configurations/launchers/linux/nuke12.0 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/nuke12.0 rename to pype/settings/defaults/system_configurations/launchers/linux/nuke12.0 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/nukestudio11.3 b/pype/settings/defaults/system_configurations/launchers/linux/nukestudio11.3 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/nukestudio11.3 rename to pype/settings/defaults/system_configurations/launchers/linux/nukestudio11.3 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/nukestudio12.0 b/pype/settings/defaults/system_configurations/launchers/linux/nukestudio12.0 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/nukestudio12.0 rename to pype/settings/defaults/system_configurations/launchers/linux/nukestudio12.0 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/nukex11.3 b/pype/settings/defaults/system_configurations/launchers/linux/nukex11.3 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/nukex11.3 rename to pype/settings/defaults/system_configurations/launchers/linux/nukex11.3 diff --git a/pype/configurations/defaults/system_configurations/launchers/linux/nukex12.0 b/pype/settings/defaults/system_configurations/launchers/linux/nukex12.0 similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/linux/nukex12.0 rename to pype/settings/defaults/system_configurations/launchers/linux/nukex12.0 diff --git a/pype/configurations/defaults/system_configurations/launchers/maya_2016.toml b/pype/settings/defaults/system_configurations/launchers/maya_2016.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/maya_2016.toml rename to pype/settings/defaults/system_configurations/launchers/maya_2016.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/maya_2017.toml b/pype/settings/defaults/system_configurations/launchers/maya_2017.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/maya_2017.toml rename to pype/settings/defaults/system_configurations/launchers/maya_2017.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/maya_2018.toml b/pype/settings/defaults/system_configurations/launchers/maya_2018.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/maya_2018.toml rename to pype/settings/defaults/system_configurations/launchers/maya_2018.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/maya_2019.toml b/pype/settings/defaults/system_configurations/launchers/maya_2019.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/maya_2019.toml rename to pype/settings/defaults/system_configurations/launchers/maya_2019.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/maya_2020.toml b/pype/settings/defaults/system_configurations/launchers/maya_2020.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/maya_2020.toml rename to pype/settings/defaults/system_configurations/launchers/maya_2020.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayabatch_2019.toml b/pype/settings/defaults/system_configurations/launchers/mayabatch_2019.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayabatch_2019.toml rename to pype/settings/defaults/system_configurations/launchers/mayabatch_2019.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayabatch_2020.toml b/pype/settings/defaults/system_configurations/launchers/mayabatch_2020.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayabatch_2020.toml rename to pype/settings/defaults/system_configurations/launchers/mayabatch_2020.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayapy2016.toml b/pype/settings/defaults/system_configurations/launchers/mayapy2016.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayapy2016.toml rename to pype/settings/defaults/system_configurations/launchers/mayapy2016.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayapy2017.toml b/pype/settings/defaults/system_configurations/launchers/mayapy2017.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayapy2017.toml rename to pype/settings/defaults/system_configurations/launchers/mayapy2017.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayapy2018.toml b/pype/settings/defaults/system_configurations/launchers/mayapy2018.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayapy2018.toml rename to pype/settings/defaults/system_configurations/launchers/mayapy2018.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayapy2019.toml b/pype/settings/defaults/system_configurations/launchers/mayapy2019.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayapy2019.toml rename to pype/settings/defaults/system_configurations/launchers/mayapy2019.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/mayapy2020.toml b/pype/settings/defaults/system_configurations/launchers/mayapy2020.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/mayapy2020.toml rename to pype/settings/defaults/system_configurations/launchers/mayapy2020.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/myapp.toml b/pype/settings/defaults/system_configurations/launchers/myapp.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/myapp.toml rename to pype/settings/defaults/system_configurations/launchers/myapp.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nuke_10.0.toml b/pype/settings/defaults/system_configurations/launchers/nuke_10.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nuke_10.0.toml rename to pype/settings/defaults/system_configurations/launchers/nuke_10.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nuke_11.0.toml b/pype/settings/defaults/system_configurations/launchers/nuke_11.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nuke_11.0.toml rename to pype/settings/defaults/system_configurations/launchers/nuke_11.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nuke_11.2.toml b/pype/settings/defaults/system_configurations/launchers/nuke_11.2.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nuke_11.2.toml rename to pype/settings/defaults/system_configurations/launchers/nuke_11.2.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nuke_11.3.toml b/pype/settings/defaults/system_configurations/launchers/nuke_11.3.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nuke_11.3.toml rename to pype/settings/defaults/system_configurations/launchers/nuke_11.3.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nuke_12.0.toml b/pype/settings/defaults/system_configurations/launchers/nuke_12.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nuke_12.0.toml rename to pype/settings/defaults/system_configurations/launchers/nuke_12.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukestudio_10.0.toml b/pype/settings/defaults/system_configurations/launchers/nukestudio_10.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukestudio_10.0.toml rename to pype/settings/defaults/system_configurations/launchers/nukestudio_10.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukestudio_11.0.toml b/pype/settings/defaults/system_configurations/launchers/nukestudio_11.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukestudio_11.0.toml rename to pype/settings/defaults/system_configurations/launchers/nukestudio_11.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukestudio_11.2.toml b/pype/settings/defaults/system_configurations/launchers/nukestudio_11.2.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukestudio_11.2.toml rename to pype/settings/defaults/system_configurations/launchers/nukestudio_11.2.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukestudio_11.3.toml b/pype/settings/defaults/system_configurations/launchers/nukestudio_11.3.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukestudio_11.3.toml rename to pype/settings/defaults/system_configurations/launchers/nukestudio_11.3.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukestudio_12.0.toml b/pype/settings/defaults/system_configurations/launchers/nukestudio_12.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukestudio_12.0.toml rename to pype/settings/defaults/system_configurations/launchers/nukestudio_12.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukex_10.0.toml b/pype/settings/defaults/system_configurations/launchers/nukex_10.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukex_10.0.toml rename to pype/settings/defaults/system_configurations/launchers/nukex_10.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukex_11.0.toml b/pype/settings/defaults/system_configurations/launchers/nukex_11.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukex_11.0.toml rename to pype/settings/defaults/system_configurations/launchers/nukex_11.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukex_11.2.toml b/pype/settings/defaults/system_configurations/launchers/nukex_11.2.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukex_11.2.toml rename to pype/settings/defaults/system_configurations/launchers/nukex_11.2.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukex_11.3.toml b/pype/settings/defaults/system_configurations/launchers/nukex_11.3.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukex_11.3.toml rename to pype/settings/defaults/system_configurations/launchers/nukex_11.3.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/nukex_12.0.toml b/pype/settings/defaults/system_configurations/launchers/nukex_12.0.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/nukex_12.0.toml rename to pype/settings/defaults/system_configurations/launchers/nukex_12.0.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/photoshop_2020.toml b/pype/settings/defaults/system_configurations/launchers/photoshop_2020.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/photoshop_2020.toml rename to pype/settings/defaults/system_configurations/launchers/photoshop_2020.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/premiere_2019.toml b/pype/settings/defaults/system_configurations/launchers/premiere_2019.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/premiere_2019.toml rename to pype/settings/defaults/system_configurations/launchers/premiere_2019.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/premiere_2020.toml b/pype/settings/defaults/system_configurations/launchers/premiere_2020.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/premiere_2020.toml rename to pype/settings/defaults/system_configurations/launchers/premiere_2020.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/python_2.toml b/pype/settings/defaults/system_configurations/launchers/python_2.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/python_2.toml rename to pype/settings/defaults/system_configurations/launchers/python_2.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/python_3.toml b/pype/settings/defaults/system_configurations/launchers/python_3.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/python_3.toml rename to pype/settings/defaults/system_configurations/launchers/python_3.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/resolve_16.toml b/pype/settings/defaults/system_configurations/launchers/resolve_16.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/resolve_16.toml rename to pype/settings/defaults/system_configurations/launchers/resolve_16.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/shell.toml b/pype/settings/defaults/system_configurations/launchers/shell.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/shell.toml rename to pype/settings/defaults/system_configurations/launchers/shell.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/storyboardpro_7.toml b/pype/settings/defaults/system_configurations/launchers/storyboardpro_7.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/storyboardpro_7.toml rename to pype/settings/defaults/system_configurations/launchers/storyboardpro_7.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/unreal_4.24.toml b/pype/settings/defaults/system_configurations/launchers/unreal_4.24.toml similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/unreal_4.24.toml rename to pype/settings/defaults/system_configurations/launchers/unreal_4.24.toml diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.80.bat b/pype/settings/defaults/system_configurations/launchers/windows/blender_2.80.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/blender_2.80.bat rename to pype/settings/defaults/system_configurations/launchers/windows/blender_2.80.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.81.bat b/pype/settings/defaults/system_configurations/launchers/windows/blender_2.81.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/blender_2.81.bat rename to pype/settings/defaults/system_configurations/launchers/windows/blender_2.81.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.82.bat b/pype/settings/defaults/system_configurations/launchers/windows/blender_2.82.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/blender_2.82.bat rename to pype/settings/defaults/system_configurations/launchers/windows/blender_2.82.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/blender_2.83.bat b/pype/settings/defaults/system_configurations/launchers/windows/blender_2.83.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/blender_2.83.bat rename to pype/settings/defaults/system_configurations/launchers/windows/blender_2.83.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/celaction_local.bat b/pype/settings/defaults/system_configurations/launchers/windows/celaction_local.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/celaction_local.bat rename to pype/settings/defaults/system_configurations/launchers/windows/celaction_local.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/celaction_publish.bat b/pype/settings/defaults/system_configurations/launchers/windows/celaction_publish.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/celaction_publish.bat rename to pype/settings/defaults/system_configurations/launchers/windows/celaction_publish.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/harmony_17.bat b/pype/settings/defaults/system_configurations/launchers/windows/harmony_17.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/harmony_17.bat rename to pype/settings/defaults/system_configurations/launchers/windows/harmony_17.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/houdini_16.bat b/pype/settings/defaults/system_configurations/launchers/windows/houdini_16.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/houdini_16.bat rename to pype/settings/defaults/system_configurations/launchers/windows/houdini_16.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/houdini_17.bat b/pype/settings/defaults/system_configurations/launchers/windows/houdini_17.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/houdini_17.bat rename to pype/settings/defaults/system_configurations/launchers/windows/houdini_17.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/houdini_18.bat b/pype/settings/defaults/system_configurations/launchers/windows/houdini_18.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/houdini_18.bat rename to pype/settings/defaults/system_configurations/launchers/windows/houdini_18.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/maya2016.bat b/pype/settings/defaults/system_configurations/launchers/windows/maya2016.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/maya2016.bat rename to pype/settings/defaults/system_configurations/launchers/windows/maya2016.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/maya2017.bat b/pype/settings/defaults/system_configurations/launchers/windows/maya2017.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/maya2017.bat rename to pype/settings/defaults/system_configurations/launchers/windows/maya2017.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/maya2018.bat b/pype/settings/defaults/system_configurations/launchers/windows/maya2018.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/maya2018.bat rename to pype/settings/defaults/system_configurations/launchers/windows/maya2018.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/maya2019.bat b/pype/settings/defaults/system_configurations/launchers/windows/maya2019.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/maya2019.bat rename to pype/settings/defaults/system_configurations/launchers/windows/maya2019.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/maya2020.bat b/pype/settings/defaults/system_configurations/launchers/windows/maya2020.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/maya2020.bat rename to pype/settings/defaults/system_configurations/launchers/windows/maya2020.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2019.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayabatch2019.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2019.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayabatch2019.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2020.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayabatch2020.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayabatch2020.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayabatch2020.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2016.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayapy2016.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayapy2016.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayapy2016.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2017.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayapy2017.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayapy2017.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayapy2017.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2018.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayapy2018.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayapy2018.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayapy2018.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2019.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayapy2019.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayapy2019.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayapy2019.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/mayapy2020.bat b/pype/settings/defaults/system_configurations/launchers/windows/mayapy2020.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/mayapy2020.bat rename to pype/settings/defaults/system_configurations/launchers/windows/mayapy2020.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nuke10.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nuke10.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nuke10.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nuke10.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nuke11.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nuke11.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nuke11.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nuke11.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nuke11.2.bat b/pype/settings/defaults/system_configurations/launchers/windows/nuke11.2.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nuke11.2.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nuke11.2.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nuke11.3.bat b/pype/settings/defaults/system_configurations/launchers/windows/nuke11.3.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nuke11.3.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nuke11.3.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nuke12.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nuke12.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nuke12.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nuke12.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio10.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukestudio10.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukestudio10.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukestudio10.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.2.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.2.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.2.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.2.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.3.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.3.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukestudio11.3.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.3.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukestudio12.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukestudio12.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukestudio12.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukestudio12.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukex10.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukex10.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukex10.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukex10.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukex11.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukex11.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukex11.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukex11.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukex11.2.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukex11.2.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukex11.2.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukex11.2.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukex11.3.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukex11.3.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukex11.3.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukex11.3.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/nukex12.0.bat b/pype/settings/defaults/system_configurations/launchers/windows/nukex12.0.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/nukex12.0.bat rename to pype/settings/defaults/system_configurations/launchers/windows/nukex12.0.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/photoshop_2020.bat b/pype/settings/defaults/system_configurations/launchers/windows/photoshop_2020.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/photoshop_2020.bat rename to pype/settings/defaults/system_configurations/launchers/windows/photoshop_2020.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat b/pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat rename to pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat b/pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat rename to pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/python3.bat b/pype/settings/defaults/system_configurations/launchers/windows/python3.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/python3.bat rename to pype/settings/defaults/system_configurations/launchers/windows/python3.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/resolve_16.bat b/pype/settings/defaults/system_configurations/launchers/windows/resolve_16.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/resolve_16.bat rename to pype/settings/defaults/system_configurations/launchers/windows/resolve_16.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/shell.bat b/pype/settings/defaults/system_configurations/launchers/windows/shell.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/shell.bat rename to pype/settings/defaults/system_configurations/launchers/windows/shell.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/storyboardpro_7.bat b/pype/settings/defaults/system_configurations/launchers/windows/storyboardpro_7.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/storyboardpro_7.bat rename to pype/settings/defaults/system_configurations/launchers/windows/storyboardpro_7.bat diff --git a/pype/configurations/defaults/system_configurations/launchers/windows/unreal.bat b/pype/settings/defaults/system_configurations/launchers/windows/unreal.bat similarity index 100% rename from pype/configurations/defaults/system_configurations/launchers/windows/unreal.bat rename to pype/settings/defaults/system_configurations/launchers/windows/unreal.bat diff --git a/pype/configurations/defaults/system_configurations/muster/templates_mapping.json b/pype/settings/defaults/system_configurations/muster/templates_mapping.json similarity index 100% rename from pype/configurations/defaults/system_configurations/muster/templates_mapping.json rename to pype/settings/defaults/system_configurations/muster/templates_mapping.json diff --git a/pype/configurations/defaults/system_configurations/standalone_publish/families.json b/pype/settings/defaults/system_configurations/standalone_publish/families.json similarity index 100% rename from pype/configurations/defaults/system_configurations/standalone_publish/families.json rename to pype/settings/defaults/system_configurations/standalone_publish/families.json diff --git a/pype/configurations/lib.py b/pype/settings/lib.py similarity index 100% rename from pype/configurations/lib.py rename to pype/settings/lib.py From 148ec89e94909e7bf08884999bf0ec5f801c2d54 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:23:45 +0200 Subject: [PATCH 540/580] fix few imports --- pype/tools/settings/settings/widgets/base.py | 4 ++-- pype/tools/settings/settings/widgets/lib.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index e1d167a9f2..6a7a65cb0f 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -1,8 +1,8 @@ import os import json from Qt import QtWidgets, QtCore, QtGui -from pype.configurations.lib import ( - SYSTEM_CONFIGURATIONS_KEY, +from pype.settings.lib import ( + SYSTEM_SETTINGS_KEY, SYSTEM_SETTINGS_PATH, PROJECT_SETTINGS_KEY, PROJECT_SETTINGS_PATH, diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index 9f54b090cb..0c3f01cef1 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -1,7 +1,7 @@ import os import json import copy -from pype.configurations.lib import OVERRIDEN_KEY +from pype.settings.lib import OVERRIDEN_KEY from queue import Queue From d0859f4b60077f8a3886225dd81648edf39cd0ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:24:30 +0200 Subject: [PATCH 541/580] renamed folders in defaults --- .../ftrack/ftrack_config.json | 0 .../ftrack/ftrack_custom_attributes.json | 0 .../ftrack/partnership_ftrack_cred.json | 0 .../ftrack/plugins/server.json | 0 .../ftrack/plugins/user.json | 0 .../ftrack/project_defaults.json | 0 .../global/creator.json | 0 .../global/project_folder_structure.json | 0 .../global/sw_folders.json | 0 .../global/workfiles.json | 0 .../maya/capture.json | 0 .../muster/templates_mapping.json | 0 .../plugins/celaction/publish.json | 0 .../plugins/config.json | 0 .../plugins/ftrack/publish.json | 0 .../plugins/global/create.json | 0 .../plugins/global/filter.json | 0 .../plugins/global/load.json | 0 .../plugins/global/publish.json | 0 .../plugins/maya/create.json | 0 .../plugins/maya/filter.json | 0 .../plugins/maya/load.json | 0 .../plugins/maya/publish.json | 0 .../plugins/maya/workfile_build.json | 0 .../plugins/nuke/create.json | 0 .../plugins/nuke/load.json | 0 .../plugins/nuke/publish.json | 0 .../plugins/nuke/workfile_build.json | 0 .../plugins/nukestudio/filter.json | 0 .../plugins/nukestudio/publish.json | 0 .../plugins/resolve/create.json | 0 .../plugins/standalonepublisher/publish.json | 0 .../plugins/test/create.json | 0 .../plugins/test/publish.json | 0 .../premiere/asset_default.json | 0 .../premiere/rules_tasks.json | 0 .../standalonepublisher/families.json | 0 .../tools/slates/example_HD.json | 0 .../unreal/project_setup.json | 0 .../environments/avalon.json | 0 .../environments/blender.json | 0 .../environments/celaction.json | 0 .../environments/deadline.json | 0 .../environments/ftrack.json | 0 .../environments/global.json | 0 .../environments/harmony.json | 0 .../environments/houdini.json | 0 .../environments/maya.json | 0 .../environments/maya_2018.json | 0 .../environments/maya_2020.json | 0 .../environments/mayabatch.json | 0 .../environments/mayabatch_2019.json | 0 .../environments/mtoa_3.1.1.json | 0 .../environments/muster.json | 0 .../environments/nuke.json | 0 .../environments/nukestudio.json | 0 .../environments/nukestudio_10.0.json | 0 .../environments/nukex.json | 0 .../environments/nukex_10.0.json | 0 .../environments/photoshop.json | 0 .../environments/premiere.json | 0 .../environments/resolve.json | 0 .../environments/storyboardpro.json | 0 .../environments/unreal_4.24.json | 0 .../environments/vray_4300.json | 0 .../global/applications.json | 0 .../{system_configurations => system_settings}/global/intent.json | 0 .../{system_configurations => system_settings}/global/tools.json | 0 .../global/tray_modules.json | 0 .../launchers/blender_2.80.toml | 0 .../launchers/blender_2.81.toml | 0 .../launchers/blender_2.82.toml | 0 .../launchers/blender_2.83.toml | 0 .../launchers/celaction_local.toml | 0 .../launchers/celaction_publish.toml | 0 .../launchers/darwin/blender_2.82 | 0 .../launchers/darwin/harmony_17 | 0 .../launchers/darwin/harmony_17_launch | 0 .../launchers/darwin/python3 | 0 .../launchers/harmony_17.toml | 0 .../launchers/houdini_16.toml | 0 .../launchers/houdini_17.toml | 0 .../launchers/houdini_18.toml | 0 .../launchers/linux/maya2016 | 0 .../launchers/linux/maya2017 | 0 .../launchers/linux/maya2018 | 0 .../launchers/linux/maya2019 | 0 .../launchers/linux/maya2020 | 0 .../launchers/linux/nuke11.3 | 0 .../launchers/linux/nuke12.0 | 0 .../launchers/linux/nukestudio11.3 | 0 .../launchers/linux/nukestudio12.0 | 0 .../launchers/linux/nukex11.3 | 0 .../launchers/linux/nukex12.0 | 0 .../launchers/maya_2016.toml | 0 .../launchers/maya_2017.toml | 0 .../launchers/maya_2018.toml | 0 .../launchers/maya_2019.toml | 0 .../launchers/maya_2020.toml | 0 .../launchers/mayabatch_2019.toml | 0 .../launchers/mayabatch_2020.toml | 0 .../launchers/mayapy2016.toml | 0 .../launchers/mayapy2017.toml | 0 .../launchers/mayapy2018.toml | 0 .../launchers/mayapy2019.toml | 0 .../launchers/mayapy2020.toml | 0 .../launchers/myapp.toml | 0 .../launchers/nuke_10.0.toml | 0 .../launchers/nuke_11.0.toml | 0 .../launchers/nuke_11.2.toml | 0 .../launchers/nuke_11.3.toml | 0 .../launchers/nuke_12.0.toml | 0 .../launchers/nukestudio_10.0.toml | 0 .../launchers/nukestudio_11.0.toml | 0 .../launchers/nukestudio_11.2.toml | 0 .../launchers/nukestudio_11.3.toml | 0 .../launchers/nukestudio_12.0.toml | 0 .../launchers/nukex_10.0.toml | 0 .../launchers/nukex_11.0.toml | 0 .../launchers/nukex_11.2.toml | 0 .../launchers/nukex_11.3.toml | 0 .../launchers/nukex_12.0.toml | 0 .../launchers/photoshop_2020.toml | 0 .../launchers/premiere_2019.toml | 0 .../launchers/premiere_2020.toml | 0 .../launchers/python_2.toml | 0 .../launchers/python_3.toml | 0 .../launchers/resolve_16.toml | 0 .../launchers/shell.toml | 0 .../launchers/storyboardpro_7.toml | 0 .../launchers/unreal_4.24.toml | 0 .../launchers/windows/blender_2.80.bat | 0 .../launchers/windows/blender_2.81.bat | 0 .../launchers/windows/blender_2.82.bat | 0 .../launchers/windows/blender_2.83.bat | 0 .../launchers/windows/celaction_local.bat | 0 .../launchers/windows/celaction_publish.bat | 0 .../launchers/windows/harmony_17.bat | 0 .../launchers/windows/houdini_16.bat | 0 .../launchers/windows/houdini_17.bat | 0 .../launchers/windows/houdini_18.bat | 0 .../launchers/windows/maya2016.bat | 0 .../launchers/windows/maya2017.bat | 0 .../launchers/windows/maya2018.bat | 0 .../launchers/windows/maya2019.bat | 0 .../launchers/windows/maya2020.bat | 0 .../launchers/windows/mayabatch2019.bat | 0 .../launchers/windows/mayabatch2020.bat | 0 .../launchers/windows/mayapy2016.bat | 0 .../launchers/windows/mayapy2017.bat | 0 .../launchers/windows/mayapy2018.bat | 0 .../launchers/windows/mayapy2019.bat | 0 .../launchers/windows/mayapy2020.bat | 0 .../launchers/windows/nuke10.0.bat | 0 .../launchers/windows/nuke11.0.bat | 0 .../launchers/windows/nuke11.2.bat | 0 .../launchers/windows/nuke11.3.bat | 0 .../launchers/windows/nuke12.0.bat | 0 .../launchers/windows/nukestudio10.0.bat | 0 .../launchers/windows/nukestudio11.0.bat | 0 .../launchers/windows/nukestudio11.2.bat | 0 .../launchers/windows/nukestudio11.3.bat | 0 .../launchers/windows/nukestudio12.0.bat | 0 .../launchers/windows/nukex10.0.bat | 0 .../launchers/windows/nukex11.0.bat | 0 .../launchers/windows/nukex11.2.bat | 0 .../launchers/windows/nukex11.3.bat | 0 .../launchers/windows/nukex12.0.bat | 0 .../launchers/windows/photoshop_2020.bat | 0 .../launchers/windows/premiere_pro_2019.bat | 0 .../launchers/windows/premiere_pro_2020.bat | 0 .../launchers/windows/python3.bat | 0 .../launchers/windows/resolve_16.bat | 0 .../launchers/windows/shell.bat | 0 .../launchers/windows/storyboardpro_7.bat | 0 .../launchers/windows/unreal.bat | 0 .../muster/templates_mapping.json | 0 .../standalone_publish/families.json | 0 178 files changed, 0 insertions(+), 0 deletions(-) rename pype/settings/defaults/{project_configurations => project_settings}/ftrack/ftrack_config.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/ftrack/ftrack_custom_attributes.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/ftrack/partnership_ftrack_cred.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/ftrack/plugins/server.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/ftrack/plugins/user.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/ftrack/project_defaults.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/global/creator.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/global/project_folder_structure.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/global/sw_folders.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/global/workfiles.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/maya/capture.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/muster/templates_mapping.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/celaction/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/config.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/ftrack/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/global/create.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/global/filter.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/global/load.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/global/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/maya/create.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/maya/filter.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/maya/load.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/maya/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/maya/workfile_build.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/nuke/create.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/nuke/load.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/nuke/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/nuke/workfile_build.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/nukestudio/filter.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/nukestudio/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/resolve/create.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/standalonepublisher/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/test/create.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/plugins/test/publish.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/premiere/asset_default.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/premiere/rules_tasks.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/standalonepublisher/families.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/tools/slates/example_HD.json (100%) rename pype/settings/defaults/{project_configurations => project_settings}/unreal/project_setup.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/avalon.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/blender.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/celaction.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/deadline.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/ftrack.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/global.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/harmony.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/houdini.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/maya.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/maya_2018.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/maya_2020.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/mayabatch.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/mayabatch_2019.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/mtoa_3.1.1.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/muster.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/nuke.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/nukestudio.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/nukestudio_10.0.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/nukex.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/nukex_10.0.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/photoshop.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/premiere.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/resolve.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/storyboardpro.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/unreal_4.24.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/environments/vray_4300.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/global/applications.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/global/intent.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/global/tools.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/global/tray_modules.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/blender_2.80.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/blender_2.81.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/blender_2.82.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/blender_2.83.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/celaction_local.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/celaction_publish.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/darwin/blender_2.82 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/darwin/harmony_17 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/darwin/harmony_17_launch (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/darwin/python3 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/harmony_17.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/houdini_16.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/houdini_17.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/houdini_18.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/maya2016 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/maya2017 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/maya2018 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/maya2019 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/maya2020 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/nuke11.3 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/nuke12.0 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/nukestudio11.3 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/nukestudio12.0 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/nukex11.3 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/linux/nukex12.0 (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/maya_2016.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/maya_2017.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/maya_2018.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/maya_2019.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/maya_2020.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayabatch_2019.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayabatch_2020.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayapy2016.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayapy2017.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayapy2018.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayapy2019.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/mayapy2020.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/myapp.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nuke_10.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nuke_11.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nuke_11.2.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nuke_11.3.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nuke_12.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukestudio_10.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukestudio_11.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukestudio_11.2.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukestudio_11.3.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukestudio_12.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukex_10.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukex_11.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukex_11.2.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukex_11.3.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/nukex_12.0.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/photoshop_2020.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/premiere_2019.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/premiere_2020.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/python_2.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/python_3.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/resolve_16.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/shell.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/storyboardpro_7.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/unreal_4.24.toml (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/blender_2.80.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/blender_2.81.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/blender_2.82.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/blender_2.83.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/celaction_local.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/celaction_publish.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/harmony_17.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/houdini_16.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/houdini_17.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/houdini_18.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/maya2016.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/maya2017.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/maya2018.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/maya2019.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/maya2020.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayabatch2019.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayabatch2020.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayapy2016.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayapy2017.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayapy2018.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayapy2019.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/mayapy2020.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nuke10.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nuke11.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nuke11.2.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nuke11.3.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nuke12.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukestudio10.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukestudio11.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukestudio11.2.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukestudio11.3.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukestudio12.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukex10.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukex11.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukex11.2.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukex11.3.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/nukex12.0.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/photoshop_2020.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/premiere_pro_2019.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/premiere_pro_2020.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/python3.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/resolve_16.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/shell.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/storyboardpro_7.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/launchers/windows/unreal.bat (100%) rename pype/settings/defaults/{system_configurations => system_settings}/muster/templates_mapping.json (100%) rename pype/settings/defaults/{system_configurations => system_settings}/standalone_publish/families.json (100%) diff --git a/pype/settings/defaults/project_configurations/ftrack/ftrack_config.json b/pype/settings/defaults/project_settings/ftrack/ftrack_config.json similarity index 100% rename from pype/settings/defaults/project_configurations/ftrack/ftrack_config.json rename to pype/settings/defaults/project_settings/ftrack/ftrack_config.json diff --git a/pype/settings/defaults/project_configurations/ftrack/ftrack_custom_attributes.json b/pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json similarity index 100% rename from pype/settings/defaults/project_configurations/ftrack/ftrack_custom_attributes.json rename to pype/settings/defaults/project_settings/ftrack/ftrack_custom_attributes.json diff --git a/pype/settings/defaults/project_configurations/ftrack/partnership_ftrack_cred.json b/pype/settings/defaults/project_settings/ftrack/partnership_ftrack_cred.json similarity index 100% rename from pype/settings/defaults/project_configurations/ftrack/partnership_ftrack_cred.json rename to pype/settings/defaults/project_settings/ftrack/partnership_ftrack_cred.json diff --git a/pype/settings/defaults/project_configurations/ftrack/plugins/server.json b/pype/settings/defaults/project_settings/ftrack/plugins/server.json similarity index 100% rename from pype/settings/defaults/project_configurations/ftrack/plugins/server.json rename to pype/settings/defaults/project_settings/ftrack/plugins/server.json diff --git a/pype/settings/defaults/project_configurations/ftrack/plugins/user.json b/pype/settings/defaults/project_settings/ftrack/plugins/user.json similarity index 100% rename from pype/settings/defaults/project_configurations/ftrack/plugins/user.json rename to pype/settings/defaults/project_settings/ftrack/plugins/user.json diff --git a/pype/settings/defaults/project_configurations/ftrack/project_defaults.json b/pype/settings/defaults/project_settings/ftrack/project_defaults.json similarity index 100% rename from pype/settings/defaults/project_configurations/ftrack/project_defaults.json rename to pype/settings/defaults/project_settings/ftrack/project_defaults.json diff --git a/pype/settings/defaults/project_configurations/global/creator.json b/pype/settings/defaults/project_settings/global/creator.json similarity index 100% rename from pype/settings/defaults/project_configurations/global/creator.json rename to pype/settings/defaults/project_settings/global/creator.json diff --git a/pype/settings/defaults/project_configurations/global/project_folder_structure.json b/pype/settings/defaults/project_settings/global/project_folder_structure.json similarity index 100% rename from pype/settings/defaults/project_configurations/global/project_folder_structure.json rename to pype/settings/defaults/project_settings/global/project_folder_structure.json diff --git a/pype/settings/defaults/project_configurations/global/sw_folders.json b/pype/settings/defaults/project_settings/global/sw_folders.json similarity index 100% rename from pype/settings/defaults/project_configurations/global/sw_folders.json rename to pype/settings/defaults/project_settings/global/sw_folders.json diff --git a/pype/settings/defaults/project_configurations/global/workfiles.json b/pype/settings/defaults/project_settings/global/workfiles.json similarity index 100% rename from pype/settings/defaults/project_configurations/global/workfiles.json rename to pype/settings/defaults/project_settings/global/workfiles.json diff --git a/pype/settings/defaults/project_configurations/maya/capture.json b/pype/settings/defaults/project_settings/maya/capture.json similarity index 100% rename from pype/settings/defaults/project_configurations/maya/capture.json rename to pype/settings/defaults/project_settings/maya/capture.json diff --git a/pype/settings/defaults/project_configurations/muster/templates_mapping.json b/pype/settings/defaults/project_settings/muster/templates_mapping.json similarity index 100% rename from pype/settings/defaults/project_configurations/muster/templates_mapping.json rename to pype/settings/defaults/project_settings/muster/templates_mapping.json diff --git a/pype/settings/defaults/project_configurations/plugins/celaction/publish.json b/pype/settings/defaults/project_settings/plugins/celaction/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/celaction/publish.json rename to pype/settings/defaults/project_settings/plugins/celaction/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/config.json b/pype/settings/defaults/project_settings/plugins/config.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/config.json rename to pype/settings/defaults/project_settings/plugins/config.json diff --git a/pype/settings/defaults/project_configurations/plugins/ftrack/publish.json b/pype/settings/defaults/project_settings/plugins/ftrack/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/ftrack/publish.json rename to pype/settings/defaults/project_settings/plugins/ftrack/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/global/create.json b/pype/settings/defaults/project_settings/plugins/global/create.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/global/create.json rename to pype/settings/defaults/project_settings/plugins/global/create.json diff --git a/pype/settings/defaults/project_configurations/plugins/global/filter.json b/pype/settings/defaults/project_settings/plugins/global/filter.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/global/filter.json rename to pype/settings/defaults/project_settings/plugins/global/filter.json diff --git a/pype/settings/defaults/project_configurations/plugins/global/load.json b/pype/settings/defaults/project_settings/plugins/global/load.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/global/load.json rename to pype/settings/defaults/project_settings/plugins/global/load.json diff --git a/pype/settings/defaults/project_configurations/plugins/global/publish.json b/pype/settings/defaults/project_settings/plugins/global/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/global/publish.json rename to pype/settings/defaults/project_settings/plugins/global/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/maya/create.json b/pype/settings/defaults/project_settings/plugins/maya/create.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/maya/create.json rename to pype/settings/defaults/project_settings/plugins/maya/create.json diff --git a/pype/settings/defaults/project_configurations/plugins/maya/filter.json b/pype/settings/defaults/project_settings/plugins/maya/filter.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/maya/filter.json rename to pype/settings/defaults/project_settings/plugins/maya/filter.json diff --git a/pype/settings/defaults/project_configurations/plugins/maya/load.json b/pype/settings/defaults/project_settings/plugins/maya/load.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/maya/load.json rename to pype/settings/defaults/project_settings/plugins/maya/load.json diff --git a/pype/settings/defaults/project_configurations/plugins/maya/publish.json b/pype/settings/defaults/project_settings/plugins/maya/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/maya/publish.json rename to pype/settings/defaults/project_settings/plugins/maya/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/maya/workfile_build.json b/pype/settings/defaults/project_settings/plugins/maya/workfile_build.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/maya/workfile_build.json rename to pype/settings/defaults/project_settings/plugins/maya/workfile_build.json diff --git a/pype/settings/defaults/project_configurations/plugins/nuke/create.json b/pype/settings/defaults/project_settings/plugins/nuke/create.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/nuke/create.json rename to pype/settings/defaults/project_settings/plugins/nuke/create.json diff --git a/pype/settings/defaults/project_configurations/plugins/nuke/load.json b/pype/settings/defaults/project_settings/plugins/nuke/load.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/nuke/load.json rename to pype/settings/defaults/project_settings/plugins/nuke/load.json diff --git a/pype/settings/defaults/project_configurations/plugins/nuke/publish.json b/pype/settings/defaults/project_settings/plugins/nuke/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/nuke/publish.json rename to pype/settings/defaults/project_settings/plugins/nuke/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/nuke/workfile_build.json b/pype/settings/defaults/project_settings/plugins/nuke/workfile_build.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/nuke/workfile_build.json rename to pype/settings/defaults/project_settings/plugins/nuke/workfile_build.json diff --git a/pype/settings/defaults/project_configurations/plugins/nukestudio/filter.json b/pype/settings/defaults/project_settings/plugins/nukestudio/filter.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/nukestudio/filter.json rename to pype/settings/defaults/project_settings/plugins/nukestudio/filter.json diff --git a/pype/settings/defaults/project_configurations/plugins/nukestudio/publish.json b/pype/settings/defaults/project_settings/plugins/nukestudio/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/nukestudio/publish.json rename to pype/settings/defaults/project_settings/plugins/nukestudio/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/resolve/create.json b/pype/settings/defaults/project_settings/plugins/resolve/create.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/resolve/create.json rename to pype/settings/defaults/project_settings/plugins/resolve/create.json diff --git a/pype/settings/defaults/project_configurations/plugins/standalonepublisher/publish.json b/pype/settings/defaults/project_settings/plugins/standalonepublisher/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/standalonepublisher/publish.json rename to pype/settings/defaults/project_settings/plugins/standalonepublisher/publish.json diff --git a/pype/settings/defaults/project_configurations/plugins/test/create.json b/pype/settings/defaults/project_settings/plugins/test/create.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/test/create.json rename to pype/settings/defaults/project_settings/plugins/test/create.json diff --git a/pype/settings/defaults/project_configurations/plugins/test/publish.json b/pype/settings/defaults/project_settings/plugins/test/publish.json similarity index 100% rename from pype/settings/defaults/project_configurations/plugins/test/publish.json rename to pype/settings/defaults/project_settings/plugins/test/publish.json diff --git a/pype/settings/defaults/project_configurations/premiere/asset_default.json b/pype/settings/defaults/project_settings/premiere/asset_default.json similarity index 100% rename from pype/settings/defaults/project_configurations/premiere/asset_default.json rename to pype/settings/defaults/project_settings/premiere/asset_default.json diff --git a/pype/settings/defaults/project_configurations/premiere/rules_tasks.json b/pype/settings/defaults/project_settings/premiere/rules_tasks.json similarity index 100% rename from pype/settings/defaults/project_configurations/premiere/rules_tasks.json rename to pype/settings/defaults/project_settings/premiere/rules_tasks.json diff --git a/pype/settings/defaults/project_configurations/standalonepublisher/families.json b/pype/settings/defaults/project_settings/standalonepublisher/families.json similarity index 100% rename from pype/settings/defaults/project_configurations/standalonepublisher/families.json rename to pype/settings/defaults/project_settings/standalonepublisher/families.json diff --git a/pype/settings/defaults/project_configurations/tools/slates/example_HD.json b/pype/settings/defaults/project_settings/tools/slates/example_HD.json similarity index 100% rename from pype/settings/defaults/project_configurations/tools/slates/example_HD.json rename to pype/settings/defaults/project_settings/tools/slates/example_HD.json diff --git a/pype/settings/defaults/project_configurations/unreal/project_setup.json b/pype/settings/defaults/project_settings/unreal/project_setup.json similarity index 100% rename from pype/settings/defaults/project_configurations/unreal/project_setup.json rename to pype/settings/defaults/project_settings/unreal/project_setup.json diff --git a/pype/settings/defaults/system_configurations/environments/avalon.json b/pype/settings/defaults/system_settings/environments/avalon.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/avalon.json rename to pype/settings/defaults/system_settings/environments/avalon.json diff --git a/pype/settings/defaults/system_configurations/environments/blender.json b/pype/settings/defaults/system_settings/environments/blender.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/blender.json rename to pype/settings/defaults/system_settings/environments/blender.json diff --git a/pype/settings/defaults/system_configurations/environments/celaction.json b/pype/settings/defaults/system_settings/environments/celaction.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/celaction.json rename to pype/settings/defaults/system_settings/environments/celaction.json diff --git a/pype/settings/defaults/system_configurations/environments/deadline.json b/pype/settings/defaults/system_settings/environments/deadline.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/deadline.json rename to pype/settings/defaults/system_settings/environments/deadline.json diff --git a/pype/settings/defaults/system_configurations/environments/ftrack.json b/pype/settings/defaults/system_settings/environments/ftrack.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/ftrack.json rename to pype/settings/defaults/system_settings/environments/ftrack.json diff --git a/pype/settings/defaults/system_configurations/environments/global.json b/pype/settings/defaults/system_settings/environments/global.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/global.json rename to pype/settings/defaults/system_settings/environments/global.json diff --git a/pype/settings/defaults/system_configurations/environments/harmony.json b/pype/settings/defaults/system_settings/environments/harmony.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/harmony.json rename to pype/settings/defaults/system_settings/environments/harmony.json diff --git a/pype/settings/defaults/system_configurations/environments/houdini.json b/pype/settings/defaults/system_settings/environments/houdini.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/houdini.json rename to pype/settings/defaults/system_settings/environments/houdini.json diff --git a/pype/settings/defaults/system_configurations/environments/maya.json b/pype/settings/defaults/system_settings/environments/maya.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/maya.json rename to pype/settings/defaults/system_settings/environments/maya.json diff --git a/pype/settings/defaults/system_configurations/environments/maya_2018.json b/pype/settings/defaults/system_settings/environments/maya_2018.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/maya_2018.json rename to pype/settings/defaults/system_settings/environments/maya_2018.json diff --git a/pype/settings/defaults/system_configurations/environments/maya_2020.json b/pype/settings/defaults/system_settings/environments/maya_2020.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/maya_2020.json rename to pype/settings/defaults/system_settings/environments/maya_2020.json diff --git a/pype/settings/defaults/system_configurations/environments/mayabatch.json b/pype/settings/defaults/system_settings/environments/mayabatch.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/mayabatch.json rename to pype/settings/defaults/system_settings/environments/mayabatch.json diff --git a/pype/settings/defaults/system_configurations/environments/mayabatch_2019.json b/pype/settings/defaults/system_settings/environments/mayabatch_2019.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/mayabatch_2019.json rename to pype/settings/defaults/system_settings/environments/mayabatch_2019.json diff --git a/pype/settings/defaults/system_configurations/environments/mtoa_3.1.1.json b/pype/settings/defaults/system_settings/environments/mtoa_3.1.1.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/mtoa_3.1.1.json rename to pype/settings/defaults/system_settings/environments/mtoa_3.1.1.json diff --git a/pype/settings/defaults/system_configurations/environments/muster.json b/pype/settings/defaults/system_settings/environments/muster.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/muster.json rename to pype/settings/defaults/system_settings/environments/muster.json diff --git a/pype/settings/defaults/system_configurations/environments/nuke.json b/pype/settings/defaults/system_settings/environments/nuke.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/nuke.json rename to pype/settings/defaults/system_settings/environments/nuke.json diff --git a/pype/settings/defaults/system_configurations/environments/nukestudio.json b/pype/settings/defaults/system_settings/environments/nukestudio.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/nukestudio.json rename to pype/settings/defaults/system_settings/environments/nukestudio.json diff --git a/pype/settings/defaults/system_configurations/environments/nukestudio_10.0.json b/pype/settings/defaults/system_settings/environments/nukestudio_10.0.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/nukestudio_10.0.json rename to pype/settings/defaults/system_settings/environments/nukestudio_10.0.json diff --git a/pype/settings/defaults/system_configurations/environments/nukex.json b/pype/settings/defaults/system_settings/environments/nukex.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/nukex.json rename to pype/settings/defaults/system_settings/environments/nukex.json diff --git a/pype/settings/defaults/system_configurations/environments/nukex_10.0.json b/pype/settings/defaults/system_settings/environments/nukex_10.0.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/nukex_10.0.json rename to pype/settings/defaults/system_settings/environments/nukex_10.0.json diff --git a/pype/settings/defaults/system_configurations/environments/photoshop.json b/pype/settings/defaults/system_settings/environments/photoshop.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/photoshop.json rename to pype/settings/defaults/system_settings/environments/photoshop.json diff --git a/pype/settings/defaults/system_configurations/environments/premiere.json b/pype/settings/defaults/system_settings/environments/premiere.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/premiere.json rename to pype/settings/defaults/system_settings/environments/premiere.json diff --git a/pype/settings/defaults/system_configurations/environments/resolve.json b/pype/settings/defaults/system_settings/environments/resolve.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/resolve.json rename to pype/settings/defaults/system_settings/environments/resolve.json diff --git a/pype/settings/defaults/system_configurations/environments/storyboardpro.json b/pype/settings/defaults/system_settings/environments/storyboardpro.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/storyboardpro.json rename to pype/settings/defaults/system_settings/environments/storyboardpro.json diff --git a/pype/settings/defaults/system_configurations/environments/unreal_4.24.json b/pype/settings/defaults/system_settings/environments/unreal_4.24.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/unreal_4.24.json rename to pype/settings/defaults/system_settings/environments/unreal_4.24.json diff --git a/pype/settings/defaults/system_configurations/environments/vray_4300.json b/pype/settings/defaults/system_settings/environments/vray_4300.json similarity index 100% rename from pype/settings/defaults/system_configurations/environments/vray_4300.json rename to pype/settings/defaults/system_settings/environments/vray_4300.json diff --git a/pype/settings/defaults/system_configurations/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json similarity index 100% rename from pype/settings/defaults/system_configurations/global/applications.json rename to pype/settings/defaults/system_settings/global/applications.json diff --git a/pype/settings/defaults/system_configurations/global/intent.json b/pype/settings/defaults/system_settings/global/intent.json similarity index 100% rename from pype/settings/defaults/system_configurations/global/intent.json rename to pype/settings/defaults/system_settings/global/intent.json diff --git a/pype/settings/defaults/system_configurations/global/tools.json b/pype/settings/defaults/system_settings/global/tools.json similarity index 100% rename from pype/settings/defaults/system_configurations/global/tools.json rename to pype/settings/defaults/system_settings/global/tools.json diff --git a/pype/settings/defaults/system_configurations/global/tray_modules.json b/pype/settings/defaults/system_settings/global/tray_modules.json similarity index 100% rename from pype/settings/defaults/system_configurations/global/tray_modules.json rename to pype/settings/defaults/system_settings/global/tray_modules.json diff --git a/pype/settings/defaults/system_configurations/launchers/blender_2.80.toml b/pype/settings/defaults/system_settings/launchers/blender_2.80.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/blender_2.80.toml rename to pype/settings/defaults/system_settings/launchers/blender_2.80.toml diff --git a/pype/settings/defaults/system_configurations/launchers/blender_2.81.toml b/pype/settings/defaults/system_settings/launchers/blender_2.81.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/blender_2.81.toml rename to pype/settings/defaults/system_settings/launchers/blender_2.81.toml diff --git a/pype/settings/defaults/system_configurations/launchers/blender_2.82.toml b/pype/settings/defaults/system_settings/launchers/blender_2.82.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/blender_2.82.toml rename to pype/settings/defaults/system_settings/launchers/blender_2.82.toml diff --git a/pype/settings/defaults/system_configurations/launchers/blender_2.83.toml b/pype/settings/defaults/system_settings/launchers/blender_2.83.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/blender_2.83.toml rename to pype/settings/defaults/system_settings/launchers/blender_2.83.toml diff --git a/pype/settings/defaults/system_configurations/launchers/celaction_local.toml b/pype/settings/defaults/system_settings/launchers/celaction_local.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/celaction_local.toml rename to pype/settings/defaults/system_settings/launchers/celaction_local.toml diff --git a/pype/settings/defaults/system_configurations/launchers/celaction_publish.toml b/pype/settings/defaults/system_settings/launchers/celaction_publish.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/celaction_publish.toml rename to pype/settings/defaults/system_settings/launchers/celaction_publish.toml diff --git a/pype/settings/defaults/system_configurations/launchers/darwin/blender_2.82 b/pype/settings/defaults/system_settings/launchers/darwin/blender_2.82 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/darwin/blender_2.82 rename to pype/settings/defaults/system_settings/launchers/darwin/blender_2.82 diff --git a/pype/settings/defaults/system_configurations/launchers/darwin/harmony_17 b/pype/settings/defaults/system_settings/launchers/darwin/harmony_17 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/darwin/harmony_17 rename to pype/settings/defaults/system_settings/launchers/darwin/harmony_17 diff --git a/pype/settings/defaults/system_configurations/launchers/darwin/harmony_17_launch b/pype/settings/defaults/system_settings/launchers/darwin/harmony_17_launch similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/darwin/harmony_17_launch rename to pype/settings/defaults/system_settings/launchers/darwin/harmony_17_launch diff --git a/pype/settings/defaults/system_configurations/launchers/darwin/python3 b/pype/settings/defaults/system_settings/launchers/darwin/python3 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/darwin/python3 rename to pype/settings/defaults/system_settings/launchers/darwin/python3 diff --git a/pype/settings/defaults/system_configurations/launchers/harmony_17.toml b/pype/settings/defaults/system_settings/launchers/harmony_17.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/harmony_17.toml rename to pype/settings/defaults/system_settings/launchers/harmony_17.toml diff --git a/pype/settings/defaults/system_configurations/launchers/houdini_16.toml b/pype/settings/defaults/system_settings/launchers/houdini_16.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/houdini_16.toml rename to pype/settings/defaults/system_settings/launchers/houdini_16.toml diff --git a/pype/settings/defaults/system_configurations/launchers/houdini_17.toml b/pype/settings/defaults/system_settings/launchers/houdini_17.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/houdini_17.toml rename to pype/settings/defaults/system_settings/launchers/houdini_17.toml diff --git a/pype/settings/defaults/system_configurations/launchers/houdini_18.toml b/pype/settings/defaults/system_settings/launchers/houdini_18.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/houdini_18.toml rename to pype/settings/defaults/system_settings/launchers/houdini_18.toml diff --git a/pype/settings/defaults/system_configurations/launchers/linux/maya2016 b/pype/settings/defaults/system_settings/launchers/linux/maya2016 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/maya2016 rename to pype/settings/defaults/system_settings/launchers/linux/maya2016 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/maya2017 b/pype/settings/defaults/system_settings/launchers/linux/maya2017 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/maya2017 rename to pype/settings/defaults/system_settings/launchers/linux/maya2017 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/maya2018 b/pype/settings/defaults/system_settings/launchers/linux/maya2018 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/maya2018 rename to pype/settings/defaults/system_settings/launchers/linux/maya2018 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/maya2019 b/pype/settings/defaults/system_settings/launchers/linux/maya2019 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/maya2019 rename to pype/settings/defaults/system_settings/launchers/linux/maya2019 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/maya2020 b/pype/settings/defaults/system_settings/launchers/linux/maya2020 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/maya2020 rename to pype/settings/defaults/system_settings/launchers/linux/maya2020 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/nuke11.3 b/pype/settings/defaults/system_settings/launchers/linux/nuke11.3 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/nuke11.3 rename to pype/settings/defaults/system_settings/launchers/linux/nuke11.3 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/nuke12.0 b/pype/settings/defaults/system_settings/launchers/linux/nuke12.0 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/nuke12.0 rename to pype/settings/defaults/system_settings/launchers/linux/nuke12.0 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/nukestudio11.3 b/pype/settings/defaults/system_settings/launchers/linux/nukestudio11.3 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/nukestudio11.3 rename to pype/settings/defaults/system_settings/launchers/linux/nukestudio11.3 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/nukestudio12.0 b/pype/settings/defaults/system_settings/launchers/linux/nukestudio12.0 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/nukestudio12.0 rename to pype/settings/defaults/system_settings/launchers/linux/nukestudio12.0 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/nukex11.3 b/pype/settings/defaults/system_settings/launchers/linux/nukex11.3 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/nukex11.3 rename to pype/settings/defaults/system_settings/launchers/linux/nukex11.3 diff --git a/pype/settings/defaults/system_configurations/launchers/linux/nukex12.0 b/pype/settings/defaults/system_settings/launchers/linux/nukex12.0 similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/linux/nukex12.0 rename to pype/settings/defaults/system_settings/launchers/linux/nukex12.0 diff --git a/pype/settings/defaults/system_configurations/launchers/maya_2016.toml b/pype/settings/defaults/system_settings/launchers/maya_2016.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/maya_2016.toml rename to pype/settings/defaults/system_settings/launchers/maya_2016.toml diff --git a/pype/settings/defaults/system_configurations/launchers/maya_2017.toml b/pype/settings/defaults/system_settings/launchers/maya_2017.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/maya_2017.toml rename to pype/settings/defaults/system_settings/launchers/maya_2017.toml diff --git a/pype/settings/defaults/system_configurations/launchers/maya_2018.toml b/pype/settings/defaults/system_settings/launchers/maya_2018.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/maya_2018.toml rename to pype/settings/defaults/system_settings/launchers/maya_2018.toml diff --git a/pype/settings/defaults/system_configurations/launchers/maya_2019.toml b/pype/settings/defaults/system_settings/launchers/maya_2019.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/maya_2019.toml rename to pype/settings/defaults/system_settings/launchers/maya_2019.toml diff --git a/pype/settings/defaults/system_configurations/launchers/maya_2020.toml b/pype/settings/defaults/system_settings/launchers/maya_2020.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/maya_2020.toml rename to pype/settings/defaults/system_settings/launchers/maya_2020.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayabatch_2019.toml b/pype/settings/defaults/system_settings/launchers/mayabatch_2019.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayabatch_2019.toml rename to pype/settings/defaults/system_settings/launchers/mayabatch_2019.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayabatch_2020.toml b/pype/settings/defaults/system_settings/launchers/mayabatch_2020.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayabatch_2020.toml rename to pype/settings/defaults/system_settings/launchers/mayabatch_2020.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayapy2016.toml b/pype/settings/defaults/system_settings/launchers/mayapy2016.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayapy2016.toml rename to pype/settings/defaults/system_settings/launchers/mayapy2016.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayapy2017.toml b/pype/settings/defaults/system_settings/launchers/mayapy2017.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayapy2017.toml rename to pype/settings/defaults/system_settings/launchers/mayapy2017.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayapy2018.toml b/pype/settings/defaults/system_settings/launchers/mayapy2018.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayapy2018.toml rename to pype/settings/defaults/system_settings/launchers/mayapy2018.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayapy2019.toml b/pype/settings/defaults/system_settings/launchers/mayapy2019.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayapy2019.toml rename to pype/settings/defaults/system_settings/launchers/mayapy2019.toml diff --git a/pype/settings/defaults/system_configurations/launchers/mayapy2020.toml b/pype/settings/defaults/system_settings/launchers/mayapy2020.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/mayapy2020.toml rename to pype/settings/defaults/system_settings/launchers/mayapy2020.toml diff --git a/pype/settings/defaults/system_configurations/launchers/myapp.toml b/pype/settings/defaults/system_settings/launchers/myapp.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/myapp.toml rename to pype/settings/defaults/system_settings/launchers/myapp.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nuke_10.0.toml b/pype/settings/defaults/system_settings/launchers/nuke_10.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nuke_10.0.toml rename to pype/settings/defaults/system_settings/launchers/nuke_10.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nuke_11.0.toml b/pype/settings/defaults/system_settings/launchers/nuke_11.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nuke_11.0.toml rename to pype/settings/defaults/system_settings/launchers/nuke_11.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nuke_11.2.toml b/pype/settings/defaults/system_settings/launchers/nuke_11.2.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nuke_11.2.toml rename to pype/settings/defaults/system_settings/launchers/nuke_11.2.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nuke_11.3.toml b/pype/settings/defaults/system_settings/launchers/nuke_11.3.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nuke_11.3.toml rename to pype/settings/defaults/system_settings/launchers/nuke_11.3.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nuke_12.0.toml b/pype/settings/defaults/system_settings/launchers/nuke_12.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nuke_12.0.toml rename to pype/settings/defaults/system_settings/launchers/nuke_12.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukestudio_10.0.toml b/pype/settings/defaults/system_settings/launchers/nukestudio_10.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukestudio_10.0.toml rename to pype/settings/defaults/system_settings/launchers/nukestudio_10.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukestudio_11.0.toml b/pype/settings/defaults/system_settings/launchers/nukestudio_11.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukestudio_11.0.toml rename to pype/settings/defaults/system_settings/launchers/nukestudio_11.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukestudio_11.2.toml b/pype/settings/defaults/system_settings/launchers/nukestudio_11.2.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukestudio_11.2.toml rename to pype/settings/defaults/system_settings/launchers/nukestudio_11.2.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukestudio_11.3.toml b/pype/settings/defaults/system_settings/launchers/nukestudio_11.3.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukestudio_11.3.toml rename to pype/settings/defaults/system_settings/launchers/nukestudio_11.3.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukestudio_12.0.toml b/pype/settings/defaults/system_settings/launchers/nukestudio_12.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukestudio_12.0.toml rename to pype/settings/defaults/system_settings/launchers/nukestudio_12.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukex_10.0.toml b/pype/settings/defaults/system_settings/launchers/nukex_10.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukex_10.0.toml rename to pype/settings/defaults/system_settings/launchers/nukex_10.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukex_11.0.toml b/pype/settings/defaults/system_settings/launchers/nukex_11.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukex_11.0.toml rename to pype/settings/defaults/system_settings/launchers/nukex_11.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukex_11.2.toml b/pype/settings/defaults/system_settings/launchers/nukex_11.2.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukex_11.2.toml rename to pype/settings/defaults/system_settings/launchers/nukex_11.2.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukex_11.3.toml b/pype/settings/defaults/system_settings/launchers/nukex_11.3.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukex_11.3.toml rename to pype/settings/defaults/system_settings/launchers/nukex_11.3.toml diff --git a/pype/settings/defaults/system_configurations/launchers/nukex_12.0.toml b/pype/settings/defaults/system_settings/launchers/nukex_12.0.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/nukex_12.0.toml rename to pype/settings/defaults/system_settings/launchers/nukex_12.0.toml diff --git a/pype/settings/defaults/system_configurations/launchers/photoshop_2020.toml b/pype/settings/defaults/system_settings/launchers/photoshop_2020.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/photoshop_2020.toml rename to pype/settings/defaults/system_settings/launchers/photoshop_2020.toml diff --git a/pype/settings/defaults/system_configurations/launchers/premiere_2019.toml b/pype/settings/defaults/system_settings/launchers/premiere_2019.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/premiere_2019.toml rename to pype/settings/defaults/system_settings/launchers/premiere_2019.toml diff --git a/pype/settings/defaults/system_configurations/launchers/premiere_2020.toml b/pype/settings/defaults/system_settings/launchers/premiere_2020.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/premiere_2020.toml rename to pype/settings/defaults/system_settings/launchers/premiere_2020.toml diff --git a/pype/settings/defaults/system_configurations/launchers/python_2.toml b/pype/settings/defaults/system_settings/launchers/python_2.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/python_2.toml rename to pype/settings/defaults/system_settings/launchers/python_2.toml diff --git a/pype/settings/defaults/system_configurations/launchers/python_3.toml b/pype/settings/defaults/system_settings/launchers/python_3.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/python_3.toml rename to pype/settings/defaults/system_settings/launchers/python_3.toml diff --git a/pype/settings/defaults/system_configurations/launchers/resolve_16.toml b/pype/settings/defaults/system_settings/launchers/resolve_16.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/resolve_16.toml rename to pype/settings/defaults/system_settings/launchers/resolve_16.toml diff --git a/pype/settings/defaults/system_configurations/launchers/shell.toml b/pype/settings/defaults/system_settings/launchers/shell.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/shell.toml rename to pype/settings/defaults/system_settings/launchers/shell.toml diff --git a/pype/settings/defaults/system_configurations/launchers/storyboardpro_7.toml b/pype/settings/defaults/system_settings/launchers/storyboardpro_7.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/storyboardpro_7.toml rename to pype/settings/defaults/system_settings/launchers/storyboardpro_7.toml diff --git a/pype/settings/defaults/system_configurations/launchers/unreal_4.24.toml b/pype/settings/defaults/system_settings/launchers/unreal_4.24.toml similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/unreal_4.24.toml rename to pype/settings/defaults/system_settings/launchers/unreal_4.24.toml diff --git a/pype/settings/defaults/system_configurations/launchers/windows/blender_2.80.bat b/pype/settings/defaults/system_settings/launchers/windows/blender_2.80.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/blender_2.80.bat rename to pype/settings/defaults/system_settings/launchers/windows/blender_2.80.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/blender_2.81.bat b/pype/settings/defaults/system_settings/launchers/windows/blender_2.81.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/blender_2.81.bat rename to pype/settings/defaults/system_settings/launchers/windows/blender_2.81.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/blender_2.82.bat b/pype/settings/defaults/system_settings/launchers/windows/blender_2.82.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/blender_2.82.bat rename to pype/settings/defaults/system_settings/launchers/windows/blender_2.82.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/blender_2.83.bat b/pype/settings/defaults/system_settings/launchers/windows/blender_2.83.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/blender_2.83.bat rename to pype/settings/defaults/system_settings/launchers/windows/blender_2.83.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/celaction_local.bat b/pype/settings/defaults/system_settings/launchers/windows/celaction_local.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/celaction_local.bat rename to pype/settings/defaults/system_settings/launchers/windows/celaction_local.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/celaction_publish.bat b/pype/settings/defaults/system_settings/launchers/windows/celaction_publish.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/celaction_publish.bat rename to pype/settings/defaults/system_settings/launchers/windows/celaction_publish.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/harmony_17.bat b/pype/settings/defaults/system_settings/launchers/windows/harmony_17.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/harmony_17.bat rename to pype/settings/defaults/system_settings/launchers/windows/harmony_17.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/houdini_16.bat b/pype/settings/defaults/system_settings/launchers/windows/houdini_16.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/houdini_16.bat rename to pype/settings/defaults/system_settings/launchers/windows/houdini_16.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/houdini_17.bat b/pype/settings/defaults/system_settings/launchers/windows/houdini_17.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/houdini_17.bat rename to pype/settings/defaults/system_settings/launchers/windows/houdini_17.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/houdini_18.bat b/pype/settings/defaults/system_settings/launchers/windows/houdini_18.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/houdini_18.bat rename to pype/settings/defaults/system_settings/launchers/windows/houdini_18.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/maya2016.bat b/pype/settings/defaults/system_settings/launchers/windows/maya2016.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/maya2016.bat rename to pype/settings/defaults/system_settings/launchers/windows/maya2016.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/maya2017.bat b/pype/settings/defaults/system_settings/launchers/windows/maya2017.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/maya2017.bat rename to pype/settings/defaults/system_settings/launchers/windows/maya2017.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/maya2018.bat b/pype/settings/defaults/system_settings/launchers/windows/maya2018.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/maya2018.bat rename to pype/settings/defaults/system_settings/launchers/windows/maya2018.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/maya2019.bat b/pype/settings/defaults/system_settings/launchers/windows/maya2019.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/maya2019.bat rename to pype/settings/defaults/system_settings/launchers/windows/maya2019.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/maya2020.bat b/pype/settings/defaults/system_settings/launchers/windows/maya2020.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/maya2020.bat rename to pype/settings/defaults/system_settings/launchers/windows/maya2020.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayabatch2019.bat b/pype/settings/defaults/system_settings/launchers/windows/mayabatch2019.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayabatch2019.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayabatch2019.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayabatch2020.bat b/pype/settings/defaults/system_settings/launchers/windows/mayabatch2020.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayabatch2020.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayabatch2020.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayapy2016.bat b/pype/settings/defaults/system_settings/launchers/windows/mayapy2016.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayapy2016.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayapy2016.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayapy2017.bat b/pype/settings/defaults/system_settings/launchers/windows/mayapy2017.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayapy2017.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayapy2017.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayapy2018.bat b/pype/settings/defaults/system_settings/launchers/windows/mayapy2018.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayapy2018.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayapy2018.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayapy2019.bat b/pype/settings/defaults/system_settings/launchers/windows/mayapy2019.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayapy2019.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayapy2019.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/mayapy2020.bat b/pype/settings/defaults/system_settings/launchers/windows/mayapy2020.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/mayapy2020.bat rename to pype/settings/defaults/system_settings/launchers/windows/mayapy2020.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nuke10.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nuke10.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nuke10.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nuke10.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nuke11.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nuke11.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nuke11.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nuke11.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nuke11.2.bat b/pype/settings/defaults/system_settings/launchers/windows/nuke11.2.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nuke11.2.bat rename to pype/settings/defaults/system_settings/launchers/windows/nuke11.2.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nuke11.3.bat b/pype/settings/defaults/system_settings/launchers/windows/nuke11.3.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nuke11.3.bat rename to pype/settings/defaults/system_settings/launchers/windows/nuke11.3.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nuke12.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nuke12.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nuke12.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nuke12.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukestudio10.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nukestudio10.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukestudio10.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukestudio10.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nukestudio11.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukestudio11.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.2.bat b/pype/settings/defaults/system_settings/launchers/windows/nukestudio11.2.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.2.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukestudio11.2.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.3.bat b/pype/settings/defaults/system_settings/launchers/windows/nukestudio11.3.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukestudio11.3.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukestudio11.3.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukestudio12.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nukestudio12.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukestudio12.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukestudio12.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukex10.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nukex10.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukex10.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukex10.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukex11.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nukex11.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukex11.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukex11.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukex11.2.bat b/pype/settings/defaults/system_settings/launchers/windows/nukex11.2.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukex11.2.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukex11.2.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukex11.3.bat b/pype/settings/defaults/system_settings/launchers/windows/nukex11.3.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukex11.3.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukex11.3.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/nukex12.0.bat b/pype/settings/defaults/system_settings/launchers/windows/nukex12.0.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/nukex12.0.bat rename to pype/settings/defaults/system_settings/launchers/windows/nukex12.0.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/photoshop_2020.bat b/pype/settings/defaults/system_settings/launchers/windows/photoshop_2020.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/photoshop_2020.bat rename to pype/settings/defaults/system_settings/launchers/windows/photoshop_2020.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat b/pype/settings/defaults/system_settings/launchers/windows/premiere_pro_2019.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2019.bat rename to pype/settings/defaults/system_settings/launchers/windows/premiere_pro_2019.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat b/pype/settings/defaults/system_settings/launchers/windows/premiere_pro_2020.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/premiere_pro_2020.bat rename to pype/settings/defaults/system_settings/launchers/windows/premiere_pro_2020.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/python3.bat b/pype/settings/defaults/system_settings/launchers/windows/python3.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/python3.bat rename to pype/settings/defaults/system_settings/launchers/windows/python3.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/resolve_16.bat b/pype/settings/defaults/system_settings/launchers/windows/resolve_16.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/resolve_16.bat rename to pype/settings/defaults/system_settings/launchers/windows/resolve_16.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/shell.bat b/pype/settings/defaults/system_settings/launchers/windows/shell.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/shell.bat rename to pype/settings/defaults/system_settings/launchers/windows/shell.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/storyboardpro_7.bat b/pype/settings/defaults/system_settings/launchers/windows/storyboardpro_7.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/storyboardpro_7.bat rename to pype/settings/defaults/system_settings/launchers/windows/storyboardpro_7.bat diff --git a/pype/settings/defaults/system_configurations/launchers/windows/unreal.bat b/pype/settings/defaults/system_settings/launchers/windows/unreal.bat similarity index 100% rename from pype/settings/defaults/system_configurations/launchers/windows/unreal.bat rename to pype/settings/defaults/system_settings/launchers/windows/unreal.bat diff --git a/pype/settings/defaults/system_configurations/muster/templates_mapping.json b/pype/settings/defaults/system_settings/muster/templates_mapping.json similarity index 100% rename from pype/settings/defaults/system_configurations/muster/templates_mapping.json rename to pype/settings/defaults/system_settings/muster/templates_mapping.json diff --git a/pype/settings/defaults/system_configurations/standalone_publish/families.json b/pype/settings/defaults/system_settings/standalone_publish/families.json similarity index 100% rename from pype/settings/defaults/system_configurations/standalone_publish/families.json rename to pype/settings/defaults/system_settings/standalone_publish/families.json From 5b50b8ede47d0507f56cf4f26701dca0ada4a110 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:31:47 +0200 Subject: [PATCH 542/580] all variables for setting not contain setting instead of configuration --- pype/api.py | 8 ++-- pype/settings/__init__.py | 8 ++-- pype/settings/lib.py | 42 +++++++++---------- .../projects_schema/0_project_gui_schema.json | 2 +- pype/tools/settings/settings/widgets/base.py | 26 ++++++------ 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/pype/api.py b/pype/api.py index 0b3439c4c2..021080b4d5 100644 --- a/pype/api.py +++ b/pype/api.py @@ -1,6 +1,6 @@ from .settings import ( - system_configurations, - project_configurations + system_settings, + project_settings ) from pypeapp import ( Logger, @@ -53,8 +53,8 @@ from .lib import ( from .lib import _subprocess as subprocess __all__ = [ - "system_configurations", - "project_configurations", + "system_settings", + "project_settings", "Logger", "Anatomy", diff --git a/pype/settings/__init__.py b/pype/settings/__init__.py index e3fc53fcfd..7e73d541a4 100644 --- a/pype/settings/__init__.py +++ b/pype/settings/__init__.py @@ -1,9 +1,9 @@ from .lib import ( - system_configurations, - project_configurations + system_settings, + project_settings ) __all__ = ( - "system_configurations", - "project_configurations" + "system_settings", + "project_settings" ) diff --git a/pype/settings/lib.py b/pype/settings/lib.py index 101b579b14..388557ca9b 100644 --- a/pype/settings/lib.py +++ b/pype/settings/lib.py @@ -14,13 +14,13 @@ POP_KEY = "__pop_key__" STUDIO_OVERRIDES_PATH = os.environ["PYPE_PROJECT_CONFIGS"] # File where studio's system overrides are stored -SYSTEM_SETTINGS_KEY = "system_configurations" +SYSTEM_SETTINGS_KEY = "system_settings" SYSTEM_SETTINGS_PATH = os.path.join( STUDIO_OVERRIDES_PATH, SYSTEM_SETTINGS_KEY + ".json" ) # File where studio's default project overrides are stored -PROJECT_SETTINGS_KEY = "project_configurations" +PROJECT_SETTINGS_KEY = "project_settings" PROJECT_SETTINGS_FILENAME = PROJECT_SETTINGS_KEY + ".json" PROJECT_SETTINGS_PATH = os.path.join( STUDIO_OVERRIDES_PATH, PROJECT_SETTINGS_FILENAME @@ -32,19 +32,19 @@ PROJECT_ANATOMY_PATH = os.path.join( STUDIO_OVERRIDES_PATH, PROJECT_ANATOMY_FILENAME ) -# Path to default configurations +# Path to default settings DEFAULTS_DIR = os.path.join(os.path.dirname(__file__), "defaults") -# Variable where cache of default configurations are stored +# Variable where cache of default settings are stored _DEFAULT_SETTINGS = None -def reset_default_configurations(): +def reset_default_settings(): global _DEFAULT_SETTINGS _DEFAULT_SETTINGS = None -def default_configuration(): +def default_settings(): global _DEFAULT_SETTINGS if _DEFAULT_SETTINGS is None: _DEFAULT_SETTINGS = load_jsons_from_dir(DEFAULTS_DIR) @@ -156,13 +156,13 @@ def load_jsons_from_dir(path, *args, **kwargs): return output -def studio_system_configurations(): +def studio_system_settings(): if os.path.exists(SYSTEM_SETTINGS_PATH): return load_json(SYSTEM_SETTINGS_PATH) return {} -def studio_project_configurations(): +def studio_project_settings(): if os.path.exists(PROJECT_SETTINGS_PATH): return load_json(PROJECT_SETTINGS_PATH) return {} @@ -190,7 +190,7 @@ def path_to_project_anatomy(project_name): ) -def project_configurations_overrides(project_name): +def project_settings_overrides(project_name): if not project_name: return {} @@ -234,25 +234,25 @@ def merge_overrides(global_dict, override_dict): return global_dict -def apply_overrides(global_presets, project_overrides): - global_presets = copy.deepcopy(global_presets) - if not project_overrides: - return global_presets - return merge_overrides(global_presets, project_overrides) +def apply_overrides(source_data, override_data): + if not override_data: + return source_data + _source_data = copy.deepcopy(source_data) + return merge_overrides(_source_data, override_data) -def system_configurations(): - default_values = default_configuration()["system_configurations"] - studio_values = studio_system_configurations() +def system_settings(): + default_values = default_settings()[SYSTEM_SETTINGS_KEY] + studio_values = studio_system_settings() return apply_overrides(default_values, studio_values) -def project_configurations(project_name): - default_values = default_configuration()["project_configurations"] - studio_values = studio_project_configurations() +def project_settings(project_name): + default_values = default_settings()[PROJECT_SETTINGS_KEY] + studio_values = studio_project_settings() studio_overrides = apply_overrides(default_values, studio_values) - project_overrides = project_configurations_overrides(project_name) + project_overrides = project_settings_overrides(project_name) return apply_overrides(studio_overrides, project_overrides) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index 3d7cac68fd..fa7c6a366d 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -18,7 +18,7 @@ ] }, { "type": "dict-invisible", - "key": "project_configurations", + "key": "project_settings", "children": [ { "type": "schema", diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 6a7a65cb0f..90e3aca677 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -11,14 +11,14 @@ from pype.settings.lib import ( DEFAULTS_DIR, - reset_default_configurations, - default_configuration, + reset_default_settings, + default_settings, - studio_system_configurations, - studio_project_configurations, + studio_system_settings, + studio_project_settings, studio_project_anatomy, - project_configurations_overrides, + project_settings_overrides, project_anatomy_overrides, path_to_project_overrides, @@ -179,7 +179,7 @@ class SystemWidget(QtWidgets.QWidget): all_values = all_values["system"] prject_defaults_dir = os.path.join( - DEFAULTS_DIR, SYSTEM_CONFIGURATIONS_KEY + DEFAULTS_DIR, SYSTEM_SETTINGS_KEY ) keys_to_file = lib.file_keys_from_schema(self.schema) for key_sequence in keys_to_file: @@ -200,7 +200,7 @@ class SystemWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(new_values, file_stream, indent=4) - reset_default_configurations() + reset_default_settings() self._update_values() @@ -208,12 +208,12 @@ class SystemWidget(QtWidgets.QWidget): self.ignore_value_changes = True default_values = { - "system": default_configuration()["system_configurations"] + "system": default_settings()[SYSTEM_SETTINGS_KEY] } for input_field in self.input_fields: input_field.update_default_values(default_values) - system_values = {"system": studio_system_configurations()} + system_values = {"system": studio_system_settings()} for input_field in self.input_fields: input_field.update_studio_values(system_values) @@ -462,7 +462,7 @@ class ProjectWidget(QtWidgets.QWidget): _project_anatomy = lib.NOT_SET self.is_overidable = False else: - _project_overrides = project_configurations_overrides(project_name) + _project_overrides = project_settings_overrides(project_name) _project_anatomy = project_anatomy_overrides(project_name) self.is_overidable = True @@ -519,7 +519,7 @@ class ProjectWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(new_values, file_stream, indent=4) - reset_default_configurations() + reset_default_settings() self._update_values() @@ -638,12 +638,12 @@ class ProjectWidget(QtWidgets.QWidget): def _update_values(self): self.ignore_value_changes = True - default_values = {"project": default_configuration()} + default_values = {"project": default_settings()} for input_field in self.input_fields: input_field.update_default_values(default_values) studio_values = {"project": { - PROJECT_SETTINGS_KEY: studio_project_configurations(), + PROJECT_SETTINGS_KEY: studio_project_settings(), PROJECT_ANATOMY_KEY: studio_project_anatomy() }} for input_field in self.input_fields: From ee612be204b6109c4f0672750339eb13a45732fc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:35:39 +0200 Subject: [PATCH 543/580] implemented set as studio override for anatomy items --- pype/tools/settings/settings/widgets/anatomy_inputs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pype/tools/settings/settings/widgets/anatomy_inputs.py b/pype/tools/settings/settings/widgets/anatomy_inputs.py index 0e7e094be5..50a6022e3c 100644 --- a/pype/tools/settings/settings/widgets/anatomy_inputs.py +++ b/pype/tools/settings/settings/widgets/anatomy_inputs.py @@ -570,6 +570,13 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): self.singleroot_widget.reset_to_pype_default() self._has_studio_override = False + def set_studio_default(self): + if self.is_multiroot: + self.multiroot_widget.reset_to_pype_default() + else: + self.singleroot_widget.reset_to_pype_default() + self._has_studio_override = True + def discard_changes(self): self._is_overriden = self._was_overriden self._is_modified = False @@ -718,6 +725,9 @@ class TemplatesWidget(QtWidgets.QWidget, SettingObject): def reset_to_pype_default(self): self.value_input.reset_to_pype_default() + def set_studio_default(self): + self.value_input.set_studio_default() + def discard_changes(self): self.value_input.discard_changes() From 38e8f5962826bd8d5edd6dc32f290b37234d6a36 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:38:51 +0200 Subject: [PATCH 544/580] renamed inputs to item_types --- pype/tools/settings/settings/widgets/__init__.py | 9 ++++----- .../widgets/{anatomy_inputs.py => anatomy_types.py} | 4 +++- .../settings/widgets/{inputs.py => item_types.py} | 0 3 files changed, 7 insertions(+), 6 deletions(-) rename pype/tools/settings/settings/widgets/{anatomy_inputs.py => anatomy_types.py} (99%) rename pype/tools/settings/settings/widgets/{inputs.py => item_types.py} (100%) diff --git a/pype/tools/settings/settings/widgets/__init__.py b/pype/tools/settings/settings/widgets/__init__.py index 034692898c..e5ea4b3129 100644 --- a/pype/tools/settings/settings/widgets/__init__.py +++ b/pype/tools/settings/settings/widgets/__init__.py @@ -1,10 +1,9 @@ from .window import MainWidget -# TODO properly register inputs to TypeToKlass class -from . import inputs -from . import anatomy_inputs +from . import item_types +from . import anatomy_type __all__ = [ "MainWidget", - "inputs", - "anatomy_inputs" + "item_types", + "anatomy_type" ] diff --git a/pype/tools/settings/settings/widgets/anatomy_inputs.py b/pype/tools/settings/settings/widgets/anatomy_types.py similarity index 99% rename from pype/tools/settings/settings/widgets/anatomy_inputs.py rename to pype/tools/settings/settings/widgets/anatomy_types.py index 50a6022e3c..9433d7a823 100644 --- a/pype/tools/settings/settings/widgets/anatomy_inputs.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -1,6 +1,8 @@ from Qt import QtWidgets, QtCore from .widgets import ExpandingWidget -from .inputs import SettingObject, ModifiableDict, PathWidget, RawJsonWidget +from .item_types import ( + SettingObject, ModifiableDict, PathWidget, RawJsonWidget +) from .lib import NOT_SET, TypeToKlass, CHILD_OFFSET, METADATA_KEY diff --git a/pype/tools/settings/settings/widgets/inputs.py b/pype/tools/settings/settings/widgets/item_types.py similarity index 100% rename from pype/tools/settings/settings/widgets/inputs.py rename to pype/tools/settings/settings/widgets/item_types.py From 0884ba26900cc7ba8e626a7a3d84a8f092a6f5bd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:39:24 +0200 Subject: [PATCH 545/580] fixed typo --- pype/tools/settings/settings/widgets/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/__init__.py b/pype/tools/settings/settings/widgets/__init__.py index e5ea4b3129..361fd9d23d 100644 --- a/pype/tools/settings/settings/widgets/__init__.py +++ b/pype/tools/settings/settings/widgets/__init__.py @@ -1,9 +1,9 @@ from .window import MainWidget from . import item_types -from . import anatomy_type +from . import anatomy_types __all__ = [ "MainWidget", "item_types", - "anatomy_type" + "anatomy_types" ] From cd36685ef8406a68b0761d5d04f346c3c511addd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:49:15 +0200 Subject: [PATCH 546/580] fix studio overrides for anatomy roots --- pype/tools/settings/settings/widgets/anatomy_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index 9433d7a823..0d94f6f86f 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -519,9 +519,9 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): @property def child_has_studio_override(self): if self.is_multiroot: - return self.multiroot_widget.child_has_studio_override + return self.multiroot_widget.has_studio_override else: - return self.singleroot_widget.child_has_studio_override + return self.singleroot_widget.has_studio_override @property def child_modified(self): From 35beb0a657182657069e2180135118a41a348141 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:54:09 +0200 Subject: [PATCH 547/580] fixed setting pype default for anatomy --- pype/tools/settings/settings/widgets/anatomy_types.py | 5 +++++ pype/tools/settings/settings/widgets/item_types.py | 8 +++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index 0d94f6f86f..dd4b5dc578 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -196,6 +196,10 @@ class AnatomyWidget(QtWidgets.QWidget, SettingObject): self.root_widget.reset_to_pype_default() self.templates_widget.reset_to_pype_default() + def set_studio_default(self): + self.root_widget.set_studio_default() + self.templates_widget.set_studio_default() + def discard_changes(self): self.root_widget.discard_changes() self.templates_widget.discard_changes() @@ -596,6 +600,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): self.singleroot_widget.discard_changes() self._is_modified = self.child_modified + self._has_studio_override = self._had_studio_override def set_as_overriden(self): self._is_overriden = True diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index aa72f1c81f..b0de7910ab 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -194,7 +194,6 @@ class SettingObject(AbstractSettingObject): not self.is_overidable and ( self.has_studio_override - or self.child_has_studio_override ) ): action = QtWidgets.QAction("Reset to pype default") @@ -203,10 +202,9 @@ class SettingObject(AbstractSettingObject): if ( not self.is_overidable - and ( - (self.is_group and not self._had_studio_override) - or self.any_parent_is_group - ) + and not self.is_overriden + and not self.any_parent_is_group + and not self._had_studio_override ): action = QtWidgets.QAction("Set sudio default") actions_mapping[action] = self._set_studio_default From 438aab08662f48f8879136a0f83635bf7be3f298 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 18:56:16 +0200 Subject: [PATCH 548/580] added window title --- pype/tools/settings/settings/widgets/window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/widgets/window.py b/pype/tools/settings/settings/widgets/window.py index 5c7a35fa52..f83da8efe0 100644 --- a/pype/tools/settings/settings/widgets/window.py +++ b/pype/tools/settings/settings/widgets/window.py @@ -9,6 +9,7 @@ class MainWidget(QtWidgets.QWidget): def __init__(self, develop, parent=None): super(MainWidget, self).__init__(parent) self.setObjectName("MainWidget") + self.setWindowTitle("Pype Settings") self.resize(self.widget_width, self.widget_height) From 3b69f890a30b15a177d937e6db1deaa59a484e04 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 14 Sep 2020 19:00:07 +0200 Subject: [PATCH 549/580] added refresh to develop mode --- pype/tools/settings/settings/widgets/base.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 90e3aca677..437a74b8c1 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -27,6 +27,7 @@ from pype.settings.lib import ( from .widgets import UnsavedChangesDialog from . import lib from avalon import io +from avalon.vendor import qtawesome class SystemWidget(QtWidgets.QWidget): @@ -65,9 +66,16 @@ class SystemWidget(QtWidgets.QWidget): if self.develop_mode: save_as_default_btn = QtWidgets.QPushButton("Save as Default") - footer_layout.addWidget(save_as_default_btn, 0) save_as_default_btn.clicked.connect(self._save_as_defaults) + refresh_icon = qtawesome.icon("fa.refresh", color="white") + refresh_button = QtWidgets.QPushButton() + refresh_button.setIcon(refresh_icon) + refresh_button.clicked.connect(self._on_refresh) + + footer_layout.addWidget(save_as_default_btn, 0) + footer_layout.addWidget(refresh_button, 0) + save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() footer_layout.addWidget(spacer_widget, 1) @@ -158,6 +166,9 @@ class SystemWidget(QtWidgets.QWidget): self._update_values() + def _on_refresh(self): + self.reset() + def _save_as_defaults(self): output = {} for item in self.input_fields: From d91c890a7d8335e245d3bf2d1f9939b1bf321e04 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 11:23:39 +0200 Subject: [PATCH 550/580] fixed path-widget default value for dev mode --- .../settings/settings/widgets/item_types.py | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index b0de7910ab..6433956484 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2136,13 +2136,18 @@ class PathWidget(QtWidgets.QWidget, SettingObject): @property def default_input_value(self): + if self.multipath: + value_type = list + else: + value_type = str + if self.multiplatform: return { - platform: "" + platform: value_type() for platform in self.platforms } else: - return "" + return value_type() def create_gui(self): if not self.multiplatform and not self.multipath: @@ -2204,9 +2209,19 @@ class PathWidget(QtWidgets.QWidget, SettingObject): value = parent_values.get(self.key, NOT_SET) if value is NOT_SET: - raise ValueError( - "Default value is not set. This is implementation BUG." - ) + if self.develop_mode: + value = {self.key: self.default_input_value} + self.defaults_not_set = True + if value is NOT_SET: + raise NotImplementedError(( + "{} Does not have implemented" + " attribute `default_input_value`" + ).format(self)) + + else: + raise ValueError( + "Default value is not set. This is implementation BUG." + ) self.default_value = value self._has_studio_override = False From 67a38042264fc622c9b7bf0833d549d055db3435 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 11:45:13 +0200 Subject: [PATCH 551/580] fixed expandable widget toggle_content --- pype/tools/settings/settings/widgets/widgets.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index bb42df6026..96f8d2ec17 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -105,7 +105,7 @@ class ExpandingWidget(QtWidgets.QWidget): self.label_widget = label_widget top_part.clicked.connect(self._top_part_clicked) - self.button_toggle.clicked.connect(self.toggle_content) + self.button_toggle.clicked.connect(self._btn_clicked) self.main_layout = QtWidgets.QVBoxLayout(self) self.main_layout.setContentsMargins(0, 0, 0, 0) @@ -123,16 +123,20 @@ class ExpandingWidget(QtWidgets.QWidget): self.main_layout.addWidget(content_widget) self.content_widget = content_widget + def _btn_clicked(self): + self.toggle_content(self.button_toggle.isChecked()) + def _top_part_clicked(self): - self.toggle_content(not self.button_toggle.isChecked()) + self.toggle_content() def toggle_content(self, *args): if self.toolbox_hidden: return + if len(args) > 0: checked = args[0] else: - checked = self.button_toggle.isChecked() + checked = not self.button_toggle.isChecked() arrow_type = QtCore.Qt.RightArrow if checked: arrow_type = QtCore.Qt.DownArrow From c42927120b1fa6a7abf1ee62624666096f905bc2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 11:47:07 +0200 Subject: [PATCH 552/580] changed `expandable` to `collapsable` and `expanded` to `collapsed` --- .../projects_schema/1_plugins_gui_schema.json | 80 +++++++++---------- .../system_schema/1_intents_gui_schema.json | 2 +- .../system_schema/1_tools_gui_schema.json | 2 +- .../system_schema/1_tray_items.json | 8 +- .../settings/settings/widgets/item_types.py | 21 ++--- 5 files changed, 57 insertions(+), 56 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json index c279a6b04a..6bb14463c1 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json @@ -1,25 +1,25 @@ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "plugins", "label": "Plugins", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "celaction", "label": "CelAction", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "publish", "label": "Publish plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ExtractCelactionDeadline", "label": "ExtractCelactionDeadline", @@ -66,20 +66,20 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ftrack", "label": "Ftrack", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "publish", "label": "Publish plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "IntegrateFtrackNote", "label": "IntegrateFtrackNote", @@ -106,20 +106,20 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "global", "label": "Global", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "publish", "label": "Publish plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "IntegrateMasterVersion", "label": "IntegrateMasterVersion", @@ -133,7 +133,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ExtractJpegEXR", "label": "ExtractJpegEXR", @@ -163,7 +163,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ExtractReview", "label": "ExtractReview", "checkbox_key": "enabled", @@ -181,7 +181,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ExtractBurnin", "label": "ExtractBurnin", "checkbox_key": "enabled", @@ -193,7 +193,7 @@ "label": "Enabled" }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "options", "label": "Burnin formating options", "children": [ @@ -231,7 +231,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "IntegrateAssetNew", "label": "IntegrateAssetNew", "is_group": true, @@ -244,7 +244,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ProcessSubmittedJobOnFarm", "label": "ProcessSubmittedJobOnFarm", "checkbox_key": "enabled", @@ -274,20 +274,20 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "maya", "label": "Maya", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "publish", "label": "Publish plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ValidateModelName", "label": "Validate Model Name", "checkbox_key": "enabled", @@ -309,7 +309,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ValidateAssemblyName", "label": "Validate Assembly Name", "checkbox_key": "enabled", @@ -323,7 +323,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ValidateShaderName", "label": "ValidateShaderName", "checkbox_key": "enabled", @@ -341,7 +341,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ValidateMeshHasOverlappingUVs", "label": "ValidateMeshHasOverlappingUVs", "checkbox_key": "enabled", @@ -364,20 +364,20 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "nuke", "label": "Nuke", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "create", "label": "Create plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": false, + "collapsable": false, "key": "CreateWriteRender", "label": "CreateWriteRender", "is_group": true, @@ -390,7 +390,7 @@ ] }, { "type": "dict", - "expandable": false, + "collapsable": false, "key": "CreateWritePrerender", "label": "CreateWritePrerender", "is_group": true, @@ -405,14 +405,14 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "publish", "label": "Publish plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ExtractThumbnail", "label": "ExtractThumbnail", @@ -430,7 +430,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ValidateNukeWriteKnobs", "label": "ValidateNukeWriteKnobs", @@ -448,7 +448,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ExtractReviewDataLut", "label": "ExtractReviewDataLut", @@ -462,7 +462,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ExtractReviewDataMov", "label": "ExtractReviewDataMov", @@ -480,7 +480,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "ExtractSlateFrame", "label": "ExtractSlateFrame", "is_group": true, @@ -493,7 +493,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "NukeSubmitDeadline", "label": "NukeSubmitDeadline", "is_group": true, @@ -527,20 +527,20 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "nukestudio", "label": "NukeStudio", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "publish", "label": "Publish plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "CollectInstanceVersion", "label": "Collect Instance Version", @@ -554,7 +554,7 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "checkbox_key": "enabled", "key": "ExtractReviewCutUpVideo", "label": "Extract Review Cut Up Video", @@ -577,20 +577,20 @@ ] }, { "type": "dict", - "expandable": true, + "collapsable": true, "key": "resolve", "label": "DaVinci Resolve", "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "create", "label": "Creator plugins", "is_file": true, "children": [ { "type": "dict", - "expandable": true, + "collapsable": true, "key": "CreateShotClip", "label": "Create Shot Clip", "is_group": true, diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_intents_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_intents_gui_schema.json index a4b5e16fa1..0c252d2ca9 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_intents_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_intents_gui_schema.json @@ -2,7 +2,7 @@ "key": "intent", "type": "dict", "label": "Intent Setting", - "expandable": true, + "collapsable": true, "is_group": true, "is_file": true, "children": [ diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_tools_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_tools_gui_schema.json index bf35326d1c..d9540eeb3e 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_tools_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_tools_gui_schema.json @@ -2,7 +2,7 @@ "key": "tools", "type": "dict", "label": "Tools", - "expandable": true, + "collapsable": true, "is_group": true, "is_file": true, "children": [ diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json index 7507050900..6da974a415 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json @@ -2,7 +2,7 @@ "key": "tray_modules", "type": "dict", "label": "Modules", - "expandable": true, + "collapsable": true, "is_group": true, "is_file": true, "children": [ @@ -69,7 +69,7 @@ "type": "dict", "key": "Rest Api", "label": "Rest Api", - "expandable": true, + "collapsable": true, "children": [ { "type": "number", @@ -92,7 +92,7 @@ "type": "dict", "key": "Timers Manager", "label": "Timers Manager", - "expandable": true, + "collapsable": true, "children": [ { "type": "number", @@ -110,7 +110,7 @@ "type": "dict", "key": "Clockify", "label": "Clockify", - "expandable": true, + "collapsable": true, "children": [ { "type": "text", diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 6433956484..729ab3a70f 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1343,14 +1343,15 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.body_widget = body_widget self.label_widget = body_widget.label_widget - expandable = input_data.get("expandable", True) - if not expandable: - body_widget.hide_toolbox(hide_content=False) - else: - expanded = input_data.get("expanded", False) - if expanded: + collapsable = input_data.get("collapsable", True) + if collapsable: + collapsed = input_data.get("collapsed", True) + if not collapsed: body_widget.toggle_content() + else: + body_widget.hide_toolbox(hide_content=False) + self.body_widget = body_widget self.content_widget = content_widget self.content_layout = content_layout @@ -1590,13 +1591,13 @@ class DictWidget(QtWidgets.QWidget, SettingObject): for child_data in input_data.get("children", []): self.add_children_gui(child_data) - expandable = input_data.get("expandable", True) + collapsable = input_data.get("collapsable", True) if len(self.input_fields) == 1 and self.checkbox_widget: body_widget.hide_toolbox(hide_content=True) - elif expandable: - expanded = input_data.get("expanded", False) - if expanded: + elif collapsable: + collapsed = input_data.get("collapsed", True) + if not collapsed: body_widget.toggle_content() else: body_widget.hide_toolbox(hide_content=False) From 0a474167663ac6001ea92539cf685ceda8defcd3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 11:47:36 +0200 Subject: [PATCH 553/580] modifiable dict fixed states --- .../settings/settings/widgets/item_types.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 729ab3a70f..2b6bcfe34c 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1165,7 +1165,6 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.set_default_attributes() self._parent = config_parent - self.is_single = False self.is_key_duplicated = False layout = QtWidgets.QHBoxLayout(self) @@ -1212,7 +1211,13 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def key_value(self): return self.key_input.text() + def _is_enabled(self): + return self.key_input.isEnabled() + def is_key_invalid(self): + if not self._is_enabled(): + return False + if self.key_value() == "": return True @@ -1244,7 +1249,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._parent.is_group def on_add_clicked(self): - if self.value_input.isEnabled(): + if self._is_enabled(): self._parent.add_row(row=self.row() + 1) else: self.set_as_empty(False) @@ -1278,15 +1283,17 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): @property def is_invalid(self): + if not self._is_enabled(): + return False return self.is_key_invalid() or self.value_input.is_invalid def update_style(self): - if self.is_key_invalid(): - state = "invalid" - elif self.is_key_modified(): - state = "modified" - else: - state = "" + state = "" + if self._is_enabled(): + if self.is_key_invalid(): + state = "invalid" + elif self.is_key_modified(): + state = "modified" self.key_input.setProperty("state", state) self.key_input.style().polish(self.key_input) From 703e17b35a2654e9696858acf6c0fd3679ef0532 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 11:53:57 +0200 Subject: [PATCH 554/580] removed bold style on label for invalid value --- pype/tools/settings/settings/style/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index f6dd354935..ab88a2c36f 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -56,8 +56,8 @@ QLabel[state="overriden-modified"] {color: #137cbd;} QLabel[state="overriden-modified"]:hover {color: #1798e8;} QLabel[state="overriden"] {color: #ff8c1a;} QLabel[state="overriden"]:hover {color: #ffa64d;} -QLabel[state="invalid"] {color: #ad2e2e; font-weight: bold;} -QLabel[state="invalid"]:hover {color: #ad2e2e; font-weight: bold;} +QLabel[state="invalid"] {color: #ad2e2e;} +QLabel[state="invalid"]:hover {color: #ad2e2e;} QWidget[input-state="studio"] {border-color: #bfccd6;} From 2d4f983a88674a21f6e05b4398e1b5a4e8ac2c3a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 11:54:12 +0200 Subject: [PATCH 555/580] using only horizontal layouts --- .../system_schema/1_applications_gui_schema.json | 2 +- pype/tools/settings/settings/widgets/item_types.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_applications_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_applications_gui_schema.json index 5ee769eed8..48f8ecbd7c 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_applications_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_applications_gui_schema.json @@ -2,7 +2,7 @@ "key": "applications", "type": "dict", "label": "Applications", - "expandable": true, + "collapsable": true, "is_group": true, "is_file": true, "children": [ diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 2b6bcfe34c..754b4512bd 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -805,9 +805,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(input_data, parent, as_widget) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) + layout.setSpacing(5) self.text_input = RawJsonInput(self) self.text_input.setSizePolicy( @@ -2117,10 +2117,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self.input_fields = [] - if not self.multiplatform and not self.multipath: - layout = QtWidgets.QHBoxLayout(self) - else: - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) From 1a7ba6f8d789572d755002cb8fb5362a7e9a6168 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 12:41:59 +0200 Subject: [PATCH 556/580] added `is_input_type` attribute for non input item types --- pype/tools/settings/settings/widgets/item_types.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 754b4512bd..5f995b40b7 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -12,6 +12,7 @@ from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET class SettingObject(AbstractSettingObject): + is_input_type = True default_input_value = NOT_SET allow_actions = True default_state = "" @@ -1612,6 +1613,12 @@ class DictWidget(QtWidgets.QWidget, SettingObject): def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) + + if not klass.is_input_type: + item = klass(child_configuration, self) + self.content_layout.addWidget(item) + return item + if self.checkbox_key and not self.checkbox_widget: key = child_configuration.get("key") if key == self.checkbox_key: @@ -1898,6 +1905,11 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) + if not klass.is_input_type: + item = klass(child_configuration, self) + self.layout().addWidget(item) + return item + item = klass(child_configuration, self) self.layout().addWidget(item) From 0a9c96d27b4d755d7cb641304bad2d43ea82ba9c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 12:42:12 +0200 Subject: [PATCH 557/580] added anatomy widgets to TypeToKlass --- pype/tools/settings/settings/widgets/anatomy_types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index dd4b5dc578..785632b08d 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -754,3 +754,5 @@ class TemplatesWidget(QtWidgets.QWidget, SettingObject): TypeToKlass.types["anatomy"] = AnatomyWidget +TypeToKlass.types["anatomy_roots"] = AnatomyWidget +TypeToKlass.types["anatomy_templates"] = AnatomyWidget From 3bde8a77a2ac5275760fd673d8cb2dc7af21062a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 12:42:27 +0200 Subject: [PATCH 558/580] added examples schema --- .../gui_schemas/system_schema/1_examples.json | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json new file mode 100644 index 0000000000..a884dcb31e --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -0,0 +1,234 @@ +{ + "key": "example_dict", + "label": "Examples", + "type": "dict", + "is_file": true, + "children": [ + { + "key": "dict_wrapper", + "type": "dict-invisible", + "children": [ + { + "type": "boolean", + "key": "bool", + "label": "Boolean checkbox" + }, { + "type": "label", + "label": "NOTE: This is label" + }, { + "type": "splitter" + }, { + "type": "number", + "key": "integer", + "label": "Integer", + "decimal": 0, + "minimum": 0, + "maximum": 10 + }, { + "type": "number", + "key": "float", + "label": "Float (2 decimals)", + "decimal": 2, + "minimum": -10, + "maximum": -5 + }, { + "type": "text", + "key": "singleline_text", + "label": "Singleline text" + }, { + "type": "text", + "key": "multiline_text", + "label": "Multiline text", + "multiline": true + }, { + "type": "raw-json", + "key": "raw_json", + "label": "Raw json input" + }, { + "type": "list", + "key": "list_item_of_multiline_texts", + "label": "List of multiline texts", + "object_type": "text", + "input_modifiers": { + "multiline": true + } + }, { + "type": "list", + "key": "list_item_of_floats", + "label": "List of floats", + "object_type": "number", + "input_modifiers": { + "decimal": 3, + "minimum": 1000, + "maximum": 2000 + } + }, { + "type": "dict-modifiable", + "key": "modifiable_dict_of_integers", + "label": "Modifiable dict of integers", + "object_type": "number", + "input_modifiers": { + "decimal": 0, + "minimum": 10, + "maximum": 100 + } + }, { + "type": "path-widget", + "key": "single_path_input", + "label": "Single path input", + "multiplatform": false, + "multipath": false + }, { + "type": "path-widget", + "key": "multi_path_input", + "label": "Multi path input", + "multiplatform": false, + "multipath": true + }, { + "type": "path-widget", + "key": "single_os_specific_path_input", + "label": "Single OS specific path input", + "multiplatform": true, + "multipath": false + }, { + "type": "path-widget", + "key": "multi_os_specific_path_input", + "label": "Multi OS specific path input", + "multiplatform": true, + "multipath": true + }, { + "key": "collapsable", + "type": "dict", + "label": "collapsable dictionary", + "collapsable": true, + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "_nothing", + "label": "Exmaple input" + } + ] + }, { + "key": "collapsable_expanded", + "type": "dict", + "label": "collapsable dictionary, expanded on creation", + "collapsable": true, + "collapsed": false, + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "_nothing", + "label": "Exmaple input" + } + ] + }, { + "key": "not_collapsable", + "type": "dict", + "label": "Not collapsable", + "collapsable": false, + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "_nothing", + "label": "Exmaple input" + } + ] + }, { + "key": "nested_dict_lvl1", + "type": "dict", + "label": "Nested dictionary (level 1)", + "children": [ + { + "key": "nested_dict_lvl2", + "type": "dict", + "label": "Nested dictionary (level 2)", + "is_group": true, + "children": [ + { + "key": "nested_dict_lvl3", + "type": "dict", + "label": "Nested dictionary (level 3)", + "children": [ + { + "type": "boolean", + "key": "_nothing", + "label": "Exmaple input" + } + ] + }, { + "key": "nested_dict_lvl3_2", + "type": "dict", + "label": "Nested dictionary (level 3) (2)", + "children": [ + { + "type": "text", + "key": "_nothing", + "label": "Exmaple input" + }, { + "type": "text", + "key": "_nothing2", + "label": "Exmaple input 2" + } + ] + } + ] + } + ] + }, { + "key": "form_examples", + "type": "dict", + "label": "Form examples", + "children": [ + { + "key": "inputs_without_form_example", + "type": "dict", + "label": "Inputs without form", + "children": [ + { + "type": "text", + "key": "_nothing_1", + "label": "Example label" + }, { + "type": "text", + "key": "_nothing_2", + "label": "Example label ####" + }, { + "type": "text", + "key": "_nothing_3", + "label": "Example label ########" + } + ] + }, { + "key": "inputs_with_form_example", + "type": "dict", + "label": "Inputs with form", + "children": [ + { + "type": "dict-form", + "children": [ + { + "type": "text", + "key": "_nothing_1", + "label": "Example label" + }, { + "type": "text", + "key": "_nothing_2", + "label": "Example label ####" + }, { + "type": "text", + "key": "_nothing_3", + "label": "Example label ########" + } + ] + } + ] + } + ] + } + ] + } + ] +} From 3cf1c91e2b2f4c94e9df67a99885bccfd9a44fca Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 12:46:10 +0200 Subject: [PATCH 559/580] implemented label widget and splitter widget --- pype/tools/settings/settings/style/style.css | 4 +++ .../settings/settings/widgets/item_types.py | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index ab88a2c36f..38f69fef50 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -152,6 +152,10 @@ QPushButton[btn-type="expand-toggle"] { background: #141a1f; } +#SplitterItem { + background-color: #1d272f; +} + QTabWidget::pane { border-top-style: none; } diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 5f995b40b7..bd9341973b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2668,6 +2668,37 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): return values, self.is_group +class LabelWidget(QtWidgets.QWidget): + is_input_type = False + + def __init__(self, configuration, parent=None): + super(LabelWidget, self).__init__(parent) + self.setObjectName("LabelWidget") + + label = configuration["label"] + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + label_widget = QtWidgets.QLabel(label, self) + layout.addWidget(label_widget) + + +class SplitterWidget(QtWidgets.QWidget): + is_input_type = False + _height = 2 + + def __init__(self, configuration, parent=None): + super(SplitterWidget, self).__init__(parent) + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(5, 5, 5, 5) + splitter_item = QtWidgets.QWidget(self) + splitter_item.setObjectName("SplitterItem") + splitter_item.setMinimumHeight(self._height) + splitter_item.setMaximumHeight(self._height) + layout.addWidget(splitter_item) + + TypeToKlass.types["boolean"] = BooleanWidget TypeToKlass.types["number"] = NumberWidget TypeToKlass.types["text"] = TextWidget @@ -2679,3 +2710,6 @@ TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictInvisible TypeToKlass.types["path-widget"] = PathWidget TypeToKlass.types["dict-form"] = DictFormWidget + +TypeToKlass.types["label"] = LabelWidget +TypeToKlass.types["splitter"] = SplitterWidget From 6329836c277d6908a28d5850d7fb121c163b3ed3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 12:46:23 +0200 Subject: [PATCH 560/580] lib fixed is file keys --- pype/tools/settings/settings/widgets/lib.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index 0c3f01cef1..e225d65417 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -123,6 +123,11 @@ class SchemaDuplicatedKeys(Exception): def file_keys_from_schema(schema_data): output = [] + item_type = schema_data["type"] + klass = TypeToKlass.types[item_type] + if not klass.is_input_type: + return output + keys = [] key = schema_data.get("key") if key: @@ -143,6 +148,11 @@ def file_keys_from_schema(schema_data): def validate_all_has_ending_file(schema_data, is_top=True): + item_type = schema_data["type"] + klass = TypeToKlass.types[item_type] + if not klass.is_input_type: + return None + if schema_data.get("is_file"): return None From c4db7bdf620a9fc2c89b890cacfbbeae12518e4e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 12:56:41 +0200 Subject: [PATCH 561/580] mod dict item return valid value if not set --- pype/tools/settings/settings/widgets/item_types.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index bd9341973b..2cc25df270 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1303,9 +1303,11 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._parent.input_fields.index(self) def config_value(self): - key = self.key_input.text() - value = self.value_input.item_value() - return {key: value} + if self._is_enabled(): + key = self.key_input.text() + value = self.value_input.item_value() + return {key: value} + return {} def mouseReleaseEvent(self, event): return QtWidgets.QWidget.mouseReleaseEvent(self, event) From 50a44e9cbc83817ebb869d562925580957bd3d13 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 13:10:56 +0200 Subject: [PATCH 562/580] modifiable dict has one more addiotional method for getting all values event invalid for roots widget --- .../tools/settings/settings/widgets/item_types.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 2cc25df270..17f8514fb9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1302,11 +1302,14 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def row(self): return self._parent.input_fields.index(self) + def item_value(self): + key = self.key_input.text() + value = self.value_input.item_value() + return {key: value} + def config_value(self): if self._is_enabled(): - key = self.key_input.text() - value = self.value_input.item_value() - return {key: value} + return self.item_value() return {} def mouseReleaseEvent(self, event): @@ -1468,6 +1471,12 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self._state = state + def all_item_values(self): + output = {} + for item in self.input_fields: + output.update(item.item_value()) + return output + def item_value(self): output = {} for item in self.input_fields: From d20665a845864791f29f957533d05faa51f0ee1f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 13:18:36 +0200 Subject: [PATCH 563/580] anatomy type fixes --- pype/tools/settings/settings/widgets/anatomy_types.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/anatomy_types.py b/pype/tools/settings/settings/widgets/anatomy_types.py index 785632b08d..6d7b3292ce 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -261,7 +261,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): content_widget = QtWidgets.QWidget(body_widget) path_widget_data = { - "key": "roots", + "key": self.key, "multipath": False, "multiplatform": True } @@ -270,7 +270,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): as_widget=True, parent_widget=content_widget ) multiroot_data = { - "key": "roots", + "key": self.key, "object_type": "path-widget", "expandable": False, "input_modifiers": { @@ -497,7 +497,7 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): self.multiroot_widget.set_value(mutli_value) def _from_multi_to_single(self): - mutli_value = self.multiroot_widget.item_value() + mutli_value = self.multiroot_widget.all_item_values() for value in mutli_value.values(): single_value = value break From 72ae67af1911fdfa31c98babf05367f7843281e0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 13:20:39 +0200 Subject: [PATCH 564/580] fixed PathWidget --- pype/tools/settings/settings/widgets/item_types.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 17f8514fb9..7914c6f04f 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2234,11 +2234,17 @@ class PathWidget(QtWidgets.QWidget, SettingObject): if self._as_widget: value = parent_values elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if not self.multiplatform: + value = parent_values + else: + value = parent_values.get(self.key, NOT_SET) if value is NOT_SET: if self.develop_mode: - value = {self.key: self.default_input_value} + if self._as_widget or not self.multiplatform: + value = {self.key: self.default_input_value} + else: + value = self.default_input_value self.defaults_not_set = True if value is NOT_SET: raise NotImplementedError(( From acc2e3db0b34e0f40c812ce8a416833e161aae50 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 13:27:02 +0200 Subject: [PATCH 565/580] added refresh button to projects too --- pype/tools/settings/settings/widgets/base.py | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 437a74b8c1..d9be84638e 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -111,6 +111,8 @@ class SystemWidget(QtWidgets.QWidget): input_field.hierarchical_style_update() def reset(self): + reset_default_settings() + if self.content_layout.count() != 0: for widget in self.input_fields: self.content_layout.removeWidget(widget) @@ -211,9 +213,7 @@ class SystemWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(new_values, file_stream, indent=4) - reset_default_settings() - - self._update_values() + self.reset() def _update_values(self): self.ignore_value_changes = True @@ -401,9 +401,16 @@ class ProjectWidget(QtWidgets.QWidget): if self.develop_mode: save_as_default_btn = QtWidgets.QPushButton("Save as Default") - footer_layout.addWidget(save_as_default_btn, 0) save_as_default_btn.clicked.connect(self._save_as_defaults) + refresh_icon = qtawesome.icon("fa.refresh", color="white") + refresh_button = QtWidgets.QPushButton() + refresh_button.setIcon(refresh_icon) + refresh_button.clicked.connect(self._on_refresh) + + footer_layout.addWidget(save_as_default_btn, 0) + footer_layout.addWidget(refresh_button, 0) + save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() footer_layout.addWidget(spacer_widget, 1) @@ -453,6 +460,8 @@ class ProjectWidget(QtWidgets.QWidget): input_field.hierarchical_style_update() def reset(self): + reset_default_settings() + self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = self.schema.get("keys", []) self.add_children_gui(self.schema) @@ -530,9 +539,7 @@ class ProjectWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(new_values, file_stream, indent=4) - reset_default_settings() - - self._update_values() + self.reset() def _save(self): has_invalid = False @@ -564,6 +571,9 @@ class ProjectWidget(QtWidgets.QWidget): else: self._save_overrides() + def _on_refresh(self): + self.reset() + def _save_overrides(self): data = {} for item in self.input_fields: From 9b3862eb74d1e1ab71e7ba2f2d1624e3879995ba Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 14:38:21 +0200 Subject: [PATCH 566/580] refresh and save as defaults works as expected --- pype/tools/settings/settings/widgets/base.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index d9be84638e..4769cb4e63 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -213,7 +213,10 @@ class SystemWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(new_values, file_stream, indent=4) - self.reset() + reset_default_settings() + + self._update_values() + self.hierarchical_style_update() def _update_values(self): self.ignore_value_changes = True @@ -460,7 +463,11 @@ class ProjectWidget(QtWidgets.QWidget): input_field.hierarchical_style_update() def reset(self): - reset_default_settings() + if self.content_layout.count() != 0: + for widget in self.input_fields: + self.content_layout.removeWidget(widget) + widget.deleteLater() + self.input_fields.clear() self.schema = lib.gui_schema("projects_schema", "0_project_gui_schema") self.keys = self.schema.get("keys", []) @@ -539,7 +546,10 @@ class ProjectWidget(QtWidgets.QWidget): with open(output_path, "w") as file_stream: json.dump(new_values, file_stream, indent=4) - self.reset() + reset_default_settings() + + self._update_values() + self.hierarchical_style_update() def _save(self): has_invalid = False From 452e5988f1350fe0cfde66a608dfb37335266e27 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 14:49:47 +0200 Subject: [PATCH 567/580] fixed PathWidget for other udpates --- pype/tools/settings/settings/widgets/item_types.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 7914c6f04f..51ae0fc985 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2276,7 +2276,10 @@ class PathWidget(QtWidgets.QWidget, SettingObject): if self._as_widget: value = parent_values elif parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if not self.multiplatform: + value = parent_values + else: + value = parent_values.get(self.key, NOT_SET) self.studio_value = value if value is not NOT_SET: @@ -2297,11 +2300,15 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._is_modified = False self._state = None self._child_state = None + override_values = NOT_SET if self._as_widget: override_values = parent_values elif parent_values is not NOT_SET: - override_values = parent_values.get(self.key, override_values) + if not self.multiplatform: + override_values = parent_values + else: + override_values = parent_values.get(self.key, NOT_SET) self._is_overriden = override_values is not NOT_SET self._was_overriden = bool(self._is_overriden) From edce6a1ea9a0fe376e62b26d6f8b0070bcc715c5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 15:19:16 +0200 Subject: [PATCH 568/580] added possibility to hide studio overrides --- pype/tools/settings/settings/widgets/base.py | 62 ++++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index 4769cb4e63..dbcc380daf 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -41,6 +41,7 @@ class SystemWidget(QtWidgets.QWidget): super(SystemWidget, self).__init__(parent) self.develop_mode = develop_mode + self._hide_studio_overrides = False self._ignore_value_changes = False self.input_fields = [] @@ -73,8 +74,25 @@ class SystemWidget(QtWidgets.QWidget): refresh_button.setIcon(refresh_icon) refresh_button.clicked.connect(self._on_refresh) + hide_studio_overrides = QtWidgets.QCheckBox() + hide_studio_overrides.setChecked(self._hide_studio_overrides) + hide_studio_overrides.stateChanged.connect( + self._on_hide_studio_overrides + ) + + hide_studio_overrides_widget = QtWidgets.QWidget() + hide_studio_overrides_layout = QtWidgets.QHBoxLayout( + hide_studio_overrides_widget + ) + _label_widget = QtWidgets.QLabel( + "Hide studio overrides", hide_studio_overrides_widget + ) + hide_studio_overrides_layout.addWidget(_label_widget) + hide_studio_overrides_layout.addWidget(hide_studio_overrides) + footer_layout.addWidget(save_as_default_btn, 0) footer_layout.addWidget(refresh_button, 0) + footer_layout.addWidget(hide_studio_overrides_widget, 0) save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() @@ -171,6 +189,11 @@ class SystemWidget(QtWidgets.QWidget): def _on_refresh(self): self.reset() + def _on_hide_studio_overrides(self, state): + self._hide_studio_overrides = (state == QtCore.Qt.Checked) + self._update_values() + self.hierarchical_style_update() + def _save_as_defaults(self): output = {} for item in self.input_fields: @@ -227,7 +250,10 @@ class SystemWidget(QtWidgets.QWidget): for input_field in self.input_fields: input_field.update_default_values(default_values) - system_values = {"system": studio_system_settings()} + if self._hide_studio_overrides: + system_values = lib.NOT_SET + else: + system_values = {"system": studio_system_settings()} for input_field in self.input_fields: input_field.update_studio_values(system_values) @@ -377,6 +403,7 @@ class ProjectWidget(QtWidgets.QWidget): super(ProjectWidget, self).__init__(parent) self.develop_mode = develop_mode + self._hide_studio_overrides = False self.is_overidable = False self._ignore_value_changes = False @@ -411,8 +438,25 @@ class ProjectWidget(QtWidgets.QWidget): refresh_button.setIcon(refresh_icon) refresh_button.clicked.connect(self._on_refresh) + hide_studio_overrides = QtWidgets.QCheckBox() + hide_studio_overrides.setChecked(self._hide_studio_overrides) + hide_studio_overrides.stateChanged.connect( + self._on_hide_studio_overrides + ) + + hide_studio_overrides_widget = QtWidgets.QWidget() + hide_studio_overrides_layout = QtWidgets.QHBoxLayout( + hide_studio_overrides_widget + ) + _label_widget = QtWidgets.QLabel( + "Hide studio overrides", hide_studio_overrides_widget + ) + hide_studio_overrides_layout.addWidget(_label_widget) + hide_studio_overrides_layout.addWidget(hide_studio_overrides) + footer_layout.addWidget(save_as_default_btn, 0) footer_layout.addWidget(refresh_button, 0) + footer_layout.addWidget(hide_studio_overrides_widget, 0) save_btn = QtWidgets.QPushButton("Save") spacer_widget = QtWidgets.QWidget() @@ -584,6 +628,11 @@ class ProjectWidget(QtWidgets.QWidget): def _on_refresh(self): self.reset() + def _on_hide_studio_overrides(self, state): + self._hide_studio_overrides = (state == QtCore.Qt.Checked) + self._update_values() + self.hierarchical_style_update() + def _save_overrides(self): data = {} for item in self.input_fields: @@ -673,10 +722,13 @@ class ProjectWidget(QtWidgets.QWidget): for input_field in self.input_fields: input_field.update_default_values(default_values) - studio_values = {"project": { - PROJECT_SETTINGS_KEY: studio_project_settings(), - PROJECT_ANATOMY_KEY: studio_project_anatomy() - }} + if self._hide_studio_overrides: + studio_values = lib.NOT_SET + else: + studio_values = {"project": { + PROJECT_SETTINGS_KEY: studio_project_settings(), + PROJECT_ANATOMY_KEY: studio_project_anatomy() + }} for input_field in self.input_fields: input_field.update_studio_values(studio_values) From 4c54afea72e2f775e781052fbb10345c35aa6090 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 15:19:38 +0200 Subject: [PATCH 569/580] main check for develop arg changed --- pype/tools/settings/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/__main__.py b/pype/tools/settings/__main__.py index 044c2ef495..55a38b3604 100644 --- a/pype/tools/settings/__main__.py +++ b/pype/tools/settings/__main__.py @@ -11,7 +11,7 @@ if __name__ == "__main__": app.setStyleSheet(stylesheet) app.setWindowIcon(QtGui.QIcon(settings.style.app_icon_path())) - develop = "-dev" in sys.argv + develop = "-d" in sys.argv or "--develop" in sys.argv widget = settings.MainWidget(develop) widget.show() From b1a181c6053be65605e1ca370e2679e51371539a Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 15 Sep 2020 15:36:25 +0200 Subject: [PATCH 570/580] Do not remove frames if outside of allowed frame ragne --- pype/hosts/harmony/__init__.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index d4b7d91fdb..7310e91e9b 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -18,12 +18,7 @@ def set_scene_settings(settings): if (args[0]["frameStart"] && args[0]["frameEnd"]) { var duration = args[0]["frameEnd"] - args[0]["frameStart"] + 1 - if (frame.numberOf() > duration) - { - frame.remove( - duration, frame.numberOf() - duration - ); - } + if (frame.numberOf() < duration) { frame.insert( From 64e84474c99f8b090146cea0eac6f88f66786480 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 15 Sep 2020 17:49:52 +0200 Subject: [PATCH 571/580] psd batch publisher was trying to always publish version 1 --- pype/plugins/global/publish/validate_version.py | 2 +- .../standalonepublisher/publish/collect_context.py | 2 +- .../publish/collect_psd_instances.py | 14 ++------------ 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/pype/plugins/global/publish/validate_version.py b/pype/plugins/global/publish/validate_version.py index 9c7ce72307..6701041541 100644 --- a/pype/plugins/global/publish/validate_version.py +++ b/pype/plugins/global/publish/validate_version.py @@ -10,7 +10,7 @@ class ValidateVersion(pyblish.api.InstancePlugin): order = pyblish.api.ValidatorOrder label = "Validate Version" - hosts = ["nuke", "maya", "blender"] + hosts = ["nuke", "maya", "blender", "standalonepublisher"] def process(self, instance): version = instance.data.get("version") diff --git a/pype/plugins/standalonepublisher/publish/collect_context.py b/pype/plugins/standalonepublisher/publish/collect_context.py index a5479fdf13..9dbeec93fb 100644 --- a/pype/plugins/standalonepublisher/publish/collect_context.py +++ b/pype/plugins/standalonepublisher/publish/collect_context.py @@ -123,7 +123,7 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin): "label": subset, "name": subset, "family": in_data["family"], - "version": in_data.get("version", 1), + # "version": in_data.get("version", 1), "frameStart": in_data.get("representations", [None])[0].get( "frameStart", None ), diff --git a/pype/plugins/standalonepublisher/publish/collect_psd_instances.py b/pype/plugins/standalonepublisher/publish/collect_psd_instances.py index 9c8e2eae83..b5db437473 100644 --- a/pype/plugins/standalonepublisher/publish/collect_psd_instances.py +++ b/pype/plugins/standalonepublisher/publish/collect_psd_instances.py @@ -9,7 +9,7 @@ class CollectPsdInstances(pyblish.api.InstancePlugin): """ label = "Collect Psd Instances" - order = pyblish.api.CollectorOrder + 0.492 + order = pyblish.api.CollectorOrder + 0.489 hosts = ["standalonepublisher"] families = ["background_batch"] @@ -34,8 +34,6 @@ class CollectPsdInstances(pyblish.api.InstancePlugin): context = instance.context asset_data = instance.data["assetEntity"] asset_name = instance.data["asset"] - anatomy_data = instance.data["anatomyData"] - for subset_name, subset_data in self.subsets.items(): instance_name = f"{asset_name}_{subset_name}" task = subset_data.get("task", "background") @@ -55,16 +53,8 @@ class CollectPsdInstances(pyblish.api.InstancePlugin): new_instance.data["label"] = f"{instance_name}" new_instance.data["subset"] = subset_name + new_instance.data["task"] = task - # fix anatomy data - anatomy_data_new = copy.deepcopy(anatomy_data) - # updating hierarchy data - anatomy_data_new.update({ - "asset": asset_data["name"], - "task": task, - "subset": subset_name - }) - new_instance.data["anatomyData"] = anatomy_data_new if subset_name in self.unchecked_by_default: new_instance.data["publish"] = False From 35a506b5f4e01f3e7dc959018489344679170bf1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 18:43:51 +0200 Subject: [PATCH 572/580] fixed some alignments --- pype/tools/settings/settings/widgets/item_types.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 51ae0fc985..b79e6f7756 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -608,15 +608,19 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.setFocusProxy(self.text_input) + layout_kwargs = {} + if self.multiline: + layout_kwargs["alignment"] = QtCore.Qt.AlignTop + if not self._as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) + layout.addWidget(label_widget, 0, **layout_kwargs) self.label_widget = label_widget - layout.addWidget(self.text_input, 1) + layout.addWidget(self.text_input, 1, **layout_kwargs) self.text_input.textChanged.connect(self._on_value_change) @@ -823,9 +827,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): if not label_widget: label = input_data["label"] label_widget = QtWidgets.QLabel(label) - layout.addWidget(label_widget, 0) + layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget - layout.addWidget(self.text_input, 1) + layout.addWidget(self.text_input, 1, alignment=QtCore.Qt.AlignTop) self.text_input.textChanged.connect(self._on_value_change) From c6b7346a9127712a142d72ae6e888fd4fe6e0224 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 11:58:20 +0200 Subject: [PATCH 573/580] list widget has move up/down btns --- .../settings/settings/widgets/item_types.py | 136 ++++++++++++++++-- 1 file changed, 123 insertions(+), 13 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index b79e6f7756..8257f79fc2 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -9,6 +9,7 @@ from .widgets import ( PathInput ) from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET +from avalon.vendor import qtawesome class SettingObject(AbstractSettingObject): @@ -898,23 +899,46 @@ class ListItem(QtWidgets.QWidget, SettingObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - self.add_btn = QtWidgets.QPushButton("+") - self.remove_btn = QtWidgets.QPushButton("-") + char_plus = qtawesome.charmap("fa.plus") + char_minus = qtawesome.charmap("fa.minus") + char_up = qtawesome.charmap("fa.angle-up") + char_down = qtawesome.charmap("fa.angle-down") + + self.add_btn = QtWidgets.QPushButton(char_plus) + self.remove_btn = QtWidgets.QPushButton(char_minus) + self.up_btn = QtWidgets.QPushButton(char_up) + self.down_btn = QtWidgets.QPushButton(char_down) + + font_plus_minus = qtawesome.font("fa", 10) + font_up_down = qtawesome.font("fa", 13) + + self.add_btn.setFont(font_plus_minus) + self.remove_btn.setFont(font_plus_minus) + self.up_btn.setFont(font_up_down) + self.down_btn.setFont(font_up_down) self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.up_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.down_btn.setFocusPolicy(QtCore.Qt.ClickFocus) self.add_btn.setFixedSize(self._btn_size, self._btn_size) self.remove_btn.setFixedSize(self._btn_size, self._btn_size) + self.up_btn.setFixedSize(self._btn_size, self._btn_size) + self.down_btn.setFixedSize(self._btn_size, self._btn_size) self.add_btn.setProperty("btn-type", "tool-item") self.remove_btn.setProperty("btn-type", "tool-item") + self.up_btn.setProperty("btn-type", "tool-item") + self.down_btn.setProperty("btn-type", "tool-item") layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) - self.add_btn.clicked.connect(self.on_add_clicked) - self.remove_btn.clicked.connect(self.on_remove_clicked) + self.add_btn.clicked.connect(self._on_add_clicked) + self.remove_btn.clicked.connect(self._on_remove_clicked) + self.up_btn.clicked.connect(self._on_up_clicked) + self.down_btn.clicked.connect(self._on_down_clicked) ItemKlass = TypeToKlass.types[object_type] self.value_input = ItemKlass( @@ -925,28 +949,62 @@ class ListItem(QtWidgets.QWidget, SettingObject): ) layout.addWidget(self.value_input, 1) + layout.addWidget(self.up_btn, 0) + layout.addWidget(self.down_btn, 0) + self.value_input.value_changed.connect(self._on_value_change) def set_as_empty(self, is_empty=True): self.value_input.setEnabled(not is_empty) self.remove_btn.setEnabled(not is_empty) + self.order_changed() self._on_value_change() + def order_changed(self): + row = self.row() + parent_row_count = self.parent_rows_count() + if parent_row_count == 1: + self.up_btn.setEnabled(False) + self.down_btn.setEnabled(False) + + elif row == 0: + self.up_btn.setEnabled(False) + self.down_btn.setEnabled(True) + + elif row == parent_row_count - 1: + self.up_btn.setEnabled(True) + self.down_btn.setEnabled(False) + + else: + self.up_btn.setEnabled(True) + self.down_btn.setEnabled(True) + def _on_value_change(self, item=None): self.value_changed.emit(self) def row(self): return self._parent.input_fields.index(self) - def on_add_clicked(self): + def parent_rows_count(self): + return len(self._parent.input_fields) + + def _on_add_clicked(self): if self.value_input.isEnabled(): self._parent.add_row(row=self.row() + 1) else: self.set_as_empty(False) - def on_remove_clicked(self): + def _on_remove_clicked(self): self._parent.remove_row(self) + def _on_up_clicked(self): + row = self.row() + self._parent.swap_rows(row - 1, row) + + def _on_down_clicked(self): + row = self.row() + self._parent.swap_rows(row, row + 1) + def config_value(self): if self.value_input.isEnabled(): return self.value_input.item_value() @@ -1044,21 +1102,58 @@ class ListWidget(QtWidgets.QWidget, InputObject): if self.count() == 0: self.add_row(is_empty=True) + def swap_rows(self, row_1, row_2): + if row_1 == row_2: + return + + if row_1 > row_2: + row_1, row_2 = row_2, row_1 + + field_1 = self.input_fields[row_1] + field_2 = self.input_fields[row_2] + + self.input_fields[row_1] = field_2 + self.input_fields[row_2] = field_1 + + layout_index = self.inputs_layout.indexOf(field_1) + self.inputs_layout.insertWidget(layout_index + 1, field_1) + + field_1.order_changed() + field_2.order_changed() + def add_row(self, row=None, value=None, is_empty=False): # Create new item item_widget = ListItem( self.object_type, self.input_modifiers, self, self.inputs_widget ) + if row is None: + if self.input_fields: + self.input_fields[-1].order_changed() + self.inputs_layout.addWidget(item_widget) + self.input_fields.append(item_widget) + else: + previous_field = None + if row > 0: + previous_field = self.input_fields[row - 1] + + next_field = None + max_index = self.count() + if row < max_index: + next_field = self.input_fields[row] + + self.inputs_layout.insertWidget(row, item_widget) + self.input_fields.insert(row, item_widget) + if previous_field: + previous_field.order_changed() + + if next_field: + next_field.order_changed() + if is_empty: item_widget.set_as_empty() item_widget.value_changed.connect(self._on_value_change) - if row is None: - self.inputs_layout.addWidget(item_widget) - self.input_fields.append(item_widget) - else: - self.inputs_layout.insertWidget(row, item_widget) - self.input_fields.insert(row, item_widget) + item_widget.order_changed() previous_input = None for input_field in self.input_fields: @@ -1085,11 +1180,26 @@ class ListWidget(QtWidgets.QWidget, InputObject): def remove_row(self, item_widget): item_widget.value_changed.disconnect() + row = self.input_fields.index(item_widget) + previous_field = None + next_field = None + if row > 0: + previous_field = self.input_fields[row - 1] + + if row != len(self.input_fields) - 1: + next_field = self.input_fields[row + 1] + self.inputs_layout.removeWidget(item_widget) - self.input_fields.remove(item_widget) + self.input_fields.pop(row) item_widget.setParent(None) item_widget.deleteLater() + if previous_field: + previous_field.order_changed() + + if next_field: + next_field.order_changed() + if self.count() == 0: self.add_row(is_empty=True) From ff2dfec0757aa7974de9f0c49e850eeba35a3180 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 13:37:14 +0200 Subject: [PATCH 574/580] plus minus signe are without awesome font --- pype/tools/settings/settings/widgets/item_types.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8257f79fc2..ef1e0ad2e1 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -899,21 +899,15 @@ class ListItem(QtWidgets.QWidget, SettingObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - char_plus = qtawesome.charmap("fa.plus") - char_minus = qtawesome.charmap("fa.minus") char_up = qtawesome.charmap("fa.angle-up") char_down = qtawesome.charmap("fa.angle-down") - self.add_btn = QtWidgets.QPushButton(char_plus) - self.remove_btn = QtWidgets.QPushButton(char_minus) + self.add_btn = QtWidgets.QPushButton("+") + self.remove_btn = QtWidgets.QPushButton("-") self.up_btn = QtWidgets.QPushButton(char_up) self.down_btn = QtWidgets.QPushButton(char_down) - font_plus_minus = qtawesome.font("fa", 10) font_up_down = qtawesome.font("fa", 13) - - self.add_btn.setFont(font_plus_minus) - self.remove_btn.setFont(font_plus_minus) self.up_btn.setFont(font_up_down) self.down_btn.setFont(font_up_down) From 1f0e5b65dde7bfe366003eca8e983af043fa964f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 13:49:28 +0200 Subject: [PATCH 575/580] labels are at the top --- pype/tools/settings/settings/widgets/item_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ef1e0ad2e1..06eb82ce74 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1060,7 +1060,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): if not label_widget: label_widget = QtWidgets.QLabel(input_data["label"], self) - layout.addWidget(label_widget) + layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget @@ -2258,7 +2258,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): label = input_data["label"] label_widget = QtWidgets.QLabel(label) label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout.addWidget(label_widget, 0) + layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget self.content_widget = QtWidgets.QWidget(self) From f943b7967949398bc75f5c81d90b12692ae9881f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 14:23:20 +0200 Subject: [PATCH 576/580] abstract methods are implemented directly in SettingObject --- .../settings/settings/widgets/item_types.py | 163 ++++++++++++- .../settings/settings/widgets/widgets.py | 230 ------------------ 2 files changed, 161 insertions(+), 232 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 06eb82ce74..1872d72def 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3,7 +3,6 @@ import logging import collections from Qt import QtWidgets, QtCore, QtGui from .widgets import ( - AbstractSettingObject, ExpandingWidget, NumberSpinBox, PathInput @@ -12,11 +11,31 @@ from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome -class SettingObject(AbstractSettingObject): +class SettingObject: is_input_type = True default_input_value = NOT_SET allow_actions = True default_state = "" + abstract_attributes = ("_parent", ) + + def __getattr__(self, name): + if name in self.abstract_attributes: + raise NotImplementedError( + "Attribute `{}` is not implemented. {}".format(name, self) + ) + return super(SettingObject, self).__getattribute__(name) + + @classmethod + def style_state(cls, is_invalid, is_overriden, is_modified): + items = [] + if is_invalid: + items.append("invalid") + else: + if is_overriden: + items.append("overriden") + if is_modified: + items.append("modified") + return "-".join(items) or cls.default_state def set_default_attributes(self): # Default input attributes @@ -245,6 +264,146 @@ class SettingObject(AbstractSettingObject): if item: return item.mouseReleaseEvent(self, event) + def _discard_changes(self): + self.ignore_value_changes = True + self.discard_changes() + self.ignore_value_changes = False + + def discard_changes(self): + raise NotImplementedError( + "{} Method `discard_changes` not implemented!".format( + repr(self) + ) + ) + + def _set_studio_default(self): + self.ignore_value_changes = True + self.set_studio_default() + self.ignore_value_changes = False + + def set_studio_default(self): + raise NotImplementedError( + "{} Method `set_studio_default` not implemented!".format( + repr(self) + ) + ) + + def _reset_to_pype_default(self): + self.ignore_value_changes = True + self.reset_to_pype_default() + self.ignore_value_changes = False + + def reset_to_pype_default(self): + raise NotImplementedError( + "{} Method `reset_to_pype_default` not implemented!".format( + repr(self) + ) + ) + + def _remove_overrides(self): + self.ignore_value_changes = True + self.remove_overrides() + self.ignore_value_changes = False + + def remove_overrides(self): + raise NotImplementedError( + "{} Method `remove_overrides` not implemented!".format( + repr(self) + ) + ) + + def _set_as_overriden(self): + self.ignore_value_changes = True + self.set_as_overriden() + self.ignore_value_changes = False + + def set_as_overriden(self): + raise NotImplementedError( + "{} Method `set_as_overriden` not implemented!".format(repr(self)) + ) + + def hierarchical_style_update(self): + raise NotImplementedError( + "{} Method `hierarchical_style_update` not implemented!".format( + repr(self) + ) + ) + + def update_default_values(self, parent_values): + raise NotImplementedError( + "{} does not have implemented `update_default_values`".format(self) + ) + + def update_studio_values(self, parent_values): + raise NotImplementedError( + "{} does not have implemented `update_studio_values`".format(self) + ) + + def apply_overrides(self, parent_values): + raise NotImplementedError( + "{} does not have implemented `apply_overrides`".format(self) + ) + + @property + def ignore_value_changes(self): + """Most of attribute changes are ignored on value change when True.""" + raise NotImplementedError( + "{} does not have implemented `ignore_value_changes`".format(self) + ) + + @ignore_value_changes.setter + def ignore_value_changes(self, value): + """Setter for global parent item to apply changes for all inputs.""" + raise NotImplementedError(( + "{} does not have implemented setter method `ignore_value_changes`" + ).format(self)) + + @property + def child_has_studio_override(self): + """Any children item is modified.""" + raise NotImplementedError( + "{} does not have implemented `child_has_studio_override`".format( + self + ) + ) + + @property + def child_modified(self): + """Any children item is modified.""" + raise NotImplementedError( + "{} does not have implemented `child_modified`".format(self) + ) + + @property + def child_overriden(self): + """Any children item is overriden.""" + raise NotImplementedError( + "{} does not have implemented `child_overriden`".format(self) + ) + + @property + def child_invalid(self): + """Any children item does not have valid value.""" + raise NotImplementedError( + "{} does not have implemented `child_invalid`".format(self) + ) + + def get_invalid(self): + """Return invalid item types all down the hierarchy.""" + raise NotImplementedError( + "{} does not have implemented `get_invalid`".format(self) + ) + + def item_value(self): + """Value of an item without key.""" + raise NotImplementedError( + "Method `item_value` not implemented!" + ) + + def studio_value(self): + """Output for saving changes or overrides.""" + return {self.key: self.item_value()} + class InputObject(SettingObject): def update_default_values(self, parent_values): diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 96f8d2ec17..400b9371fd 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -226,233 +226,3 @@ class UnsavedChangesDialog(QtWidgets.QDialog): def on_discard_pressed(self): self.done(2) - - -class AbstractSettingObject: - abstract_attributes = ("_parent", ) - - def __getattr__(self, name): - if name in self.abstract_attributes: - raise NotImplementedError( - "Attribute `{}` is not implemented. {}".format(name, self) - ) - return super(AbstractSettingObject, self).__getattribute__(name) - - def update_default_values(self, parent_values): - raise NotImplementedError( - "{} does not have implemented `update_default_values`".format(self) - ) - - def update_studio_values(self, parent_values): - raise NotImplementedError( - "{} does not have implemented `update_studio_values`".format(self) - ) - - def apply_overrides(self, parent_values): - raise NotImplementedError( - "{} does not have implemented `apply_overrides`".format(self) - ) - - @property - def is_modified(self): - """Has object any changes that require saving.""" - raise NotImplementedError( - "{} does not have implemented `is_modified`".format(self) - ) - - @property - def is_overriden(self): - """Is object overriden so should be saved to overrides.""" - raise NotImplementedError( - "{} does not have implemented `is_overriden`".format(self) - ) - - @property - def any_parent_is_group(self): - raise NotImplementedError( - "{} does not have implemented `any_parent_is_group`".format(self) - ) - - @property - def was_overriden(self): - """Initial state after applying overrides.""" - raise NotImplementedError( - "{} does not have implemented `was_overriden`".format(self) - ) - - @property - def is_invalid(self): - """Value set in is not valid.""" - raise NotImplementedError( - "{} does not have implemented `is_invalid`".format(self) - ) - - @property - def is_group(self): - """Value set in is not valid.""" - raise NotImplementedError( - "{} does not have implemented `is_group`".format(self) - ) - - @property - def is_nullable(self): - raise NotImplementedError( - "{} does not have implemented `is_nullable`".format(self) - ) - - @property - def is_overidable(self): - """Should care about overrides.""" - raise NotImplementedError( - "{} does not have implemented `is_overidable`".format(self) - ) - - def any_parent_overriden(self): - """Any of parent object up to top hiearchy is overriden.""" - raise NotImplementedError( - "{} does not have implemented `any_parent_overriden`".format(self) - ) - - @property - def ignore_value_changes(self): - """Most of attribute changes are ignored on value change when True.""" - raise NotImplementedError( - "{} does not have implemented `ignore_value_changes`".format(self) - ) - - @ignore_value_changes.setter - def ignore_value_changes(self, value): - """Setter for global parent item to apply changes for all inputs.""" - raise NotImplementedError(( - "{} does not have implemented setter method `ignore_value_changes`" - ).format(self)) - - @property - def child_has_studio_override(self): - """Any children item is modified.""" - raise NotImplementedError( - "{} does not have implemented `child_has_studio_override`".format( - self - ) - ) - - @property - def child_modified(self): - """Any children item is modified.""" - raise NotImplementedError( - "{} does not have implemented `child_modified`".format(self) - ) - - @property - def child_overriden(self): - """Any children item is overriden.""" - raise NotImplementedError( - "{} does not have implemented `child_overriden`".format(self) - ) - - @property - def child_invalid(self): - """Any children item does not have valid value.""" - raise NotImplementedError( - "{} does not have implemented `child_invalid`".format(self) - ) - - def get_invalid(self): - """Returns invalid items all down the hierarchy.""" - raise NotImplementedError( - "{} does not have implemented `get_invalid`".format(self) - ) - - def item_value(self): - """Value of an item without key.""" - raise NotImplementedError( - "Method `item_value` not implemented!" - ) - - def studio_value(self): - """Output for saving changes or overrides.""" - return {self.key: self.item_value()} - - @classmethod - def style_state(cls, is_invalid, is_overriden, is_modified): - items = [] - if is_invalid: - items.append("invalid") - else: - if is_overriden: - items.append("overriden") - if is_modified: - items.append("modified") - return "-".join(items) or cls.default_state - - def add_children_gui(self, child_configuration, values): - raise NotImplementedError( - "{} Method `add_children_gui` is not implemented!.".format( - repr(self) - ) - ) - - def _discard_changes(self): - self.ignore_value_changes = True - self.discard_changes() - self.ignore_value_changes = False - - def discard_changes(self): - raise NotImplementedError( - "{} Method `discard_changes` not implemented!".format( - repr(self) - ) - ) - - def _set_studio_default(self): - self.ignore_value_changes = True - self.set_studio_default() - self.ignore_value_changes = False - - def set_studio_default(self): - raise NotImplementedError( - "{} Method `set_studio_default` not implemented!".format( - repr(self) - ) - ) - - def _reset_to_pype_default(self): - self.ignore_value_changes = True - self.reset_to_pype_default() - self.ignore_value_changes = False - - def reset_to_pype_default(self): - raise NotImplementedError( - "{} Method `reset_to_pype_default` not implemented!".format( - repr(self) - ) - ) - - def _remove_overrides(self): - self.ignore_value_changes = True - self.remove_overrides() - self.ignore_value_changes = False - - def remove_overrides(self): - raise NotImplementedError( - "{} Method `remove_overrides` not implemented!".format( - repr(self) - ) - ) - - def _set_as_overriden(self): - self.ignore_value_changes = True - self.set_as_overriden() - self.ignore_value_changes = False - - def set_as_overriden(self): - raise NotImplementedError( - "{} Method `set_as_overriden` not implemented!".format(repr(self)) - ) - - def hierarchical_style_update(self): - raise NotImplementedError( - "{} Method `hierarchical_style_update` not implemented!".format( - repr(self) - ) - ) From 81df713212f3259a9b60fc76af1e179588892f46 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 15:32:59 +0200 Subject: [PATCH 577/580] added few docstrings --- .../settings/settings/widgets/item_types.py | 117 ++++++++++++------ 1 file changed, 80 insertions(+), 37 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 1872d72def..19bfdabb9e 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -12,21 +12,19 @@ from avalon.vendor import qtawesome class SettingObject: + # `is_input_type` attribute says if has implemented item type methods is_input_type = True + # each input must have implemented default value for development + # when defaults are not filled yet default_input_value = NOT_SET + # will allow to show actions for the item type (disabled for proxies) allow_actions = True + # default state of item type default_state = "" - abstract_attributes = ("_parent", ) - - def __getattr__(self, name): - if name in self.abstract_attributes: - raise NotImplementedError( - "Attribute `{}` is not implemented. {}".format(name, self) - ) - return super(SettingObject, self).__getattribute__(name) @classmethod def style_state(cls, is_invalid, is_overriden, is_modified): + """Return stylesheet state by intered booleans.""" items = [] if is_invalid: items.append("invalid") @@ -37,7 +35,11 @@ class SettingObject: items.append("modified") return "-".join(items) or cls.default_state - def set_default_attributes(self): + def _set_default_attributes(self): + """Create and reset attributes required for all item types. + + They may not be used in the item but are required to be set. + """ # Default input attributes self._has_studio_override = False self._had_studio_override = False @@ -73,7 +75,12 @@ class SettingObject: self.defaults_not_set = False def initial_attributes(self, input_data, parent, as_widget): - self.set_default_attributes() + """Prepare attributes based on entered arguments. + + This method should be same for each item type. Few item types + may require to extend with specific attributes for their case. + """ + self._set_default_attributes() self._parent = parent self._as_widget = as_widget @@ -90,24 +97,70 @@ class SettingObject: @property def develop_mode(self): + """Tool is in develop mode or not. + + Returns: + bool + + """ return self._parent.develop_mode @property def log(self): + """Auto created logger for debugging.""" if self._log is None: self._log = logging.getLogger(self.__class__.__name__) return self._log - @property - def has_studio_override(self): - return self._has_studio_override or self._parent.has_studio_override - @property def had_studio_override(self): + """Item had studio overrides on refresh. + + Returns: + bool + + """ return self._had_studio_override + @property + def has_studio_override(self): + """Item has studio override at the moment. + + With combination of `had_studio_override` is possible to know if item + has changes (not just value change). + + Returns: + bool + + """ + return self._has_studio_override or self._parent.has_studio_override + + @property + def is_group(self): + """Item represents key that can be overriden. + + Attribute `is_group` can be set to True only once in item hierarchy. + + Returns: + bool + + """ + return self._is_group + @property def any_parent_is_group(self): + """Any parent of item is group. + + Attribute holding this information is set during creation and + stored to `_any_parent_is_group`. + + Why is this information useful: If any parent is group and + the parent is set as overriden, this item is overriden too. + + Returns: + bool + + """ if self._any_parent_is_group is None: return super(SettingObject, self).any_parent_is_group return self._any_parent_is_group @@ -130,7 +183,7 @@ class SettingObject: @property def was_overriden(self): - """Initial state after applying overrides.""" + """Item had set value of project overrides on project change.""" if self._as_widget: return self._parent.was_overriden return self._was_overriden @@ -140,13 +193,12 @@ class SettingObject: """Value set in is not valid.""" return self._is_invalid - @property - def is_group(self): - """Value set in is not valid.""" - return self._is_group - @property def is_nullable(self): + """Value of item can be set to None. + + NOT IMPLEMENTED! + """ return self._is_nullable @property @@ -155,7 +207,12 @@ class SettingObject: return self._parent.is_overidable def any_parent_overriden(self): - """Any of parent object up to top hiearchy is overriden.""" + """Any of parent objects up to top hiearchy item is overriden. + + Returns: + bool + + """ if self._parent._is_overriden: return True return self._parent.any_parent_overriden() @@ -344,20 +401,6 @@ class SettingObject: "{} does not have implemented `apply_overrides`".format(self) ) - @property - def ignore_value_changes(self): - """Most of attribute changes are ignored on value change when True.""" - raise NotImplementedError( - "{} does not have implemented `ignore_value_changes`".format(self) - ) - - @ignore_value_changes.setter - def ignore_value_changes(self, value): - """Setter for global parent item to apply changes for all inputs.""" - raise NotImplementedError(( - "{} does not have implemented setter method `ignore_value_changes`" - ).format(self)) - @property def child_has_studio_override(self): """Any children item is modified.""" @@ -1049,7 +1092,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): def __init__(self, object_type, input_modifiers, config_parent, parent): super(ListItem, self).__init__(parent) - self.set_default_attributes() + self._set_default_attributes() self._parent = config_parent self._any_parent_is_group = True @@ -1430,7 +1473,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def __init__(self, object_type, input_modifiers, config_parent, parent): super(ModifiableDictItem, self).__init__(parent) - self.set_default_attributes() + self._set_default_attributes() self._parent = config_parent self.is_key_duplicated = False From 1273e7c6ef9367302a77b50c2198b87b3bba84f1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 15:36:26 +0200 Subject: [PATCH 578/580] fixed typo --- pype/tools/settings/settings/widgets/item_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 19bfdabb9e..e2d59c2e69 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -284,7 +284,7 @@ class SettingObject: and not self.any_parent_is_group and not self._had_studio_override ): - action = QtWidgets.QAction("Set sudio default") + action = QtWidgets.QAction("Set studio default") actions_mapping[action] = self._set_studio_default menu.addAction(action) From d6fbbc31e8452e12d17094418f25ac0efefde8c3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 16 Sep 2020 16:03:11 +0200 Subject: [PATCH 579/580] feat(global): add `burnin` suffix only if more burnin profiles active --- pype/plugins/global/publish/extract_burnin.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index 4443cfe223..6e8da1b054 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -195,11 +195,14 @@ class ExtractBurnin(pype.api.Extractor): if "delete" in new_repre["tags"]: new_repre["tags"].remove("delete") - # Update name and outputName to be able have multiple outputs - # Join previous "outputName" with filename suffix - new_name = "_".join([new_repre["outputName"], filename_suffix]) - new_repre["name"] = new_name - new_repre["outputName"] = new_name + if len(repre_burnin_defs.keys()) > 1: + # Update name and outputName to be + # able have multiple outputs in case of more burnin presets + # Join previous "outputName" with filename suffix + new_name = "_".join( + [new_repre["outputName"], filename_suffix]) + new_repre["name"] = new_name + new_repre["outputName"] = new_name # Prepare paths and files for process. self.input_output_paths(new_repre, temp_data, filename_suffix) From 91ac877a1e88bce9acd72218f24156fa6e02d770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Wed, 16 Sep 2020 16:05:48 +0200 Subject: [PATCH 580/580] Revert "388 Extract review a representation name with `*_burnin`" --- pype/plugins/global/publish/extract_burnin.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index 6e8da1b054..4443cfe223 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -195,14 +195,11 @@ class ExtractBurnin(pype.api.Extractor): if "delete" in new_repre["tags"]: new_repre["tags"].remove("delete") - if len(repre_burnin_defs.keys()) > 1: - # Update name and outputName to be - # able have multiple outputs in case of more burnin presets - # Join previous "outputName" with filename suffix - new_name = "_".join( - [new_repre["outputName"], filename_suffix]) - new_repre["name"] = new_name - new_repre["outputName"] = new_name + # Update name and outputName to be able have multiple outputs + # Join previous "outputName" with filename suffix + new_name = "_".join([new_repre["outputName"], filename_suffix]) + new_repre["name"] = new_name + new_repre["outputName"] = new_name # Prepare paths and files for process. self.input_output_paths(new_repre, temp_data, filename_suffix)