From 2909b7453e2117282d7181a84fb850824bf86b5f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 23 Jul 2020 11:03:44 +0200 Subject: [PATCH 001/662] 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 002/662] 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 003/662] 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 004/662] 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 005/662] 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 006/662] 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 007/662] 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 008/662] 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 009/662] 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 010/662] 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 011/662] 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 012/662] 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 013/662] 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 014/662] 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 015/662] 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 016/662] 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 017/662] 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 018/662] 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 019/662] 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 020/662] 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 021/662] 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 022/662] 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 023/662] 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 024/662] 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 025/662] 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 026/662] 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 027/662] 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 028/662] 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 029/662] 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 030/662] 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 031/662] 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 032/662] 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 033/662] 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 034/662] 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 035/662] 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 036/662] 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 037/662] 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 038/662] 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 039/662] 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 040/662] 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 041/662] 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 042/662] 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 043/662] 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 68822216ca15a263130b71dc6711d8ec1605477b Mon Sep 17 00:00:00 2001 From: "petr.kalis" Date: Tue, 11 Aug 2020 10:23:54 +0200 Subject: [PATCH 044/662] Added client support --- .../websocket_server/websocket_server.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 56e71ea895..9d0d01d156 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -22,12 +22,16 @@ class WebSocketServer(): WIP """ + _instance = None def __init__(self): self.qaction = None self.failed_icon = None self._is_running = False default_port = 8099 + WebSocketServer._instance = self + self.client = None + self.handlers = {} try: self.presets = config.get_presets()["services"]["websocket_server"] @@ -76,8 +80,26 @@ class WebSocketServer(): module = importlib.import_module(module_name) cls = getattr(module, class_name) WebSocketAsync.add_route(class_name, cls) + self.handlers[class_name] = cls() # TODO refactor sys.path.pop() + def call(self, func): + log.debug("websocket.call {}".format(func)) + return self.websocket_thread.call_async(func) + + def task_finished(self, task): + print("task finished {}".format(task.result)) + print("client socket {}".format(self.client.client.socket)) + + def get_routes(self): + WebSocketAsync.get_routes() + + @staticmethod + def get_instance(): + if WebSocketServer._instance == None: + WebSocketServer() + return WebSocketServer._instance + def tray_start(self): self.websocket_thread.start() @@ -124,6 +146,7 @@ class WebsocketServerThread(threading.Thread): self.loop = None self.runner = None self.site = None + self.tasks = [] def run(self): self.is_running = True @@ -153,6 +176,20 @@ class WebsocketServerThread(threading.Thread): self.module.thread_stopped() log.info("Websocket server stopped") + def call_async(self, func): + # log.debug("call async") + # print("call aysnc") + # log.debug("my loop {}".format(self.loop)) + # task = self.loop.create_task(func) + # print("waitning") + # log.debug("waiting for task {}".format(func)) + # self.loop.run_until_complete(task) + # log.debug("returned value {}".format(task.result)) + # return task.result + task = self.loop.create_task(func) + task.add_done_callback(self.module.task_finished) + self.tasks.append(task) + async def start_server(self): """ Starts runner and TCPsite """ self.runner = web.AppRunner(self.module.app) @@ -169,6 +206,12 @@ class WebsocketServerThread(threading.Thread): periodically. """ while self.is_running: + while self.tasks: + task = self.tasks.pop(0) + log.debug("waiting for task {}".format(task)) + await task + log.debug("returned value {}".format(task.result)) + await asyncio.sleep(0.5) log.debug("Starting shutdown") From 0badfc0a5ace0cebc8252122f1e14b4a521a15c2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 13 Aug 2020 11:22:07 +0200 Subject: [PATCH 045/662] 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 046/662] 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 047/662] 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 048/662] 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 049/662] 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 050/662] 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 051/662] 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 052/662] 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 053/662] 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 054/662] 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 055/662] 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 056/662] 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 057/662] 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 058/662] 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 41c101695238e3667c6392e155a5996dd335f85f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 18 Aug 2020 18:03:35 +0200 Subject: [PATCH 059/662] Working implementation of collect_instances\n extract_review, etract_image --- .../clients/photoshop_client.py | 102 ++++++++++++++++++ .../websocket_server/hosts/photoshop.py | 34 ++++++ .../websocket_server/websocket_server.py | 35 +++--- .../photoshop/publish/collect_instances.py | 23 ++-- .../photoshop/publish/extract_image.py | 43 +++++--- .../photoshop/publish/extract_review.py | 62 +++++++---- .../photoshop/publish/extract_save_scene.py | 5 +- 7 files changed, 240 insertions(+), 64 deletions(-) create mode 100644 pype/modules/websocket_server/clients/photoshop_client.py create mode 100644 pype/modules/websocket_server/hosts/photoshop.py diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py new file mode 100644 index 0000000000..0090c10db2 --- /dev/null +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -0,0 +1,102 @@ +from pype.modules.websocket_server import WebSocketServer +""" + Stub handling connection from server to client. + Used anywhere solution is calling client methods. +""" +import json +from collections import namedtuple + +class PhotoshopClientStub(): + + def __init__(self): + self.websocketserver = WebSocketServer.get_instance() + self.client = self.websocketserver.get_client() + + def read(self, layer): + layers_data = {} + res = self.websocketserver.call(self.client.call('Photoshop.read')) + try: + layers_data = json.loads(res) + except json.decoder.JSONDecodeError: + pass + + return layers_data.get(str(layer.id)) + + def get_layers(self): + """ + Returns JSON document with all(?) layers in active document. + + :return: + Format of tuple: { 'id':'123', + 'name': 'My Layer 1', + 'type': 'GUIDE'|'FG'|'BG'|'OBJ' + 'visible': 'true'|'false' + """ + layers = {} + res = self.websocketserver.call(self.client.call + ('Photoshop.get_layers')) + print("get_layers:: {}".format(res)) + try: + layers_data = json.loads(res) + except json.decoder.JSONDecodeError: + raise ValueError("Received broken JSON {}".format(res)) + ret = [] + # convert to namedtuple to use dot donation + for d in layers_data: + ret.append(namedtuple('Layer', d.keys())(*d.values())) + + return ret + + def get_layers_in_layers(self, layers): + """ + Return all layers that belong to layers (might be groups). + :param layers: + :return: + """ + all_layers = self.get_layers() + print("get_layers_in_layers {}".format(layers)) + print("get_layers_in_layers len {}".format(len(layers))) + print("get_layers_in_layers type {}".format(type(layers))) + ret = [] + layer_ids = [lay.id for lay in layers] + layer_group_ids = [ll.groupId for ll in layers if ll.group] + for layer in all_layers: + if layer.groupId in layer_group_ids: # all from group + ret.append(layer) + if layer.id in layer_ids: + ret.append(layer) + + return ret + + + def select_layers(self, layers): + layer_ids = [layer.id for layer in layers] + + res = self.websocketserver.call(self.client.call + ('Photoshop.get_layers', + layers=layer_ids) + ) + + def get_active_document_name(self): + res = self.websocketserver.call(self.client.call + ('Photoshop.get_active_document_name')) + + return res + + def set_visible(self, layer_id, visibility): + print("set_visible {}, {}".format(layer_id, visibility)) + res = self.websocketserver.call(self.client.call + ('Photoshop.set_visible', + layer_id=layer_id, + visibility=visibility)) + + def saveAs(self, image_path, ext, as_copy): + res = self.websocketserver.call(self.client.call + ('Photoshop.saveAs', + image_path=image_path, + ext=ext, + as_copy=as_copy)) + + def close(self): + self.client.close() + diff --git a/pype/modules/websocket_server/hosts/photoshop.py b/pype/modules/websocket_server/hosts/photoshop.py new file mode 100644 index 0000000000..9092530e48 --- /dev/null +++ b/pype/modules/websocket_server/hosts/photoshop.py @@ -0,0 +1,34 @@ +import asyncio + +from pype.api import Logger +from wsrpc_aiohttp import WebSocketRoute + +log = Logger().get_logger("WebsocketServer") + + +class Photoshop(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 + """ + instance = None + + def init(self, **kwargs): + # Python __init__ must be return "self". + # This method might return anything. + log.debug("someone called Photoshop route") + self.instance = self + return kwargs + + # server functions + async def ping(self): + log.debug("someone called Photoshop route ping") + + # This method calls function on the client side + # client functions + + async def read(self): + log.debug("photoshop.read client calls server server calls Photo client") + return await self.socket.call('Photoshop.read') diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 9d0d01d156..f9be7c88a9 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -80,19 +80,26 @@ class WebSocketServer(): module = importlib.import_module(module_name) cls = getattr(module, class_name) WebSocketAsync.add_route(class_name, cls) - self.handlers[class_name] = cls() # TODO refactor sys.path.pop() def call(self, func): log.debug("websocket.call {}".format(func)) - return self.websocket_thread.call_async(func) + future = asyncio.run_coroutine_threadsafe(func, + self.websocket_thread.loop) + result = future.result() + return result - def task_finished(self, task): - print("task finished {}".format(task.result)) - print("client socket {}".format(self.client.client.socket)) + def get_client(self): + """ + Return first connected client to WebSocket + TODO implement selection by Route + :return: client + """ + clients = WebSocketAsync.get_clients() + key = list(clients.keys())[0] + client = clients.get(key) - def get_routes(self): - WebSocketAsync.get_routes() + return client @staticmethod def get_instance(): @@ -176,20 +183,6 @@ class WebsocketServerThread(threading.Thread): self.module.thread_stopped() log.info("Websocket server stopped") - def call_async(self, func): - # log.debug("call async") - # print("call aysnc") - # log.debug("my loop {}".format(self.loop)) - # task = self.loop.create_task(func) - # print("waitning") - # log.debug("waiting for task {}".format(func)) - # self.loop.run_until_complete(task) - # log.debug("returned value {}".format(task.result)) - # return task.result - task = self.loop.create_task(func) - task.add_done_callback(self.module.task_finished) - self.tasks.append(task) - async def start_server(self): """ Starts runner and TCPsite """ self.runner = web.AppRunner(self.module.app) diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index 4937f2a1e4..cc7341f384 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -4,6 +4,7 @@ from avalon import photoshop import pyblish.api +from pype.modules.websocket_server.clients.photoshop_client import PhotoshopClientStub class CollectInstances(pyblish.api.ContextPlugin): """Gather instances by LayerSet and file metadata @@ -27,8 +28,13 @@ class CollectInstances(pyblish.api.ContextPlugin): # can be. pythoncom.CoInitialize() - for layer in photoshop.get_layers_in_document(): - layer_data = photoshop.read(layer) + from datetime import datetime + start = datetime.now() + # for timing + photoshop_client = PhotoshopClientStub() + layers = photoshop_client.get_layers() + for layer in layers: + layer_data = photoshop_client.read(layer) # Skip layers without metadata. if layer_data is None: @@ -38,18 +44,19 @@ class CollectInstances(pyblish.api.ContextPlugin): if "container" in layer_data["id"]: continue - child_layers = [*layer.Layers] - if not child_layers: - self.log.info("%s skipped, it was empty." % layer.Name) - continue + # child_layers = [*layer.Layers] + # self.log.debug("child_layers {}".format(child_layers)) + # if not child_layers: + # self.log.info("%s skipped, it was empty." % layer.Name) + # continue - instance = context.create_instance(layer.Name) + instance = context.create_instance(layer.name) instance.append(layer) instance.data.update(layer_data) instance.data["families"] = self.families_mapping[ layer_data["family"] ] - instance.data["publish"] = layer.Visible + instance.data["publish"] = layer.visible # Produce diagnostic message for any graphical # user interface interested in visualising it. diff --git a/pype/plugins/photoshop/publish/extract_image.py b/pype/plugins/photoshop/publish/extract_image.py index 6dfccdc4f2..0451308ef1 100644 --- a/pype/plugins/photoshop/publish/extract_image.py +++ b/pype/plugins/photoshop/publish/extract_image.py @@ -3,6 +3,8 @@ import os import pype.api from avalon import photoshop +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub class ExtractImage(pype.api.Extractor): """Produce a flattened image file from instance @@ -20,36 +22,49 @@ class ExtractImage(pype.api.Extractor): staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) + layers = [] + for image_instance in instance.context: + if image_instance.data["family"] != "image": + continue + layers.append(image_instance[0]) + # Perform extraction + photoshop_client = PhotoshopClientStub() files = {} with photoshop.maintained_selection(): self.log.info("Extracting %s" % str(list(instance))) with photoshop.maintained_visibility(): # Hide all other layers. - extract_ids = [ - x.id for x in photoshop.get_layers_in_layers([instance[0]]) - ] - for layer in photoshop.get_layers_in_document(): - if layer.id not in extract_ids: - layer.Visible = False + extract_ids = set([ll.id for ll in photoshop_client. + get_layers_in_layers(layers)]) - save_options = {} + for layer in photoshop_client.get_layers(): + # limit unnecessary calls to client + if layer.visible and layer.id not in extract_ids: + photoshop_client.set_visible(layer.id, + False) + if not layer.visible and layer.id in extract_ids: + photoshop_client.set_visible(layer.id, + True) + + save_options = [] if "png" in self.formats: - save_options["png"] = photoshop.com_objects.PNGSaveOptions() + save_options.append('png') if "jpg" in self.formats: - save_options["jpg"] = photoshop.com_objects.JPEGSaveOptions() + save_options.append('jpg') file_basename = os.path.splitext( - photoshop.app().ActiveDocument.Name + photoshop_client.get_active_document_name() )[0] - for extension, save_option in save_options.items(): + for extension in save_options: _filename = "{}.{}".format(file_basename, extension) files[extension] = _filename full_filename = os.path.join(staging_dir, _filename) - photoshop.app().ActiveDocument.SaveAs( - full_filename, save_option, True - ) + photoshop_client.saveAs(full_filename, + extension, + True) + representations = [] for extension, filename in files.items(): diff --git a/pype/plugins/photoshop/publish/extract_review.py b/pype/plugins/photoshop/publish/extract_review.py index 078ee53899..1c3aeaffb5 100644 --- a/pype/plugins/photoshop/publish/extract_review.py +++ b/pype/plugins/photoshop/publish/extract_review.py @@ -4,6 +4,10 @@ import pype.api import pype.lib from avalon import photoshop +from datetime import datetime +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub + class ExtractReview(pype.api.Extractor): """Produce a flattened image file from all instances.""" @@ -13,10 +17,12 @@ class ExtractReview(pype.api.Extractor): families = ["review"] def process(self, instance): - + start = datetime.now() staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) + photoshop_client = PhotoshopClientStub() + layers = [] for image_instance in instance.context: if image_instance.data["family"] != "image": @@ -25,26 +31,39 @@ class ExtractReview(pype.api.Extractor): # Perform extraction output_image = "{}.jpg".format( - os.path.splitext(photoshop.app().ActiveDocument.Name)[0] + os.path.splitext(photoshop_client.get_active_document_name())[0] ) output_image_path = os.path.join(staging_dir, output_image) + self.log.info( + "first part took {}".format(datetime.now() - start)) with photoshop.maintained_visibility(): # Hide all other layers. - extract_ids = [ - x.id for x in photoshop.get_layers_in_layers(layers) - ] - for layer in photoshop.get_layers_in_document(): - if layer.id in extract_ids: - layer.Visible = True - else: - layer.Visible = False + start = datetime.now() + extract_ids = set([ll.id for ll in photoshop_client. + get_layers_in_layers(layers)]) + self.log.info("extract_ids {}".format(extract_ids)) - photoshop.app().ActiveDocument.SaveAs( - output_image_path, - photoshop.com_objects.JPEGSaveOptions(), - True - ) + for layer in photoshop_client.get_layers(): + # limit unnecessary calls to client + if layer.visible and layer.id not in extract_ids: + photoshop_client.set_visible(layer.id, + False) + if not layer.visible and layer.id in extract_ids: + photoshop_client.set_visible(layer.id, + True) + self.log.info( + "get_layers_in_layers took {}".format(datetime.now() - start)) + start = datetime.now() + + self.log.info("output_image_path {}".format(output_image_path)) + photoshop_client.saveAs(output_image_path, + 'jpg', + True) + self.log.info( + "saveAs {} took {}".format('JPG', datetime.now() - start)) + + start = datetime.now() ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") instance.data["representations"].append({ @@ -65,7 +84,8 @@ class ExtractReview(pype.api.Extractor): thumbnail_path ] output = pype.lib._subprocess(args) - + self.log.info( + "thumbnail {} took {}".format('JPG', datetime.now() - start)) self.log.debug(output) instance.data["representations"].append({ @@ -75,7 +95,7 @@ class ExtractReview(pype.api.Extractor): "stagingDir": staging_dir, "tags": ["thumbnail"] }) - + start = datetime.now() # Generate mov. mov_path = os.path.join(staging_dir, "review.mov") args = [ @@ -86,9 +106,10 @@ class ExtractReview(pype.api.Extractor): mov_path ] output = pype.lib._subprocess(args) - + self.log.info( + "review {} took {}".format('JPG', datetime.now() - start)) self.log.debug(output) - + start = datetime.now() instance.data["representations"].append({ "name": "mov", "ext": "mov", @@ -105,5 +126,6 @@ class ExtractReview(pype.api.Extractor): instance.data["frameStart"] = 1 instance.data["frameEnd"] = 1 instance.data["fps"] = 25 - + self.log.info( + "end {} took {}".format('JPG', datetime.now() - start)) self.log.info(f"Extracted {instance} to {staging_dir}") diff --git a/pype/plugins/photoshop/publish/extract_save_scene.py b/pype/plugins/photoshop/publish/extract_save_scene.py index b3d4f0e447..e2068501db 100644 --- a/pype/plugins/photoshop/publish/extract_save_scene.py +++ b/pype/plugins/photoshop/publish/extract_save_scene.py @@ -1,7 +1,7 @@ import pype.api from avalon import photoshop - +from datetime import datetime class ExtractSaveScene(pype.api.Extractor): """Save scene before extraction.""" @@ -11,4 +11,7 @@ class ExtractSaveScene(pype.api.Extractor): families = ["workfile"] def process(self, instance): + start = datetime.now() photoshop.app().ActiveDocument.Save() + self.log.info( + "ExtractSaveScene took {}".format(datetime.now() - start)) From 7e65e5c830a63cf05aff5438cbcd1f18bfd57ec2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 19 Aug 2020 12:06:59 +0200 Subject: [PATCH 060/662] 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 a9f146e2fca896a8558c3c8d65d6df1a0f3af3ec Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 19 Aug 2020 12:54:42 +0200 Subject: [PATCH 061/662] Fixed fullName, implemented imprint --- .../clients/photoshop_client.py | 73 ++++++++++++++++--- .../photoshop/publish/collect_current_file.py | 6 +- .../photoshop/publish/collect_instances.py | 6 ++ .../photoshop/publish/extract_save_scene.py | 6 +- .../photoshop/publish/increment_workfile.py | 5 +- .../publish/validate_instance_asset.py | 11 ++- .../photoshop/publish/validate_naming.py | 9 ++- 7 files changed, 96 insertions(+), 20 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index 0090c10db2..6d3615e1a4 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -13,15 +13,34 @@ class PhotoshopClientStub(): self.client = self.websocketserver.get_client() def read(self, layer): - layers_data = {} - res = self.websocketserver.call(self.client.call('Photoshop.read')) - try: - layers_data = json.loads(res) - except json.decoder.JSONDecodeError: - pass + layers_data = self._get_layers_metadata() return layers_data.get(str(layer.id)) + def imprint(self, layer, data): + layers_data = self._get_layers_metadata() + # json.dumps writes integer values in a dictionary to string, so + # anticipating it here. + if str(layer.id) in layers_data: + layers_data[str(layer.id)].update(data) + else: + layers_data[str(layer.id)] = data + + # Ensure only valid ids are stored. + layer_ids = [layer.id for layer in self.get_layers()] + cleaned_data = {} + + for id in layers_data: + if int(id) in layer_ids: + cleaned_data[id] = layers_data[id] + + payload = json.dumps(cleaned_data, indent=4) + + res = self.websocketserver.call(self.client.call + ('Photoshop.imprint', + payload=payload) + ) + def get_layers(self): """ Returns JSON document with all(?) layers in active document. @@ -77,18 +96,34 @@ class PhotoshopClientStub(): layers=layer_ids) ) + def get_active_document_full_name(self): + """ + Returns full name with path of active document via ws call + :return: full path with name + """ + res = self.websocketserver.call( + self.client.call('Photoshop.get_active_document_full_name')) + + return res + def get_active_document_name(self): + """ + Returns just a name of active document via ws call + :return: file name + """ res = self.websocketserver.call(self.client.call ('Photoshop.get_active_document_name')) return res - def set_visible(self, layer_id, visibility): - print("set_visible {}, {}".format(layer_id, visibility)) + def save(self): + """ + Saves active document + :return: None + """ res = self.websocketserver.call(self.client.call - ('Photoshop.set_visible', - layer_id=layer_id, - visibility=visibility)) + ('Photoshop.save')) + def saveAs(self, image_path, ext, as_copy): res = self.websocketserver.call(self.client.call @@ -97,6 +132,22 @@ class PhotoshopClientStub(): ext=ext, as_copy=as_copy)) + def set_visible(self, layer_id, visibility): + print("set_visible {}, {}".format(layer_id, visibility)) + res = self.websocketserver.call(self.client.call + ('Photoshop.set_visible', + layer_id=layer_id, + visibility=visibility)) + + def _get_layers_metadata(self): + layers_data = {} + res = self.websocketserver.call(self.client.call('Photoshop.read')) + try: + layers_data = json.loads(res) + except json.decoder.JSONDecodeError: + pass + return layers_data + def close(self): self.client.close() diff --git a/pype/plugins/photoshop/publish/collect_current_file.py b/pype/plugins/photoshop/publish/collect_current_file.py index 4308588559..bb81718bcc 100644 --- a/pype/plugins/photoshop/publish/collect_current_file.py +++ b/pype/plugins/photoshop/publish/collect_current_file.py @@ -3,6 +3,9 @@ import os import pyblish.api from avalon import photoshop +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub + class CollectCurrentFile(pyblish.api.ContextPlugin): """Inject the current working file into context""" @@ -12,6 +15,7 @@ class CollectCurrentFile(pyblish.api.ContextPlugin): hosts = ["photoshop"] def process(self, context): + photoshop_client = PhotoshopClientStub() context.data["currentFile"] = os.path.normpath( - photoshop.app().ActiveDocument.FullName + photoshop_client.get_active_document_full_name() ).replace("\\", "/") diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index cc7341f384..d94adde00b 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -33,8 +33,14 @@ class CollectInstances(pyblish.api.ContextPlugin): # for timing photoshop_client = PhotoshopClientStub() layers = photoshop_client.get_layers() + for layer in layers: layer_data = photoshop_client.read(layer) + self.log.info("layer_data {}".format(layer_data)) + + photoshop_client.imprint(layer, layer_data) + new_layer_data = photoshop_client.read(layer) + assert layer_data == new_layer_data # Skip layers without metadata. if layer_data is None: diff --git a/pype/plugins/photoshop/publish/extract_save_scene.py b/pype/plugins/photoshop/publish/extract_save_scene.py index e2068501db..ea7bdda9af 100644 --- a/pype/plugins/photoshop/publish/extract_save_scene.py +++ b/pype/plugins/photoshop/publish/extract_save_scene.py @@ -1,6 +1,9 @@ import pype.api from avalon import photoshop +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub + from datetime import datetime class ExtractSaveScene(pype.api.Extractor): """Save scene before extraction.""" @@ -11,7 +14,8 @@ class ExtractSaveScene(pype.api.Extractor): families = ["workfile"] def process(self, instance): + photoshop_client = PhotoshopClientStub() start = datetime.now() - photoshop.app().ActiveDocument.Save() + photoshop_client.save() self.log.info( "ExtractSaveScene took {}".format(datetime.now() - start)) diff --git a/pype/plugins/photoshop/publish/increment_workfile.py b/pype/plugins/photoshop/publish/increment_workfile.py index ba9ab8606a..0ae7e9772f 100644 --- a/pype/plugins/photoshop/publish/increment_workfile.py +++ b/pype/plugins/photoshop/publish/increment_workfile.py @@ -3,6 +3,8 @@ from pype.action import get_errored_plugins_from_data from pype.lib import version_up from avalon import photoshop +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub class IncrementWorkfile(pyblish.api.InstancePlugin): """Increment the current workfile. @@ -24,6 +26,7 @@ class IncrementWorkfile(pyblish.api.InstancePlugin): ) scene_path = version_up(instance.context.data["currentFile"]) - photoshop.app().ActiveDocument.SaveAs(scene_path) + photoshop_client = PhotoshopClientStub() + photoshop_client.saveAs(scene_path, 'psd', True) self.log.info("Incremented workfile to: {}".format(scene_path)) diff --git a/pype/plugins/photoshop/publish/validate_instance_asset.py b/pype/plugins/photoshop/publish/validate_instance_asset.py index ab1d02269f..6a0a408878 100644 --- a/pype/plugins/photoshop/publish/validate_instance_asset.py +++ b/pype/plugins/photoshop/publish/validate_instance_asset.py @@ -4,6 +4,8 @@ import pyblish.api import pype.api from avalon import photoshop +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub class ValidateInstanceAssetRepair(pyblish.api.Action): """Repair the instance asset.""" @@ -23,11 +25,14 @@ class ValidateInstanceAssetRepair(pyblish.api.Action): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) - + photoshop_client = PhotoshopClientStub() for instance in instances: - data = photoshop.read(instance[0]) + self.log.info("validate_instance_asset instance[0] {}".format(instance[0])) + self.log.info("validate_instance_asset instance {}".format(instance)) + data = photoshop_client.read(instance[0]) + data["asset"] = os.environ["AVALON_ASSET"] - photoshop.imprint(instance[0], data) + photoshop_client.imprint(instance[0], data) class ValidateInstanceAsset(pyblish.api.InstancePlugin): diff --git a/pype/plugins/photoshop/publish/validate_naming.py b/pype/plugins/photoshop/publish/validate_naming.py index 51e00da352..7734a0e5a0 100644 --- a/pype/plugins/photoshop/publish/validate_naming.py +++ b/pype/plugins/photoshop/publish/validate_naming.py @@ -2,6 +2,8 @@ import pyblish.api import pype.api from avalon import photoshop +from pype.modules.websocket_server.clients.photoshop_client import \ + PhotoshopClientStub class ValidateNamingRepair(pyblish.api.Action): """Repair the instance asset.""" @@ -21,13 +23,14 @@ class ValidateNamingRepair(pyblish.api.Action): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) - + photoshop_client = PhotoshopClientStub() for instance in instances: + self.log.info("validate_naming instance {}".format(instance)) name = instance.data["name"].replace(" ", "_") instance[0].Name = name - data = photoshop.read(instance[0]) + data = photoshop_client.read(instance[0]) data["subset"] = "image" + name - photoshop.imprint(instance[0], data) + photoshop_client.imprint(instance[0], data) return True From 76992b0629c6e99a0fb68e2084516c933bcd6dbe Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 19 Aug 2020 15:13:41 +0200 Subject: [PATCH 062/662] 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 063/662] 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 064/662] 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 fe3cfc24422580c99f837c6bf02de029e80d54a9 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 19 Aug 2020 20:50:14 +0200 Subject: [PATCH 065/662] Added group_selected_layers, get_selected_layers, import_smart_object, replace_smart_object Fixed imprint for performance --- .../clients/photoshop_client.py | 157 ++++++++++++++---- .../websocket_server/websocket_server.py | 6 +- pype/plugins/photoshop/load/load_image.py | 9 +- .../photoshop/publish/collect_instances.py | 6 +- 4 files changed, 138 insertions(+), 40 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index 6d3615e1a4..eea297954f 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -6,18 +6,38 @@ from pype.modules.websocket_server import WebSocketServer import json from collections import namedtuple + class PhotoshopClientStub(): + """ + Stub for calling function on client (Photoshop js) side. + Expects that client is already connected (started when avalon menu + is opened). + """ def __init__(self): self.websocketserver = WebSocketServer.get_instance() self.client = self.websocketserver.get_client() def read(self, layer): + """ + Parses layer metadata from Headline field of active document + :param layer: + :return: + """ layers_data = self._get_layers_metadata() return layers_data.get(str(layer.id)) - def imprint(self, layer, data): + def imprint(self, layer, data, all_layers=None): + """ + Save layer metadata to Headline field of active document + :param layer: Layer("id": XXX, "name":'YYY') + :param data: json representation for single layer + :param all_layers: - for performance, could be + injected for usage in loop, if not, single call will be + triggered + :return: None + """ layers_data = self._get_layers_metadata() # json.dumps writes integer values in a dictionary to string, so # anticipating it here. @@ -27,7 +47,9 @@ class PhotoshopClientStub(): layers_data[str(layer.id)] = data # Ensure only valid ids are stored. - layer_ids = [layer.id for layer in self.get_layers()] + if not all_layers: + all_layers = self.get_layers() + layer_ids = [layer.id for layer in all_layers] cleaned_data = {} for id in layers_data: @@ -36,10 +58,9 @@ class PhotoshopClientStub(): payload = json.dumps(cleaned_data, indent=4) - res = self.websocketserver.call(self.client.call - ('Photoshop.imprint', - payload=payload) - ) + self.websocketserver.call(self.client.call + ('Photoshop.imprint', payload=payload) + ) def get_layers(self): """ @@ -51,20 +72,10 @@ class PhotoshopClientStub(): 'type': 'GUIDE'|'FG'|'BG'|'OBJ' 'visible': 'true'|'false' """ - layers = {} res = self.websocketserver.call(self.client.call ('Photoshop.get_layers')) - print("get_layers:: {}".format(res)) - try: - layers_data = json.loads(res) - except json.decoder.JSONDecodeError: - raise ValueError("Received broken JSON {}".format(res)) - ret = [] - # convert to namedtuple to use dot donation - for d in layers_data: - ret.append(namedtuple('Layer', d.keys())(*d.values())) - return ret + return self._to_records(res) def get_layers_in_layers(self, layers): """ @@ -87,14 +98,35 @@ class PhotoshopClientStub(): return ret + def group_selected_layers(self): + """ + Group selected layers into new layer + :return: + """ + self.websocketserver.call(self.client.call + ('Photoshop.group_selected_layers')) + + def get_selected_layers(self): + """ + Get a list of actually selected layers + :return: + """ + res = self.websocketserver.call(self.client.call + ('Photoshop.get_selected_layers')) + return self._to_records(res) def select_layers(self, layers): + """ + Selecte specified layers in Photoshop + :param layers: + :return: None + """ layer_ids = [layer.id for layer in layers] - res = self.websocketserver.call(self.client.call - ('Photoshop.get_layers', - layers=layer_ids) - ) + self.websocketserver.call(self.client.call + ('Photoshop.get_layers', + layers=layer_ids) + ) def get_active_document_full_name(self): """ @@ -121,25 +153,41 @@ class PhotoshopClientStub(): Saves active document :return: None """ - res = self.websocketserver.call(self.client.call - ('Photoshop.save')) - + self.websocketserver.call(self.client.call + ('Photoshop.save')) def saveAs(self, image_path, ext, as_copy): - res = self.websocketserver.call(self.client.call - ('Photoshop.saveAs', - image_path=image_path, - ext=ext, - as_copy=as_copy)) + """ + Saves active document to psd (copy) or png or jpg + :param image_path: full local path + :param ext: + :param as_copy: + :return: None + """ + self.websocketserver.call(self.client.call + ('Photoshop.saveAs', + image_path=image_path, + ext=ext, + as_copy=as_copy)) def set_visible(self, layer_id, visibility): - print("set_visible {}, {}".format(layer_id, visibility)) - res = self.websocketserver.call(self.client.call - ('Photoshop.set_visible', - layer_id=layer_id, - visibility=visibility)) + """ + Set layer with 'layer_id' to 'visibility' + :param layer_id: + :param visibility: + :return: None + """ + self.websocketserver.call(self.client.call + ('Photoshop.set_visible', + layer_id=layer_id, + visibility=visibility)) def _get_layers_metadata(self): + """ + Reads layers metadata from Headline from active document in PS. + (Headline accessible by File > File Info) + :return: - json documents + """ layers_data = {} res = self.websocketserver.call(self.client.call('Photoshop.read')) try: @@ -148,6 +196,47 @@ class PhotoshopClientStub(): pass return layers_data + def import_smart_object(self, path): + """ + Import the file at `path` as a smart object to active document. + + Args: + path (str): File path to import. + """ + + def replace_smart_object(self, layer, path): + """ + Replace the smart object `layer` with file at `path` + + Args: + layer (namedTuple): Layer("id":XX, "name":"YY"..). + path (str): File to import. + """ + self.websocketserver.call(self.client.call + ('Photoshop.replace_smart_object', + layer=layer, + path=path)) + def close(self): self.client.close() + def _to_records(self, res): + """ + Converts string json representation into list of named tuples for + dot notation access to work. + :return: + :param res: - json representation + """ + try: + layers_data = json.loads(res) + except json.decoder.JSONDecodeError: + raise ValueError("Received broken JSON {}".format(res)) + ret = [] + # convert to namedtuple to use dot donation + for d in layers_data: + ret.append(namedtuple('Layer', d.keys())(*d.values())) + return ret + + + + diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index f9be7c88a9..02fde4d56a 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -96,8 +96,10 @@ class WebSocketServer(): :return: client """ clients = WebSocketAsync.get_clients() - key = list(clients.keys())[0] - client = clients.get(key) + client = None + if len(clients) > 0: + key = list(clients.keys())[0] + client = clients.get(key) return client diff --git a/pype/plugins/photoshop/load/load_image.py b/pype/plugins/photoshop/load/load_image.py index 18efe750d5..0e437b15ba 100644 --- a/pype/plugins/photoshop/load/load_image.py +++ b/pype/plugins/photoshop/load/load_image.py @@ -1,5 +1,10 @@ from avalon import api, photoshop +from pype.modules.websocket_server.clients.photoshop_client \ + import PhotoshopClientStub + +photoshopClient = PhotoshopClientStub() + class ImageLoader(api.Loader): """Load images @@ -28,11 +33,11 @@ class ImageLoader(api.Loader): layer = container.pop("layer") with photoshop.maintained_selection(): - photoshop.replace_smart_object( + photoshopClient.replace_smart_object( layer, api.get_representation_path(representation) ) - photoshop.imprint( + photoshopClient.imprint( layer, {"representation": str(representation["_id"])} ) diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index d94adde00b..f2d1c141fd 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -4,7 +4,9 @@ from avalon import photoshop import pyblish.api -from pype.modules.websocket_server.clients.photoshop_client import PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client \ + import PhotoshopClientStub + class CollectInstances(pyblish.api.ContextPlugin): """Gather instances by LayerSet and file metadata @@ -38,7 +40,7 @@ class CollectInstances(pyblish.api.ContextPlugin): layer_data = photoshop_client.read(layer) self.log.info("layer_data {}".format(layer_data)) - photoshop_client.imprint(layer, layer_data) + photoshop_client.imprint(layer, layer_data, layers) new_layer_data = photoshop_client.read(layer) assert layer_data == new_layer_data From 180035731b329fe617460389bebdc995e79260ab Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 19 Aug 2020 21:10:51 +0200 Subject: [PATCH 066/662] Hound --- .../websocket_server/hosts/photoshop.py | 5 ++-- .../websocket_server/websocket_server.py | 2 +- pype/plugins/photoshop/load/load_image.py | 2 +- .../photoshop/publish/collect_current_file.py | 3 +- .../photoshop/publish/collect_instances.py | 7 +---- .../photoshop/publish/extract_image.py | 4 +-- .../photoshop/publish/extract_review.py | 28 ++----------------- .../photoshop/publish/extract_save_scene.py | 7 ++--- .../photoshop/publish/increment_workfile.py | 4 +-- .../publish/validate_instance_asset.py | 2 -- .../photoshop/publish/validate_naming.py | 3 +- 11 files changed, 17 insertions(+), 50 deletions(-) diff --git a/pype/modules/websocket_server/hosts/photoshop.py b/pype/modules/websocket_server/hosts/photoshop.py index 9092530e48..c63f66865e 100644 --- a/pype/modules/websocket_server/hosts/photoshop.py +++ b/pype/modules/websocket_server/hosts/photoshop.py @@ -1,5 +1,3 @@ -import asyncio - from pype.api import Logger from wsrpc_aiohttp import WebSocketRoute @@ -30,5 +28,6 @@ class Photoshop(WebSocketRoute): # client functions async def read(self): - log.debug("photoshop.read client calls server server calls Photo client") + log.debug("photoshop.read client calls server server calls " + "Photo client") return await self.socket.call('Photoshop.read') diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 02fde4d56a..6b730d4eb3 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -105,7 +105,7 @@ class WebSocketServer(): @staticmethod def get_instance(): - if WebSocketServer._instance == None: + if WebSocketServer._instance is None: WebSocketServer() return WebSocketServer._instance diff --git a/pype/plugins/photoshop/load/load_image.py b/pype/plugins/photoshop/load/load_image.py index 0e437b15ba..a24280553c 100644 --- a/pype/plugins/photoshop/load/load_image.py +++ b/pype/plugins/photoshop/load/load_image.py @@ -1,7 +1,7 @@ from avalon import api, photoshop from pype.modules.websocket_server.clients.photoshop_client \ - import PhotoshopClientStub + import PhotoshopClientStub photoshopClient = PhotoshopClientStub() diff --git a/pype/plugins/photoshop/publish/collect_current_file.py b/pype/plugins/photoshop/publish/collect_current_file.py index bb81718bcc..604ce97f89 100644 --- a/pype/plugins/photoshop/publish/collect_current_file.py +++ b/pype/plugins/photoshop/publish/collect_current_file.py @@ -1,10 +1,9 @@ import os import pyblish.api -from avalon import photoshop from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub + PhotoshopClientStub class CollectCurrentFile(pyblish.api.ContextPlugin): diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index f2d1c141fd..82a0c35311 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -1,11 +1,9 @@ import pythoncom -from avalon import photoshop - import pyblish.api from pype.modules.websocket_server.clients.photoshop_client \ - import PhotoshopClientStub + import PhotoshopClientStub class CollectInstances(pyblish.api.ContextPlugin): @@ -30,9 +28,6 @@ class CollectInstances(pyblish.api.ContextPlugin): # can be. pythoncom.CoInitialize() - from datetime import datetime - start = datetime.now() - # for timing photoshop_client = PhotoshopClientStub() layers = photoshop_client.get_layers() diff --git a/pype/plugins/photoshop/publish/extract_image.py b/pype/plugins/photoshop/publish/extract_image.py index 0451308ef1..4cbac38ce7 100644 --- a/pype/plugins/photoshop/publish/extract_image.py +++ b/pype/plugins/photoshop/publish/extract_image.py @@ -4,7 +4,8 @@ import pype.api from avalon import photoshop from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub + PhotoshopClientStub + class ExtractImage(pype.api.Extractor): """Produce a flattened image file from instance @@ -65,7 +66,6 @@ class ExtractImage(pype.api.Extractor): extension, True) - representations = [] for extension, filename in files.items(): representations.append({ diff --git a/pype/plugins/photoshop/publish/extract_review.py b/pype/plugins/photoshop/publish/extract_review.py index 1c3aeaffb5..1e8d726720 100644 --- a/pype/plugins/photoshop/publish/extract_review.py +++ b/pype/plugins/photoshop/publish/extract_review.py @@ -4,9 +4,8 @@ import pype.api import pype.lib from avalon import photoshop -from datetime import datetime from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub + PhotoshopClientStub class ExtractReview(pype.api.Extractor): @@ -17,7 +16,6 @@ class ExtractReview(pype.api.Extractor): families = ["review"] def process(self, instance): - start = datetime.now() staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) @@ -34,14 +32,10 @@ class ExtractReview(pype.api.Extractor): os.path.splitext(photoshop_client.get_active_document_name())[0] ) output_image_path = os.path.join(staging_dir, output_image) - self.log.info( - "first part took {}".format(datetime.now() - start)) with photoshop.maintained_visibility(): # Hide all other layers. - start = datetime.now() extract_ids = set([ll.id for ll in photoshop_client. - get_layers_in_layers(layers)]) - self.log.info("extract_ids {}".format(extract_ids)) + get_layers_in_layers(layers)]) for layer in photoshop_client.get_layers(): # limit unnecessary calls to client @@ -51,19 +45,11 @@ class ExtractReview(pype.api.Extractor): if not layer.visible and layer.id in extract_ids: photoshop_client.set_visible(layer.id, True) - self.log.info( - "get_layers_in_layers took {}".format(datetime.now() - start)) - start = datetime.now() - - self.log.info("output_image_path {}".format(output_image_path)) photoshop_client.saveAs(output_image_path, 'jpg', True) - self.log.info( - "saveAs {} took {}".format('JPG', datetime.now() - start)) - start = datetime.now() ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") instance.data["representations"].append({ @@ -84,9 +70,6 @@ class ExtractReview(pype.api.Extractor): thumbnail_path ] output = pype.lib._subprocess(args) - self.log.info( - "thumbnail {} took {}".format('JPG', datetime.now() - start)) - self.log.debug(output) instance.data["representations"].append({ "name": "thumbnail", @@ -95,7 +78,6 @@ class ExtractReview(pype.api.Extractor): "stagingDir": staging_dir, "tags": ["thumbnail"] }) - start = datetime.now() # Generate mov. mov_path = os.path.join(staging_dir, "review.mov") args = [ @@ -106,10 +88,7 @@ class ExtractReview(pype.api.Extractor): mov_path ] output = pype.lib._subprocess(args) - self.log.info( - "review {} took {}".format('JPG', datetime.now() - start)) self.log.debug(output) - start = datetime.now() instance.data["representations"].append({ "name": "mov", "ext": "mov", @@ -126,6 +105,5 @@ class ExtractReview(pype.api.Extractor): instance.data["frameStart"] = 1 instance.data["frameEnd"] = 1 instance.data["fps"] = 25 - self.log.info( - "end {} took {}".format('JPG', datetime.now() - start)) + self.log.info(f"Extracted {instance} to {staging_dir}") diff --git a/pype/plugins/photoshop/publish/extract_save_scene.py b/pype/plugins/photoshop/publish/extract_save_scene.py index ea7bdda9af..3357a05f24 100644 --- a/pype/plugins/photoshop/publish/extract_save_scene.py +++ b/pype/plugins/photoshop/publish/extract_save_scene.py @@ -2,9 +2,9 @@ import pype.api from avalon import photoshop from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub + PhotoshopClientStub + -from datetime import datetime class ExtractSaveScene(pype.api.Extractor): """Save scene before extraction.""" @@ -15,7 +15,4 @@ class ExtractSaveScene(pype.api.Extractor): def process(self, instance): photoshop_client = PhotoshopClientStub() - start = datetime.now() photoshop_client.save() - self.log.info( - "ExtractSaveScene took {}".format(datetime.now() - start)) diff --git a/pype/plugins/photoshop/publish/increment_workfile.py b/pype/plugins/photoshop/publish/increment_workfile.py index 0ae7e9772f..4298eb8e77 100644 --- a/pype/plugins/photoshop/publish/increment_workfile.py +++ b/pype/plugins/photoshop/publish/increment_workfile.py @@ -1,10 +1,10 @@ import pyblish.api from pype.action import get_errored_plugins_from_data from pype.lib import version_up -from avalon import photoshop from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub + PhotoshopClientStub + class IncrementWorkfile(pyblish.api.InstancePlugin): """Increment the current workfile. diff --git a/pype/plugins/photoshop/publish/validate_instance_asset.py b/pype/plugins/photoshop/publish/validate_instance_asset.py index 6a0a408878..4bbea69eb4 100644 --- a/pype/plugins/photoshop/publish/validate_instance_asset.py +++ b/pype/plugins/photoshop/publish/validate_instance_asset.py @@ -27,8 +27,6 @@ class ValidateInstanceAssetRepair(pyblish.api.Action): instances = pyblish.api.instances_by_plugin(failed, plugin) photoshop_client = PhotoshopClientStub() for instance in instances: - self.log.info("validate_instance_asset instance[0] {}".format(instance[0])) - self.log.info("validate_instance_asset instance {}".format(instance)) data = photoshop_client.read(instance[0]) data["asset"] = os.environ["AVALON_ASSET"] diff --git a/pype/plugins/photoshop/publish/validate_naming.py b/pype/plugins/photoshop/publish/validate_naming.py index 7734a0e5a0..ba8a3e997e 100644 --- a/pype/plugins/photoshop/publish/validate_naming.py +++ b/pype/plugins/photoshop/publish/validate_naming.py @@ -3,7 +3,8 @@ import pype.api from avalon import photoshop from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub + PhotoshopClientStub + class ValidateNamingRepair(pyblish.api.Action): """Repair the instance asset.""" From 91e65b1f15a3b7b5f795d0e6fbbbc6755a957391 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 20 Aug 2020 00:09:28 +0100 Subject: [PATCH 067/662] 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 068/662] 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 de9aca5f8f3ecdb3e635079c4cbd37c79b1c91a7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 10:52:18 +0200 Subject: [PATCH 069/662] Speedup of collect_instances.py --- .../clients/photoshop_client.py | 25 +++++++++++-------- .../photoshop/publish/collect_instances.py | 14 ++++------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index eea297954f..bf72c1bc5a 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -18,17 +18,19 @@ class PhotoshopClientStub(): self.websocketserver = WebSocketServer.get_instance() self.client = self.websocketserver.get_client() - def read(self, layer): + def read(self, layer, layers_meta=None): """ Parses layer metadata from Headline field of active document - :param layer: + :param layer: Layer("id": XXX, "name":'YYY') @@ -38,13 +40,14 @@ class PhotoshopClientStub(): triggered :return: None """ - layers_data = self._get_layers_metadata() + if not layers_meta: + layers_meta = self._get_layers_metadata() # json.dumps writes integer values in a dictionary to string, so # anticipating it here. - if str(layer.id) in layers_data: - layers_data[str(layer.id)].update(data) + if str(layer.id) in layers_meta and layers_meta[str(layer.id)]: + layers_meta[str(layer.id)].update(data) else: - layers_data[str(layer.id)] = data + layers_meta[str(layer.id)] = data # Ensure only valid ids are stored. if not all_layers: @@ -52,9 +55,9 @@ class PhotoshopClientStub(): layer_ids = [layer.id for layer in all_layers] cleaned_data = {} - for id in layers_data: + for id in layers_meta: if int(id) in layer_ids: - cleaned_data[id] = layers_data[id] + cleaned_data[id] = layers_meta[id] payload = json.dumps(cleaned_data, indent=4) diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index 82a0c35311..47584272d2 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -2,8 +2,9 @@ import pythoncom import pyblish.api -from pype.modules.websocket_server.clients.photoshop_client \ - import PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class CollectInstances(pyblish.api.ContextPlugin): @@ -30,14 +31,9 @@ class CollectInstances(pyblish.api.ContextPlugin): photoshop_client = PhotoshopClientStub() layers = photoshop_client.get_layers() - + layers_meta = photoshop_client._get_layers_metadata() for layer in layers: - layer_data = photoshop_client.read(layer) - self.log.info("layer_data {}".format(layer_data)) - - photoshop_client.imprint(layer, layer_data, layers) - new_layer_data = photoshop_client.read(layer) - assert layer_data == new_layer_data + layer_data = photoshop_client.read(layer, layers_meta) # Skip layers without metadata. if layer_data is None: From e551039c124cfe82252479dcf6b506aac17cd31d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 15:42:43 +0200 Subject: [PATCH 070/662] Speedup of collect_instances.py --- .../websocket_server/clients/photoshop_client.py | 13 ++++++++----- pype/plugins/photoshop/publish/extract_review.py | 7 ++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index bf72c1bc5a..00e5355786 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -91,14 +91,17 @@ class PhotoshopClientStub(): print("get_layers_in_layers len {}".format(len(layers))) print("get_layers_in_layers type {}".format(type(layers))) ret = [] - layer_ids = [lay.id for lay in layers] - layer_group_ids = [ll.groupId for ll in layers if ll.group] + parent_ids = set([lay.id for lay in layers]) + print("parent_ids ".format(parent_ids)) for layer in all_layers: - if layer.groupId in layer_group_ids: # all from group + print("layer {}".format(layer)) + parents = set(layer.parents) + print("parents {}".format(layer)) + if len(parent_ids & parents) > 0: ret.append(layer) - if layer.id in layer_ids: + if layer.id in parent_ids: ret.append(layer) - + print("ret {}".format(ret)) return ret def group_selected_layers(self): diff --git a/pype/plugins/photoshop/publish/extract_review.py b/pype/plugins/photoshop/publish/extract_review.py index 1e8d726720..806b59341b 100644 --- a/pype/plugins/photoshop/publish/extract_review.py +++ b/pype/plugins/photoshop/publish/extract_review.py @@ -4,8 +4,9 @@ import pype.api import pype.lib from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class ExtractReview(pype.api.Extractor): @@ -36,7 +37,7 @@ class ExtractReview(pype.api.Extractor): # Hide all other layers. extract_ids = set([ll.id for ll in photoshop_client. get_layers_in_layers(layers)]) - + self.log.info("extract_ids {}".format(extract_ids)) for layer in photoshop_client.get_layers(): # limit unnecessary calls to client if layer.visible and layer.id not in extract_ids: From 41e2149d1295d5f89363648bd64da9cd11ec9f5c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 17:15:36 +0200 Subject: [PATCH 071/662] Fix select correct layers for multiple images --- .../clients/photoshop_client.py | 29 ++++++++----------- .../photoshop/publish/collect_instances.py | 2 +- .../photoshop/publish/extract_image.py | 13 +++------ 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index 00e5355786..330c2ceff0 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -26,7 +26,7 @@ class PhotoshopClientStub(): :return: """ if layers_meta is None: - layers_meta = self._get_layers_metadata() + layers_meta = self.get_layers_metadata() return layers_meta.get(str(layer.id)) @@ -38,10 +38,13 @@ class PhotoshopClientStub(): :param all_layers: - for performance, could be injected for usage in loop, if not, single call will be triggered + :param layers_meta: json representation from Headline + (for performance - provide only if imprint is in + loop - value should be same) :return: None """ if not layers_meta: - layers_meta = self._get_layers_metadata() + layers_meta = self.get_layers_metadata() # json.dumps writes integer values in a dictionary to string, so # anticipating it here. if str(layer.id) in layers_meta and layers_meta[str(layer.id)]: @@ -83,25 +86,20 @@ class PhotoshopClientStub(): def get_layers_in_layers(self, layers): """ Return all layers that belong to layers (might be groups). - :param layers: - :return: + :param layers: + :return: """ all_layers = self.get_layers() - print("get_layers_in_layers {}".format(layers)) - print("get_layers_in_layers len {}".format(len(layers))) - print("get_layers_in_layers type {}".format(type(layers))) ret = [] parent_ids = set([lay.id for lay in layers]) - print("parent_ids ".format(parent_ids)) + for layer in all_layers: - print("layer {}".format(layer)) parents = set(layer.parents) - print("parents {}".format(layer)) if len(parent_ids & parents) > 0: ret.append(layer) if layer.id in parent_ids: ret.append(layer) - print("ret {}".format(ret)) + return ret def group_selected_layers(self): @@ -140,7 +138,8 @@ class PhotoshopClientStub(): :return: full path with name """ res = self.websocketserver.call( - self.client.call('Photoshop.get_active_document_full_name')) + self.client.call + ('Photoshop.get_active_document_full_name')) return res @@ -188,7 +187,7 @@ class PhotoshopClientStub(): layer_id=layer_id, visibility=visibility)) - def _get_layers_metadata(self): + def get_layers_metadata(self): """ Reads layers metadata from Headline from active document in PS. (Headline accessible by File > File Info) @@ -242,7 +241,3 @@ class PhotoshopClientStub(): for d in layers_data: ret.append(namedtuple('Layer', d.keys())(*d.values())) return ret - - - - diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index 47584272d2..7e433bc92f 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -31,7 +31,7 @@ class CollectInstances(pyblish.api.ContextPlugin): photoshop_client = PhotoshopClientStub() layers = photoshop_client.get_layers() - layers_meta = photoshop_client._get_layers_metadata() + layers_meta = photoshop_client.get_layers_metadata() for layer in layers: layer_data = photoshop_client.read(layer, layers_meta) diff --git a/pype/plugins/photoshop/publish/extract_image.py b/pype/plugins/photoshop/publish/extract_image.py index 4cbac38ce7..e32444c641 100644 --- a/pype/plugins/photoshop/publish/extract_image.py +++ b/pype/plugins/photoshop/publish/extract_image.py @@ -3,8 +3,9 @@ import os import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class ExtractImage(pype.api.Extractor): @@ -23,12 +24,6 @@ class ExtractImage(pype.api.Extractor): staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) - layers = [] - for image_instance in instance.context: - if image_instance.data["family"] != "image": - continue - layers.append(image_instance[0]) - # Perform extraction photoshop_client = PhotoshopClientStub() files = {} @@ -37,7 +32,7 @@ class ExtractImage(pype.api.Extractor): with photoshop.maintained_visibility(): # Hide all other layers. extract_ids = set([ll.id for ll in photoshop_client. - get_layers_in_layers(layers)]) + get_layers_in_layers([instance[0]])]) for layer in photoshop_client.get_layers(): # limit unnecessary calls to client From dce5de49380c618b89cf899424e356e7bfe82c90 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 17:31:20 +0200 Subject: [PATCH 072/662] Finish loader --- pype/modules/websocket_server/clients/photoshop_client.py | 3 +++ pype/plugins/photoshop/load/load_image.py | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index 330c2ceff0..a81870a4ee 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -208,6 +208,9 @@ class PhotoshopClientStub(): Args: path (str): File path to import. """ + self.websocketserver.call(self.client.call + ('Photoshop.import_smart_object', + path=path)) def replace_smart_object(self, layer, path): """ diff --git a/pype/plugins/photoshop/load/load_image.py b/pype/plugins/photoshop/load/load_image.py index a24280553c..1856155b2a 100644 --- a/pype/plugins/photoshop/load/load_image.py +++ b/pype/plugins/photoshop/load/load_image.py @@ -1,7 +1,8 @@ from avalon import api, photoshop -from pype.modules.websocket_server.clients.photoshop_client \ - import PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) photoshopClient = PhotoshopClientStub() @@ -17,7 +18,7 @@ class ImageLoader(api.Loader): def load(self, context, name=None, namespace=None, data=None): with photoshop.maintained_selection(): - layer = photoshop.import_smart_object(self.fname) + layer = photoshopClient.import_smart_object(self.fname) self[:] = [layer] From fc2018e22b5a3e69a34577b123c07b7d522254c4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 20:12:03 +0200 Subject: [PATCH 073/662] Finished Creator --- .../clients/photoshop_client.py | 27 +++++++++++++--- pype/plugins/photoshop/create/create_image.py | 32 ++++++++++--------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/clients/photoshop_client.py index a81870a4ee..4f0bca99cc 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/clients/photoshop_client.py @@ -102,13 +102,28 @@ class PhotoshopClientStub(): return ret - def group_selected_layers(self): + def create_group(self, name): """ - Group selected layers into new layer - :return: + Create new group (eg. LayerSet) + :return: """ - self.websocketserver.call(self.client.call - ('Photoshop.group_selected_layers')) + ret = self.websocketserver.call(self.client.call + ('Photoshop.create_group', + name=name)) + # create group on PS is asynchronous, returns only id + layer = {"id": ret, "name": name, "group": True} + return namedtuple('Layer', layer.keys())(*layer.values()) + + def group_selected_layers(self, name): + """ + Group selected layers into new LayerSet (eg. group) + :return: + """ + res = self.websocketserver.call(self.client.call + ('Photoshop.group_selected_layers', + name=name) + ) + return self._to_records(res) def get_selected_layers(self): """ @@ -241,6 +256,8 @@ class PhotoshopClientStub(): raise ValueError("Received broken JSON {}".format(res)) ret = [] # convert to namedtuple to use dot donation + if isinstance(layers_data, dict): # TODO refactore + layers_data = [layers_data] for d in layers_data: ret.append(namedtuple('Layer', d.keys())(*d.values())) return ret diff --git a/pype/plugins/photoshop/create/create_image.py b/pype/plugins/photoshop/create/create_image.py index 5b2f9f7981..6b54b2a036 100644 --- a/pype/plugins/photoshop/create/create_image.py +++ b/pype/plugins/photoshop/create/create_image.py @@ -1,5 +1,8 @@ -from avalon import api, photoshop +from avalon import api from avalon.vendor import Qt +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class CreateImage(api.Creator): @@ -13,11 +16,12 @@ class CreateImage(api.Creator): groups = [] layers = [] create_group = False - group_constant = photoshop.get_com_objects().constants().psLayerSet + + photoshopClient = PhotoshopClientStub() if (self.options or {}).get("useSelection"): multiple_instances = False - selection = photoshop.get_selected_layers() - + selection = photoshopClient.get_selected_layers() + self.log.info("selection {}".format(selection)) if len(selection) > 1: # Ask user whether to create one image or image per selected # item. @@ -40,19 +44,19 @@ class CreateImage(api.Creator): if multiple_instances: for item in selection: - if item.LayerType == group_constant: + if item.group: groups.append(item) else: layers.append(item) else: - group = photoshop.group_selected_layers() - group.Name = self.name + group = photoshopClient.group_selected_layers() + group.name = self.name groups.append(group) elif len(selection) == 1: # One selected item. Use group if its a LayerSet (group), else # create a new group. - if selection[0].LayerType == group_constant: + if selection[0].group: groups.append(selection[0]) else: layers.append(selection[0]) @@ -63,16 +67,14 @@ class CreateImage(api.Creator): create_group = True if create_group: - group = photoshop.app().ActiveDocument.LayerSets.Add() - group.Name = self.name + group = photoshopClient.create_group(self.name) groups.append(group) for layer in layers: - photoshop.select_layers([layer]) - group = photoshop.group_selected_layers() - group.Name = layer.Name + photoshopClient.select_layers([layer]) + group = photoshopClient.group_selected_layers(layer.name) groups.append(group) for group in groups: - self.data.update({"subset": "image" + group.Name}) - photoshop.imprint(group, self.data) + self.data.update({"subset": "image" + group.name}) + photoshopClient.imprint(group, self.data) From 4fb557c8376ed44280e1a73f50ba10a5c2e0d1e1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 20:15:09 +0200 Subject: [PATCH 074/662] Hound --- pype/plugins/photoshop/publish/collect_current_file.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/plugins/photoshop/publish/collect_current_file.py b/pype/plugins/photoshop/publish/collect_current_file.py index 604ce97f89..7877caa137 100644 --- a/pype/plugins/photoshop/publish/collect_current_file.py +++ b/pype/plugins/photoshop/publish/collect_current_file.py @@ -2,8 +2,9 @@ import os import pyblish.api -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class CollectCurrentFile(pyblish.api.ContextPlugin): From 7f5fc953ce98167b5f70127d6eb0506ec2d05cd3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 20 Aug 2020 20:15:09 +0200 Subject: [PATCH 075/662] Hound --- pype/plugins/photoshop/publish/collect_current_file.py | 5 +++-- pype/plugins/photoshop/publish/extract_save_scene.py | 5 +++-- pype/plugins/photoshop/publish/increment_workfile.py | 5 +++-- pype/plugins/photoshop/publish/validate_instance_asset.py | 6 ++++-- pype/plugins/photoshop/publish/validate_naming.py | 5 +++-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pype/plugins/photoshop/publish/collect_current_file.py b/pype/plugins/photoshop/publish/collect_current_file.py index 604ce97f89..7877caa137 100644 --- a/pype/plugins/photoshop/publish/collect_current_file.py +++ b/pype/plugins/photoshop/publish/collect_current_file.py @@ -2,8 +2,9 @@ import os import pyblish.api -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class CollectCurrentFile(pyblish.api.ContextPlugin): diff --git a/pype/plugins/photoshop/publish/extract_save_scene.py b/pype/plugins/photoshop/publish/extract_save_scene.py index 3357a05f24..c56e5418c9 100644 --- a/pype/plugins/photoshop/publish/extract_save_scene.py +++ b/pype/plugins/photoshop/publish/extract_save_scene.py @@ -1,8 +1,9 @@ import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class ExtractSaveScene(pype.api.Extractor): diff --git a/pype/plugins/photoshop/publish/increment_workfile.py b/pype/plugins/photoshop/publish/increment_workfile.py index 4298eb8e77..af8ba0b6ae 100644 --- a/pype/plugins/photoshop/publish/increment_workfile.py +++ b/pype/plugins/photoshop/publish/increment_workfile.py @@ -2,8 +2,9 @@ import pyblish.api from pype.action import get_errored_plugins_from_data from pype.lib import version_up -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class IncrementWorkfile(pyblish.api.InstancePlugin): diff --git a/pype/plugins/photoshop/publish/validate_instance_asset.py b/pype/plugins/photoshop/publish/validate_instance_asset.py index 4bbea69eb4..aa8d2661ff 100644 --- a/pype/plugins/photoshop/publish/validate_instance_asset.py +++ b/pype/plugins/photoshop/publish/validate_instance_asset.py @@ -4,8 +4,10 @@ import pyblish.api import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) + class ValidateInstanceAssetRepair(pyblish.api.Action): """Repair the instance asset.""" diff --git a/pype/plugins/photoshop/publish/validate_naming.py b/pype/plugins/photoshop/publish/validate_naming.py index ba8a3e997e..c612270802 100644 --- a/pype/plugins/photoshop/publish/validate_naming.py +++ b/pype/plugins/photoshop/publish/validate_naming.py @@ -2,8 +2,9 @@ import pyblish.api import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import \ - PhotoshopClientStub +from pype.modules.websocket_server.clients.photoshop_client import ( + PhotoshopClientStub +) class ValidateNamingRepair(pyblish.api.Action): From 690bb9f8b16b85c36616ae0031a39874322827c5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 21 Aug 2020 10:54:38 +0200 Subject: [PATCH 076/662] Fix missed providing name to group_selected_layers --- pype/plugins/photoshop/create/create_image.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pype/plugins/photoshop/create/create_image.py b/pype/plugins/photoshop/create/create_image.py index 6b54b2a036..0a019fe2f8 100644 --- a/pype/plugins/photoshop/create/create_image.py +++ b/pype/plugins/photoshop/create/create_image.py @@ -49,8 +49,7 @@ class CreateImage(api.Creator): else: layers.append(item) else: - group = photoshopClient.group_selected_layers() - group.name = self.name + group = photoshopClient.group_selected_layers(self.name) groups.append(group) elif len(selection) == 1: From b855038889b8b7ccb7e0e3cc849f7f896297c5a5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 12:56:14 +0200 Subject: [PATCH 077/662] 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 078/662] 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 079/662] 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 f8743e3b80dedfb37da392fd4c7108e5680ae2f6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 21 Aug 2020 15:23:35 +0200 Subject: [PATCH 080/662] Removed usage of http_server --- .../websocket_server/hosts/photoshop.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pype/modules/websocket_server/hosts/photoshop.py b/pype/modules/websocket_server/hosts/photoshop.py index c63f66865e..ae72963b1b 100644 --- a/pype/modules/websocket_server/hosts/photoshop.py +++ b/pype/modules/websocket_server/hosts/photoshop.py @@ -1,5 +1,8 @@ from pype.api import Logger from wsrpc_aiohttp import WebSocketRoute +import functools + +import avalon.photoshop as photoshop log = Logger().get_logger("WebsocketServer") @@ -31,3 +34,31 @@ class Photoshop(WebSocketRoute): log.debug("photoshop.read client calls server server calls " "Photo client") return await self.socket.call('Photoshop.read') + + # panel routes for tools + async def creator_route(self): + self._tool_route("creator") + + async def workfiles_route(self): + self._tool_route("workfiles") + + async def loader_route(self): + self._tool_route("loader") + + async def publish_route(self): + self._tool_route("publish") + + async def sceneinventory_route(self): + self._tool_route("sceneinventory") + + async def projectmanager_route(self): + self._tool_route("projectmanager") + + def _tool_route(self, tool_name): + """The address accessed when clicking on the buttons.""" + partial_method = functools.partial(photoshop.show, tool_name) + + photoshop.execute_in_main_thread(partial_method) + + # Required return statement. + return "nothing" \ No newline at end of file From f8492befdfe8b4a0c5f73139f61a046ec1fac645 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 15:38:09 +0200 Subject: [PATCH 081/662] 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 082/662] 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 083/662] 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 084/662] 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 085/662] 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 086/662] 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 087/662] 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 088/662] 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 089/662] 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 1ac12eadb2d3e2a4c0530e830e195c30e4cf9970 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 21 Aug 2020 17:38:03 +0200 Subject: [PATCH 090/662] 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 091/662] 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 092/662] 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 093/662] 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 094/662] _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 095/662] 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 096/662] 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 097/662] 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 098/662] 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 099/662] 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 100/662] 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 a5e6979a86009d56a52a7ccf41651e4a51277dac Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 10:52:52 +0200 Subject: [PATCH 101/662] 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 102/662] 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 103/662] 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 104/662] 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 105/662] 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 106/662] 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 107/662] 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 108/662] 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 109/662] 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 110/662] 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 111/662] 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 112/662] 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 113/662] 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 114/662] 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 115/662] 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 116/662] 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 117/662] 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 f31fb3e03426830a1e1b3d10502230e453fa9e6f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 24 Aug 2020 17:44:16 +0200 Subject: [PATCH 118/662] Removed com32 objects Refactore - changed names to highlight 'stub' approach Small fixes --- .../photoshop_server_stub.py} | 35 +++++++++++++++---- pype/plugins/photoshop/create/create_image.py | 18 +++++----- pype/plugins/photoshop/load/load_image.py | 12 +++---- .../photoshop/publish/collect_current_file.py | 7 ++-- .../photoshop/publish/collect_instances.py | 12 +++---- .../photoshop/publish/extract_image.py | 22 ++++-------- .../photoshop/publish/extract_review.py | 22 ++++-------- .../photoshop/publish/extract_save_scene.py | 7 +--- .../photoshop/publish/increment_workfile.py | 7 ++-- .../publish/validate_instance_asset.py | 10 ++---- .../photoshop/publish/validate_naming.py | 10 ++---- 11 files changed, 70 insertions(+), 92 deletions(-) rename pype/modules/websocket_server/{clients/photoshop_client.py => stubs/photoshop_server_stub.py} (89%) diff --git a/pype/modules/websocket_server/clients/photoshop_client.py b/pype/modules/websocket_server/stubs/photoshop_server_stub.py similarity index 89% rename from pype/modules/websocket_server/clients/photoshop_client.py rename to pype/modules/websocket_server/stubs/photoshop_server_stub.py index 4f0bca99cc..f798a09b92 100644 --- a/pype/modules/websocket_server/clients/photoshop_client.py +++ b/pype/modules/websocket_server/stubs/photoshop_server_stub.py @@ -7,17 +7,28 @@ import json from collections import namedtuple -class PhotoshopClientStub(): +class PhotoshopServerStub(): """ Stub for calling function on client (Photoshop js) side. Expects that client is already connected (started when avalon menu is opened). + 'self.websocketserver.call' is used as async wrapper """ def __init__(self): self.websocketserver = WebSocketServer.get_instance() self.client = self.websocketserver.get_client() + def open(self, path): + """ + Open file located at 'path' (local). + :param path: file path locally + :return: None + """ + self.websocketserver.call(self.client.call + ('Photoshop.open', path=path) + ) + def read(self, layer, layers_meta=None): """ Parses layer metadata from Headline field of active document @@ -107,9 +118,9 @@ class PhotoshopClientStub(): Create new group (eg. LayerSet) :return: """ - ret = self.websocketserver.call(self.client.call - ('Photoshop.create_group', - name=name)) + ret = self.websocketserver.call(self.client.call + ('Photoshop.create_group', + name=name)) # create group on PS is asynchronous, returns only id layer = {"id": ret, "name": name, "group": True} return namedtuple('Layer', layer.keys())(*layer.values()) @@ -168,6 +179,14 @@ class PhotoshopClientStub(): return res + def is_saved(self): + """ + Returns true if no changes in active document + :return: + """ + return self.websocketserver.call(self.client.call + ('Photoshop.is_saved')) + def save(self): """ Saves active document @@ -223,9 +242,11 @@ class PhotoshopClientStub(): Args: path (str): File path to import. """ - self.websocketserver.call(self.client.call - ('Photoshop.import_smart_object', - path=path)) + res = self.websocketserver.call(self.client.call + ('Photoshop.import_smart_object', + path=path)) + + return self._to_records(res).pop() def replace_smart_object(self, layer, path): """ diff --git a/pype/plugins/photoshop/create/create_image.py b/pype/plugins/photoshop/create/create_image.py index 0a019fe2f8..c1a7d92a2c 100644 --- a/pype/plugins/photoshop/create/create_image.py +++ b/pype/plugins/photoshop/create/create_image.py @@ -1,8 +1,6 @@ from avalon import api from avalon.vendor import Qt -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) +from avalon import photoshop class CreateImage(api.Creator): @@ -17,10 +15,10 @@ class CreateImage(api.Creator): layers = [] create_group = False - photoshopClient = PhotoshopClientStub() + stub = photoshop.stub() if (self.options or {}).get("useSelection"): multiple_instances = False - selection = photoshopClient.get_selected_layers() + selection = stub.get_selected_layers() self.log.info("selection {}".format(selection)) if len(selection) > 1: # Ask user whether to create one image or image per selected @@ -49,7 +47,7 @@ class CreateImage(api.Creator): else: layers.append(item) else: - group = photoshopClient.group_selected_layers(self.name) + group = stub.group_selected_layers(self.name) groups.append(group) elif len(selection) == 1: @@ -66,14 +64,14 @@ class CreateImage(api.Creator): create_group = True if create_group: - group = photoshopClient.create_group(self.name) + group = stub.create_group(self.name) groups.append(group) for layer in layers: - photoshopClient.select_layers([layer]) - group = photoshopClient.group_selected_layers(layer.name) + stub.select_layers([layer]) + group = stub.group_selected_layers(layer.name) groups.append(group) for group in groups: self.data.update({"subset": "image" + group.name}) - photoshopClient.imprint(group, self.data) + stub.imprint(group, self.data) diff --git a/pype/plugins/photoshop/load/load_image.py b/pype/plugins/photoshop/load/load_image.py index 1856155b2a..75c02bb327 100644 --- a/pype/plugins/photoshop/load/load_image.py +++ b/pype/plugins/photoshop/load/load_image.py @@ -1,10 +1,6 @@ from avalon import api, photoshop -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) - -photoshopClient = PhotoshopClientStub() +stub = photoshop.stub() class ImageLoader(api.Loader): @@ -18,7 +14,7 @@ class ImageLoader(api.Loader): def load(self, context, name=None, namespace=None, data=None): with photoshop.maintained_selection(): - layer = photoshopClient.import_smart_object(self.fname) + layer = stub.import_smart_object(self.fname) self[:] = [layer] @@ -34,11 +30,11 @@ class ImageLoader(api.Loader): layer = container.pop("layer") with photoshop.maintained_selection(): - photoshopClient.replace_smart_object( + stub.replace_smart_object( layer, api.get_representation_path(representation) ) - photoshopClient.imprint( + stub.imprint( layer, {"representation": str(representation["_id"])} ) diff --git a/pype/plugins/photoshop/publish/collect_current_file.py b/pype/plugins/photoshop/publish/collect_current_file.py index 7877caa137..3cc3e3f636 100644 --- a/pype/plugins/photoshop/publish/collect_current_file.py +++ b/pype/plugins/photoshop/publish/collect_current_file.py @@ -2,9 +2,7 @@ import os import pyblish.api -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) +from avalon import photoshop class CollectCurrentFile(pyblish.api.ContextPlugin): @@ -15,7 +13,6 @@ class CollectCurrentFile(pyblish.api.ContextPlugin): hosts = ["photoshop"] def process(self, context): - photoshop_client = PhotoshopClientStub() context.data["currentFile"] = os.path.normpath( - photoshop_client.get_active_document_full_name() + photoshop.stub().get_active_document_full_name() ).replace("\\", "/") diff --git a/pype/plugins/photoshop/publish/collect_instances.py b/pype/plugins/photoshop/publish/collect_instances.py index 7e433bc92f..81d1c80bf6 100644 --- a/pype/plugins/photoshop/publish/collect_instances.py +++ b/pype/plugins/photoshop/publish/collect_instances.py @@ -2,9 +2,7 @@ import pythoncom import pyblish.api -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) +from avalon import photoshop class CollectInstances(pyblish.api.ContextPlugin): @@ -29,11 +27,11 @@ class CollectInstances(pyblish.api.ContextPlugin): # can be. pythoncom.CoInitialize() - photoshop_client = PhotoshopClientStub() - layers = photoshop_client.get_layers() - layers_meta = photoshop_client.get_layers_metadata() + stub = photoshop.stub() + layers = stub.get_layers() + layers_meta = stub.get_layers_metadata() for layer in layers: - layer_data = photoshop_client.read(layer, layers_meta) + layer_data = stub.read(layer, layers_meta) # Skip layers without metadata. if layer_data is None: diff --git a/pype/plugins/photoshop/publish/extract_image.py b/pype/plugins/photoshop/publish/extract_image.py index e32444c641..38920b5557 100644 --- a/pype/plugins/photoshop/publish/extract_image.py +++ b/pype/plugins/photoshop/publish/extract_image.py @@ -3,10 +3,6 @@ import os import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) - class ExtractImage(pype.api.Extractor): """Produce a flattened image file from instance @@ -25,23 +21,21 @@ class ExtractImage(pype.api.Extractor): self.log.info("Outputting image to {}".format(staging_dir)) # Perform extraction - photoshop_client = PhotoshopClientStub() + stub = photoshop.stub() files = {} with photoshop.maintained_selection(): self.log.info("Extracting %s" % str(list(instance))) with photoshop.maintained_visibility(): # Hide all other layers. - extract_ids = set([ll.id for ll in photoshop_client. + extract_ids = set([ll.id for ll in stub. get_layers_in_layers([instance[0]])]) - for layer in photoshop_client.get_layers(): + for layer in stub.get_layers(): # limit unnecessary calls to client if layer.visible and layer.id not in extract_ids: - photoshop_client.set_visible(layer.id, - False) + stub.set_visible(layer.id, False) if not layer.visible and layer.id in extract_ids: - photoshop_client.set_visible(layer.id, - True) + stub.set_visible(layer.id, True) save_options = [] if "png" in self.formats: @@ -50,16 +44,14 @@ class ExtractImage(pype.api.Extractor): save_options.append('jpg') file_basename = os.path.splitext( - photoshop_client.get_active_document_name() + stub.get_active_document_name() )[0] for extension in save_options: _filename = "{}.{}".format(file_basename, extension) files[extension] = _filename full_filename = os.path.join(staging_dir, _filename) - photoshop_client.saveAs(full_filename, - extension, - True) + stub.saveAs(full_filename, extension, True) representations = [] for extension, filename in files.items(): diff --git a/pype/plugins/photoshop/publish/extract_review.py b/pype/plugins/photoshop/publish/extract_review.py index 806b59341b..6fb50bba9f 100644 --- a/pype/plugins/photoshop/publish/extract_review.py +++ b/pype/plugins/photoshop/publish/extract_review.py @@ -4,10 +4,6 @@ import pype.api import pype.lib from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) - class ExtractReview(pype.api.Extractor): """Produce a flattened image file from all instances.""" @@ -20,7 +16,7 @@ class ExtractReview(pype.api.Extractor): staging_dir = self.staging_dir(instance) self.log.info("Outputting image to {}".format(staging_dir)) - photoshop_client = PhotoshopClientStub() + stub = photoshop.stub() layers = [] for image_instance in instance.context: @@ -30,26 +26,22 @@ class ExtractReview(pype.api.Extractor): # Perform extraction output_image = "{}.jpg".format( - os.path.splitext(photoshop_client.get_active_document_name())[0] + os.path.splitext(stub.get_active_document_name())[0] ) output_image_path = os.path.join(staging_dir, output_image) with photoshop.maintained_visibility(): # Hide all other layers. - extract_ids = set([ll.id for ll in photoshop_client. + extract_ids = set([ll.id for ll in stub. get_layers_in_layers(layers)]) self.log.info("extract_ids {}".format(extract_ids)) - for layer in photoshop_client.get_layers(): + for layer in stub.get_layers(): # limit unnecessary calls to client if layer.visible and layer.id not in extract_ids: - photoshop_client.set_visible(layer.id, - False) + stub.set_visible(layer.id, False) if not layer.visible and layer.id in extract_ids: - photoshop_client.set_visible(layer.id, - True) + stub.set_visible(layer.id, True) - photoshop_client.saveAs(output_image_path, - 'jpg', - True) + stub.saveAs(output_image_path, 'jpg', True) ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg") diff --git a/pype/plugins/photoshop/publish/extract_save_scene.py b/pype/plugins/photoshop/publish/extract_save_scene.py index c56e5418c9..63a4b7b7ea 100644 --- a/pype/plugins/photoshop/publish/extract_save_scene.py +++ b/pype/plugins/photoshop/publish/extract_save_scene.py @@ -1,10 +1,6 @@ import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) - class ExtractSaveScene(pype.api.Extractor): """Save scene before extraction.""" @@ -15,5 +11,4 @@ class ExtractSaveScene(pype.api.Extractor): families = ["workfile"] def process(self, instance): - photoshop_client = PhotoshopClientStub() - photoshop_client.save() + photoshop.stub().save() diff --git a/pype/plugins/photoshop/publish/increment_workfile.py b/pype/plugins/photoshop/publish/increment_workfile.py index af8ba0b6ae..eca2583595 100644 --- a/pype/plugins/photoshop/publish/increment_workfile.py +++ b/pype/plugins/photoshop/publish/increment_workfile.py @@ -2,9 +2,7 @@ import pyblish.api from pype.action import get_errored_plugins_from_data from pype.lib import version_up -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) +from avalon import photoshop class IncrementWorkfile(pyblish.api.InstancePlugin): @@ -27,7 +25,6 @@ class IncrementWorkfile(pyblish.api.InstancePlugin): ) scene_path = version_up(instance.context.data["currentFile"]) - photoshop_client = PhotoshopClientStub() - photoshop_client.saveAs(scene_path, 'psd', True) + photoshop.stub().saveAs(scene_path, 'psd', True) self.log.info("Incremented workfile to: {}".format(scene_path)) diff --git a/pype/plugins/photoshop/publish/validate_instance_asset.py b/pype/plugins/photoshop/publish/validate_instance_asset.py index aa8d2661ff..f05d9601dd 100644 --- a/pype/plugins/photoshop/publish/validate_instance_asset.py +++ b/pype/plugins/photoshop/publish/validate_instance_asset.py @@ -4,10 +4,6 @@ import pyblish.api import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) - class ValidateInstanceAssetRepair(pyblish.api.Action): """Repair the instance asset.""" @@ -27,12 +23,12 @@ class ValidateInstanceAssetRepair(pyblish.api.Action): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) - photoshop_client = PhotoshopClientStub() + stub = photoshop.stub() for instance in instances: - data = photoshop_client.read(instance[0]) + data = stub.read(instance[0]) data["asset"] = os.environ["AVALON_ASSET"] - photoshop_client.imprint(instance[0], data) + stub.imprint(instance[0], data) class ValidateInstanceAsset(pyblish.api.InstancePlugin): diff --git a/pype/plugins/photoshop/publish/validate_naming.py b/pype/plugins/photoshop/publish/validate_naming.py index c612270802..2483adcb5e 100644 --- a/pype/plugins/photoshop/publish/validate_naming.py +++ b/pype/plugins/photoshop/publish/validate_naming.py @@ -2,10 +2,6 @@ import pyblish.api import pype.api from avalon import photoshop -from pype.modules.websocket_server.clients.photoshop_client import ( - PhotoshopClientStub -) - class ValidateNamingRepair(pyblish.api.Action): """Repair the instance asset.""" @@ -25,14 +21,14 @@ class ValidateNamingRepair(pyblish.api.Action): # Apply pyblish.logic to get the instances for the plug-in instances = pyblish.api.instances_by_plugin(failed, plugin) - photoshop_client = PhotoshopClientStub() + stub = photoshop.stub() for instance in instances: self.log.info("validate_naming instance {}".format(instance)) name = instance.data["name"].replace(" ", "_") instance[0].Name = name - data = photoshop_client.read(instance[0]) + data = stub.read(instance[0]) data["subset"] = "image" + name - photoshop_client.imprint(instance[0], data) + stub.imprint(instance[0], data) return True From dbd50e0ad24e76f9c15a429f43620f0439c37031 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 24 Aug 2020 18:59:51 +0200 Subject: [PATCH 119/662] 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 120/662] 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 121/662] 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 122/662] 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 123/662] 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 e35ef732b84f8d7e9603dc50c7aca70e3b957920 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 10:49:02 +0200 Subject: [PATCH 124/662] 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 125/662] 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 126/662] 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 127/662] 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 128/662] 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 129/662] 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 130/662] 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 509776ddc074af2571716308a2eb7fea5ee9d8b3 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 25 Aug 2020 11:16:07 +0100 Subject: [PATCH 131/662] Optional camera creation on image plane loading. --- pype/plugins/maya/load/load_image_plane.py | 38 +++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/pype/plugins/maya/load/load_image_plane.py b/pype/plugins/maya/load/load_image_plane.py index 08f7c99156..7ec56aab3a 100644 --- a/pype/plugins/maya/load/load_image_plane.py +++ b/pype/plugins/maya/load/load_image_plane.py @@ -29,6 +29,8 @@ class ImagePlaneLoader(api.Loader): # Getting camera from selection. selection = pc.ls(selection=True) + camera = None + if len(selection) > 1: QtWidgets.QMessageBox.critical( None, @@ -39,25 +41,29 @@ class ImagePlaneLoader(api.Loader): return if len(selection) < 1: - QtWidgets.QMessageBox.critical( + result = QtWidgets.QMessageBox.critical( None, "Error!", - "No camera selected.", - QtWidgets.QMessageBox.Ok + "No camera selected. Do you want to create a camera?", + QtWidgets.QMessageBox.Ok, + QtWidgets.QMessageBox.Cancel ) - return - - relatives = pc.listRelatives(selection[0], shapes=True) - if not pc.ls(relatives, type="camera"): - QtWidgets.QMessageBox.critical( - None, - "Error!", - "Selected node is not a camera.", - QtWidgets.QMessageBox.Ok - ) - return - - camera = selection[0] + if result == QtWidgets.QMessageBox.Ok: + camera = pc.createNode("camera") + else: + return + else: + relatives = pc.listRelatives(selection[0], shapes=True) + if pc.ls(relatives, type="camera"): + camera = selection[0] + else: + QtWidgets.QMessageBox.critical( + None, + "Error!", + "Selected node is not a camera.", + QtWidgets.QMessageBox.Ok + ) + return try: camera.displayResolution.set(1) From 34416f46ddeeb16ec44dee7873341a14da9e38ee Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 25 Aug 2020 13:20:07 +0200 Subject: [PATCH 132/662] 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 133/662] 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 134/662] 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 135/662] 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 136/662] 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 137/662] 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 138/662] 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 139/662] 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 140/662] 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 141/662] 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 142/662] 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 143/662] 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 144/662] 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 145/662] 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 146/662] 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 147/662] 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 148/662] 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 149/662] 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 150/662] 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 151/662] 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 152/662] 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 153/662] 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 154/662] 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 155/662] 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 156/662] 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 a00b11d31fe2e1c58dab6b124a1a62a2d377a768 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 26 Aug 2020 14:29:57 +0200 Subject: [PATCH 157/662] Added pulling websocket server port from environment variable WEBSOCKET_URL --- .../websocket_server/websocket_server.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 6b730d4eb3..777bcf1f61 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -9,6 +9,7 @@ import os import sys import pyclbr import importlib +import urllib log = Logger().get_logger("WebsocketServer") @@ -28,19 +29,16 @@ class WebSocketServer(): self.qaction = None self.failed_icon = None self._is_running = False - default_port = 8099 WebSocketServer._instance = self self.client = None self.handlers = {} - 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))) + websocket_url = os.getenv("WEBSOCKET_URL") + if websocket_url: + parsed = urllib.parse.urlparse(websocket_url) + port = parsed.port + if not port: + port = 8099 # try default port self.app = web.Application() @@ -52,7 +50,7 @@ class WebSocketServer(): directories_with_routes = ['hosts'] self.add_routes_for_directories(directories_with_routes) - self.websocket_thread = WebsocketServerThread(self, default_port) + self.websocket_thread = WebsocketServerThread(self, port) def add_routes_for_directories(self, directories_with_routes): """ Loops through selected directories to find all modules and From f66d14e582d540bf262dc3d3d5cacf60f96bede0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 26 Aug 2020 17:55:53 +0200 Subject: [PATCH 158/662] 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 159/662] 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 160/662] 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 161/662] 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 162/662] 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 163/662] 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 164/662] 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 165/662] 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 166/662] 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 167/662] 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 168/662] 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 e074bc7733fa9464bbb0abef8f4011f56dcba6b3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 27 Aug 2020 16:01:19 +0200 Subject: [PATCH 169/662] 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 170/662] 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 171/662] 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 172/662] 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 173/662] 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 174/662] 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 175/662] 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 176/662] 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 177/662] 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 178/662] 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 179/662] 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 180/662] 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 06359c6dc335779f251dc426af8d6bda5be76422 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 27 Aug 2020 19:22:15 +0200 Subject: [PATCH 181/662] Hound --- pype/modules/websocket_server/hosts/photoshop.py | 2 +- .../modules/websocket_server/stubs/photoshop_server_stub.py | 3 +-- pype/modules/websocket_server/websocket_server.py | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/modules/websocket_server/hosts/photoshop.py b/pype/modules/websocket_server/hosts/photoshop.py index ae72963b1b..cdfb9413a0 100644 --- a/pype/modules/websocket_server/hosts/photoshop.py +++ b/pype/modules/websocket_server/hosts/photoshop.py @@ -61,4 +61,4 @@ class Photoshop(WebSocketRoute): photoshop.execute_in_main_thread(partial_method) # Required return statement. - return "nothing" \ No newline at end of file + return "nothing" diff --git a/pype/modules/websocket_server/stubs/photoshop_server_stub.py b/pype/modules/websocket_server/stubs/photoshop_server_stub.py index f798a09b92..da69127799 100644 --- a/pype/modules/websocket_server/stubs/photoshop_server_stub.py +++ b/pype/modules/websocket_server/stubs/photoshop_server_stub.py @@ -164,8 +164,7 @@ class PhotoshopServerStub(): :return: full path with name """ res = self.websocketserver.call( - self.client.call - ('Photoshop.get_active_document_full_name')) + self.client.call('Photoshop.get_active_document_full_name')) return res diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 777bcf1f61..4556dd0491 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -1,4 +1,4 @@ -from pype.api import config, Logger +from pype.api import Logger import threading from aiohttp import web @@ -37,8 +37,8 @@ class WebSocketServer(): if websocket_url: parsed = urllib.parse.urlparse(websocket_url) port = parsed.port - if not port: - port = 8099 # try default port + if not port: + port = 8099 # fallback self.app = web.Application() From 401d1ad6132d7fd4dcc781150e41ca7785f9a73a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 10:04:04 +0200 Subject: [PATCH 182/662] 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 183/662] 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 184/662] 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 185/662] 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 186/662] 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 187/662] 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 98f7be5f9047f25a87b4401ca90573549e1fd667 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 28 Aug 2020 12:26:16 +0200 Subject: [PATCH 188/662] 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 189/662] 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 190/662] 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 191/662] 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 192/662] 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 193/662] 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 194/662] 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 195/662] 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 196/662] 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 197/662] 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 198/662] 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 199/662] 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 200/662] 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 201/662] 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 202/662] 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 203/662] 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 204/662] 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 205/662] 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 206/662] 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 207/662] 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 208/662] 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 209/662] 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 210/662] 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 211/662] 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 212/662] 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 213/662] 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 214/662] 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 215/662] 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 216/662] 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 217/662] 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 218/662] 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 219/662] 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 220/662] 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 221/662] 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 222/662] 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 223/662] 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 224/662] 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 225/662] 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 226/662] 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 227/662] 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 228/662] 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 229/662] 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 230/662] 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 231/662] 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 232/662] 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 233/662] 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 234/662] 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 235/662] 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 236/662] 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 237/662] 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 238/662] 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 239/662] 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 240/662] 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 241/662] 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 242/662] 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 243/662] 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 244/662] 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 245/662] 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 246/662] 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 247/662] 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 248/662] 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 249/662] 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 250/662] 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 251/662] 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 252/662] 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 253/662] 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 254/662] 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 255/662] 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 256/662] 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 257/662] 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 258/662] 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 259/662] 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 260/662] 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 261/662] 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 262/662] 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 263/662] 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 264/662] 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 dabe68f28cd1c391a2b4930af40d60b801bc78e2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 1 Sep 2020 16:50:00 +0200 Subject: [PATCH 265/662] 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 266/662] 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 267/662] 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 268/662] 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 269/662] 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 270/662] 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 271/662] 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 272/662] 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 273/662] 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 274/662] 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 275/662] 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 276/662] 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 277/662] 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 278/662] 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 279/662] 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 280/662] 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 281/662] 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 282/662] 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 283/662] 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 284/662] 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 285/662] 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 f71aad40e04ac934522f25edad1d358bf4a8f5f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:01:09 +0200 Subject: [PATCH 286/662] removed icon attribute --- .../ftrack/ftrack_server/sub_event_status.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/sub_event_status.py b/pype/modules/ftrack/ftrack_server/sub_event_status.py index c2e7b7477f..00a6687de3 100644 --- a/pype/modules/ftrack/ftrack_server/sub_event_status.py +++ b/pype/modules/ftrack/ftrack_server/sub_event_status.py @@ -12,7 +12,7 @@ from pype.modules.ftrack.ftrack_server.lib import ( SocketSession, StatusEventHub, TOPIC_STATUS_SERVER, TOPIC_STATUS_SERVER_RESULT ) -from pype.api import Logger, config +from pype.api import Logger log = Logger().get_logger("Event storer") action_identifier = ( @@ -23,17 +23,7 @@ action_data = { "label": "Pype Admin", "variant": "- Event server Status ({})".format(host_ip), "description": "Get Infromation about event server", - "actionIdentifier": action_identifier, - "icon": "{}/ftrack/action_icons/PypeAdmin.svg".format( - os.environ.get( - "PYPE_STATICS_SERVER", - "http://localhost:{}".format( - config.get_presets().get("services", {}).get( - "rest_api", {} - ).get("default_port", 8021) - ) - ) - ) + "actionIdentifier": action_identifier } From a88fcfe9fa3de9e2b52478b70f1ddb0b8a72f7c2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 3 Sep 2020 11:19:57 +0200 Subject: [PATCH 287/662] 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 288/662] 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 289/662] 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 290/662] 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 291/662] 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 292/662] 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 293/662] 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 294/662] 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 295/662] 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 296/662] 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 297/662] 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 298/662] 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 299/662] 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 300/662] 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 301/662] 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 302/662] 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 303/662] 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 304/662] 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 305/662] 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 306/662] 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 307/662] 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 308/662] 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 309/662] 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 310/662] 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 311/662] _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 312/662] 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 313/662] 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 314/662] 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 315/662] 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 316/662] _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 317/662] 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 318/662] 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 319/662] 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 320/662] 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 321/662] 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 322/662] 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 323/662] 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 324/662] 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 325/662] 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 326/662] 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 327/662] 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 328/662] 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 329/662] 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 330/662] 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 331/662] 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 332/662] 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 333/662] 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 334/662] 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 335/662] 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 336/662] 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 337/662] 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 338/662] 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 339/662] 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 340/662] 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 341/662] 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 342/662] 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 343/662] 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 344/662] 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 345/662] 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 346/662] 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 347/662] 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 348/662] 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 349/662] 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 350/662] 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 351/662] 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 352/662] 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 353/662] 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 354/662] 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 355/662] 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 356/662] 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 357/662] 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 358/662] 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 359/662] 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 360/662] 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 361/662] 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 362/662] 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 363/662] 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 364/662] 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 365/662] 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 366/662] 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 367/662] 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 368/662] 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 369/662] 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 370/662] 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 371/662] 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 372/662] 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 373/662] 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 019ed41e23ac3b9de57e865cf8645219fdb5a5f7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 16:08:54 +0200 Subject: [PATCH 374/662] 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 6e2dab91b2e6a7c148f28ebdfe6d85c766774807 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 8 Sep 2020 16:06:11 +0100 Subject: [PATCH 375/662] Image plane cache and PNG reprensentations. --- pype/plugins/maya/load/load_image_plane.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/plugins/maya/load/load_image_plane.py b/pype/plugins/maya/load/load_image_plane.py index 17a6866f80..42e7a058ed 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", "preview"] + representations = ["mov", "exr", "preview", "png"] icon = "image" color = "orange" @@ -81,6 +81,7 @@ class ImagePlaneLoader(api.Loader): image_plane_shape.frameOffset.set(1 - start_frame) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) + image_plane_shape.frameCache.set(end_frame) image_plane_shape.useFrameExtension.set(1) movie_representations = ["mov", "preview"] From 504ae4a1b3f054c1fb8327be89675eede5c56978 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 8 Sep 2020 18:22:13 +0200 Subject: [PATCH 376/662] 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 377/662] 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 378/662] 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 379/662] 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 380/662] 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 381/662] 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 382/662] 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 383/662] 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 384/662] 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 385/662] 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 386/662] 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 387/662] 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 388/662] 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 389/662] 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 390/662] 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 391/662] 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 392/662] 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 393/662] 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 394/662] 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 395/662] 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 396/662] 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 397/662] 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 398/662] 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 399/662] 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 400/662] 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 401/662] 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 402/662] 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 403/662] 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 404/662] 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 405/662] 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 406/662] 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 407/662] 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 408/662] 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 409/662] 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 410/662] 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 411/662] 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 412/662] 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 413/662] 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 414/662] 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 415/662] 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 416/662] 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 417/662] 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 418/662] 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 419/662] 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 420/662] 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 93f7391e5a899a14adb1c8a0c964a26a9e565c23 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 9 Sep 2020 17:49:19 +0200 Subject: [PATCH 421/662] 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 422/662] 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 423/662] 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 424/662] 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 425/662] 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 426/662] 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 431a52689ebdd91e7c1047a815da3a1c277b5f1a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 10 Sep 2020 10:25:34 +0200 Subject: [PATCH 427/662] 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 428/662] 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 429/662] 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 430/662] 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 431/662] 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 432/662] 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 433/662] 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 434/662] 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 435/662] 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 436/662] 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 437/662] 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 438/662] 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 439/662] 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 440/662] 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 441/662] 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 442/662] 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 443/662] 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 444/662] 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 445/662] 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 446/662] 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 447/662] 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 448/662] 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 449/662] 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 b161dda7adea6a43b2e58f99a29823dddd7ea255 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 11 Sep 2020 11:27:13 +0200 Subject: [PATCH 450/662] 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 451/662] 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 452/662] 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 453/662] 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 454/662] 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 455/662] 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 456/662] 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 457/662] 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 458/662] 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 459/662] 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 460/662] 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 461/662] 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 462/662] 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 463/662] 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 464/662] 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 465/662] 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 466/662] 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 467/662] 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 468/662] 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 469/662] 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 470/662] 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 471/662] 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 472/662] 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 473/662] 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 474/662] 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 475/662] 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 476/662] 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 477/662] 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 478/662] 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 479/662] 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 480/662] 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 481/662] 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 482/662] 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 483/662] 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 484/662] 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 485/662] 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 486/662] 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 487/662] 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 488/662] 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 489/662] 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 490/662] 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 491/662] 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 492/662] 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 493/662] 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 494/662] 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 495/662] 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 496/662] 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 497/662] 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 498/662] 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 499/662] 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 500/662] 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 501/662] 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 502/662] 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 503/662] 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 504/662] 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 505/662] 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 506/662] 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 507/662] 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 508/662] 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 509/662] 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 510/662] 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 511/662] 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 512/662] 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 513/662] 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 514/662] 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 515/662] 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 516/662] 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 517/662] 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 518/662] 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 519/662] 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 520/662] 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 521/662] 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 522/662] 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 523/662] 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 524/662] 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 525/662] 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 526/662] 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 527/662] 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 528/662] 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 529/662] 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 530/662] 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 47ef4b64f297186c6d929a8f56ecfb93dd0f44e8 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 15 Sep 2020 17:59:53 +0200 Subject: [PATCH 531/662] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index 95a6d3a792..96fc614cb2 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.12.0" +__version__ = "2.12.1" From 35a506b5f4e01f3e7dc959018489344679170bf1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 15 Sep 2020 18:43:51 +0200 Subject: [PATCH 532/662] 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 533/662] 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 534/662] 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 535/662] 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 536/662] 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 1e2e278ede49f79f218b964e4dd694f87ca1c69a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 16 Sep 2020 14:25:44 +0200 Subject: [PATCH 537/662] #241 - Implementation of pype-config/presets/plugins/standalonepublisher --- .../projects_schema/1_plugins_gui_schema.json | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) 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 6bb14463c1..2e64e6a40b 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 @@ -614,6 +614,100 @@ ] } ] + }, + { + "type": "dict", + "collapsable": true, + "key": "standalonepublisher", + "label": "Standalone Publisher", + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "ExtractThumbnailSP", + "label": "ExtractThumbnailSP", + "is_group": true, + "children": [ + { + "type": "dict", + "collapsable": false, + "key": "ffmpeg_args", + "label": "ffmpeg_args", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "input", + "label": "input" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "output" + } + ] + } + ] + }, + { + "type": "dict", + "collapsable": true, + "key": "ExtractReviewSP", + "label": "ExtractReviewSP", + "is_group": true, + "children": [ + { + "type": "dict", + "collapsable": false, + "key": "outputs", + "label": "outputs", + "children": [ + { + "type": "dict", + "collapsable": false, + "key": "h264", + "label": "h264", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "input", + "label": "input" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "output" + }, + { + "type": "list", + "object_type": "text", + "key": "tags", + "label": "tags" + }, + { + "type": "text", + "key": "ext", + "label": "ext" + } + ] + } + ] + } + ] + } + ] + } + ] } ] } From 81df713212f3259a9b60fc76af1e179588892f46 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 15:32:59 +0200 Subject: [PATCH 538/662] 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 539/662] 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 540/662] 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 541/662] 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) From 22132f6e4db34e3989621c8a30281d6c6dbdac66 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 16 Sep 2020 16:11:13 +0200 Subject: [PATCH 542/662] feat(global): adding burnin suffix only if more filtered burnin profil --- 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 9049554abf7970fa8cff8ca111096ffcb8fb4fa9 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 16 Sep 2020 16:42:43 +0200 Subject: [PATCH 543/662] #241 - Removed ExtractReviewSP element --- .../projects_schema/1_plugins_gui_schema.json | 45 +------------------ 1 file changed, 1 insertion(+), 44 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 2e64e6a40b..96aad3e5a9 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 @@ -642,39 +642,7 @@ "label": "ffmpeg_args", "children": [ { - "type": "list", - "object_type": "text", - "key": "input", - "label": "input" - }, - { - "type": "list", - "object_type": "text", - "key": "output", - "label": "output" - } - ] - } - ] - }, - { - "type": "dict", - "collapsable": true, - "key": "ExtractReviewSP", - "label": "ExtractReviewSP", - "is_group": true, - "children": [ - { - "type": "dict", - "collapsable": false, - "key": "outputs", - "label": "outputs", - "children": [ - { - "type": "dict", - "collapsable": false, - "key": "h264", - "label": "h264", + "type": "dict-form", "children": [ { "type": "list", @@ -687,17 +655,6 @@ "object_type": "text", "key": "output", "label": "output" - }, - { - "type": "list", - "object_type": "text", - "key": "tags", - "label": "tags" - }, - { - "type": "text", - "key": "ext", - "label": "ext" } ] } From 923c00d646b91450ce25d8ff121c9dd2c61b549c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 16 Sep 2020 17:20:22 +0200 Subject: [PATCH 544/662] #241 - Implemented pype-config/presets/plugins/nukestudio/filter.json --- .../projects_schema/1_plugins_gui_schema.json | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) 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 96aad3e5a9..0c3b2c25d2 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 @@ -531,6 +531,55 @@ "key": "nukestudio", "label": "NukeStudio", "children": [ + { + "type": "dict", + "collapsable": true, + "key": "filter", + "label": "Filter", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "strict", + "label": "strict", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "ValidateVersion", + "label": "ValidateVersion" + }, + { + "type": "boolean", + "key": "VersionUpWorkfile", + "label": "VersionUpWorkfile" + } + ] + }, + { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "benevolent", + "label": "benevolent", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "ValidateVersion", + "label": "ValidateVersion" + }, + { + "type": "boolean", + "key": "VersionUpWorkfile", + "label": "VersionUpWorkfile" + } + ] + } + ] + }, { "type": "dict", "collapsable": true, From 3c0fc416d45cc990fd7eabdf5a62eaeef4fecf74 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 17:44:22 +0200 Subject: [PATCH 545/662] removed duplicated method --- pype/tools/settings/settings/widgets/item_types.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e2d59c2e69..24c22e754a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -22,19 +22,6 @@ class SettingObject: # default state of item type default_state = "" - @classmethod - def style_state(cls, is_invalid, is_overriden, is_modified): - """Return stylesheet state by intered booleans.""" - 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): """Create and reset attributes required for all item types. From 737d02ec9ed37123a7abcecfff5b2ae27a6d3aca Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 17:44:40 +0200 Subject: [PATCH 546/662] added docstrings to SettingObject's methods --- .../settings/settings/widgets/item_types.py | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 24c22e754a..9388d5e124 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -103,6 +103,9 @@ class SettingObject: def had_studio_override(self): """Item had studio overrides on refresh. + Use attribute `_had_studio_override` which should be changed only + during methods `update_studio_values` and `update_default_values`. + Returns: bool @@ -114,7 +117,7 @@ class SettingObject: """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). + is modified (not value change). Returns: bool @@ -190,7 +193,8 @@ class SettingObject: @property def is_overidable(self): - """Should care about overrides.""" + """ care about overrides.""" + return self._parent.is_overidable def any_parent_overriden(self): @@ -200,6 +204,7 @@ class SettingObject: bool """ + if self._parent._is_overriden: return True return self._parent.any_parent_overriden() @@ -222,6 +227,7 @@ class SettingObject: def style_state( cls, has_studio_override, is_invalid, is_overriden, is_modified ): + """Return stylesheet state by intered booleans.""" items = [] if is_invalid: items.append("invalid") @@ -314,6 +320,15 @@ class SettingObject: self.ignore_value_changes = False def discard_changes(self): + """Item's implementation to discard all changes made by user. + + Reset all values to same values as had when opened GUI + or when changed project. + + Must not affect `had_studio_override` value or `was_overriden` + value. It must be marked that there are keys/values which are not in + defaults or overrides. + """ raise NotImplementedError( "{} Method `discard_changes` not implemented!".format( repr(self) @@ -326,6 +341,10 @@ class SettingObject: self.ignore_value_changes = False def set_studio_default(self): + """Item's implementation to set current values as studio's overrides. + + Mark item and it's children as they have studio overrides. + """ raise NotImplementedError( "{} Method `set_studio_default` not implemented!".format( repr(self) @@ -338,6 +357,11 @@ class SettingObject: self.ignore_value_changes = False def reset_to_pype_default(self): + """Item's implementation to remove studio overrides. + + Mark item as it does not have studio overrides unset studio + override values. + """ raise NotImplementedError( "{} Method `reset_to_pype_default` not implemented!".format( repr(self) @@ -350,6 +374,11 @@ class SettingObject: self.ignore_value_changes = False def remove_overrides(self): + """Item's implementation to remove project overrides. + + Mark item as does not have project overrides. Must not change + `was_overriden` attribute value. + """ raise NotImplementedError( "{} Method `remove_overrides` not implemented!".format( repr(self) @@ -362,11 +391,21 @@ class SettingObject: self.ignore_value_changes = False def set_as_overriden(self): + """Item's implementation to set values as overriden for project. + + Mark item and all it's children as they're overriden. Must skip + items with children items that has attributes `is_group` + and `any_parent_is_group` set to False. In that case those items + are not meant to be overridable and should trigger the method on it's + children. + + """ raise NotImplementedError( "{} Method `set_as_overriden` not implemented!".format(repr(self)) ) def hierarchical_style_update(self): + """Trigger update style method down the hierarchy.""" raise NotImplementedError( "{} Method `hierarchical_style_update` not implemented!".format( repr(self) @@ -374,23 +413,51 @@ class SettingObject: ) def update_default_values(self, parent_values): + """Fill default values on startup or on refresh. + + Default values stored in `pype` repository should update all items in + schema. Each item should take values for his key and set it's value or + pass values down to children items. + + Args: + parent_values (dict): Values of parent's item. But in case item is + used as widget, `parent_values` contain value for item. + """ raise NotImplementedError( "{} does not have implemented `update_default_values`".format(self) ) def update_studio_values(self, parent_values): + """Fill studio override values on startup or on refresh. + + Set studio value if is not set to NOT_SET, in that case studio + overrides are not set yet. + + Args: + parent_values (dict): Values of parent's item. But in case item is + used as widget, `parent_values` contain value for item. + """ raise NotImplementedError( "{} does not have implemented `update_studio_values`".format(self) ) def apply_overrides(self, parent_values): + """Fill project override values on startup, refresh or project change. + + Set project value if is not set to NOT_SET, in that case project + overrides are not set yet. + + Args: + parent_values (dict): Values of parent's item. But in case item is + used as widget, `parent_values` contain value for item. + """ raise NotImplementedError( "{} does not have implemented `apply_overrides`".format(self) ) @property def child_has_studio_override(self): - """Any children item is modified.""" + """Any children item has studio overrides.""" raise NotImplementedError( "{} does not have implemented `child_has_studio_override`".format( self @@ -406,7 +473,7 @@ class SettingObject: @property def child_overriden(self): - """Any children item is overriden.""" + """Any children item has project overrides.""" raise NotImplementedError( "{} does not have implemented `child_overriden`".format(self) ) From b74375325fc9656331287796a017068267168d65 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 18:22:39 +0200 Subject: [PATCH 547/662] default_state removed --- pype/tools/settings/settings/widgets/item_types.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 9388d5e124..d78d335902 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -19,8 +19,6 @@ class SettingObject: 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 = "" def _set_default_attributes(self): """Create and reset attributes required for all item types. @@ -240,7 +238,7 @@ class SettingObject: if not items and has_studio_override: items.append("studio") - return "-".join(items) or cls.default_state + return "-".join(items) or "" def mouseReleaseEvent(self, event): if self.allow_actions and event.button() == QtCore.Qt.RightButton: From a8e03ee091e7a311a0a866a9c13ab7275a07b235 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 18:25:00 +0200 Subject: [PATCH 548/662] few more docstrings --- .../settings/settings/widgets/item_types.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d78d335902..ea32d9c79c 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -12,13 +12,18 @@ from avalon.vendor import qtawesome class SettingObject: + """Partially abstract class for Setting's item type workflow.""" # `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 + # 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) + # Will allow to show actions for the item type (disabled for proxies) else + # item is skipped and try to trigger actions on it's parent. allow_actions = True + # All item types must have implemented Qt signal which is emitted when + # it's or it's children value has changed, + value_changed = None def _set_default_attributes(self): """Create and reset attributes required for all item types. @@ -501,6 +506,11 @@ class SettingObject: class InputObject(SettingObject): + """Class for inputs with pre-implemented methods. + + Class is for item types not creating or using other item types, most + of methods has same code in that case. + """ def update_default_values(self, parent_values): self._state = None self._is_modified = False From 84d5580873ea0b34da3ee65fc339c858dc08d77f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 16 Sep 2020 19:05:12 +0200 Subject: [PATCH 549/662] attribute `is_input_type` renamed to `is_item_type` and added better check --- pype/tools/settings/settings/widgets/item_types.py | 12 ++++++------ pype/tools/settings/settings/widgets/lib.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e2d59c2e69..ff95ba82c3 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -12,8 +12,8 @@ from avalon.vendor import qtawesome class SettingObject: - # `is_input_type` attribute says if has implemented item type methods - is_input_type = True + # `is_item_type` attribute says if has implemented item type methods + is_item_type = True # each input must have implemented default value for development # when defaults are not filled yet default_input_value = NOT_SET @@ -1935,7 +1935,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) - if not klass.is_input_type: + if not getattr(klass, "is_item_type", False): item = klass(child_configuration, self) self.content_layout.addWidget(item) return item @@ -2226,7 +2226,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) - if not klass.is_input_type: + if not klass.is_item_type: item = klass(child_configuration, self) self.layout().addWidget(item) return item @@ -3003,7 +3003,7 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): class LabelWidget(QtWidgets.QWidget): - is_input_type = False + is_item_type = False def __init__(self, configuration, parent=None): super(LabelWidget, self).__init__(parent) @@ -3018,7 +3018,7 @@ class LabelWidget(QtWidgets.QWidget): class SplitterWidget(QtWidgets.QWidget): - is_input_type = False + is_item_type = False _height = 2 def __init__(self, configuration, parent=None): diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index e225d65417..a2646ad4e6 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -125,7 +125,7 @@ def file_keys_from_schema(schema_data): output = [] item_type = schema_data["type"] klass = TypeToKlass.types[item_type] - if not klass.is_input_type: + if not klass.is_item_type: return output keys = [] @@ -150,7 +150,7 @@ 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: + if not klass.is_item_type: return None if schema_data.get("is_file"): From 733ae9d8b1130c584d74345c7631d69717e16757 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 17 Sep 2020 10:26:06 +0200 Subject: [PATCH 550/662] #241 - Reverted checkboxes back to raw-json Both keys and values for this field are editable, no valid widget for such a case --- .../projects_schema/1_plugins_gui_schema.json | 48 ++----------------- 1 file changed, 3 insertions(+), 45 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 0c3b2c25d2..721b0924e8 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 @@ -532,53 +532,11 @@ "label": "NukeStudio", "children": [ { - "type": "dict", + "type": "raw-json", "collapsable": true, "key": "filter", - "label": "Filter", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "strict", - "label": "strict", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "ValidateVersion", - "label": "ValidateVersion" - }, - { - "type": "boolean", - "key": "VersionUpWorkfile", - "label": "VersionUpWorkfile" - } - ] - }, - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "benevolent", - "label": "benevolent", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "ValidateVersion", - "label": "ValidateVersion" - }, - { - "type": "boolean", - "key": "VersionUpWorkfile", - "label": "VersionUpWorkfile" - } - ] - } - ] + "label": "Publish GUI Filters", + "is_file": true }, { "type": "dict", From 20230fbccd10e47abd1fcb130305ddf1b7bafea7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 10:28:17 +0200 Subject: [PATCH 551/662] Revert "attribute `is_input_type` renamed to `is_item_type` and added better check" This reverts commit 84d5580873ea0b34da3ee65fc339c858dc08d77f. --- pype/tools/settings/settings/widgets/item_types.py | 12 ++++++------ pype/tools/settings/settings/widgets/lib.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ff95ba82c3..e2d59c2e69 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -12,8 +12,8 @@ from avalon.vendor import qtawesome class SettingObject: - # `is_item_type` attribute says if has implemented item type methods - is_item_type = True + # `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 @@ -1935,7 +1935,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) - if not getattr(klass, "is_item_type", False): + if not klass.is_input_type: item = klass(child_configuration, self) self.content_layout.addWidget(item) return item @@ -2226,7 +2226,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) - if not klass.is_item_type: + if not klass.is_input_type: item = klass(child_configuration, self) self.layout().addWidget(item) return item @@ -3003,7 +3003,7 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): class LabelWidget(QtWidgets.QWidget): - is_item_type = False + is_input_type = False def __init__(self, configuration, parent=None): super(LabelWidget, self).__init__(parent) @@ -3018,7 +3018,7 @@ class LabelWidget(QtWidgets.QWidget): class SplitterWidget(QtWidgets.QWidget): - is_item_type = False + is_input_type = False _height = 2 def __init__(self, configuration, parent=None): diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index a2646ad4e6..e225d65417 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -125,7 +125,7 @@ def file_keys_from_schema(schema_data): output = [] item_type = schema_data["type"] klass = TypeToKlass.types[item_type] - if not klass.is_item_type: + if not klass.is_input_type: return output keys = [] @@ -150,7 +150,7 @@ 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_item_type: + if not klass.is_input_type: return None if schema_data.get("is_file"): From 828ebde3deea11a28251420d516962be0b0e7bfd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 12:25:47 +0200 Subject: [PATCH 552/662] added attribute to know if item type should be expanded in grid layout --- pype/tools/settings/settings/widgets/item_types.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ea32d9c79c..ffbb128c3d 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -24,6 +24,8 @@ class SettingObject: # All item types must have implemented Qt signal which is emitted when # it's or it's children value has changed, value_changed = None + # Item will expand to full width in grid layout + expand_in_grid = False def _set_default_attributes(self): """Create and reset attributes required for all item types. @@ -1693,6 +1695,7 @@ 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) + expand_in_grid = True def __init__( self, input_data, parent, @@ -1926,6 +1929,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): # Dictionaries class DictWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) + expand_in_grid = True def __init__( self, input_data, parent, @@ -2256,6 +2260,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) allow_actions = False + expand_in_grid = True def __init__( self, input_data, parent, @@ -2871,6 +2876,7 @@ class FormLabel(QtWidgets.QLabel): class DictFormWidget(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) allow_actions = False + expand_in_grid = True def __init__( self, input_data, parent, From 365c6852c0bb0d91ab3248a00d9182ea226ea610 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 12:26:53 +0200 Subject: [PATCH 553/662] using QGridLayout in dict and dict-invisible --- pype/tools/settings/settings/widgets/item_types.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ffbb128c3d..d745e83ffa 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1969,7 +1969,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): 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 = QtWidgets.QGridLayout(content_widget) content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, bottom_margin) body_widget.set_content_widget(content_widget) @@ -2278,10 +2278,12 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): self.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout = QtWidgets.QVBoxLayout(self) + layout = QtWidgets.QGridLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) + self.content_layout = layout + self.input_fields = [] self.key = input_data["key"] From 5f574c1643bc6db92327ffd8cb9e570ed60adbdd Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 12:27:13 +0200 Subject: [PATCH 554/662] items are added to grid layout in right order --- .../settings/settings/widgets/item_types.py | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d745e83ffa..628b7262e8 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2001,9 +2001,10 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) - if not klass.is_input_type: + row = self.content_layout.rowCount() + if not getattr(klass, "is_input_type", False): item = klass(child_configuration, self) - self.content_layout.addWidget(item) + self.content_layout.addWidget(item, row, 0, 1, 2) return item if self.checkbox_key and not self.checkbox_widget: @@ -2011,9 +2012,20 @@ class DictWidget(QtWidgets.QWidget, SettingObject): if key == self.checkbox_key: return self._add_checkbox_child(child_configuration) - item = klass(child_configuration, self) + label_widget = None + if not klass.expand_in_grid: + label = child_configuration.get("label") + if label is not None: + label_widget = QtWidgets.QLabel(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) + + item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) - self.content_layout.addWidget(item) + + if label_widget: + self.content_layout.addWidget(item, row, 1, 1, 1) + else: + self.content_layout.addWidget(item, row, 0, 1, 2) self.input_fields.append(item) return item @@ -2295,16 +2307,27 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) - if not klass.is_input_type: + row = self.content_layout.rowCount() + if not getattr(klass, "is_input_type", False): item = klass(child_configuration, self) - self.layout().addWidget(item) + self.content_layout.addWidget(item, row, 0, 1, 2) return item - item = klass(child_configuration, self) - self.layout().addWidget(item) + label_widget = None + if not klass.expand_in_grid: + label = child_configuration.get("label") + if label is not None: + label_widget = QtWidgets.QLabel(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) + item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) + if label_widget: + self.content_layout.addWidget(item, row, 1, 1, 1) + else: + self.content_layout.addWidget(item, row, 0, 1, 2) + self.input_fields.append(item) return item From 3e24555f49b384cc4863db81806e4831dc39741b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 12:27:57 +0200 Subject: [PATCH 555/662] removed dict-form from schemas --- .../projects_schema/1_plugins_gui_schema.json | 83 +++--- .../1_applications_gui_schema.json | 259 +++++++++--------- .../system_schema/1_tools_gui_schema.json | 35 +-- .../system_schema/1_tray_items.json | 91 +++--- 4 files changed, 218 insertions(+), 250 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 721b0924e8..b2d7914c84 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 @@ -30,34 +30,29 @@ "key": "enabled", "label": "Enabled" }, { - "type": "dict-form", - "children": [ - { - "type": "text", - "key": "deadline_department", - "label": "Deadline apartment" - }, { - "type": "number", - "key": "deadline_priority", - "label": "Deadline priority" - }, { - "type": "text", - "key": "deadline_pool", - "label": "Deadline pool" - }, { - "type": "text", - "key": "deadline_pool_secondary", - "label": "Deadline pool (secondary)" - }, { - "type": "text", - "key": "deadline_group", - "label": "Deadline Group" - }, { - "type": "number", - "key": "deadline_chunk_size", - "label": "Deadline Chunk size" - } - ] + "type": "text", + "key": "deadline_department", + "label": "Deadline apartment" + }, { + "type": "number", + "key": "deadline_priority", + "label": "Deadline priority" + }, { + "type": "text", + "key": "deadline_pool", + "label": "Deadline pool" + }, { + "type": "text", + "key": "deadline_pool_secondary", + "label": "Deadline pool (secondary)" + }, { + "type": "text", + "key": "deadline_group", + "label": "Deadline Group" + }, { + "type": "number", + "key": "deadline_chunk_size", + "label": "Deadline Chunk size" } ] } @@ -531,13 +526,6 @@ "key": "nukestudio", "label": "NukeStudio", "children": [ - { - "type": "raw-json", - "collapsable": true, - "key": "filter", - "label": "Publish GUI Filters", - "is_file": true - }, { "type": "dict", "collapsable": true, @@ -649,21 +637,16 @@ "label": "ffmpeg_args", "children": [ { - "type": "dict-form", - "children": [ - { - "type": "list", - "object_type": "text", - "key": "input", - "label": "input" - }, - { - "type": "list", - "object_type": "text", - "key": "output", - "label": "output" - } - ] + "type": "list", + "object_type": "text", + "key": "input", + "label": "input" + }, + { + "type": "list", + "object_type": "text", + "key": "output", + "label": "output" } ] } 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 48f8ecbd7c..3427f98253 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 @@ -7,138 +7,133 @@ "is_file": true, "children": [ { - "type": "dict-form", - "children": [ - { - "type": "boolean", - "key": "blender_2.80", - "label": "Blender 2.80" - }, { - "type": "boolean", - "key": "blender_2.81", - "label": "Blender 2.81" - }, { - "type": "boolean", - "key": "blender_2.82", - "label": "Blender 2.82" - }, { - "type": "boolean", - "key": "blender_2.83", - "label": "Blender 2.83" - }, { - "type": "boolean", - "key": "celaction_local", - "label": "Celaction Local" - }, { - "type": "boolean", - "key": "celaction_remote", - "label": "Celaction Remote" - }, { - "type": "boolean", - "key": "harmony_17", - "label": "Harmony 17" - }, { - "type": "boolean", - "key": "maya_2017", - "label": "Autodest Maya 2017" - }, { - "type": "boolean", - "key": "maya_2018", - "label": "Autodest Maya 2018" - }, { - "type": "boolean", - "key": "maya_2019", - "label": "Autodest Maya 2019" - }, { - "type": "boolean", - "key": "maya_2020", - "label": "Autodest Maya 2020" - }, { - "key": "nuke_10.0", - "type": "boolean", - "label": "Nuke 10.0" - }, { - "type": "boolean", - "key": "nuke_11.2", - "label": "Nuke 11.2" - }, { - "type": "boolean", - "key": "nuke_11.3", - "label": "Nuke 11.3" - }, { - "type": "boolean", - "key": "nuke_12.0", - "label": "Nuke 12.0" - }, { - "type": "boolean", - "key": "nukex_10.0", - "label": "NukeX 10.0" - }, { - "type": "boolean", - "key": "nukex_11.2", - "label": "NukeX 11.2" - }, { - "type": "boolean", - "key": "nukex_11.3", - "label": "NukeX 11.3" - }, { - "type": "boolean", - "key": "nukex_12.0", - "label": "NukeX 12.0" - }, { - "type": "boolean", - "key": "nukestudio_10.0", - "label": "NukeStudio 10.0" - }, { - "type": "boolean", - "key": "nukestudio_11.2", - "label": "NukeStudio 11.2" - }, { - "type": "boolean", - "key": "nukestudio_11.3", - "label": "NukeStudio 11.3" - }, { - "type": "boolean", - "key": "nukestudio_12.0", - "label": "NukeStudio 12.0" - }, { - "type": "boolean", - "key": "houdini_16", - "label": "Houdini 16" - }, { - "type": "boolean", - "key": "houdini_16.5", - "label": "Houdini 16.5" - }, { - "type": "boolean", - "key": "houdini_17", - "label": "Houdini 17" - }, { - "type": "boolean", - "key": "houdini_18", - "label": "Houdini 18" - }, { - "type": "boolean", - "key": "premiere_2019", - "label": "Premiere 2019" - }, { - "type": "boolean", - "key": "premiere_2020", - "label": "Premiere 2020" - }, { - "type": "boolean", - "key": "resolve_16", - "label": "BM DaVinci Resolve 16" - }, { - "type": "boolean", - "key": "storyboardpro_7", - "label": "Storyboard Pro 7" - }, { - "type": "boolean", - "key": "unreal_4.24", - "label": "Unreal Editor 4.24" - } - ] + "type": "boolean", + "key": "blender_2.80", + "label": "Blender 2.80" + }, { + "type": "boolean", + "key": "blender_2.81", + "label": "Blender 2.81" + }, { + "type": "boolean", + "key": "blender_2.82", + "label": "Blender 2.82" + }, { + "type": "boolean", + "key": "blender_2.83", + "label": "Blender 2.83" + }, { + "type": "boolean", + "key": "celaction_local", + "label": "Celaction Local" + }, { + "type": "boolean", + "key": "celaction_remote", + "label": "Celaction Remote" + }, { + "type": "boolean", + "key": "harmony_17", + "label": "Harmony 17" + }, { + "type": "boolean", + "key": "maya_2017", + "label": "Autodest Maya 2017" + }, { + "type": "boolean", + "key": "maya_2018", + "label": "Autodest Maya 2018" + }, { + "type": "boolean", + "key": "maya_2019", + "label": "Autodest Maya 2019" + }, { + "type": "boolean", + "key": "maya_2020", + "label": "Autodest Maya 2020" + }, { + "key": "nuke_10.0", + "type": "boolean", + "label": "Nuke 10.0" + }, { + "type": "boolean", + "key": "nuke_11.2", + "label": "Nuke 11.2" + }, { + "type": "boolean", + "key": "nuke_11.3", + "label": "Nuke 11.3" + }, { + "type": "boolean", + "key": "nuke_12.0", + "label": "Nuke 12.0" + }, { + "type": "boolean", + "key": "nukex_10.0", + "label": "NukeX 10.0" + }, { + "type": "boolean", + "key": "nukex_11.2", + "label": "NukeX 11.2" + }, { + "type": "boolean", + "key": "nukex_11.3", + "label": "NukeX 11.3" + }, { + "type": "boolean", + "key": "nukex_12.0", + "label": "NukeX 12.0" + }, { + "type": "boolean", + "key": "nukestudio_10.0", + "label": "NukeStudio 10.0" + }, { + "type": "boolean", + "key": "nukestudio_11.2", + "label": "NukeStudio 11.2" + }, { + "type": "boolean", + "key": "nukestudio_11.3", + "label": "NukeStudio 11.3" + }, { + "type": "boolean", + "key": "nukestudio_12.0", + "label": "NukeStudio 12.0" + }, { + "type": "boolean", + "key": "houdini_16", + "label": "Houdini 16" + }, { + "type": "boolean", + "key": "houdini_16.5", + "label": "Houdini 16.5" + }, { + "type": "boolean", + "key": "houdini_17", + "label": "Houdini 17" + }, { + "type": "boolean", + "key": "houdini_18", + "label": "Houdini 18" + }, { + "type": "boolean", + "key": "premiere_2019", + "label": "Premiere 2019" + }, { + "type": "boolean", + "key": "premiere_2020", + "label": "Premiere 2020" + }, { + "type": "boolean", + "key": "resolve_16", + "label": "BM DaVinci Resolve 16" + }, { + "type": "boolean", + "key": "storyboardpro_7", + "label": "Storyboard Pro 7" + }, { + "type": "boolean", + "key": "unreal_4.24", + "label": "Unreal Editor 4.24" } ] } 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 d9540eeb3e..08b8d13d89 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 @@ -7,26 +7,21 @@ "is_file": true, "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" - } - ] + "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/settings/settings/gui_schemas/system_schema/1_tray_items.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json index 6da974a415..0d27ccdc4b 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 @@ -11,54 +11,49 @@ "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": "Timers Manager", - "label": "Timers Manager" - }, { - "type": "boolean", - "key": "Rest Api", - "label": "Rest Api" - }, { - "type": "boolean", - "key": "Adobe Communicator", - "label": "Adobe Communicator" - } - ] + "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": "Timers Manager", + "label": "Timers Manager" + }, { + "type": "boolean", + "key": "Rest Api", + "label": "Rest Api" + }, { + "type": "boolean", + "key": "Adobe Communicator", + "label": "Adobe Communicator" } ] }, { From 35d7f0b1d28f2c2248a49a2eff5063669ab4b44a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 12:30:37 +0200 Subject: [PATCH 556/662] added Gui schema README --- pype/tools/settings/settings/README.md | 261 +++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 pype/tools/settings/settings/README.md diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md new file mode 100644 index 0000000000..db444eb3bd --- /dev/null +++ b/pype/tools/settings/settings/README.md @@ -0,0 +1,261 @@ +# Creating GUI schemas + +## 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 + - this keys is not allowed for all inputs as they may have not reason for that + - key is validated, can be only once in hierarchy but is not required +- currently there are `system configurations` and `project configurations` + +## Inner schema +- GUI schemas are huge json files, to be able to split whole configuration into multiple schema there's type `schema` +- system configuration schemas are stored in `~/tools/settings/settings/gui_schemas/system_schema/` and project configurations in `~/tools/settings/settings/gui_schemas/projects_schema/` +- each schema name is filename of json file except extension (without ".json") + +### schema +- can have only key `"children"` which is list of strings, each string should represent another schema (order matters) string represebts name of the schema +- will just paste schemas from other schema file in order of "children" list + +``` +{ + "type": "schema", + "children": [ + "my_schema_name", + "my_other_schema_name" + ] +} +``` + +## 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 for example 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}` +- can't have `"is_group"` key set to True as it breaks visual override showing +``` +{ + "type": "dict-invisible", + "key": "global", + "children": [ + ...ITEMS... + ] +} +``` + +## dict +- this is another dictionary input wrapping more inputs but visually makes them different +- required keys are `"key"` under which will be stored and `"label"` which will be shown in GUI +- 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`) +- it is possible to add darker background with `"highlight_content"` (Default: `False`) + - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color +``` +{ + "key": "applications", + "type": "dict", + "label": "Applications", + "expandable": true, + "highlight_content": true, + "is_group": true, + "is_file": true, + "children": [ + ...ITEMS... + ] +} +``` + +## 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" +} +``` + +### path-input +- enhanced text input + - does not allow to enter backslash, is auto-converted to forward slash + - may be added another validations, like do not allow end path with slash +- this input is implemented to add additional features to text input +- this is meant to be used in proxy input `path-widget` + - DO NOT USE this input in schema please + +### 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 +} +``` + +### path-widget +- input for paths, use `path-input` internally +- has 2 input modifiers `"multiplatform"` and `"multipath"` + - `"multiplatform"` - adds `"windows"`, `"linux"` and `"darwin"` path inputs result is dictionary + - `"multipath"` - it is possible to enter multiple paths + - if both are enabled result is dictionary with lists + +``` +{ + "type": "path-widget", + "key": "ffmpeg_path", + "label": "FFmpeg path", + "multiplatform": true, + "multipath": true +} +``` + +## Noninteractive widgets +- have nothing to do with data + +### label +- add label with note or explanations +- it is possible to use html tags inside the label + +``` +{ + "type": "label", + "label": "RED LABEL: Normal label" +} +``` + +### splitter +- visual splitter of items (more divider than splitter) + +``` +{ + "type": "splitter" +} +``` + +## Proxy wrappers +- should wraps multiple inputs only visually +- these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled + +### dict-form +- DEPRECATED + - may be used only in `dict` and `dict-invisible` where is currently used grid layout so form is not needed + - item is kept as still may be used in specific cases +- wraps inputs into form look layout +- should be used only for Pure inputs + +``` +{ + "type": "dict-form", + "children": [ + { + "type": "text", + "key": "deadline_department", + "label": "Deadline apartment" + }, { + "type": "number", + "key": "deadline_priority", + "label": "Deadline priority" + }, { + ... + } + ] +} +``` From b676fc22b6e4991c9c744716d6c354765acfadea Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 13:57:38 +0200 Subject: [PATCH 557/662] order_changed is triggered after new item is added, not before --- .../settings/settings/widgets/item_types.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ea32d9c79c..9188cd5cb4 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1384,28 +1384,31 @@ class ListWidget(QtWidgets.QWidget, InputObject): item_widget = ListItem( self.object_type, self.input_modifiers, self, self.inputs_widget ) + + previous_field = None + next_field = None + if row is None: if self.input_fields: - self.input_fields[-1].order_changed() + previous_field = self.input_fields[-1] 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 previous_field: + previous_field.order_changed() + + if next_field: + next_field.order_changed() if is_empty: item_widget.set_as_empty() From 1d08c4db454edc4a4524fb571c75efbffa7b8dd6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 17:22:28 +0200 Subject: [PATCH 558/662] content of modifiable dictionary can be also highlighted --- .../settings/settings/widgets/item_types.py | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 4088537a9a..72200f5a95 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1715,21 +1715,22 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.key = input_data["key"] + if input_data.get("highlight_content", False): + content_state = "hightlighted" + bottom_margin = 5 + else: + content_state = "" + bottom_margin = 0 + main_layout = QtWidgets.QHBoxLayout(self) 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(CHILD_OFFSET, 3, 0, 3) - if as_widget: - main_layout.addWidget(content_widget) body_widget = None 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 @@ -1743,6 +1744,22 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): else: body_widget.hide_toolbox(hide_content=False) + if body_widget is None: + content_parent_widget = self + else: + content_parent_widget = body_widget + + content_widget = QtWidgets.QWidget(content_parent_widget) + content_widget.setObjectName("ContentWidget") + content_widget.setProperty("content_state", content_state) + content_layout = QtWidgets.QVBoxLayout(content_widget) + content_layout.setContentsMargins(CHILD_OFFSET, 3, 0, bottom_margin) + + if body_widget is None: + main_layout.addWidget(content_widget) + else: + body_widget.set_content_widget(content_widget) + self.body_widget = body_widget self.content_widget = content_widget self.content_layout = content_layout From ef6c68e89431456ecf4430f9561dae80e64c453a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 17:24:39 +0200 Subject: [PATCH 559/662] align labels in dict and dict-invisible to top right --- 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 72200f5a95..c8d558e044 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2037,7 +2037,10 @@ class DictWidget(QtWidgets.QWidget, SettingObject): label = child_configuration.get("label") if label is not None: label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget(label_widget, row, 0, 1, 1) + self.content_layout.addWidget( + label_widget, row, 0, 1, 1, + alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop + ) item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) @@ -2338,7 +2341,10 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): label = child_configuration.get("label") if label is not None: label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget(label_widget, row, 0, 1, 1) + self.content_layout.addWidget( + label_widget, row, 0, 1, 1, + alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop + ) item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) From 4934f65432f9e030c88b346adab7571b2b06d3a8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 17:26:00 +0200 Subject: [PATCH 560/662] implemented basic dict-item item type --- pype/tools/settings/settings/style/style.css | 6 + .../settings/settings/widgets/item_types.py | 116 ++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 38f69fef50..221f297219 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -152,6 +152,12 @@ QPushButton[btn-type="expand-toggle"] { background: #141a1f; } +#DictItemWidgetBody{ + background: transparent; + border: 2px solid #cccccc; + border-radius: 5px; +} + #SplitterItem { background-color: #1d272f; } diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index c8d558e044..31455ecd98 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1149,6 +1149,121 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): return self.text_input.json_value() +class DictItemWidget(QtWidgets.QWidget, SettingObject): + default_input_value = True + value_changed = QtCore.Signal(object) + + def __init__( + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None + ): + if parent_widget is None: + parent_widget = parent + super(DictItemWidget, self).__init__(parent_widget) + + self.initial_attributes(input_data, parent, as_widget) + + if not self._as_widget: + raise TypeError("{} can be used only as widget.".format( + self.__class__.__name__ + )) + + self.input_fields = [] + + body = QtWidgets.QWidget(self) + body.setObjectName("DictItemWidgetBody") + + content_layout = QtWidgets.QGridLayout(body) + content_layout.setContentsMargins(5, 5, 5, 5) + self.content_layout = content_layout + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(body) + + for child_configuration in input_data["children"]: + self.add_children_gui(child_configuration) + + def add_children_gui(self, child_configuration): + item_type = child_configuration["type"] + klass = TypeToKlass.types.get(item_type) + + row = self.content_layout.rowCount() + if not getattr(klass, "is_input_type", False): + item = klass(child_configuration, self) + self.content_layout.addWidget(item, row, 0, 1, 2) + return item + + label_widget = None + if not klass.expand_in_grid: + label = child_configuration.get("label") + if label is not None: + label_widget = QtWidgets.QLabel(label, self) + self.content_layout.addWidget( + label_widget, row, 0, 1, 1, + alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop + ) + + item = klass(child_configuration, self, label_widget=label_widget) + item.value_changed.connect(self._on_value_change) + + if label_widget: + self.content_layout.addWidget(item, row, 1, 1, 1) + else: + self.content_layout.addWidget(item, row, 0, 1, 2) + + self.input_fields.append(item) + return item + + def hierarchical_style_update(self): + print("hierarchical_style_update") + + def _on_value_change(self, item=None): + print("_on_value_change") + + 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) + + def update_style(self): + 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, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + if self._state == state: + return + + if 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) + self._state = state + + def item_value(self): + output = {} + for input_field in self.input_fields: + output.update(input_field.config_value()) + return output + + class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -3159,6 +3274,7 @@ TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict +TypeToKlass.types["dict-item"] = DictItemWidget TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictInvisible TypeToKlass.types["path-widget"] = PathWidget From 5621f029d0a55f64c7aa924710ea17479009f956 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 17:31:25 +0200 Subject: [PATCH 561/662] hode item in ListItem if is set as empty --- .../settings/settings/widgets/item_types.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 31455ecd98..ec75272f07 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1307,9 +1307,6 @@ class ListItem(QtWidgets.QWidget, SettingObject): 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.up_btn.clicked.connect(self._on_up_clicked) @@ -1322,7 +1319,15 @@ class ListItem(QtWidgets.QWidget, SettingObject): as_widget=True, label_widget=None ) + + self.spacer_widget = QtWidgets.QWidget(self) + self.spacer_widget.setVisible(False) + + layout.addWidget(self.add_btn, 0) + layout.addWidget(self.remove_btn, 0) + layout.addWidget(self.value_input, 1) + layout.addWidget(self.spacer_widget, 1) layout.addWidget(self.up_btn, 0) layout.addWidget(self.down_btn, 0) @@ -1330,8 +1335,11 @@ class ListItem(QtWidgets.QWidget, SettingObject): 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.spacer_widget.setVisible(is_empty) + self.value_input.setVisible(not is_empty) + self.remove_btn.setVisible(not is_empty) + self.up_btn.setVisible(not is_empty) + self.down_btn.setVisible(not is_empty) self.order_changed() self._on_value_change() @@ -1364,7 +1372,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): return len(self._parent.input_fields) def _on_add_clicked(self): - if self.value_input.isEnabled(): + if self.value_input.isVisible(): self._parent.add_row(row=self.row() + 1) else: self.set_as_empty(False) From cd41394f1cf9efec6799a852655f32564888e7aa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 17:40:26 +0200 Subject: [PATCH 562/662] keep visible minus button and added same feature to modifable dict --- .../tools/settings/settings/widgets/item_types.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ec75272f07..293b2f5503 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1321,6 +1321,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): ) self.spacer_widget = QtWidgets.QWidget(self) + self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.spacer_widget.setVisible(False) layout.addWidget(self.add_btn, 0) @@ -1337,7 +1338,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): def set_as_empty(self, is_empty=True): self.spacer_widget.setVisible(is_empty) self.value_input.setVisible(not is_empty) - self.remove_btn.setVisible(not is_empty) + self.remove_btn.setEnabled(not is_empty) self.up_btn.setVisible(not is_empty) self.down_btn.setVisible(not is_empty) self.order_changed() @@ -1692,9 +1693,14 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self.add_btn.setProperty("btn-type", "tool-item") self.remove_btn.setProperty("btn-type", "tool-item") + self.spacer_widget = QtWidgets.QWidget(self) + self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.spacer_widget.setVisible(False) + layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) layout.addWidget(self.key_input, 0) + layout.addWidget(self.spacer_widget, 1) layout.addWidget(self.value_input, 1) self.setFocusProxy(self.value_input) @@ -1713,7 +1719,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self.key_input.text() def _is_enabled(self): - return self.key_input.isEnabled() + return self.key_input.isVisible() def is_key_invalid(self): if not self._is_enabled(): @@ -1759,9 +1765,10 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): 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.key_input.setVisible(not is_empty) + self.value_input.setVisible(not is_empty) self.remove_btn.setEnabled(not is_empty) + self.spacer_widget.setVisible(is_empty) self._on_value_change() @property From 04977d223e2cb301c4f6bef5b76ba39a191fe374 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 17:45:12 +0200 Subject: [PATCH 563/662] hide up/down btns if there is only one item --- pype/tools/settings/settings/widgets/item_types.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 293b2f5503..f0a26227a1 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1348,10 +1348,15 @@ class ListItem(QtWidgets.QWidget, SettingObject): 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) + self.up_btn.setVisible(False) + self.down_btn.setVisible(False) + return - elif row == 0: + if not self.up_btn.isVisible(): + self.up_btn.setVisible(True) + self.down_btn.setVisible(True) + + if row == 0: self.up_btn.setEnabled(False) self.down_btn.setEnabled(True) From 4fa53fd2e3c996ceba410af4f7af140a8c4f1f56 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 18:55:17 +0200 Subject: [PATCH 564/662] added few attributes to bases --- pype/tools/settings/settings/widgets/base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index dbcc380daf..423380d54c 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -34,6 +34,8 @@ class SystemWidget(QtWidgets.QWidget): is_overidable = False has_studio_override = _has_studio_override = False is_overriden = _is_overriden = False + as_widget = _as_widget = False + any_parent_as_widget = _any_parent_as_widget = False is_group = _is_group = False any_parent_is_group = _any_parent_is_group = False @@ -396,6 +398,8 @@ class ProjectListWidget(QtWidgets.QWidget): class ProjectWidget(QtWidgets.QWidget): has_studio_override = _has_studio_override = False is_overriden = _is_overriden = False + as_widget = _as_widget = False + any_parent_as_widget = _any_parent_as_widget = False is_group = _is_group = False any_parent_is_group = _any_parent_is_group = False From c88e48f1af61d6f9c8598ffaa2c67739c8831e6d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 18:55:52 +0200 Subject: [PATCH 565/662] removed not used method --- pype/tools/settings/settings/widgets/item_types.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index f0a26227a1..d09fd3d1ee 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -502,10 +502,6 @@ class SettingObject: "Method `item_value` not implemented!" ) - def studio_value(self): - """Output for saving changes or overrides.""" - return {self.key: self.item_value()} - class InputObject(SettingObject): """Class for inputs with pre-implemented methods. From 3544d819051465d911edeff4fa49d0f054893b92 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:23:14 +0200 Subject: [PATCH 566/662] added any_parent_as_widget attribute --- .../settings/settings/widgets/item_types.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d09fd3d1ee..07f57c994d 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -46,6 +46,7 @@ class SettingObject: self._as_widget = False self._is_group = False + self._any_parent_as_widget = None self._any_parent_is_group = None # Parent input @@ -81,6 +82,12 @@ class SettingObject: # TODO not implemented yet self._is_nullable = input_data.get("is_nullable", False) + any_parent_as_widget = parent.as_widget + if not any_parent_as_widget: + any_parent_as_widget = parent.any_parent_as_widget + + self._any_parent_as_widget = any_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 @@ -130,6 +137,34 @@ class SettingObject: """ return self._has_studio_override or self._parent.has_studio_override + @property + def as_widget(self): + """Item is used as widget in parent item. + + Returns: + bool + + """ + return self._as_widget + + @property + def any_parent_as_widget(self): + """Any parent of item is used as widget. + + Attribute holding this information is set during creation and + stored to `_any_parent_as_widget`. + + Why is this information useful: If any parent is used as widget then + modifications and override are not important for whole part. + + Returns: + bool + + """ + if self._any_parent_as_widget is None: + return super(SettingObject, self).any_parent_as_widget + return self._any_parent_as_widget + @property def is_group(self): """Item represents key that can be overriden. From ccfec4759f8202be4c49ff8f345d1d3757afd9f1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:24:17 +0200 Subject: [PATCH 567/662] added attribute is empty to list item --- pype/tools/settings/settings/widgets/item_types.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 07f57c994d..b013dd24f7 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1306,6 +1306,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): self._parent = config_parent self._any_parent_is_group = True + self._is_empty = False layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -1367,6 +1368,8 @@ class ListItem(QtWidgets.QWidget, SettingObject): self.value_input.value_changed.connect(self._on_value_change) def set_as_empty(self, is_empty=True): + self._is_empty = is_empty + self.spacer_widget.setVisible(is_empty) self.value_input.setVisible(not is_empty) self.remove_btn.setEnabled(not is_empty) @@ -1409,7 +1412,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): return len(self._parent.input_fields) def _on_add_clicked(self): - if self.value_input.isVisible(): + if self._is_empty: self._parent.add_row(row=self.row() + 1) else: self.set_as_empty(False) @@ -1426,7 +1429,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): self._parent.swap_rows(row, row + 1) def config_value(self): - if self.value_input.isEnabled(): + if not self._is_empty: return self.value_input.item_value() return NOT_SET From e0e7b29f4b2d4494ff6e3ad918d45359ae2de179 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:27:18 +0200 Subject: [PATCH 568/662] added _is_empty to ModifiableDictItem too --- .../settings/settings/widgets/item_types.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index b013dd24f7..71d6d2370d 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1706,6 +1706,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._set_default_attributes() self._parent = config_parent + self._is_empty = False self.is_key_duplicated = False layout = QtWidgets.QHBoxLayout(self) @@ -1757,11 +1758,8 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): def key_value(self): return self.key_input.text() - def _is_enabled(self): - return self.key_input.isVisible() - def is_key_invalid(self): - if not self._is_enabled(): + if self._is_empty: return False if self.key_value() == "": @@ -1795,15 +1793,17 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return self._parent.is_group def on_add_clicked(self): - if self._is_enabled(): - self._parent.add_row(row=self.row() + 1) - else: + if self._is_empty: self.set_as_empty(False) + else: + self._parent.add_row(row=self.row() + 1) def on_remove_clicked(self): self._parent.remove_row(self) def set_as_empty(self, is_empty=True): + self._is_empty = is_empty + self.key_input.setVisible(not is_empty) self.value_input.setVisible(not is_empty) self.remove_btn.setEnabled(not is_empty) @@ -1830,13 +1830,13 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): @property def is_invalid(self): - if not self._is_enabled(): + if self._is_empty: return False return self.is_key_invalid() or self.value_input.is_invalid def update_style(self): state = "" - if self._is_enabled(): + if not self._is_empty: if self.is_key_invalid(): state = "invalid" elif self.is_key_modified(): @@ -1854,9 +1854,9 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): return {key: value} def config_value(self): - if self._is_enabled(): - return self.item_value() - return {} + if self._is_empty: + return {} + return self.item_value() def mouseReleaseEvent(self, event): return QtWidgets.QWidget.mouseReleaseEvent(self, event) From 180626ec2d0072779a75a9e678cba5bb388f619c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:27:44 +0200 Subject: [PATCH 569/662] implemented few methods in dict-item --- .../settings/settings/widgets/item_types.py | 44 ++++--------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 71d6d2370d..875965db32 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1248,45 +1248,19 @@ class DictItemWidget(QtWidgets.QWidget, SettingObject): return item def hierarchical_style_update(self): - print("hierarchical_style_update") + for input_field in self.input_fields: + input_field.hierarchical_style_update() def _on_value_change(self, item=None): - print("_on_value_change") + self.value_changed.emit(self) - 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) + def update_default_values(self, parent_values): + for input_field in self.input_fields: + input_field.update_default_values(parent_values) - def update_style(self): - 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, - self.is_invalid, - self.is_overriden, - self.is_modified - ) - if self._state == state: - return - - if 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) - self._state = state + def update_studio_values(self, parent_values): + for input_field in self.input_fields: + input_field.update_studio_values(parent_values) def item_value(self): output = {} From 127426e7864b03459c22df17eea7d6b8fb2d24f2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:31:22 +0200 Subject: [PATCH 570/662] added apply_overrides to widget item --- pype/tools/settings/settings/widgets/item_types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 875965db32..d4faaedcf6 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1262,6 +1262,10 @@ class DictItemWidget(QtWidgets.QWidget, SettingObject): for input_field in self.input_fields: input_field.update_studio_values(parent_values) + def apply_overrides(self, parent_values): + for input_field in self.input_fields: + input_field.apply_overrides(parent_values) + def item_value(self): output = {} for input_field in self.input_fields: From 02ba2a6f16b5304b2a9c1b724adbdf801f77ef98 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:32:17 +0200 Subject: [PATCH 571/662] using more attribute as_widget and any_parent_as_widget --- .../settings/settings/widgets/item_types.py | 78 +++++++++++++++---- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d4faaedcf6..9275ccbecb 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -198,6 +198,9 @@ class SettingObject: @property def is_modified(self): """Has object any changes that require saving.""" + if self.any_parent_as_widget: + return self._is_modified + if self._is_modified or self.defaults_not_set: return True @@ -626,10 +629,11 @@ class InputObject(SettingObject): if self.ignore_value_changes: return - if self.is_overidable: - self._is_overriden = True - else: - self._has_studio_override = True + if not self.any_parent_as_widget: + if self.is_overidable: + self._is_overriden = True + else: + self._has_studio_override = True if self._is_invalid: self._is_modified = True @@ -645,12 +649,18 @@ class InputObject(SettingObject): self.value_changed.emit(self) def studio_overrides(self): - if not self.has_studio_override: + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.has_studio_override + ): return NOT_SET, False return self.config_value(), self.is_group def overrides(self): - if not self.is_overriden: + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.is_overriden + ): return NOT_SET, False return self.config_value(), self.is_group @@ -1213,6 +1223,8 @@ class DictItemWidget(QtWidgets.QWidget, SettingObject): layout.setSpacing(5) layout.addWidget(body) + self.label_widget = label_widget + for child_configuration in input_data["children"]: self.add_children_gui(child_configuration) @@ -1345,6 +1357,14 @@ class ListItem(QtWidgets.QWidget, SettingObject): self.value_input.value_changed.connect(self._on_value_change) + @property + def as_widget(self): + return self._parent.as_widget + + @property + def any_parent_as_widget(self): + return self.as_widget or self._parent.any_parent_as_widget + def set_as_empty(self, is_empty=True): self._is_empty = is_empty @@ -1684,6 +1704,13 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): self._set_default_attributes() self._parent = config_parent + any_parent_as_widget = config_parent.as_widget + if not any_parent_as_widget: + any_parent_as_widget = config_parent.any_parent_as_widget + + self._any_parent_as_widget = any_parent_as_widget + self._any_parent_is_group = True + self._is_empty = False self.is_key_duplicated = False @@ -2303,7 +2330,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): if self.ignore_value_changes: return - if self.is_group: + if self.is_group and not self.any_parent_as_widget: if self.is_overidable: self._is_overriden = True else: @@ -2406,7 +2433,11 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return output def studio_overrides(self): - if not self.has_studio_override and not self.child_has_studio_override: + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.has_studio_override + and not self.child_has_studio_override + ): return NOT_SET, False values = {} @@ -2556,7 +2587,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if self.ignore_value_changes: return - if self.is_group: + if self.is_group and not self.any_parent_as_widget: if self.is_overidable: self._is_overriden = True else: @@ -2653,7 +2684,11 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): self._was_overriden = bool(self._is_overriden) def studio_overrides(self): - if not self.has_studio_override and not self.child_has_studio_override: + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.has_studio_override + and not self.child_has_studio_override + ): return NOT_SET, False values = {} @@ -2916,10 +2951,11 @@ class PathWidget(QtWidgets.QWidget, SettingObject): if self.ignore_value_changes: return - if self.is_overidable: - self._is_overriden = True - else: - self._has_studio_override = True + if not self.any_parent_as_widget: + if self.is_overidable: + self._is_overriden = True + else: + self._has_studio_override = True if self._is_invalid: self._is_modified = True @@ -3046,7 +3082,11 @@ class PathWidget(QtWidgets.QWidget, SettingObject): return output def studio_overrides(self): - if not self.has_studio_override and not self.child_has_studio_override: + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.has_studio_override + and not self.child_has_studio_override + ): return NOT_SET, False value = self.item_value() @@ -3236,7 +3276,11 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): return self.item_value() def studio_overrides(self): - if not self.has_studio_override and not self.child_has_studio_override: + if ( + not (self.as_widget or self.any_parent_as_widget) + and not self.has_studio_override + and not self.child_has_studio_override + ): return NOT_SET, False values = {} @@ -3310,7 +3354,7 @@ TypeToKlass.types["dict-item"] = DictItemWidget TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictInvisible TypeToKlass.types["path-widget"] = PathWidget -TypeToKlass.types["dict-form"] = DictFormWidget +TypeToKlass.types["form"] = DictFormWidget TypeToKlass.types["label"] = LabelWidget TypeToKlass.types["splitter"] = SplitterWidget From 2517f13266d3ccffed41e1323c31daf6b084b8f9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:32:47 +0200 Subject: [PATCH 572/662] ExtractReview plugin converted to use new DictItemWidget --- .../projects_schema/1_plugins_gui_schema.json | 89 ++++++++++++++++++- 1 file changed, 87 insertions(+), 2 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 b2d7914c84..f70495017e 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 @@ -169,9 +169,94 @@ "key": "enabled", "label": "Enabled" }, { - "type": "raw-json", + "type": "list", "key": "profiles", - "label": "Profiles" + "label": "Profiles", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + }, { + "type": "splitter" + }, { + "key": "outputs", + "label": "Output Definitions", + "type": "dict-modifiable", + "highlight_content": true, + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "ext", + "label": "Output extension", + "type": "text" + }, { + "key": "tags", + "label": "Tags", + "type": "list", + "object_type": "text" + }, { + "key": "ffmpeg_args", + "label": "FFmpeg arguments", + "type": "dict", + "highlight_content": true, + "children": [ + { + "key": "video_filters", + "label": "Video filters", + "type": "list", + "object_type": "text" + }, { + "type": "splitter" + }, { + "key": "audio_filters", + "label": "Audio filters", + "type": "list", + "object_type": "text" + }, { + "type": "splitter" + }, { + "key": "input", + "label": "Input arguments", + "type": "list", + "object_type": "text" + }, { + "type": "splitter" + }, { + "key": "output", + "label": "Output arguments", + "type": "list", + "object_type": "text" + } + ] + }, { + "key": "filter", + "label": "Additional output filtering", + "type": "dict", + "highlight_content": true, + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + } + ] + } + ] + } + } + ] + } } ] }, { From fae0b851281b5e2fc55085c6f3cff7ee2b262c6b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:34:36 +0200 Subject: [PATCH 573/662] fixed list item again --- 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 9275ccbecb..ea93acddb2 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1411,9 +1411,9 @@ class ListItem(QtWidgets.QWidget, SettingObject): def _on_add_clicked(self): if self._is_empty: - self._parent.add_row(row=self.row() + 1) - else: self.set_as_empty(False) + else: + self._parent.add_row(row=self.row() + 1) def _on_remove_clicked(self): self._parent.remove_row(self) From db928a85baf01b488ec5c2117a9f2e9055c53641 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 17 Sep 2020 19:37:28 +0200 Subject: [PATCH 574/662] make sure inputs won't affect it's potential children o remove project overrides --- pype/tools/settings/settings/widgets/item_types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ea93acddb2..d1fd219258 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -668,6 +668,8 @@ class InputObject(SettingObject): self.update_style() def remove_overrides(self): + self._is_overriden = False + self._is_modified = False if self.has_studio_override: self.set_value(self.studio_value) else: From bad080ee3ac877ddade28c3441699ed0807b5f19 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 09:53:04 +0200 Subject: [PATCH 575/662] modified defaults --- .../plugins/global/publish.json | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pype/settings/defaults/project_settings/plugins/global/publish.json b/pype/settings/defaults/project_settings/plugins/global/publish.json index b946ac4b32..0a7f6fbf3d 100644 --- a/pype/settings/defaults/project_settings/plugins/global/publish.json +++ b/pype/settings/defaults/project_settings/plugins/global/publish.json @@ -19,30 +19,30 @@ "hosts": [], "outputs": { "h264": { - "filter": { - "families": [ - "render", - "review", - "ftrack" - ] - }, "ext": "mp4", + "tags": [ + "burnin", + "ftrackreview" + ], "ffmpeg_args": { + "video_filters": [], + "audio_filters": [], "input": [ "-gamma 2.2" ], - "video_filters": [], - "audio_filters": [], "output": [ "-pix_fmt yuv420p", "-crf 18", "-intra" ] }, - "tags": [ - "burnin", - "ftrackreview" - ] + "filter": { + "families": [ + "render", + "review", + "ftrack" + ] + } } } } From dba17756003a1f554f07ce2a90b70da7d2192231 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 11:14:38 +0200 Subject: [PATCH 576/662] ApplicationAction has pype logger --- pype/lib.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index 601c85f521..73b47b8594 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -19,7 +19,7 @@ from abc import ABCMeta, abstractmethod from avalon import io, pipeline import six import avalon.api -from .api import config, Anatomy +from .api import config, Anatomy, Logger log = logging.getLogger(__name__) @@ -1622,7 +1622,7 @@ class ApplicationAction(avalon.api.Action): parsed application `.toml` this can launch the application. """ - + _log = None config = None group = None variant = None @@ -1632,6 +1632,12 @@ class ApplicationAction(avalon.api.Action): "AVALON_TASK" ) + @property + def log(self): + if self._log is None: + self._log = Logger().get_logger(self.__class__.__name__) + return self._log + def is_compatible(self, session): for key in self.required_session_keys: if key not in session: From b326855be0656047ac508dad3a118c36a212dbb9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 11:15:04 +0200 Subject: [PATCH 577/662] Application also change ftrack status and trigger ftrack timer --- pype/lib.py | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 1 deletion(-) diff --git a/pype/lib.py b/pype/lib.py index 73b47b8594..6fa204b379 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -1650,6 +1650,165 @@ class ApplicationAction(avalon.api.Action): project_name = session["AVALON_PROJECT"] asset_name = session["AVALON_ASSET"] task_name = session["AVALON_TASK"] - return launch_application( + launch_application( project_name, asset_name, task_name, self.name ) + + self._ftrack_after_launch_procedure( + project_name, asset_name, task_name + ) + + def _ftrack_after_launch_procedure( + self, project_name, asset_name, task_name + ): + # TODO move to launch hook + required_keys = ("FTRACK_SERVER", "FTRACK_API_USER", "FTRACK_API_KEY") + for key in required_keys: + if not os.environ.get(key): + self.log.debug(( + "Missing required environment \"{}\"" + " for Ftrack after launch procedure." + ).format(key)) + return + + try: + import ftrack_api + session = ftrack_api.Session(auto_connect_event_hub=True) + self.log.debug("Ftrack session created") + except Exception: + self.log.warning("Couldn't create Ftrack session") + return + + try: + entity = self._find_ftrack_task_entity( + session, project_name, asset_name, task_name + ) + self._ftrack_status_change(session, entity, project_name) + self._start_timer(session, entity, ftrack_api) + except Exception: + self.log.warning( + "Couldn't finish Ftrack procedure.", exc_info=True + ) + return + + finally: + session.close() + + def _find_ftrack_task_entity( + self, session, project_name, asset_name, task_name + ): + project_entity = session.query( + "Project where full_name is \"{}\"".format(project_name) + ).first() + if not project_entity: + self.log.warning( + "Couldn't find project \"{}\" in Ftrack.".format(project_name) + ) + return + + potential_task_entities = session.query(( + "TypedContext where parent.name is \"{}\" and project_id is \"{}\"" + ).format(asset_name, project_entity["id"])).all() + filtered_entities = [] + for _entity in potential_task_entities: + if ( + _entity.entity_type.lower() == "task" + and _entity["name"] == task_name + ): + filtered_entities.append(_entity) + + if not filtered_entities: + self.log.warning(( + "Couldn't find task \"{}\" under parent \"{}\" in Ftrack." + ).format(task_name, asset_name)) + return + + if len(filtered_entities) > 1: + self.log.warning(( + "Found more than one task \"{}\"" + " under parent \"{}\" in Ftrack." + ).format(task_name, asset_name)) + return + + return filtered_entities[0] + + def _ftrack_status_change(self, session, entity, project_name): + presets = config.get_presets(project_name)["ftrack"]["ftrack_config"] + statuses = presets.get("status_update") + if not statuses: + return + + actual_status = entity["status"]["name"].lower() + already_tested = set() + ent_path = "/".join( + [ent["name"] for ent in entity["link"]] + ) + while True: + next_status_name = None + for key, value in statuses.items(): + if key in already_tested: + continue + if actual_status in value or "_any_" in value: + if key != "_ignore_": + next_status_name = key + already_tested.add(key) + break + already_tested.add(key) + + if next_status_name is None: + break + + try: + query = "Status where name is \"{}\"".format( + next_status_name + ) + status = session.query(query).one() + + entity["status"] = status + session.commit() + self.log.debug("Changing status to \"{}\" <{}>".format( + next_status_name, ent_path + )) + break + + except Exception: + session.rollback() + msg = ( + "Status \"{}\" in presets wasn't found" + " on Ftrack entity type \"{}\"" + ).format(next_status_name, entity.entity_type) + self.log.warning(msg) + + def _start_timer(self, session, entity, _ftrack_api): + self.log.debug("Triggering timer start.") + + user_entity = session.query("User where username is \"{}\"".format( + os.environ["FTRACK_API_USER"] + )).first() + if not user_entity: + self.log.warning( + "Couldn't find user with username \"{}\" in Ftrack".format( + os.environ["FTRACK_API_USER"] + ) + ) + return + + source = { + "user": { + "id": user_entity["id"], + "username": user_entity["username"] + } + } + event_data = { + "actionIdentifier": "start.timer", + "selection": [{"entityId": entity["id"], "entityType": "task"}] + } + session.event_hub.publish( + _ftrack_api.event.base.Event( + topic="ftrack.action.launch", + data=event_data, + source=source + ), + on_error="ignore" + ) + self.log.debug("Timer start triggered successfully.") From cfcd24318fc6cd200011021205c7279223507043 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 11:48:25 +0200 Subject: [PATCH 578/662] avoid bugs when same event is more than once stored in mongo --- pype/modules/ftrack/ftrack_server/lib.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/modules/ftrack/ftrack_server/lib.py b/pype/modules/ftrack/ftrack_server/lib.py index acf31ab437..ee6b1216dc 100644 --- a/pype/modules/ftrack/ftrack_server/lib.py +++ b/pype/modules/ftrack/ftrack_server/lib.py @@ -205,10 +205,16 @@ class ProcessEventHub(SocketBaseEventHub): else: try: self._handle(event) + + mongo_id = event["data"].get("_event_mongo_id") + if mongo_id is None: + continue + self.dbcon.update_one( - {"id": event["id"]}, + {"_id": mongo_id}, {"$set": {"pype_data.is_processed": True}} ) + except pymongo.errors.AutoReconnect: self.pypelog.error(( "Mongo server \"{}\" is not responding, exiting." @@ -244,6 +250,7 @@ class ProcessEventHub(SocketBaseEventHub): } try: event = ftrack_api.event.base.Event(**new_event_data) + event["data"]["_event_mongo_id"] = event_data["_id"] except Exception: self.logger.exception(L( 'Failed to convert payload into event: {0}', From 384c2382063b050f0547f0499f5647992d33f9b1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 12:20:27 +0200 Subject: [PATCH 579/662] ListWidget can be now used as widget in other item types --- .../tools/settings/settings/widgets/item_types.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index d1fd219258..68cebf6642 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1479,17 +1479,17 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.object_type = input_data["object_type"] self.input_modifiers = input_data.get("input_modifiers") or {} - self.key = input_data["key"] - self.input_fields = [] layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 5) layout.setSpacing(5) - if not label_widget: - label_widget = QtWidgets.QLabel(input_data["label"], self) - layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) + if not self.as_widget: + self.key = input_data["key"] + if not label_widget: + label_widget = QtWidgets.QLabel(input_data["label"], self) + layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) self.label_widget = label_widget @@ -1684,8 +1684,9 @@ class ListWidget(QtWidgets.QWidget, InputObject): if self._state == state: return - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) def item_value(self): output = [] From 9a5007a9aad24d788aad04bd3cf50cdc4529cf05 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 12:21:06 +0200 Subject: [PATCH 580/662] changed `dict-form` to `form` in examples --- .../settings/settings/gui_schemas/system_schema/1_examples.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index a884dcb31e..73f72c875c 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -207,7 +207,7 @@ "label": "Inputs with form", "children": [ { - "type": "dict-form", + "type": "form", "children": [ { "type": "text", From 5b867b2def2ea19ca25d3c23f6c67c3343b70d1b Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 18 Sep 2020 12:23:24 +0200 Subject: [PATCH 581/662] change dict-form to form in examples --- .../settings/settings/gui_schemas/system_schema/1_examples.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index a884dcb31e..73f72c875c 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -207,7 +207,7 @@ "label": "Inputs with form", "children": [ { - "type": "dict-form", + "type": "form", "children": [ { "type": "text", From c5d5492c3375cc22866481beec7fc82faeffaa01 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 18 Sep 2020 12:23:38 +0200 Subject: [PATCH 582/662] start converting ftrack settings --- .../system_schema/1_tray_items.json | 272 ++++++++++-------- 1 file changed, 156 insertions(+), 116 deletions(-) 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 0d27ccdc4b..deb84673f0 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 @@ -1,120 +1,160 @@ { - "key": "tray_modules", - "type": "dict", - "label": "Modules", - "collapsable": true, - "is_group": true, - "is_file": true, - "children": [ - { - "key": "item_usage", - "type": "dict-invisible", - "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": "Timers Manager", - "label": "Timers Manager" - }, { - "type": "boolean", - "key": "Rest Api", - "label": "Rest Api" - }, { - "type": "boolean", - "key": "Adobe Communicator", - "label": "Adobe Communicator" - } - ] + "key": "tray_modules", + "type": "dict", + "label": "Modules", + "collapsable": true, + "is_file": true, + "children": [{ + "key": "item_usage", + "type": "dict-invisible", + "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": "Timers Manager", + "label": "Timers Manager" + }, { + "type": "boolean", + "key": "Rest Api", + "label": "Rest Api" + }, { + "type": "boolean", + "key": "Adobe Communicator", + "label": "Adobe Communicator" + }] + }, { + "key": "attributes", + "type": "dict-invisible", + "children": [{ + "type": "dict", + "key": "Ftrack", + "label": "Ftrack", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "ftrack_server", + "label": "Server" + }, + { + "type": "dict", + "key": "sync_to_avalon", + "label": "Sync to avalon", + "children": [{ + "type": "list", + "key": "statuses_name_change", + "label": "Status name change", + "object_type": "text", + "input_modifiers": { + "multiline": false + } + }] + }, + { + "type": "dict-modifiable", + "key": "status_version_to_task", + "label": "Version to Task status mapping", + "object_type": "text" + } + ] + }, + { + "type": "dict", + "key": "Rest Api", + "label": "Rest Api", + "collapsable": true, + "children": [{ + "type": "number", + "key": "default_port", + "label": "Default Port", + "minimum": 1, + "maximum": 65535 }, { - "key": "attributes", - "type": "dict-invisible", - "children": [ - { - "type": "dict", - "key": "Rest Api", - "label": "Rest Api", - "collapsable": true, - "children": [ - { - "type": "number", - "key": "default_port", - "label": "Default Port", - "minimum": 1, - "maximum": 65535 - }, { - "type": "list", - "object_type": "number", - "key": "exclude_ports", - "label": "Exclude ports", - "input_modifiers": { - "minimum": 1, - "maximum": 65535 - } - } - ] - }, { - "type": "dict", - "key": "Timers Manager", - "label": "Timers Manager", - "collapsable": true, - "children": [ - { - "type": "number", - "decimal": 2, - "key": "full_time", - "label": "Max idle time" - }, { - "type": "number", - "decimal": 2, - "key": "message_time", - "label": "When dialog will show" - } - ] - }, { - "type": "dict", - "key": "Clockify", - "label": "Clockify", - "collapsable": true, - "children": [ - { - "type": "text", - "key": "workspace_name", - "label": "Workspace name" - } - ] - } - ] - } + "type": "list", + "object_type": "number", + "key": "exclude_ports", + "label": "Exclude ports", + "input_modifiers": { + "minimum": 1, + "maximum": 65535 + } + }] + }, { + "type": "dict", + "key": "Timers Manager", + "label": "Timers Manager", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "number", + "decimal": 2, + "key": "full_time", + "label": "Max idle time" + }, { + "type": "number", + "decimal": 2, + "key": "message_time", + "label": "When dialog will show" + } + ] + }, { + "type": "dict", + "key": "Clockify", + "label": "Clockify", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "workspace_name", + "label": "Workspace name" + } + ] + } ] + }] } From 75fd8c666ee0fc7b867386486a9a9ac13aa13bd1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:09:03 +0200 Subject: [PATCH 583/662] added possibility to set placeholder for text input --- pype/tools/settings/settings/widgets/item_types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 68cebf6642..fea78b713b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -906,6 +906,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(input_data, parent, as_widget) self.multiline = input_data.get("multiline", False) + placeholder = input_data.get("placeholder") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -916,6 +917,9 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.text_input = QtWidgets.QLineEdit(self) + if placeholder: + self.text_input.setPlaceholderText(placeholder) + self.setFocusProxy(self.text_input) layout_kwargs = {} From a28e154580c4bb5eef3dcbc38c280a3bb8780c02 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:09:09 +0200 Subject: [PATCH 584/662] added info to README --- pype/tools/settings/settings/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..da8868199a 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -111,6 +111,7 @@ ### text - simple text input - key `"multiline"` allows to enter multiple lines of text (Default: `False`) + - key `"placeholder"` allows to show text inside input when is empty (Default: `None`) ``` { From 98569e4fed3469f7bb19a4b4923dfff1c2ae4add Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:14:45 +0200 Subject: [PATCH 585/662] schema item does not have key `children` but `name`, schema type can represent only one schema name --- pype/tools/settings/settings/widgets/lib.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index e225d65417..f54989cfd7 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -69,12 +69,11 @@ def _fill_inner_schemas(schema_data, schema_collection): new_children.append(new_child) continue - for schema_name in child["children"]: - new_child = _fill_inner_schemas( - schema_collection[schema_name], - schema_collection - ) - new_children.append(new_child) + new_child = _fill_inner_schemas( + schema_collection[child["name"]], + schema_collection + ) + new_children.append(new_child) schema_data["children"] = new_children return schema_data From 44dc6805ade48fd2edd94bb1db1479afdc84f0a8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:14:56 +0200 Subject: [PATCH 586/662] modified current schemas --- .../projects_schema/0_project_gui_schema.json | 4 +--- .../system_schema/0_system_gui_schema.json | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) 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 fa7c6a366d..cf95bf4c45 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 @@ -22,9 +22,7 @@ "children": [ { "type": "schema", - "children": [ - "1_plugins_gui_schema" - ] + "name": "1_plugins_gui_schema" } ] } diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json index b16545111c..456af7ac0f 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json @@ -7,12 +7,16 @@ "key": "global", "children": [{ "type": "schema", - "children": [ - "1_tray_items", - "1_applications_gui_schema", - "1_tools_gui_schema", - "1_intents_gui_schema" - ] + "name": "1_tray_items" + }, { + "type": "schema", + "name": "1_applications_gui_schema" + }, { + "type": "schema", + "name": "1_tools_gui_schema" + }, { + "type": "schema", + "name": "1_intents_gui_schema" }] }, { "type": "dict-invisible", @@ -29,6 +33,9 @@ "label": "Muster - Templates mapping", "is_file": true }] + }, { + "type": "schema", + "name": "1_examples" } ] } From aa472d66de0eb674bad32cc31747a38710eeea09 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:15:02 +0200 Subject: [PATCH 587/662] modified README --- pype/tools/settings/settings/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..adacd62772 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -27,10 +27,7 @@ ``` { "type": "schema", - "children": [ - "my_schema_name", - "my_other_schema_name" - ] + "name": "my_schema_name" } ``` From dd9809e3edd9fc9657f296748d5f2f77a8541267 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 18 Sep 2020 15:39:35 +0200 Subject: [PATCH 588/662] update modules settings, in system --- .../system_settings/global/applications.json | 28 +- .../system_settings/global/modules.json | 57 ++++ .../system_settings/global/tools.json | 4 +- .../system_settings/global/tray_modules.json | 28 -- .../system_schema/0_system_gui_schema.json | 17 +- .../system_schema/1_modules_gui_schema.json | 266 ++++++++++++++++++ .../system_schema/1_tray_items.json | 160 ----------- 7 files changed, 340 insertions(+), 220 deletions(-) create mode 100644 pype/settings/defaults/system_settings/global/modules.json delete mode 100644 pype/settings/defaults/system_settings/global/tray_modules.json create mode 100644 pype/tools/settings/settings/gui_schemas/system_schema/1_modules_gui_schema.json delete mode 100644 pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json diff --git a/pype/settings/defaults/system_settings/global/applications.json b/pype/settings/defaults/system_settings/global/applications.json index 3a74a85468..e85e5864d9 100644 --- a/pype/settings/defaults/system_settings/global/applications.json +++ b/pype/settings/defaults/system_settings/global/applications.json @@ -1,32 +1,32 @@ { - "blender_2.80": true, - "blender_2.81": true, - "blender_2.82": true, + "blender_2.80": false, + "blender_2.81": false, + "blender_2.82": false, "blender_2.83": true, "celaction_local": true, "celaction_remote": true, "harmony_17": true, - "maya_2017": true, - "maya_2018": true, + "maya_2017": false, + "maya_2018": false, "maya_2019": true, "maya_2020": true, - "nuke_10.0": true, - "nuke_11.2": true, + "nuke_10.0": false, + "nuke_11.2": false, "nuke_11.3": true, "nuke_12.0": true, - "nukex_10.0": true, - "nukex_11.2": true, + "nukex_10.0": false, + "nukex_11.2": false, "nukex_11.3": true, "nukex_12.0": true, - "nukestudio_10.0": true, - "nukestudio_11.2": true, + "nukestudio_10.0": false, + "nukestudio_11.2": false, "nukestudio_11.3": true, "nukestudio_12.0": true, - "houdini_16": true, + "houdini_16": false, "houdini_16.5": false, - "houdini_17": true, + "houdini_17": false, "houdini_18": true, - "premiere_2019": true, + "premiere_2019": false, "premiere_2020": true, "resolve_16": true, "storyboardpro_7": true, diff --git a/pype/settings/defaults/system_settings/global/modules.json b/pype/settings/defaults/system_settings/global/modules.json new file mode 100644 index 0000000000..6400c2e3f3 --- /dev/null +++ b/pype/settings/defaults/system_settings/global/modules.json @@ -0,0 +1,57 @@ +{ + "Avalon": { + "AVALON_MONGO": "", + "AVALON_DB_DATA": "", + "AVALON_THUMBNAIL_ROOT": "" + }, + "Ftrack": { + "enabled": true, + "ftrack_server": "", + "ftrack_actions_path": [], + "ftrack_events_path": [], + "FTRACK_EVENTS_MONGO_DB": "", + "FTRACK_EVENTS_MONGO_COL": "", + "sync_to_avalon": { + "statuses_name_change": [] + }, + "status_version_to_task": {}, + "status_update": {} + }, + "Rest Api": { + "default_port": 1, + "exclude_ports": [] + }, + "Timers Manager": { + "enabled": true, + "full_time": 0.0, + "message_time": 0.0 + }, + "Clockify": { + "enabled": true, + "workspace_name": "" + }, + "Deadline": { + "enabled": true, + "DEADLINE_REST_URL": "" + }, + "Muster": { + "enabled": true, + "MUSTER_REST_URL": "", + "templates_mapping": {} + }, + "Logging": { + "enabled": true + }, + "Adobe Communicator": { + "enabled": true + }, + "User setting": { + "enabled": true + }, + "Standalone Publish": { + "enabled": true + }, + "Idle Manager": { + "enabled": true + } +} \ No newline at end of file diff --git a/pype/settings/defaults/system_settings/global/tools.json b/pype/settings/defaults/system_settings/global/tools.json index 93895c0e81..1f8c2ad1ea 100644 --- a/pype/settings/defaults/system_settings/global/tools.json +++ b/pype/settings/defaults/system_settings/global/tools.json @@ -1,6 +1,6 @@ { - "mtoa_3.0.1": true, - "mtoa_3.1.1": true, + "mtoa_3.0.1": false, + "mtoa_3.1.1": false, "mtoa_3.2.0": true, "yeti_2.1.2": true } \ No newline at end of file diff --git a/pype/settings/defaults/system_settings/global/tray_modules.json b/pype/settings/defaults/system_settings/global/tray_modules.json deleted file mode 100644 index 0ff5b15552..0000000000 --- a/pype/settings/defaults/system_settings/global/tray_modules.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.0, - "message_time": 0.5 - }, - "Clockify": { - "workspace_name": "" - } - } -} \ No newline at end of file diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json index b16545111c..a979ae1fed 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json @@ -8,27 +8,12 @@ "children": [{ "type": "schema", "children": [ - "1_tray_items", + "1_modules_gui_schema", "1_applications_gui_schema", "1_tools_gui_schema", "1_intents_gui_schema" ] }] - }, { - "type": "dict-invisible", - "key": "muster", - "children": [{ - "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 - }] } ] } diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_modules_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_modules_gui_schema.json new file mode 100644 index 0000000000..feec5735f5 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_modules_gui_schema.json @@ -0,0 +1,266 @@ +{ + "key": "modules", + "type": "dict", + "label": "Modules", + "collapsable": true, + "is_file": true, + "children": [{ + "type": "dict", + "key": "Avalon", + "label": "Avalon", + "collapsable": true, + "children": [ + { + "type": "text", + "key": "AVALON_MONGO", + "label": "Avalon Mongo URL" + }, + { + "type": "text", + "key": "AVALON_DB_DATA", + "label": "Avalon Mongo Data Location" + }, + { + "type": "text", + "key": "AVALON_THUMBNAIL_ROOT", + "label": "Thumbnail Storage Location" + } + ] + },{ + "type": "dict", + "key": "Ftrack", + "label": "Ftrack", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "ftrack_server", + "label": "Server" + }, + { + "type": "label", + "label": "Additional Ftrack paths" + }, + { + "type": "list", + "key": "ftrack_actions_path", + "label": "Action paths", + "object_type": "text" + }, + { + "type": "list", + "key": "ftrack_events_path", + "label": "Event paths", + "object_type": "text" + }, + { + "type": "label", + "label": "Ftrack event server advanced settings" + }, + { + "type": "text", + "key": "FTRACK_EVENTS_MONGO_DB", + "label": "Event Mongo DB" + }, + { + "type": "text", + "key": "FTRACK_EVENTS_MONGO_COL", + "label": "Events Mongo Collection" + }, + { + "type": "dict", + "key": "sync_to_avalon", + "label": "Sync to avalon", + "children": [{ + "type": "list", + "key": "statuses_name_change", + "label": "Status name change", + "object_type": "text", + "input_modifiers": { + "multiline": false + } + }] + }, + { + "type": "dict-modifiable", + "key": "status_version_to_task", + "label": "Version to Task status mapping", + "object_type": "text" + }, + { + "type": "dict-modifiable", + "key": "status_update", + "label": "Status Updates", + "object_type": "list", + "input_modifiers": { + "object_type": "text" + } + } + ] + }, { + "type": "dict", + "key": "Rest Api", + "label": "Rest Api", + "collapsable": true, + "children": [{ + "type": "number", + "key": "default_port", + "label": "Default Port", + "minimum": 1, + "maximum": 65535 + }, + { + "type": "list", + "object_type": "number", + "key": "exclude_ports", + "label": "Exclude ports", + "input_modifiers": { + "minimum": 1, + "maximum": 65535 + } + } + ] + }, { + "type": "dict", + "key": "Timers Manager", + "label": "Timers Manager", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "number", + "decimal": 2, + "key": "full_time", + "label": "Max idle time" + }, { + "type": "number", + "decimal": 2, + "key": "message_time", + "label": "When dialog will show" + } + ] + }, { + "type": "dict", + "key": "Clockify", + "label": "Clockify", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "text", + "key": "workspace_name", + "label": "Workspace name" + } + ] + }, { + "type": "dict", + "key": "Deadline", + "label": "Deadline", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + },{ + "type": "text", + "key": "DEADLINE_REST_URL", + "label": "Deadline Resl URL" + }] + }, { + "type": "dict", + "key": "Muster", + "label": "Muster", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + },{ + "type": "text", + "key": "MUSTER_REST_URL", + "label": "Muster Resl URL" + },{ + "type": "dict-modifiable", + "object_type": "number", + "input_modifiers": { + "minimum": 0, + "maximum": 300 + }, + "is_group": true, + "key": "templates_mapping", + "label": "Templates mapping", + "is_file": true + }] + }, { + "type": "dict", + "key": "Logging", + "label": "Logging", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "key": "Adobe Communicator", + "label": "Adobe Communicator", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "key": "User setting", + "label": "User setting", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "key": "Standalone Publish", + "label": "Standalone Publish", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "key": "Idle Manager", + "label": "Idle Manager", + "collapsable": true, + "checkbox_key": "enabled", + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + } + ] +} 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 deleted file mode 100644 index deb84673f0..0000000000 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_tray_items.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "key": "tray_modules", - "type": "dict", - "label": "Modules", - "collapsable": true, - "is_file": true, - "children": [{ - "key": "item_usage", - "type": "dict-invisible", - "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": "Timers Manager", - "label": "Timers Manager" - }, { - "type": "boolean", - "key": "Rest Api", - "label": "Rest Api" - }, { - "type": "boolean", - "key": "Adobe Communicator", - "label": "Adobe Communicator" - }] - }, { - "key": "attributes", - "type": "dict-invisible", - "children": [{ - "type": "dict", - "key": "Ftrack", - "label": "Ftrack", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "text", - "key": "ftrack_server", - "label": "Server" - }, - { - "type": "dict", - "key": "sync_to_avalon", - "label": "Sync to avalon", - "children": [{ - "type": "list", - "key": "statuses_name_change", - "label": "Status name change", - "object_type": "text", - "input_modifiers": { - "multiline": false - } - }] - }, - { - "type": "dict-modifiable", - "key": "status_version_to_task", - "label": "Version to Task status mapping", - "object_type": "text" - } - ] - }, - { - "type": "dict", - "key": "Rest Api", - "label": "Rest Api", - "collapsable": true, - "children": [{ - "type": "number", - "key": "default_port", - "label": "Default Port", - "minimum": 1, - "maximum": 65535 - }, { - "type": "list", - "object_type": "number", - "key": "exclude_ports", - "label": "Exclude ports", - "input_modifiers": { - "minimum": 1, - "maximum": 65535 - } - }] - }, { - "type": "dict", - "key": "Timers Manager", - "label": "Timers Manager", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "number", - "decimal": 2, - "key": "full_time", - "label": "Max idle time" - }, { - "type": "number", - "decimal": 2, - "key": "message_time", - "label": "When dialog will show" - } - ] - }, { - "type": "dict", - "key": "Clockify", - "label": "Clockify", - "collapsable": true, - "checkbox_key": "enabled", - "children": [{ - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, - { - "type": "text", - "key": "workspace_name", - "label": "Workspace name" - } - ] - } - ] - }] -} From 162dc8a4bdfef487b1a804f7adb7022b07276715 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 18 Sep 2020 15:42:51 +0200 Subject: [PATCH 589/662] fill defaults --- .../system_settings/global/modules.json | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/pype/settings/defaults/system_settings/global/modules.json b/pype/settings/defaults/system_settings/global/modules.json index 6400c2e3f3..3fb52fa129 100644 --- a/pype/settings/defaults/system_settings/global/modules.json +++ b/pype/settings/defaults/system_settings/global/modules.json @@ -1,30 +1,40 @@ { "Avalon": { - "AVALON_MONGO": "", - "AVALON_DB_DATA": "", - "AVALON_THUMBNAIL_ROOT": "" + "AVALON_MONGO": "mongodb://localhost:2707", + "AVALON_DB_DATA": "{PYPE_SETUP_PATH}/../mongo_db_data", + "AVALON_THUMBNAIL_ROOT": "{PYPE_SETUP_PATH}/../avalon_thumails" }, "Ftrack": { "enabled": true, - "ftrack_server": "", + "ftrack_server": "https://pype.ftrackapp.com", "ftrack_actions_path": [], "ftrack_events_path": [], - "FTRACK_EVENTS_MONGO_DB": "", - "FTRACK_EVENTS_MONGO_COL": "", + "FTRACK_EVENTS_MONGO_DB": "pype", + "FTRACK_EVENTS_MONGO_COL": "ftrack_events", "sync_to_avalon": { - "statuses_name_change": [] + "statuses_name_change": [ + "ready", + "not ready" + ] }, "status_version_to_task": {}, - "status_update": {} + "status_update": { + "Ready": [ + "Not Ready" + ], + "In Progress": [ + "_any_" + ] + } }, "Rest Api": { - "default_port": 1, + "default_port": 8021, "exclude_ports": [] }, "Timers Manager": { "enabled": true, - "full_time": 0.0, - "message_time": 0.0 + "full_time": 15.0, + "message_time": 0.5 }, "Clockify": { "enabled": true, @@ -32,12 +42,17 @@ }, "Deadline": { "enabled": true, - "DEADLINE_REST_URL": "" + "DEADLINE_REST_URL": "http://localhost:8082" }, "Muster": { - "enabled": true, + "enabled": false, "MUSTER_REST_URL": "", - "templates_mapping": {} + "templates_mapping": { + "arnold": 46, + "redshift": 55, + "renderman": 29, + "vray": 37 + } }, "Logging": { "enabled": true @@ -54,4 +69,4 @@ "Idle Manager": { "enabled": true } -} \ No newline at end of file +} From 7da75db742701e42f2c6a020413e6d1bcfc4ab07 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 18 Sep 2020 15:43:48 +0200 Subject: [PATCH 590/662] fill muster templates --- .../system_settings/global/modules.json | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/pype/settings/defaults/system_settings/global/modules.json b/pype/settings/defaults/system_settings/global/modules.json index 3fb52fa129..8a2b326d46 100644 --- a/pype/settings/defaults/system_settings/global/modules.json +++ b/pype/settings/defaults/system_settings/global/modules.json @@ -48,10 +48,23 @@ "enabled": false, "MUSTER_REST_URL": "", "templates_mapping": { - "arnold": 46, - "redshift": 55, - "renderman": 29, - "vray": 37 + "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 } }, "Logging": { From 2ee94bd890d0f86052f4d6278f751383d688a82b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:33:07 +0200 Subject: [PATCH 591/662] ListItem can be set as strict --- .../settings/settings/widgets/item_types.py | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 68cebf6642..8c9fbd8640 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1291,11 +1291,16 @@ class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, input_modifiers, config_parent, parent): + def __init__( + self, object_type, input_modifiers, config_parent, parent, + is_strict=False + ): super(ListItem, self).__init__(parent) self._set_default_attributes() + self._is_strict = is_strict + self._parent = config_parent self._any_parent_is_group = True self._is_empty = False @@ -1307,34 +1312,38 @@ class ListItem(QtWidgets.QWidget, SettingObject): char_up = qtawesome.charmap("fa.angle-up") char_down = qtawesome.charmap("fa.angle-down") - self.add_btn = QtWidgets.QPushButton("+") - self.remove_btn = QtWidgets.QPushButton("-") - self.up_btn = QtWidgets.QPushButton(char_up) - self.down_btn = QtWidgets.QPushButton(char_down) + if not self._is_strict: + 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_up_down = qtawesome.font("fa", 13) - self.up_btn.setFont(font_up_down) - self.down_btn.setFont(font_up_down) + font_up_down = qtawesome.font("fa", 13) + 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.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.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") + 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") - 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) + 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) + + layout.addWidget(self.add_btn, 0) + layout.addWidget(self.remove_btn, 0) ItemKlass = TypeToKlass.types[object_type] self.value_input = ItemKlass( @@ -1344,18 +1353,17 @@ class ListItem(QtWidgets.QWidget, SettingObject): label_widget=None ) - self.spacer_widget = QtWidgets.QWidget(self) - self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - self.spacer_widget.setVisible(False) - - layout.addWidget(self.add_btn, 0) - layout.addWidget(self.remove_btn, 0) - layout.addWidget(self.value_input, 1) - layout.addWidget(self.spacer_widget, 1) - layout.addWidget(self.up_btn, 0) - layout.addWidget(self.down_btn, 0) + if not self._is_strict: + self.spacer_widget = QtWidgets.QWidget(self) + self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.spacer_widget.setVisible(False) + + layout.addWidget(self.spacer_widget, 1) + + layout.addWidget(self.up_btn, 0) + layout.addWidget(self.down_btn, 0) self.value_input.value_changed.connect(self._on_value_change) From 0cccd9e3a7fe7a12866ba627f8d6770813838eca Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:44:55 +0200 Subject: [PATCH 592/662] implemented strict list --- .../settings/settings/widgets/item_types.py | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8c9fbd8640..7afa6fca18 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1705,6 +1705,153 @@ class ListWidget(QtWidgets.QWidget, InputObject): return output +class ListStrictWidget(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + _default_input_value = None + + def __init__( + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None + ): + if parent_widget is None: + parent_widget = parent + super(ListStrictWidget, self).__init__(parent_widget) + self.setObjectName("ListStrictWidget") + + horizontal = input_data.get("horizontal", True) + + self.initial_attributes(input_data, parent, as_widget) + + self.input_fields = [] + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 5) + layout.setSpacing(5) + + if not self.as_widget: + self.key = input_data["key"] + if not label_widget: + label_widget = QtWidgets.QLabel(input_data["label"], self) + layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) + + self.label_widget = label_widget + + inputs_widget = QtWidgets.QWidget(self) + inputs_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(inputs_widget) + + if horizontal: + inputs_layout = QtWidgets.QHBoxLayout(inputs_widget) + else: + inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout.setContentsMargins(0, 0, 0, 0) + inputs_layout.setSpacing(3) + + self.inputs_widget = inputs_widget + self.inputs_layout = inputs_layout + + for child_configuration in input_data["object_types"]: + object_type = child_configuration["type"] + + proxy_widget = QtWidgets.QWidget(self) + proxy_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + item_widget = ListItem( + object_type, child_configuration, self, proxy_widget, + is_strict=True + ) + + self.input_fields.append(item_widget) + item_widget.value_changed.connect(self._on_value_change) + + proxy_layout = QtWidgets.QHBoxLayout(proxy_widget) + proxy_layout.setContentsMargins(0, 0, 0, 0) + proxy_layout.setSpacing(5) + + label = child_configuration.get("label") + label_widget = None + if label: + label_widget = QtWidgets.QLabel(label, self) + proxy_layout.addWidget(label_widget, 0) + + proxy_layout.addWidget(item_widget, 0) + + if not horizontal: + spacer_widget = QtWidgets.QWidget(proxy_widget) + proxy_layout.addWidget(spacer_widget, 1) + + self.inputs_layout.addWidget(proxy_widget) + + if horizontal: + spacer_widget = QtWidgets.QWidget(proxy_widget) + self.inputs_layout.addWidget(spacer_widget, 1) + + self.updateGeometry() + + @property + def default_input_value(self): + if self._default_input_value is None: + self.set_value(NOT_SET) + self._default_input_value = self.item_value() + return self._default_input_value + + def set_value(self, value): + if self._is_overriden: + method_name = "apply_overrides" + elif not self._has_studio_override: + method_name = "update_default_values" + else: + method_name = "update_studio_values" + + for idx, input_field in enumerate(self.input_fields): + if value is NOT_SET: + _value = value + else: + if idx > len(value) - 1: + _value = NOT_SET + else: + _value = value[idx] + _method = getattr(input_field, method_name) + _method(_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): + 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, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + + if self._state == state: + return + + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + output = [] + for item in self.input_fields: + output.append(item.config_value()) + return output + + class ModifiableDictItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -3360,6 +3507,7 @@ TypeToKlass.types["text"] = TextWidget TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget +TypeToKlass.types["list-strict"] = ListStrictWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["dict-item"] = DictItemWidget TypeToKlass.types["dict"] = DictWidget From a13755c341d67a91b9a70ce23440c16ce0d544d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:46:08 +0200 Subject: [PATCH 593/662] make sure defaults_not_set is set to False if defaults are available --- pype/tools/settings/settings/widgets/item_types.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 7afa6fca18..4a9e092a99 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -547,6 +547,7 @@ class InputObject(SettingObject): Class is for item types not creating or using other item types, most of methods has same code in that case. """ + def update_default_values(self, parent_values): self._state = None self._is_modified = False @@ -559,8 +560,8 @@ class InputObject(SettingObject): if value is NOT_SET: if self.develop_mode: - value = self.default_input_value self.defaults_not_set = True + value = self.default_input_value if value is NOT_SET: raise NotImplementedError(( "{} Does not have implemented" @@ -571,6 +572,8 @@ class InputObject(SettingObject): raise ValueError( "Default value is not set. This is implementation BUG." ) + else: + self.defaults_not_set = False self.default_value = value self._has_studio_override = False @@ -3024,6 +3027,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): raise ValueError( "Default value is not set. This is implementation BUG." ) + else: + self.defaults_not_set = False self.default_value = value self._has_studio_override = False From d3e61cea7dd01d4d950c9786d9184d20a0b59485 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:46:24 +0200 Subject: [PATCH 594/662] added strict list and dict-item to readme --- pype/tools/settings/settings/README.md | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..9d12467cc9 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -207,6 +207,85 @@ } ``` +### dict-item +- item represents dictionary with strict keys in and data types of its values +- can be used only as widget (in `list` or `dict-modifiable`) + - only key modifier is `children` which is list of it's keys +- USAGE: e.g. List of dictionaries where each dictionary have same structure. + +``` +{ + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ... + ] + } +} +``` + +### list-strict +- input for strict number of items in list +- each child item can be different type with different possible modifiers +- it is possible to display them in horizontal or vertical layout + - key `"horizontal"` as `True`/`False` (Default: `True`) +- each child may have defined `"label"` which is shown next to input + - label does not reflect modifications or overrides (TODO) +- children item are defined under key `"object_types"` which is list of dictionaries + - key `"children"` is not used because is used for hierarchy validations in schema +- USAGE: For colors, transformations, etc. Custom number and different modifiers + give ability to define if color is HUE or RGB, 0-255, 0-1, 0-100 etc. + +``` +{ + "type": "list-strict", + "key": "color", + "label": "Color", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] +} +``` + + ## Noninteractive widgets - have nothing to do with data From 060aa04f93f6999ddc9146ba762d81eb9ffeb8fa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:49:16 +0200 Subject: [PATCH 595/662] added dict-item and list-strict to examples --- .../gui_schemas/system_schema/1_examples.json | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) 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 index 73f72c875c..1284c9948b 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -72,6 +72,57 @@ "minimum": 10, "maximum": 100 } + }, { + "type": "list-strict", + "key": "strict_list", + "label": "StrictList (color)", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] + }, { + "type": "list", + "key": "dict_item", + "label": "DictItem in List", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ] + } }, { "type": "path-widget", "key": "single_path_input", From 8f967c9d6df25f85bad8ef633890688f51a54aff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:16:21 +0200 Subject: [PATCH 596/662] added more variants to list-strict --- .../gui_schemas/system_schema/1_examples.json | 91 ++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) 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 index 1284c9948b..0578968508 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -74,8 +74,8 @@ } }, { "type": "list-strict", - "key": "strict_list", - "label": "StrictList (color)", + "key": "strict_list_labels_horizontal", + "label": "StrictList-labels-horizontal (color)", "object_types": [ { "label": "Red", @@ -103,6 +103,93 @@ "decimal": 6 } ] + }, { + "type": "list-strict", + "key": "strict_list_labels_vertical", + "label": "StrictList-labels-vertical (color)", + "horizontal": false, + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] + }, { + "type": "list-strict", + "key": "strict_list_nolabels_horizontal", + "label": "StrictList-nolabels-horizontal (color)", + "object_types": [ + { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] + }, { + "type": "list-strict", + "key": "strict_list_nolabels_vertical", + "label": "StrictList-nolabels-vertical (color)", + "horizontal": false, + "object_types": [ + { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] }, { "type": "list", "key": "dict_item", From 85a55b4f1b649c5d9d6bd3f27360ae2deaca6239 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:16:34 +0200 Subject: [PATCH 597/662] list-strict use grid layout now --- .../settings/settings/widgets/item_types.py | 90 ++++++++++++++----- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 4a9e092a99..01dab9ccc9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1721,8 +1721,6 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): super(ListStrictWidget, self).__init__(parent_widget) self.setObjectName("ListStrictWidget") - horizontal = input_data.get("horizontal", True) - self.initial_attributes(input_data, parent, as_widget) self.input_fields = [] @@ -1739,58 +1737,91 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): self.label_widget = label_widget + self._add_children(layout, input_data) + + def _add_children(self, layout, input_data): inputs_widget = QtWidgets.QWidget(self) inputs_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(inputs_widget) + horizontal = input_data.get("horizontal", True) if horizontal: inputs_layout = QtWidgets.QHBoxLayout(inputs_widget) else: - inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout = QtWidgets.QGridLayout(inputs_widget) + inputs_layout.setContentsMargins(0, 0, 0, 0) inputs_layout.setSpacing(3) self.inputs_widget = inputs_widget self.inputs_layout = inputs_layout + children_item_mapping = [] for child_configuration in input_data["object_types"]: object_type = child_configuration["type"] - proxy_widget = QtWidgets.QWidget(self) - proxy_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - item_widget = ListItem( - object_type, child_configuration, self, proxy_widget, + object_type, child_configuration, self, self.inputs_widget, is_strict=True ) self.input_fields.append(item_widget) item_widget.value_changed.connect(self._on_value_change) - proxy_layout = QtWidgets.QHBoxLayout(proxy_widget) - proxy_layout.setContentsMargins(0, 0, 0, 0) - proxy_layout.setSpacing(5) - label = child_configuration.get("label") label_widget = None if label: label_widget = QtWidgets.QLabel(label, self) - proxy_layout.addWidget(label_widget, 0) - proxy_layout.addWidget(item_widget, 0) - - if not horizontal: - spacer_widget = QtWidgets.QWidget(proxy_widget) - proxy_layout.addWidget(spacer_widget, 1) - - self.inputs_layout.addWidget(proxy_widget) + children_item_mapping.append((label_widget, item_widget)) if horizontal: - spacer_widget = QtWidgets.QWidget(proxy_widget) - self.inputs_layout.addWidget(spacer_widget, 1) + self._add_children_horizontally(children_item_mapping) + else: + self._add_children_vertically(children_item_mapping) self.updateGeometry() + def _add_children_vertically(self, children_item_mapping): + any_has_label = False + for item_mapping in children_item_mapping: + if item_mapping[0]: + any_has_label = True + break + + row = self.inputs_layout.count() + if not any_has_label: + self.inputs_layout.setColumnStretch(1, 1) + for item_mapping in children_item_mapping: + item_widget = item_mapping[1] + self.inputs_layout.addWidget(item_widget, row, 0, 1, 1) + + spacer_widget = QtWidgets.QWidget(self.inputs_widget) + self.inputs_layout.addWidget(spacer_widget, row, 1, 1, 1) + row += 1 + + else: + self.inputs_layout.setColumnStretch(2, 1) + for label_widget, item_widget in children_item_mapping: + self.inputs_layout.addWidget( + label_widget, row, 0, 1, 1, + alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop + ) + self.inputs_layout.addWidget(item_widget, row, 1, 1, 1) + + spacer_widget = QtWidgets.QWidget(self.inputs_widget) + self.inputs_layout.addWidget(spacer_widget, row, 2, 1, 1) + row += 1 + + def _add_children_horizontally(self, children_item_mapping): + for label_widget, item_widget in children_item_mapping: + if label_widget: + self.inputs_layout.addWidget(label_widget, 0) + self.inputs_layout.addWidget(item_widget, 0) + + spacer_widget = QtWidgets.QWidget(self.inputs_widget) + self.inputs_layout.addWidget(spacer_widget, 1) + @property def default_input_value(self): if self._default_input_value is None: @@ -1840,7 +1871,7 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): self.is_overriden, self.is_modified ) - + if self._state == state: return @@ -2630,6 +2661,18 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return {self.key: values}, self.is_group +class GridLabel(QtWidgets.QLabel): + def __init__(self, *args, **kwargs): + super(GridLabel, self).__init__(*args, **kwargs) + self.input_field = None + + def mouseReleaseEvent(self, event): + if self.input_field: + print("here", self.input_field) + self.input_field.mouseReleaseEvent(event) + return super(GridLabel, self).mouseReleaseEvent(event) + + class DictInvisible(QtWidgets.QWidget, SettingObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) @@ -2679,7 +2722,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidgets.QLabel(label, self) + label_widget = GridLabel(label, self) self.content_layout.addWidget( label_widget, row, 0, 1, 1, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop @@ -2689,6 +2732,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item.value_changed.connect(self._on_value_change) if label_widget: + label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) From dcb0db7937a94e438568308d942cbd13e76d48bc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:19:51 +0200 Subject: [PATCH 598/662] reverse testing changes --- .../tools/settings/settings/widgets/item_types.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 01dab9ccc9..3bbf352f8b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2661,18 +2661,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return {self.key: values}, self.is_group -class GridLabel(QtWidgets.QLabel): - def __init__(self, *args, **kwargs): - super(GridLabel, self).__init__(*args, **kwargs) - self.input_field = None - - def mouseReleaseEvent(self, event): - if self.input_field: - print("here", self.input_field) - self.input_field.mouseReleaseEvent(event) - return super(GridLabel, self).mouseReleaseEvent(event) - - class DictInvisible(QtWidgets.QWidget, SettingObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) @@ -2722,7 +2710,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = GridLabel(label, self) + label_widget = QtWidget.QLabel(label, self) self.content_layout.addWidget( label_widget, row, 0, 1, 1, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop @@ -2732,7 +2720,6 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item.value_changed.connect(self._on_value_change) if label_widget: - label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) From cc8faba5bffbabec5e6f0d6f7d253ebd4a59aa8d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:20:52 +0200 Subject: [PATCH 599/662] typo fix --- 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 3bbf352f8b..bf9155f765 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2710,7 +2710,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidget.QLabel(label, self) + label_widget = QtWidgets.QLabel(label, self) self.content_layout.addWidget( label_widget, row, 0, 1, 1, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop From bbab7178c7ca1637ccdbcf7291a9209ebcd5954b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:53:27 +0200 Subject: [PATCH 600/662] DictWidget can be used as widget --- .../settings/settings/widgets/item_types.py | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 68cebf6642..8a88fbf829 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2132,18 +2132,26 @@ class DictWidget(QtWidgets.QWidget, SettingObject): 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__ - )) - if parent_widget is None: parent_widget = parent super(DictWidget, self).__init__(parent_widget) - self.setObjectName("DictWidget") self.initial_attributes(input_data, parent, as_widget) + self.input_fields = [] + + self.checkbox_widget = None + self.checkbox_key = input_data.get("checkbox_key") + + self.label_widget = label_widget + + if self.as_widget: + self._ui_as_widget(input_data) + else: + self._ui_as_item(input_data) + + def _ui_as_item(self, input_data): + self.key = input_data["key"] if input_data.get("highlight_content", False): content_state = "hightlighted" bottom_margin = 5 @@ -2151,10 +2159,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): content_state = "" bottom_margin = 0 - self.input_fields = [] - - self.key = input_data["key"] - main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) @@ -2177,9 +2181,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.label_widget = body_widget.label_widget - 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) @@ -2194,6 +2195,22 @@ class DictWidget(QtWidgets.QWidget, SettingObject): else: body_widget.hide_toolbox(hide_content=False) + def _ui_as_widget(self, input_data): + body = QtWidgets.QWidget(self) + body.setObjectName("DictAsWidgetBody") + + content_layout = QtWidgets.QGridLayout(body) + content_layout.setContentsMargins(5, 5, 5, 5) + self.content_layout = content_layout + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(body) + + for child_configuration in input_data["children"]: + self.add_children_gui(child_configuration) + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) From bd5e1ae310168996eda083fc008b190d8f671a64 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:55:16 +0200 Subject: [PATCH 601/662] minor tweaks in DictWidget to be able used as widget --- .../settings/settings/widgets/item_types.py | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8a88fbf829..83805d9948 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2297,8 +2297,12 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item.set_as_overriden() def update_default_values(self, parent_values): + # Make sure this is set to False + self._state = None + self._child_state = None + value = NOT_SET - if self._as_widget: + if self.as_widget: value = parent_values elif parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) @@ -2307,15 +2311,21 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item.update_default_values(value) def update_studio_values(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, 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) - self._has_studio_override = False - if self.is_group and value is not NOT_SET: - self._has_studio_override = True + 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) + self._had_studio_override = bool(self._has_studio_override) for item in self.input_fields: item.update_studio_values(value) @@ -2325,37 +2335,40 @@ class DictWidget(QtWidgets.QWidget, SettingObject): 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) + if not self.as_widget: + 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 + 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) + if not self.as_widget: + 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 and not self.any_parent_as_widget: + if self.is_group and not (self.as_widget or self.any_parent_as_widget): if self.is_overidable: self._is_overriden = True else: self._has_studio_override = True + # TODO check if this is required self.hierarchical_style_update() self.value_changed.emit(self) @@ -2368,6 +2381,10 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.update_style() def update_style(self, is_overriden=None): + # TODO add style update when used as widget + if self.as_widget: + return + child_has_studio_override = self.child_has_studio_override child_modified = self.child_modified child_invalid = self.child_invalid From cbbbefc76dd939cbd5e327086825f4eb5d508033 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:56:25 +0200 Subject: [PATCH 602/662] "dict-item" is set to DictWidget for backwards compatibility --- pype/tools/settings/settings/widgets/item_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 83805d9948..e6fb2d32e3 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3387,7 +3387,8 @@ TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict -TypeToKlass.types["dict-item"] = DictItemWidget +# DEPRECATED - remove when removed from schemas +TypeToKlass.types["dict-item"] = DictWidget TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictInvisible TypeToKlass.types["path-widget"] = PathWidget From 4bd7a6c4fa2ddabf5a90e0ec39d80c970e069da8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:56:45 +0200 Subject: [PATCH 603/662] removed DictItemWidget as is not used --- .../settings/settings/widgets/item_types.py | 95 ------------------- 1 file changed, 95 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e6fb2d32e3..3cf9cfcc74 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1192,101 +1192,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): return self.text_input.json_value() -class DictItemWidget(QtWidgets.QWidget, SettingObject): - default_input_value = True - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None - ): - if parent_widget is None: - parent_widget = parent - super(DictItemWidget, self).__init__(parent_widget) - - self.initial_attributes(input_data, parent, as_widget) - - if not self._as_widget: - raise TypeError("{} can be used only as widget.".format( - self.__class__.__name__ - )) - - self.input_fields = [] - - body = QtWidgets.QWidget(self) - body.setObjectName("DictItemWidgetBody") - - content_layout = QtWidgets.QGridLayout(body) - content_layout.setContentsMargins(5, 5, 5, 5) - self.content_layout = content_layout - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(body) - - self.label_widget = label_widget - - for child_configuration in input_data["children"]: - self.add_children_gui(child_configuration) - - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - - row = self.content_layout.rowCount() - if not getattr(klass, "is_input_type", False): - item = klass(child_configuration, self) - self.content_layout.addWidget(item, row, 0, 1, 2) - return item - - label_widget = None - if not klass.expand_in_grid: - label = child_configuration.get("label") - if label is not None: - label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget( - label_widget, row, 0, 1, 1, - alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop - ) - - item = klass(child_configuration, self, label_widget=label_widget) - item.value_changed.connect(self._on_value_change) - - if label_widget: - self.content_layout.addWidget(item, row, 1, 1, 1) - else: - self.content_layout.addWidget(item, row, 0, 1, 2) - - self.input_fields.append(item) - return item - - def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() - - def _on_value_change(self, item=None): - self.value_changed.emit(self) - - def update_default_values(self, parent_values): - for input_field in self.input_fields: - input_field.update_default_values(parent_values) - - def update_studio_values(self, parent_values): - for input_field in self.input_fields: - input_field.update_studio_values(parent_values) - - def apply_overrides(self, parent_values): - for input_field in self.input_fields: - input_field.apply_overrides(parent_values) - - def item_value(self): - output = {} - for input_field in self.input_fields: - output.update(input_field.config_value()) - return output - - class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) From ba8b1b8015b5821996b1b4140d6d2831c1394f03 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:57:00 +0200 Subject: [PATCH 604/662] changed object name in styles --- pype/tools/settings/settings/style/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 221f297219..3f648abef8 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -152,7 +152,7 @@ QPushButton[btn-type="expand-toggle"] { background: #141a1f; } -#DictItemWidgetBody{ +#DictAsWidgetBody{ background: transparent; border: 2px solid #cccccc; border-radius: 5px; From 14a15c9a8cbedae0641583869b552a8a84af78b1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:57:35 +0200 Subject: [PATCH 605/662] current schemas in example does not have dict-item --- .../gui_schemas/projects_schema/1_plugins_gui_schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 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 f70495017e..f357b51dc5 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 @@ -172,7 +172,7 @@ "type": "list", "key": "profiles", "label": "Profiles", - "object_type": "dict-item", + "object_type": "dict", "input_modifiers": { "children": [ { @@ -192,7 +192,7 @@ "label": "Output Definitions", "type": "dict-modifiable", "highlight_content": true, - "object_type": "dict-item", + "object_type": "dict", "input_modifiers": { "children": [ { From 83ff6bc85bd8c0016c97fca91e8ac07169ac4a58 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 12:03:57 +0200 Subject: [PATCH 606/662] removed dict-item from readme --- pype/tools/settings/settings/README.md | 31 -------------------------- 1 file changed, 31 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 9d12467cc9..8fa0a4616a 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -207,37 +207,6 @@ } ``` -### dict-item -- item represents dictionary with strict keys in and data types of its values -- can be used only as widget (in `list` or `dict-modifiable`) - - only key modifier is `children` which is list of it's keys -- USAGE: e.g. List of dictionaries where each dictionary have same structure. - -``` -{ - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": "dict-item", - "input_modifiers": { - "children": [ - { - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }, { - "key": "hosts", - "label": "Hosts", - "type": "list", - "object_type": "text" - } - ... - ] - } -} -``` - ### list-strict - input for strict number of items in list - each child item can be different type with different possible modifiers From 7361e86cb9341d9b92e092920711091a71342463 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 12:04:50 +0200 Subject: [PATCH 607/662] added new usage to readme --- pype/tools/settings/settings/README.md | 43 +++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..969c9dc574 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -57,13 +57,18 @@ ## dict - this is another dictionary input wrapping more inputs but visually makes them different -- required keys are `"key"` under which will be stored and `"label"` which will be shown in GUI -- 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`) -- it is possible to add darker background with `"highlight_content"` (Default: `False`) - - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color +- item may be used as widget (in `list` or `dict-modifiable`) + - in that case the only key modifier is `children` which is list of it's keys + - USAGE: e.g. List of dictionaries where each dictionary have same structure. +- item options if is not used as widget + - required keys are `"key"` under which will be stored and `"label"` which will be shown in GUI + - 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`) + - it is possible to add darker background with `"highlight_content"` (Default: `False`) + - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color ``` +# Example { "key": "applications", "type": "dict", @@ -76,6 +81,30 @@ ...ITEMS... ] } + +# When used as widget +{ + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ... + ] + } +} ``` ## Inputs for setting any kind of value (`Pure` inputs) @@ -234,7 +263,7 @@ - should wraps multiple inputs only visually - these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled -### dict-form +### form - DEPRECATED - may be used only in `dict` and `dict-invisible` where is currently used grid layout so form is not needed - item is kept as still may be used in specific cases From ac26fb31eb873ad784202d8575c4f56e7071e913 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 18:01:23 +0200 Subject: [PATCH 608/662] implemented label widget used in grid layout --- .../settings/settings/widgets/widgets.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 400b9371fd..2a1f5fe804 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -226,3 +226,56 @@ class UnsavedChangesDialog(QtWidgets.QDialog): def on_discard_pressed(self): self.done(2) + + +class SpacerWidget(QtWidgets.QWidget): + def __init__(self, parent=None): + super(SpacerWidget, self).__init__(parent) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + +class GridLabelWidget(QtWidgets.QWidget): + def __init__(self, label, parent=None): + super(GridLabelWidget, self).__init__(parent) + + self.input_field = None + + self.properties = {} + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + label_proxy = QtWidgets.QWidget(self) + label_proxy_layout = QtWidgets.QHBoxLayout(label_proxy) + label_proxy_layout.setContentsMargins(0, 0, 0, 0) + label_proxy_layout.setSpacing(0) + + label_widget = QtWidgets.QLabel(label, label_proxy) + spacer_widget_h = SpacerWidget(label_proxy) + label_proxy_layout.addWidget( + spacer_widget_h, 0, alignment=QtCore.Qt.AlignRight + ) + label_proxy_layout.addWidget( + label_widget, 0, alignment=QtCore.Qt.AlignRight + ) + + spacer_widget_v = SpacerWidget(self) + + layout.addWidget(label_proxy, 0) + layout.addWidget(spacer_widget_v, 1) + + self.label_widget = label_widget + + def setProperty(self, name, value): + cur_value = self.properties.get(name) + if cur_value == value: + return + + self.label_widget.setProperty(name, value) + self.label_widget.style().polish(self.label_widget) + + def mouseReleaseEvent(self, event): + if self.input_field: + return self.input_field.show_actions_menu(event) + return super(GridLabelWidget, self).mouseReleaseEvent(event) From 65e9a6a2541f3cacc3f2a98c11c749a9798d50a4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 18:01:54 +0200 Subject: [PATCH 609/662] `show_actions_menu` is separate method now triggered with right click on item --- .../settings/settings/widgets/item_types.py | 124 ++++++++++-------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fea78b713b..9f7d951241 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -285,65 +285,75 @@ class SettingObject: return "-".join(items) or "" + def show_actions_menu(self, event=None): + if event and event.button() != QtCore.Qt.RightButton: + return + + if not self.allow_actions: + if event: + return self.mouseReleaseEvent(event) + return + + 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.is_overidable + and not self.is_overriden + and not self.any_parent_is_group + ): + action = QtWidgets.QAction("Set project override") + actions_mapping[action] = self._set_as_overriden + menu.addAction(action) + + if ( + not self.is_overidable + and ( + self.has_studio_override + ) + ): + action = QtWidgets.QAction("Reset to pype default") + actions_mapping[action] = self._reset_to_pype_default + menu.addAction(action) + + if ( + not self.is_overidable + and not self.is_overriden + and not self.any_parent_is_group + and not self._had_studio_override + ): + action = QtWidgets.QAction("Set studio 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) + ): + # TODO better label + action = QtWidgets.QAction("Remove project 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() + 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 ( - self.is_overidable - and not self.is_overriden - and not self.any_parent_is_group - ): - action = QtWidgets.QAction("Set project override") - actions_mapping[action] = self._set_as_overriden - menu.addAction(action) - - if ( - not self.is_overidable - and ( - self.has_studio_override - ) - ): - action = QtWidgets.QAction("Reset to pype default") - actions_mapping[action] = self._reset_to_pype_default - menu.addAction(action) - - if ( - not self.is_overidable - and not self.is_overriden - and not self.any_parent_is_group - and not self._had_studio_override - ): - action = QtWidgets.QAction("Set studio 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) - ): - # TODO better label - action = QtWidgets.QAction("Remove project 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 + return self.show_actions_menu() mro = type(self).mro() index = mro.index(self.__class__) From 0d2110a6cce03fafe1682c5189904120c7777013 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 18:03:28 +0200 Subject: [PATCH 610/662] GridLabelWidget is used in dict and dict-invisible --- .../settings/settings/widgets/item_types.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 9f7d951241..213bd00a1b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -5,7 +5,8 @@ from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ExpandingWidget, NumberSpinBox, - PathInput + PathInput, + GridLabelWidget ) from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome @@ -2227,16 +2228,14 @@ class DictWidget(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget( - label_widget, row, 0, 1, 1, - alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop - ) + label_widget = GridLabelWidget(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) if label_widget: + label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) @@ -2535,16 +2534,14 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget( - label_widget, row, 0, 1, 1, - alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop - ) + label_widget = GridLabelWidget(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) if label_widget: + label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) From 4e5226cdc581e05b41730bf4780e982b48b06f49 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 11:42:23 +0200 Subject: [PATCH 611/662] fixed clipboard copy in global loaders when Qt is runnign QCoreApplication --- pype/plugins/global/load/copy_file.py | 5 ++--- pype/plugins/global/load/copy_file_path.py | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pype/plugins/global/load/copy_file.py b/pype/plugins/global/load/copy_file.py index bbb8e1d6f7..1acacf6b27 100644 --- a/pype/plugins/global/load/copy_file.py +++ b/pype/plugins/global/load/copy_file.py @@ -20,8 +20,8 @@ class CopyFile(api.Loader): def copy_file_to_clipboard(path): from avalon.vendor.Qt import QtCore, QtWidgets - app = QtWidgets.QApplication.instance() - assert app, "Must have running QApplication instance" + clipboard = QtWidgets.QApplication.clipboard() + assert clipboard, "Must have running QApplication instance" # Build mime data for clipboard data = QtCore.QMimeData() @@ -29,5 +29,4 @@ class CopyFile(api.Loader): data.setUrls([url]) # Set to Clipboard - clipboard = app.clipboard() clipboard.setMimeData(data) diff --git a/pype/plugins/global/load/copy_file_path.py b/pype/plugins/global/load/copy_file_path.py index cfda9dc271..f64f3e76d8 100644 --- a/pype/plugins/global/load/copy_file_path.py +++ b/pype/plugins/global/load/copy_file_path.py @@ -19,11 +19,10 @@ class CopyFilePath(api.Loader): @staticmethod def copy_path_to_clipboard(path): - from avalon.vendor.Qt import QtCore, QtWidgets + from avalon.vendor.Qt import QtWidgets - app = QtWidgets.QApplication.instance() - assert app, "Must have running QApplication instance" + clipboard = QtWidgets.QApplication.clipboard() + assert clipboard, "Must have running QApplication instance" # Set to Clipboard - clipboard = app.clipboard() clipboard.setText(os.path.normpath(path)) From 3cf6962d3c344a45a809b2ee7450fc56bf763d43 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:44:00 +0200 Subject: [PATCH 612/662] location configrations are refreshed if is triggered session.rollback() in ftrack plugins --- pype/plugins/ftrack/publish/integrate_ftrack_api.py | 8 ++++++++ .../plugins/ftrack/publish/integrate_ftrack_note.py | 1 + .../ftrack/publish/integrate_hierarchy_ftrack.py | 13 +++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_api.py b/pype/plugins/ftrack/publish/integrate_ftrack_api.py index 0c4c6d49b5..2c8e06a099 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_api.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_api.py @@ -97,6 +97,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) def process(self, instance): @@ -178,6 +179,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) # Adding metadata @@ -228,6 +230,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) # Adding metadata @@ -242,6 +245,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): session.commit() except Exception: session.rollback() + session._configure_locations() self.log.warning(( "Comment was not possible to set for AssetVersion" "\"{0}\". Can't set it's value to: \"{1}\"" @@ -258,6 +262,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): continue except Exception: session.rollback() + session._configure_locations() self.log.warning(( "Custom Attrubute \"{0}\"" @@ -272,6 +277,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) # Component @@ -316,6 +322,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) # Reset members in memory @@ -432,6 +439,7 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) if assetversion_entity not in used_asset_versions: diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_note.py b/pype/plugins/ftrack/publish/integrate_ftrack_note.py index 9566207145..acd295854d 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_note.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_note.py @@ -145,4 +145,5 @@ class IntegrateFtrackNote(pyblish.api.InstancePlugin): except Exception: tp, value, tb = sys.exc_info() session.rollback() + session._configure_locations() six.reraise(tp, value, tb) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index c4d8f2f705..95408e90ee 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -128,6 +128,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) # TASKS @@ -156,6 +157,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) # Incoming links. @@ -165,6 +167,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) # Create notes. @@ -185,6 +188,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) # Import children. @@ -201,6 +205,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) # Create new links. @@ -242,6 +247,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) return task @@ -256,6 +262,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() + self.session._configure_locations() six.reraise(tp, value, tb) return entity @@ -270,7 +277,8 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() - raise + self.session._configure_locations() + six.reraise(tp, value, tb) def auto_sync_on(self, project): @@ -283,4 +291,5 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): except Exception: tp, value, tb = sys.exc_info() self.session.rollback() - raise + self.session._configure_locations() + six.reraise(tp, value, tb) From c2d8868ac043bf1a041510d15d6696bb9848074f Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 22 Sep 2020 15:25:46 +0100 Subject: [PATCH 613/662] FIx missing update of frame range. --- pype/plugins/maya/load/load_image_plane.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pype/plugins/maya/load/load_image_plane.py b/pype/plugins/maya/load/load_image_plane.py index 7d8ae27f89..e17382f7ed 100644 --- a/pype/plugins/maya/load/load_image_plane.py +++ b/pype/plugins/maya/load/load_image_plane.py @@ -1,7 +1,7 @@ import pymel.core as pc import maya.cmds as cmds -from avalon import api +from avalon import api, io from avalon.maya.pipeline import containerise from avalon.maya import lib from Qt import QtWidgets @@ -147,6 +147,17 @@ class ImagePlaneLoader(api.Loader): type="string" ) + # Set frame range. + version = io.find_one({"_id": representation["parent"]}) + subset = io.find_one({"_id": version["parent"]}) + asset = io.find_one({"_id": subset["parent"]}) + start_frame = asset["data"]["frameStart"] + end_frame = asset["data"]["frameEnd"] + image_plane_shape.frameOffset.set(1 - start_frame) + image_plane_shape.frameIn.set(start_frame) + image_plane_shape.frameOut.set(end_frame) + image_plane_shape.frameCache.set(end_frame) + def switch(self, container, representation): self.update(container, representation) From 40c8b3fd7975cd8972e7aa6f66c8473406a12072 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Tue, 22 Sep 2020 15:26:16 +0100 Subject: [PATCH 614/662] Fix missing frame range update. --- pype/plugins/maya/load/load_audio.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/plugins/maya/load/load_audio.py b/pype/plugins/maya/load/load_audio.py index ca38082ed0..81bcca48e1 100644 --- a/pype/plugins/maya/load/load_audio.py +++ b/pype/plugins/maya/load/load_audio.py @@ -1,7 +1,7 @@ from maya import cmds, mel import pymel.core as pc -from avalon import api +from avalon import api, io from avalon.maya.pipeline import containerise from avalon.maya import lib @@ -58,6 +58,13 @@ class AudioLoader(api.Loader): type="string" ) + # Set frame range. + version = io.find_one({"_id": representation["parent"]}) + subset = io.find_one({"_id": version["parent"]}) + asset = io.find_one({"_id": subset["parent"]}) + audio_node.sourceStart.set(1 - asset["data"]["frameStart"]) + audio_node.sourceEnd.set(asset["data"]["frameEnd"]) + def switch(self, container, representation): self.update(container, representation) From b193cc3b519d9c399c459b96f725c9cb556a358f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 23 Sep 2020 12:37:05 +0200 Subject: [PATCH 615/662] fix(ftrack): filter only activated instances in hierarchy assets --- .../publish/integrate_hierarchy_ftrack.py | 69 ++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index cc569ce2d1..ed328ac30d 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -2,6 +2,7 @@ import sys import six import pyblish.api from avalon import io +from pprint import pformat try: from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_AUTO_SYNC @@ -39,10 +40,74 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): optional = False def process(self, context): + # additional inner methods + def _get_assets(input_dict): + """ Returns only asset dictionary. + Usually the last part of deep dictionary which + is not having any children + """ + for key in input_dict.keys(): + # check if child key is available + if input_dict[key].get("childs"): + # loop deeper + return _get_assets(input_dict[key]["childs"]) + else: + # give the dictionary with assets + return input_dict + + def _set_assets(input_dict, new_assets=None): + """ Modify the hierarchy context dictionary. + It will replace the asset dictionary with only the filtred one. + """ + for key in input_dict.keys(): + # check if child key is available + if input_dict[key].get("childs"): + # return if this is just for testing purpose and no + # new_assets property is avalable + if not new_assets: + return True + + # test for deeper inner children availabelity + if _set_assets(input_dict[key]["childs"]): + # if one level deeper is still children available + # then process farther + _set_assets(input_dict[key]["childs"], new_assets) + else: + # or just assign the filtred asset ditionary + input_dict[key]["childs"] = new_assets + else: + # test didnt find more childs in input dictionary + return None + + # processing starts here + active_assets = [] self.context = context - if "hierarchyContext" not in context.data: + if "hierarchyContext" not in self.context.data: return + hierarchy_context = self.context.data["hierarchyContext"] + hierarchy_assets = _get_assets(hierarchy_context) + + # filter only the active publishing insatnces + for instance in self.context: + if instance.data.get("publish") is False: + continue + + if not instance.data.get("asset"): + continue + + active_assets.append(instance.data["asset"]) + + # filter out only assets which are activated as isntances + new_hierarchy_assets = {k: v for k, v in hierarchy_assets.items() + if k in active_assets} + + # modify the hierarchy context so there are only fitred assets + _set_assets(hierarchy_context, new_hierarchy_assets) + + self.log.debug( + f"__ hierarchy_context: `{pformat(hierarchy_context)}`") + self.session = self.context.data["ftrackSession"] project_name = self.context.data["projectEntity"]["name"] query = 'Project where full_name is "{}"'.format(project_name) @@ -55,7 +120,7 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): self.ft_project = None - input_data = context.data["hierarchyContext"] + input_data = hierarchy_context # disable termporarily ftrack project's autosyncing if auto_sync_state: From 8835617fe4cd8cf06b08f35f519ea17ad7f46a0b Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 23 Sep 2020 12:37:37 +0200 Subject: [PATCH 616/662] fix(standalonepublisher): adding commonly used extension for video --- pype/plugins/standalonepublisher/publish/collect_editorial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/standalonepublisher/publish/collect_editorial.py b/pype/plugins/standalonepublisher/publish/collect_editorial.py index a31125d9a8..5e6fd106e4 100644 --- a/pype/plugins/standalonepublisher/publish/collect_editorial.py +++ b/pype/plugins/standalonepublisher/publish/collect_editorial.py @@ -32,7 +32,7 @@ class CollectEditorial(pyblish.api.InstancePlugin): actions = [] # presets - extensions = [".mov"] + extensions = [".mov", ".mp4"] def process(self, instance): # remove context test attribute From 7cc52fe28a332f9af3b27377e7a425d356745252 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 23 Sep 2020 12:55:02 +0200 Subject: [PATCH 617/662] fix(ftrack, global): moving asset filter to avalon hierarchy integrator --- .../publish/integrate_hierarchy_ftrack.py | 59 ----------------- .../publish/extract_hierarchy_avalon.py | 63 ++++++++++++++++++- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index ed328ac30d..0616382569 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -40,70 +40,11 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): optional = False def process(self, context): - # additional inner methods - def _get_assets(input_dict): - """ Returns only asset dictionary. - Usually the last part of deep dictionary which - is not having any children - """ - for key in input_dict.keys(): - # check if child key is available - if input_dict[key].get("childs"): - # loop deeper - return _get_assets(input_dict[key]["childs"]) - else: - # give the dictionary with assets - return input_dict - - def _set_assets(input_dict, new_assets=None): - """ Modify the hierarchy context dictionary. - It will replace the asset dictionary with only the filtred one. - """ - for key in input_dict.keys(): - # check if child key is available - if input_dict[key].get("childs"): - # return if this is just for testing purpose and no - # new_assets property is avalable - if not new_assets: - return True - - # test for deeper inner children availabelity - if _set_assets(input_dict[key]["childs"]): - # if one level deeper is still children available - # then process farther - _set_assets(input_dict[key]["childs"], new_assets) - else: - # or just assign the filtred asset ditionary - input_dict[key]["childs"] = new_assets - else: - # test didnt find more childs in input dictionary - return None - - # processing starts here - active_assets = [] self.context = context if "hierarchyContext" not in self.context.data: return hierarchy_context = self.context.data["hierarchyContext"] - hierarchy_assets = _get_assets(hierarchy_context) - - # filter only the active publishing insatnces - for instance in self.context: - if instance.data.get("publish") is False: - continue - - if not instance.data.get("asset"): - continue - - active_assets.append(instance.data["asset"]) - - # filter out only assets which are activated as isntances - new_hierarchy_assets = {k: v for k, v in hierarchy_assets.items() - if k in active_assets} - - # modify the hierarchy context so there are only fitred assets - _set_assets(hierarchy_context, new_hierarchy_assets) self.log.debug( f"__ hierarchy_context: `{pformat(hierarchy_context)}`") diff --git a/pype/plugins/global/publish/extract_hierarchy_avalon.py b/pype/plugins/global/publish/extract_hierarchy_avalon.py index 1d8191f2e3..4253c35929 100644 --- a/pype/plugins/global/publish/extract_hierarchy_avalon.py +++ b/pype/plugins/global/publish/extract_hierarchy_avalon.py @@ -10,6 +10,7 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): families = ["clip", "shot"] def process(self, context): + # processing starts here if "hierarchyContext" not in context.data: self.log.info("skipping IntegrateHierarchyToAvalon") return @@ -17,7 +18,29 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): if not io.Session: io.install() - input_data = context.data["hierarchyContext"] + active_assets = [] + hierarchy_context = context.data["hierarchyContext"] + hierarchy_assets = self._get_assets(hierarchy_context) + + # filter only the active publishing insatnces + for instance in context: + if instance.data.get("publish") is False: + continue + + if not instance.data.get("asset"): + continue + + active_assets.append(instance.data["asset"]) + + # filter out only assets which are activated as isntances + new_hierarchy_assets = {k: v for k, v in hierarchy_assets.items() + if k in active_assets} + + # modify the hierarchy context so there are only fitred assets + self._set_assets(hierarchy_context, new_hierarchy_assets) + + input_data = context.data["hierarchyContext"] = hierarchy_context + self.project = None self.import_to_avalon(input_data) @@ -149,3 +172,41 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): entity_id = io.insert_one(item).inserted_id return io.find_one({"_id": entity_id}) + + def _get_assets(self, input_dict): + """ Returns only asset dictionary. + Usually the last part of deep dictionary which + is not having any children + """ + for key in input_dict.keys(): + # check if child key is available + if input_dict[key].get("childs"): + # loop deeper + return self._get_assets(input_dict[key]["childs"]) + else: + # give the dictionary with assets + return input_dict + + def _set_assets(self, input_dict, new_assets=None): + """ Modify the hierarchy context dictionary. + It will replace the asset dictionary with only the filtred one. + """ + for key in input_dict.keys(): + # check if child key is available + if input_dict[key].get("childs"): + # return if this is just for testing purpose and no + # new_assets property is avalable + if not new_assets: + return True + + # test for deeper inner children availabelity + if self._set_assets(input_dict[key]["childs"]): + # if one level deeper is still children available + # then process farther + self._set_assets(input_dict[key]["childs"], new_assets) + else: + # or just assign the filtred asset ditionary + input_dict[key]["childs"] = new_assets + else: + # test didnt find more childs in input dictionary + return None From f7104a1f7ecb9dd509478c638eaafaeade854f08 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 16:49:28 +0200 Subject: [PATCH 618/662] first commit recreated entity before any modification are applied --- pype/modules/ftrack/lib/avalon_sync.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 65a59452da..03124ab10d 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -2144,6 +2144,7 @@ class SyncEntitiesFactory: "name": _name, "parent": parent_entity }) + self.session.commit() final_entity = {} for k, v in av_entity.items(): From bff280b867b70418acf70a90cc053d50ef81d6f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 16:49:50 +0200 Subject: [PATCH 619/662] fixed way how to access to attribute `self._avalon_ents` --- pype/modules/ftrack/events/event_sync_to_avalon.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pype/modules/ftrack/events/event_sync_to_avalon.py b/pype/modules/ftrack/events/event_sync_to_avalon.py index 314871f5b3..7f33d7b660 100644 --- a/pype/modules/ftrack/events/event_sync_to_avalon.py +++ b/pype/modules/ftrack/events/event_sync_to_avalon.py @@ -878,8 +878,9 @@ class SyncToAvalonEvent(BaseEvent): self.process_session.commit() found_idx = None - for idx, _entity in enumerate(self._avalon_ents): - if _entity["_id"] == avalon_entity["_id"]: + proj_doc, asset_docs = self._avalon_ents + for idx, asset_doc in enumerate(asset_docs): + if asset_doc["_id"] == avalon_entity["_id"]: found_idx = idx break @@ -894,7 +895,8 @@ class SyncToAvalonEvent(BaseEvent): new_entity_id ) # Update cached entities - self._avalon_ents[found_idx] = avalon_entity + asset_docs[found_idx] = avalon_entity + self._avalon_ents = proj_doc, asset_docs if self._avalon_ents_by_id is not None: mongo_id = avalon_entity["_id"] From dca974af2b288b25abd5e6639ab3a555d6920711 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 16:49:58 +0200 Subject: [PATCH 620/662] added debugging logs --- .../ftrack/events/event_sync_to_avalon.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pype/modules/ftrack/events/event_sync_to_avalon.py b/pype/modules/ftrack/events/event_sync_to_avalon.py index 7f33d7b660..d0c9ea2e96 100644 --- a/pype/modules/ftrack/events/event_sync_to_avalon.py +++ b/pype/modules/ftrack/events/event_sync_to_avalon.py @@ -717,6 +717,9 @@ class SyncToAvalonEvent(BaseEvent): if not self.ftrack_removed: return ent_infos = self.ftrack_removed + self.log.debug( + "Processing removed entities: {}".format(str(ent_infos)) + ) removable_ids = [] recreate_ents = [] removed_names = [] @@ -1260,6 +1263,10 @@ class SyncToAvalonEvent(BaseEvent): if not ent_infos: return + self.log.debug( + "Processing renamed entities: {}".format(str(ent_infos)) + ) + renamed_tasks = {} not_found = {} changeable_queue = queue.Queue() @@ -1455,6 +1462,10 @@ class SyncToAvalonEvent(BaseEvent): if not ent_infos: return + self.log.debug( + "Processing added entities: {}".format(str(ent_infos)) + ) + cust_attrs, hier_attrs = self.avalon_cust_attrs entity_type_conf_ids = {} # Skip if already exit in avalon db or tasks entities @@ -1731,6 +1742,10 @@ class SyncToAvalonEvent(BaseEvent): if not self.ftrack_moved: return + self.log.debug( + "Processing moved entities: {}".format(str(self.ftrack_moved)) + ) + ftrack_moved = {k: v for k, v in sorted( self.ftrack_moved.items(), key=(lambda line: len( @@ -1861,6 +1876,10 @@ class SyncToAvalonEvent(BaseEvent): if not self.ftrack_updated: return + self.log.debug( + "Processing updated entities: {}".format(str(self.ftrack_updated)) + ) + ent_infos = self.ftrack_updated ftrack_mongo_mapping = {} not_found_ids = [] From ce29b1e8623e3dba1436db4fc96d3d3d1ea9b86e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 24 Sep 2020 10:38:18 +0200 Subject: [PATCH 621/662] append in terminal model adds all items at once instead of one by one --- pype/tools/pyblish_pype/model.py | 66 +++++++++++++++++--------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/pype/tools/pyblish_pype/model.py b/pype/tools/pyblish_pype/model.py index fdcdffd33f..05699043d8 100644 --- a/pype/tools/pyblish_pype/model.py +++ b/pype/tools/pyblish_pype/model.py @@ -1145,48 +1145,52 @@ class TerminalModel(QtGui.QStandardItemModel): return prepared_records - def append(self, record_item): - record_type = record_item["type"] + def append(self, record_items): + all_record_items = [] + for record_item in record_items: + record_type = record_item["type"] - terminal_item_type = None - if record_type == "record": - for level, _type in self.level_to_record: - if level > record_item["levelno"]: - break - terminal_item_type = _type + terminal_item_type = None + if record_type == "record": + for level, _type in self.level_to_record: + if level > record_item["levelno"]: + break + terminal_item_type = _type - else: - terminal_item_type = record_type + else: + terminal_item_type = record_type - icon_color = self.item_icon_colors.get(terminal_item_type) - icon_name = self.item_icon_name.get(record_type) + icon_color = self.item_icon_colors.get(terminal_item_type) + icon_name = self.item_icon_name.get(record_type) - top_item_icon = None - if icon_color and icon_name: - top_item_icon = QAwesomeIconFactory.icon(icon_name, icon_color) + top_item_icon = None + if icon_color and icon_name: + top_item_icon = QAwesomeIconFactory.icon(icon_name, icon_color) - label = record_item["label"].split("\n")[0] + label = record_item["label"].split("\n")[0] - top_item = QtGui.QStandardItem() - top_item.setData(TerminalLabelType, Roles.TypeRole) - top_item.setData(terminal_item_type, Roles.TerminalItemTypeRole) - top_item.setData(label, QtCore.Qt.DisplayRole) - top_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled - ) + top_item = QtGui.QStandardItem() + all_record_items.append(top_item) - if top_item_icon: - top_item.setData(top_item_icon, QtCore.Qt.DecorationRole) + detail_item = TerminalDetailItem(record_item) + top_item.appendRow(detail_item) - self.appendRow(top_item) + top_item.setData(TerminalLabelType, Roles.TypeRole) + top_item.setData(terminal_item_type, Roles.TerminalItemTypeRole) + top_item.setData(label, QtCore.Qt.DisplayRole) + top_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled + ) - detail_item = TerminalDetailItem(record_item) - detail_item.setData(TerminalDetailType, Roles.TypeRole) - top_item.appendRow(detail_item) + if top_item_icon: + top_item.setData(top_item_icon, QtCore.Qt.DecorationRole) + + detail_item.setData(TerminalDetailType, Roles.TypeRole) + + self.invisibleRootItem().appendRows(all_record_items) def update_with_result(self, result): - for record in result["records"]: - self.append(record) + self.append(result["records"]) class TerminalProxy(QtCore.QSortFilterProxyModel): From 4e193159816a87c37339a742b0bc42e6324f574f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 24 Sep 2020 10:38:31 +0200 Subject: [PATCH 622/662] info messages are added same way as records --- pype/tools/pyblish_pype/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/pyblish_pype/window.py b/pype/tools/pyblish_pype/window.py index 76f31e2442..2a037ba4bc 100644 --- a/pype/tools/pyblish_pype/window.py +++ b/pype/tools/pyblish_pype/window.py @@ -1087,10 +1087,10 @@ class Window(QtWidgets.QDialog): info.setText(message) # Include message in terminal - self.terminal_model.append({ + self.terminal_model.append([{ "label": message, "type": "info" - }) + }]) self.animation_info_msg.stop() self.animation_info_msg.start() From 2e8f5ee55cf460e118d16647af34918f43123751 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 24 Sep 2020 12:47:08 +0200 Subject: [PATCH 623/662] collect anatomy instance data plugin converted to context plugin --- pype/plugins/global/publish/collect_anatomy_instance_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/collect_anatomy_instance_data.py b/pype/plugins/global/publish/collect_anatomy_instance_data.py index 44a4d43946..455b44c4f1 100644 --- a/pype/plugins/global/publish/collect_anatomy_instance_data.py +++ b/pype/plugins/global/publish/collect_anatomy_instance_data.py @@ -28,7 +28,7 @@ from avalon import io import pyblish.api -class CollectAnatomyInstanceData(pyblish.api.InstancePlugin): +class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): """Collect Instance specific Anatomy data.""" order = pyblish.api.CollectorOrder + 0.49 From 2831f3f4b4cde563fcb0da7690b528b0f0c221f6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 24 Sep 2020 12:48:18 +0200 Subject: [PATCH 624/662] collecting was separated to 3 parts with only 3 calls to mongo database --- .../publish/collect_anatomy_instance_data.py | 315 +++++++++++++----- 1 file changed, 224 insertions(+), 91 deletions(-) diff --git a/pype/plugins/global/publish/collect_anatomy_instance_data.py b/pype/plugins/global/publish/collect_anatomy_instance_data.py index 455b44c4f1..446f671b86 100644 --- a/pype/plugins/global/publish/collect_anatomy_instance_data.py +++ b/pype/plugins/global/publish/collect_anatomy_instance_data.py @@ -23,123 +23,256 @@ Provides: import copy import json +import collections from avalon import io import pyblish.api class CollectAnatomyInstanceData(pyblish.api.ContextPlugin): - """Collect Instance specific Anatomy data.""" + """Collect Instance specific Anatomy data. + + Plugin is running for all instances on context even not active instances. + """ order = pyblish.api.CollectorOrder + 0.49 label = "Collect Anatomy Instance data" - def process(self, instance): - # get all the stuff from the database - anatomy_data = copy.deepcopy(instance.context.data["anatomyData"]) - project_entity = instance.context.data["projectEntity"] - context_asset_entity = instance.context.data["assetEntity"] - instance_asset_entity = instance.data.get("assetEntity") + def process(self, context): + self.log.info("Collecting anatomy data for all instances.") - asset_name = instance.data["asset"] + self.fill_missing_asset_docs(context) + self.fill_latest_versions(context) + self.fill_anatomy_data(context) - # There is possibility that assetEntity on instance is already set - # which can happen in standalone publisher - if ( - instance_asset_entity - and instance_asset_entity["name"] == asset_name - ): - asset_entity = instance_asset_entity + self.log.info("Anatomy Data collection finished.") - # Check if asset name is the same as what is in context - # - they may be different, e.g. in NukeStudio - elif context_asset_entity["name"] == asset_name: - asset_entity = context_asset_entity + def fill_missing_asset_docs(self, context): + self.log.debug("Qeurying asset documents for instances.") - else: - asset_entity = io.find_one({ - "type": "asset", - "name": asset_name, - "parent": project_entity["_id"] - }) + context_asset_doc = context.data["assetEntity"] - subset_name = instance.data["subset"] - version_number = instance.data.get("version") - latest_version = None + instances_with_missing_asset_doc = collections.defaultdict(list) + for instance in context: + instance_asset_doc = instance.data.get("assetEntity") + _asset_name = instance.data["asset"] - if asset_entity: - subset_entity = io.find_one({ - "type": "subset", - "name": subset_name, - "parent": asset_entity["_id"] - }) + # There is possibility that assetEntity on instance is already set + # which can happen in standalone publisher + if ( + instance_asset_doc + and instance_asset_doc["name"] == _asset_name + ): + continue + + # Check if asset name is the same as what is in context + # - they may be different, e.g. in NukeStudio + if context_asset_doc["name"] == _asset_name: + instance.data["assetEntity"] = context_asset_doc - if subset_entity is None: - self.log.debug("Subset entity does not exist yet.") else: - version_entity = io.find_one( - { - "type": "version", - "parent": subset_entity["_id"] - }, - sort=[("name", -1)] - ) - if version_entity: - latest_version = version_entity["name"] + instances_with_missing_asset_doc[_asset_name].append(instance) - # If version is not specified for instance or context - if version_number is None: - # TODO we should be able to change default version by studio - # preferences (like start with version number `0`) - version_number = 1 - # use latest version (+1) if already any exist - if latest_version is not None: - version_number += int(latest_version) + if not instances_with_missing_asset_doc: + self.log.debug("All instances already had right asset document.") + return - anatomy_updates = { - "asset": asset_name, - "family": instance.data["family"], - "subset": subset_name, - "version": version_number + asset_names = list(instances_with_missing_asset_doc.keys()) + self.log.debug("Querying asset documents with names: {}".format( + ", ".join(["\"{}\"".format(name) for name in asset_names]) + )) + asset_docs = io.find({ + "type": "asset", + "name": {"$in": asset_names} + }) + asset_docs_by_name = { + asset_doc["name"]: asset_doc + for asset_doc in asset_docs } - if ( - asset_entity - and asset_entity["_id"] != context_asset_entity["_id"] - ): - parents = asset_entity["data"].get("parents") or list() - anatomy_updates["hierarchy"] = "/".join(parents) - task_name = instance.data.get("task") - if task_name: - anatomy_updates["task"] = task_name + not_found_asset_names = [] + for asset_name, instances in instances_with_missing_asset_doc.items(): + asset_doc = asset_docs_by_name.get(asset_name) + if not asset_doc: + not_found_asset_names.append(asset_name) + continue - # Version should not be collected since may be instance - anatomy_data.update(anatomy_updates) + for _instance in instances: + _instance.data["assetEntity"] = asset_doc - resolution_width = instance.data.get("resolutionWidth") - if resolution_width: - anatomy_data["resolution_width"] = resolution_width + if not_found_asset_names: + joined_asset_names = ", ".join( + ["\"{}\"".format(name) for name in not_found_asset_names] + ) + self.log.warning(( + "Not found asset documents with names \"{}\"." + ).format(joined_asset_names)) - resolution_height = instance.data.get("resolutionHeight") - if resolution_height: - anatomy_data["resolution_height"] = resolution_height + def fill_latest_versions(self, context): + """Try to find latest version for each instance's subset. - pixel_aspect = instance.data.get("pixelAspect") - if pixel_aspect: - anatomy_data["pixel_aspect"] = float("{:0.2f}".format( - float(pixel_aspect))) + Key "latestVersion" is always set to latest version or `None`. - fps = instance.data.get("fps") - if fps: - anatomy_data["fps"] = float("{:0.2f}".format( - float(fps))) + Args: + context (pyblish.Context) - instance.data["projectEntity"] = project_entity - instance.data["assetEntity"] = asset_entity - instance.data["anatomyData"] = anatomy_data - instance.data["latestVersion"] = latest_version - # TODO should be version number set here? - instance.data["version"] = version_number + Returns: + None - self.log.info("Instance anatomy Data collected") - self.log.debug(json.dumps(anatomy_data, indent=4)) + """ + self.log.debug("Qeurying latest versions for instances.") + + hierarchy = {} + subset_names = set() + asset_ids = set() + for instance in context: + # Make sure `"latestVersion"` key is set + latest_version = instance.data.get("latestVersion") + instance.data["latestVersion"] = latest_version + + # Skip instances withou "assetEntity" + asset_doc = instance.data.get("assetEntity") + if not asset_doc: + continue + + # Store asset ids and subset names for queries + asset_id = asset_doc["_id"] + subset_name = instance.data["subset"] + asset_ids.add(asset_id) + subset_names.add(subset_name) + + # Prepare instance hiearchy for faster filling latest versions + if asset_id not in hierarchy: + hierarchy[asset_id] = {} + if subset_name not in hierarchy[asset_id]: + hierarchy[asset_id][subset_name] = [] + hierarchy[asset_id][subset_name].append(instance) + + subset_docs = list(io.find({ + "type": "subset", + "parent": {"$in": list(asset_ids)}, + "name": {"$in": list(subset_names)} + })) + + subset_ids = [ + subset_doc["_id"] + for subset_doc in subset_docs + ] + + last_version_by_subset_id = self._query_last_versions(subset_ids) + for subset_doc in subset_docs: + subset_id = subset_doc["_id"] + last_version = last_version_by_subset_id.get(subset_id) + if last_version is None: + continue + + asset_id = subset_doc["parent"] + subset_name = subset_doc["name"] + _instances = hierarchy[asset_id][subset_name] + for _instance in _instances: + _instance.data["latestVersion"] = last_version + + def _query_last_versions(self, subset_ids): + """Retrieve all latest versions for entered subset_ids. + + Args: + subset_ids (list): List of subset ids with type `ObjectId`. + + Returns: + dict: Key is subset id and value is last version name. + """ + _pipeline = [ + # Find all versions of those subsets + {"$match": { + "type": "version", + "parent": {"$in": subset_ids} + }}, + # Sorting versions all together + {"$sort": {"name": 1}}, + # Group them by "parent", but only take the last + {"$group": { + "_id": "$parent", + "_version_id": {"$last": "$_id"}, + "name": {"$last": "$name"} + }} + ] + + last_version_by_subset_id = {} + for doc in io.aggregate(_pipeline): + subset_id = doc["_id"] + last_version_by_subset_id[subset_id] = doc["name"] + + return last_version_by_subset_id + + def fill_anatomy_data(self, context): + self.log.debug("Storing anatomy data to instance data.") + + project_doc = context.data["projectEntity"] + context_asset_doc = context.data["assetEntity"] + + for instance in context: + version_number = instance.data.get("version") + # If version is not specified for instance or context + if version_number is None: + # TODO we should be able to change default version by studio + # preferences (like start with version number `0`) + version_number = 1 + # use latest version (+1) if already any exist + latest_version = instance.data["latestVersion"] + if latest_version is not None: + version_number += int(latest_version) + + anatomy_updates = { + "asset": instance.data["asset"], + "family": instance.data["family"], + "subset": instance.data["subset"], + "version": version_number + } + + # Hiearchy + asset_doc = instance.data.get("assetEntity") + if asset_doc and asset_doc["_id"] != context_asset_doc["_id"]: + parents = asset_doc["data"].get("parents") or list() + anatomy_updates["hierarchy"] = "/".join(parents) + + # Task + task_name = instance.data.get("task") + if task_name: + anatomy_updates["task"] = task_name + + # Additional data + resolution_width = instance.data.get("resolutionWidth") + if resolution_width: + anatomy_updates["resolution_width"] = resolution_width + + resolution_height = instance.data.get("resolutionHeight") + if resolution_height: + anatomy_updates["resolution_height"] = resolution_height + + pixel_aspect = instance.data.get("pixelAspect") + if pixel_aspect: + anatomy_updates["pixel_aspect"] = float( + "{:0.2f}".format(float(pixel_aspect)) + ) + + fps = instance.data.get("fps") + if fps: + anatomy_updates["fps"] = float("{:0.2f}".format(float(fps))) + + anatomy_data = copy.deepcopy(context.data["anatomyData"]) + anatomy_data.update(anatomy_updates) + + # Store anatomy data + instance.data["projectEntity"] = project_doc + instance.data["anatomyData"] = anatomy_data + instance.data["version"] = version_number + + # Log collected data + instance_name = instance.data["name"] + instance_label = instance.data.get("label") + if instance_label: + instance_name += "({})".format(instance_label) + self.log.debug("Anatomy data for instance {}: {}".format( + instance_name, + json.dumps(anatomy_data, indent=4) + )) From 7104ac3fbce20b3bb2391e1db781d60b074d85e1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 24 Sep 2020 17:30:08 +0200 Subject: [PATCH 625/662] rest api module is not using QThread for running but python's Thread --- pype/modules/rest_api/rest_api.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/pype/modules/rest_api/rest_api.py b/pype/modules/rest_api/rest_api.py index cc98b56a3b..3e0c646560 100644 --- a/pype/modules/rest_api/rest_api.py +++ b/pype/modules/rest_api/rest_api.py @@ -1,6 +1,6 @@ import os import socket -from Qt import QtCore +import threading from socketserver import ThreadingMixIn from http.server import HTTPServer @@ -155,14 +155,15 @@ class RestApiServer: def is_running(self): return self.rest_api_thread.is_running + def tray_exit(self): + self.stop() + def stop(self): - self.rest_api_thread.is_running = False - - def thread_stopped(self): - self._is_running = False + self.rest_api_thread.stop() + self.rest_api_thread.join() -class RestApiThread(QtCore.QThread): +class RestApiThread(threading.Thread): """ Listener for REST requests. It is possible to register callbacks for url paths. @@ -174,6 +175,12 @@ class RestApiThread(QtCore.QThread): self.is_running = False self.module = module self.port = port + self.httpd = None + + def stop(self): + self.is_running = False + if self.httpd: + self.httpd.server_close() def run(self): self.is_running = True @@ -185,12 +192,14 @@ class RestApiThread(QtCore.QThread): ) with ThreadingSimpleServer(("", self.port), Handler) as httpd: + self.httpd = httpd while self.is_running: httpd.handle_request() + except Exception: log.warning( "Rest Api Server service has failed", exc_info=True ) + self.httpd = None self.is_running = False - self.module.thread_stopped() From 71a5a036ddc1658df5444004a4a09c92321e8fab Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 25 Sep 2020 10:15:10 +0200 Subject: [PATCH 626/662] validate intent --- .../plugins/global/publish/validate_intent.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 pype/plugins/global/publish/validate_intent.py diff --git a/pype/plugins/global/publish/validate_intent.py b/pype/plugins/global/publish/validate_intent.py new file mode 100644 index 0000000000..80bcb0e164 --- /dev/null +++ b/pype/plugins/global/publish/validate_intent.py @@ -0,0 +1,31 @@ +import pyblish.api +import os + + +class ValidateIntent(pyblish.api.ContextPlugin): + """Validate intent of the publish. + + It is required to fill the intent of this publish. Chech the log + for more details + """ + + order = pyblish.api.ValidatorOrder + + label = "Validate Intent" + # TODO: this should be off by default and only activated viac config + tasks = ["animation"] + hosts = ["harmony"] + if os.environ.get("AVALON_TASK") not in tasks: + active = False + + def process(self, context): + msg = ( + "Please make sure that you select the intent of this publish." + ) + + intent = context.data.get("intent") + self.log.debug(intent) + assert intent, msg + + intent_value = intent.get("value") + assert intent is not "", msg From 76a241afe9001f7fc816f741d56c377abc95f8ce Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Fri, 25 Sep 2020 13:24:30 +0200 Subject: [PATCH 627/662] bump version --- pype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/version.py b/pype/version.py index 96fc614cb2..0f90260218 100644 --- a/pype/version.py +++ b/pype/version.py @@ -1 +1 @@ -__version__ = "2.12.1" +__version__ = "2.12.2" From 2416d4d33f616dcf8f6c854e4cbad0e97961a753 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 14:46:04 +0200 Subject: [PATCH 628/662] set port variable to None so the variable exists --- pype/modules/websocket_server/websocket_server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/modules/websocket_server/websocket_server.py b/pype/modules/websocket_server/websocket_server.py index 1152c65e00..ec6785625a 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -31,6 +31,7 @@ class WebSocketServer(): self.client = None self.handlers = {} + port = None websocket_url = os.getenv("WEBSOCKET_URL") if websocket_url: parsed = urllib.parse.urlparse(websocket_url) From 64052aa44e8c159a2429d842e88d2fa3220fc124 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 16:08:34 +0200 Subject: [PATCH 629/662] logging module without qt in globals --- pype/modules/logging/{ => tray}/gui/__init__.py | 0 pype/modules/logging/{ => tray}/gui/app.py | 0 pype/modules/logging/{ => tray}/gui/models.py | 0 pype/modules/logging/{ => tray}/gui/widgets.py | 0 pype/modules/logging/tray/logging_module.py | 8 +++++--- 5 files changed, 5 insertions(+), 3 deletions(-) rename pype/modules/logging/{ => tray}/gui/__init__.py (100%) rename pype/modules/logging/{ => tray}/gui/app.py (100%) rename pype/modules/logging/{ => tray}/gui/models.py (100%) rename pype/modules/logging/{ => tray}/gui/widgets.py (100%) diff --git a/pype/modules/logging/gui/__init__.py b/pype/modules/logging/tray/gui/__init__.py similarity index 100% rename from pype/modules/logging/gui/__init__.py rename to pype/modules/logging/tray/gui/__init__.py diff --git a/pype/modules/logging/gui/app.py b/pype/modules/logging/tray/gui/app.py similarity index 100% rename from pype/modules/logging/gui/app.py rename to pype/modules/logging/tray/gui/app.py diff --git a/pype/modules/logging/gui/models.py b/pype/modules/logging/tray/gui/models.py similarity index 100% rename from pype/modules/logging/gui/models.py rename to pype/modules/logging/tray/gui/models.py diff --git a/pype/modules/logging/gui/widgets.py b/pype/modules/logging/tray/gui/widgets.py similarity index 100% rename from pype/modules/logging/gui/widgets.py rename to pype/modules/logging/tray/gui/widgets.py diff --git a/pype/modules/logging/tray/logging_module.py b/pype/modules/logging/tray/logging_module.py index 9b26d5d9bf..a40ce90ea9 100644 --- a/pype/modules/logging/tray/logging_module.py +++ b/pype/modules/logging/tray/logging_module.py @@ -1,6 +1,4 @@ -from Qt import QtWidgets from pype.api import Logger -from ..gui.app import LogsWindow class LoggingModule: @@ -8,7 +6,11 @@ class LoggingModule: self.parent = parent self.log = Logger().get_logger(self.__class__.__name__, "logging") + self.tray_init(main_parent, parent) + + def tray_init(self, main_parent, parent): try: + from .gui.app import LogsWindow self.window = LogsWindow() self.tray_menu = self._tray_menu except Exception: @@ -18,9 +20,9 @@ class LoggingModule: # Definition of Tray menu def _tray_menu(self, parent_menu): + from Qt import QtWidgets # Menu for Tray App menu = QtWidgets.QMenu('Logging', parent_menu) - # menu.setProperty('submenu', 'on') show_action = QtWidgets.QAction("Show Logs", menu) show_action.triggered.connect(self.on_show_logs) From d67a8a5f833845f6fa077cea607eff51253bce94 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 16:09:03 +0200 Subject: [PATCH 630/662] TimersManager is not singleton --- pype/modules/timers_manager/timers_manager.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/pype/modules/timers_manager/timers_manager.py b/pype/modules/timers_manager/timers_manager.py index 82ba1013f0..aeefddc75a 100644 --- a/pype/modules/timers_manager/timers_manager.py +++ b/pype/modules/timers_manager/timers_manager.py @@ -2,20 +2,7 @@ from .widget_user_idle import WidgetUserIdle, SignalHandler from pype.api import Logger, config -class Singleton(type): - """ Signleton implementation - """ - _instances = {} - - def __call__(cls, *args, **kwargs): - if cls not in cls._instances: - cls._instances[cls] = super( - Singleton, cls - ).__call__(*args, **kwargs) - return cls._instances[cls] - - -class TimersManager(metaclass=Singleton): +class TimersManager: """ Handles about Timers. Should be able to start/stop all timers at once. From 480acb9238eac4f183ae9f0a7022cb4250f27ed5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 16:09:30 +0200 Subject: [PATCH 631/662] timers manager has tray_init where all qt imports are done --- pype/modules/timers_manager/__init__.py | 1 - pype/modules/timers_manager/timers_manager.py | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pype/modules/timers_manager/__init__.py b/pype/modules/timers_manager/__init__.py index a8a478d7ae..9de205f088 100644 --- a/pype/modules/timers_manager/__init__.py +++ b/pype/modules/timers_manager/__init__.py @@ -1,5 +1,4 @@ from .timers_manager import TimersManager -from .widget_user_idle import WidgetUserIdle CLASS_DEFINIION = TimersManager diff --git a/pype/modules/timers_manager/timers_manager.py b/pype/modules/timers_manager/timers_manager.py index aeefddc75a..62767c24f1 100644 --- a/pype/modules/timers_manager/timers_manager.py +++ b/pype/modules/timers_manager/timers_manager.py @@ -1,5 +1,4 @@ -from .widget_user_idle import WidgetUserIdle, SignalHandler -from pype.api import Logger, config +from pype.api import Logger class TimersManager: @@ -28,7 +27,13 @@ class TimersManager: self.idle_man = None self.signal_handler = None + + self.trat_init(tray_widget, main_widget) + + def trat_init(self, tray_widget, main_widget): + from .widget_user_idle import WidgetUserIdle, SignalHandler self.widget_user_idle = WidgetUserIdle(self, tray_widget) + self.signal_handler = SignalHandler(self) def set_signal_times(self): try: @@ -106,7 +111,6 @@ class TimersManager: """ if 'IdleManager' in modules: - self.signal_handler = SignalHandler(self) if self.set_signal_times() is True: self.register_to_idle_manager(modules['IdleManager']) From 903713c7497a36b699dbbc7e77dec0469a5013cb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 16:11:48 +0200 Subject: [PATCH 632/662] user module has also `tray_init` method for all Qt imports --- pype/modules/user/user_module.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pype/modules/user/user_module.py b/pype/modules/user/user_module.py index f2de9dc2fb..dc57fe4a63 100644 --- a/pype/modules/user/user_module.py +++ b/pype/modules/user/user_module.py @@ -3,8 +3,6 @@ import json import getpass import appdirs -from Qt import QtWidgets -from .widget_user import UserWidget from pype.api import Logger @@ -24,6 +22,12 @@ class UserModule: self.cred_path = os.path.normpath(os.path.join( self.cred_folder_path, self.cred_filename )) + self.widget_login = None + + self.tray_init(main_parent, parent) + + def tray_init(self, main_parent=None, parent=None): + from .widget_user import UserWidget self.widget_login = UserWidget(self) self.load_credentials() @@ -66,6 +70,7 @@ class UserModule: # Definition of Tray menu def tray_menu(self, parent_menu): + from Qt import QtWidgets """Add menu or action to Tray(or parent)'s menu""" action = QtWidgets.QAction("Username", parent_menu) action.triggered.connect(self.show_widget) @@ -121,7 +126,8 @@ class UserModule: self.cred = {"username": username} os.environ[self.env_name] = username - self.widget_login.set_user(username) + if self.widget_login: + self.widget_login.set_user(username) try: file = open(self.cred_path, "w") file.write(json.dumps(self.cred)) From 06b1501cacc27dd21a828851c66236ffeffd01cc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 16:11:58 +0200 Subject: [PATCH 633/662] small modification in logging module --- pype/modules/logging/tray/logging_module.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pype/modules/logging/tray/logging_module.py b/pype/modules/logging/tray/logging_module.py index a40ce90ea9..84b40f68e1 100644 --- a/pype/modules/logging/tray/logging_module.py +++ b/pype/modules/logging/tray/logging_module.py @@ -6,6 +6,8 @@ class LoggingModule: self.parent = parent self.log = Logger().get_logger(self.__class__.__name__, "logging") + self.window = None + self.tray_init(main_parent, parent) def tray_init(self, main_parent, parent): @@ -25,7 +27,7 @@ class LoggingModule: menu = QtWidgets.QMenu('Logging', parent_menu) show_action = QtWidgets.QAction("Show Logs", menu) - show_action.triggered.connect(self.on_show_logs) + show_action.triggered.connect(self._show_logs_gui) menu.addAction(show_action) parent_menu.addMenu(menu) @@ -36,5 +38,6 @@ class LoggingModule: def process_modules(self, modules): return - def on_show_logs(self): - self.window.show() + def _show_logs_gui(self): + if self.window: + self.window.show() From 0c92ca3808dce4adf017c72d329b9a4fb2c0cce7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 25 Sep 2020 16:12:18 +0200 Subject: [PATCH 634/662] moved gui imports in standalone publisher from globals --- pype/modules/standalonepublish/standalonepublish_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/modules/standalonepublish/standalonepublish_module.py b/pype/modules/standalonepublish/standalonepublish_module.py index ed997bfd9f..f8bc0c6f24 100644 --- a/pype/modules/standalonepublish/standalonepublish_module.py +++ b/pype/modules/standalonepublish/standalonepublish_module.py @@ -2,7 +2,6 @@ import os import sys import subprocess import pype -from pype import tools class StandAlonePublishModule: @@ -30,6 +29,7 @@ class StandAlonePublishModule: )) def show(self): + from pype import tools standalone_publisher_tool_path = os.path.join( os.path.dirname(tools.__file__), "standalonepublish" From 6d3cd04e459b253732932dfd90ee4bebf066b327 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 25 Sep 2020 16:35:17 +0200 Subject: [PATCH 635/662] fix wrong exception catch --- pype/plugins/maya/publish/extract_camera_mayaScene.py | 2 +- pype/plugins/maya/publish/extract_maya_scene_raw.py | 2 +- pype/plugins/maya/publish/extract_model.py | 2 +- pype/plugins/maya/publish/extract_yeti_rig.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/plugins/maya/publish/extract_camera_mayaScene.py b/pype/plugins/maya/publish/extract_camera_mayaScene.py index 03dde031e9..1a0f4694d1 100644 --- a/pype/plugins/maya/publish/extract_camera_mayaScene.py +++ b/pype/plugins/maya/publish/extract_camera_mayaScene.py @@ -101,7 +101,7 @@ class ExtractCameraMayaScene(pype.api.Extractor): self.log.info( "Using {} as scene type".format(self.scene_type)) break - except AttributeError: + except KeyError: # no preset found pass diff --git a/pype/plugins/maya/publish/extract_maya_scene_raw.py b/pype/plugins/maya/publish/extract_maya_scene_raw.py index 2971572552..d273646af8 100644 --- a/pype/plugins/maya/publish/extract_maya_scene_raw.py +++ b/pype/plugins/maya/publish/extract_maya_scene_raw.py @@ -33,7 +33,7 @@ class ExtractMayaSceneRaw(pype.api.Extractor): self.log.info( "Using {} as scene type".format(self.scene_type)) break - except AttributeError: + except KeyError: # no preset found pass # Define extract output file path diff --git a/pype/plugins/maya/publish/extract_model.py b/pype/plugins/maya/publish/extract_model.py index 330e471e53..d77e65f989 100644 --- a/pype/plugins/maya/publish/extract_model.py +++ b/pype/plugins/maya/publish/extract_model.py @@ -41,7 +41,7 @@ class ExtractModel(pype.api.Extractor): self.log.info( "Using {} as scene type".format(self.scene_type)) break - except AttributeError: + except KeyError: # no preset found pass # Define extract output file path diff --git a/pype/plugins/maya/publish/extract_yeti_rig.py b/pype/plugins/maya/publish/extract_yeti_rig.py index 2f66d3e026..d48a956b88 100644 --- a/pype/plugins/maya/publish/extract_yeti_rig.py +++ b/pype/plugins/maya/publish/extract_yeti_rig.py @@ -111,7 +111,7 @@ class ExtractYetiRig(pype.api.Extractor): self.log.info( "Using {} as scene type".format(self.scene_type)) break - except AttributeError: + except KeyError: # no preset found pass yeti_nodes = cmds.ls(instance, type="pgYetiMaya") From bfb906f37ad1efcfc3d72768a12fb2841a9b583b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 11:06:06 +0200 Subject: [PATCH 636/662] moved custom db connector to folder where is used --- .../custom_db_connector.py | 102 ++++++++---------- 1 file changed, 43 insertions(+), 59 deletions(-) rename pype/modules/ftrack/{lib => ftrack_server}/custom_db_connector.py (71%) diff --git a/pype/modules/ftrack/lib/custom_db_connector.py b/pype/modules/ftrack/ftrack_server/custom_db_connector.py similarity index 71% rename from pype/modules/ftrack/lib/custom_db_connector.py rename to pype/modules/ftrack/ftrack_server/custom_db_connector.py index d498d041dc..232481e6f4 100644 --- a/pype/modules/ftrack/lib/custom_db_connector.py +++ b/pype/modules/ftrack/ftrack_server/custom_db_connector.py @@ -16,9 +16,9 @@ import pymongo from pype.api import decompose_url -class NotActiveTable(Exception): +class NotActiveCollection(Exception): def __init__(self, *args, **kwargs): - msg = "Active table is not set. (This is bug)" + msg = "Active collection is not set. (This is bug)" if not (args or kwargs): args = [msg] super().__init__(*args, **kwargs) @@ -40,12 +40,12 @@ def auto_reconnect(func): return decorated -def check_active_table(func): +def check_active_collection(func): """Check if CustomDbConnector has active collection.""" @functools.wraps(func) def decorated(obj, *args, **kwargs): - if not obj.active_table: - raise NotActiveTable() + if not obj.active_collection: + raise NotActiveCollection() return func(obj, *args, **kwargs) return decorated @@ -55,7 +55,7 @@ class CustomDbConnector: timeout = int(os.environ["AVALON_TIMEOUT"]) def __init__( - self, uri, database_name, port=None, table_name=None + self, uri, database_name, port=None, collection_name=None ): self._mongo_client = None self._sentry_client = None @@ -76,10 +76,10 @@ class CustomDbConnector: self._port = port self._database_name = database_name - self.active_table = table_name + self.active_collection = collection_name def __getitem__(self, key): - # gives direct access to collection withou setting `active_table` + # gives direct access to collection withou setting `active_collection` return self._database[key] def __getattribute__(self, attr): @@ -88,9 +88,11 @@ class CustomDbConnector: try: return super(CustomDbConnector, self).__getattribute__(attr) except AttributeError: - if self.active_table is None: - raise NotActiveTable() - return self._database[self.active_table].__getattribute__(attr) + if self.active_collection is None: + raise NotActiveCollection() + return self._database[self.active_collection].__getattribute__( + attr + ) def install(self): """Establish a persistent connection to the database""" @@ -146,46 +148,28 @@ class CustomDbConnector: self._is_installed = False atexit.unregister(self.uninstall) - def create_table(self, name, **options): - if self.exist_table(name): + def collection_exists(self, collection_name): + return collection_name in self.collections() + + def create_collection(self, name, **options): + if self.collection_exists(name): return return self._database.create_collection(name, **options) - def exist_table(self, table_name): - return table_name in self.tables() - - def create_table(self, name, **options): - if self.exist_table(name): - return - - return self._database.create_collection(name, **options) - - def exist_table(self, table_name): - return table_name in self.tables() - - def tables(self): - """List available tables - Returns: - list of table names - """ - collection_names = self.collections() - for table_name in collection_names: - if table_name in ("system.indexes",): - continue - yield table_name - @auto_reconnect def collections(self): - return self._database.collection_names() + for col_name in self._database.collection_names(): + if col_name not in ("system.indexes",): + yield col_name - @check_active_table + @check_active_collection @auto_reconnect def insert_one(self, item, **options): assert isinstance(item, dict), "item must be of type " - return self._database[self.active_table].insert_one(item, **options) + return self._database[self.active_collection].insert_one(item, **options) - @check_active_table + @check_active_collection @auto_reconnect def insert_many(self, items, ordered=True, **options): # check if all items are valid @@ -194,72 +178,72 @@ class CustomDbConnector: assert isinstance(item, dict), "`item` must be of type " options["ordered"] = ordered - return self._database[self.active_table].insert_many(items, **options) + return self._database[self.active_collection].insert_many(items, **options) - @check_active_table + @check_active_collection @auto_reconnect def find(self, filter, projection=None, sort=None, **options): options["sort"] = sort - return self._database[self.active_table].find( + return self._database[self.active_collection].find( filter, projection, **options ) - @check_active_table + @check_active_collection @auto_reconnect def find_one(self, filter, projection=None, sort=None, **options): assert isinstance(filter, dict), "filter must be " options["sort"] = sort - return self._database[self.active_table].find_one( + return self._database[self.active_collection].find_one( filter, projection, **options ) - @check_active_table + @check_active_collection @auto_reconnect def replace_one(self, filter, replacement, **options): - return self._database[self.active_table].replace_one( + return self._database[self.active_collection].replace_one( filter, replacement, **options ) - @check_active_table + @check_active_collection @auto_reconnect def update_one(self, filter, update, **options): - return self._database[self.active_table].update_one( + return self._database[self.active_collection].update_one( filter, update, **options ) - @check_active_table + @check_active_collection @auto_reconnect def update_many(self, filter, update, **options): - return self._database[self.active_table].update_many( + return self._database[self.active_collection].update_many( filter, update, **options ) - @check_active_table + @check_active_collection @auto_reconnect def distinct(self, **options): - return self._database[self.active_table].distinct(**options) + return self._database[self.active_collection].distinct(**options) - @check_active_table + @check_active_collection @auto_reconnect def drop_collection(self, name_or_collection, **options): - return self._database[self.active_table].drop( + return self._database[self.active_collection].drop( name_or_collection, **options ) - @check_active_table + @check_active_collection @auto_reconnect def delete_one(self, filter, collation=None, **options): options["collation"] = collation - return self._database[self.active_table].delete_one( + return self._database[self.active_collection].delete_one( filter, **options ) - @check_active_table + @check_active_collection @auto_reconnect def delete_many(self, filter, collation=None, **options): options["collation"] = collation - return self._database[self.active_table].delete_many( + return self._database[self.active_collection].delete_many( filter, **options ) From b41f9ac8bc63c54f380c24780fe7ac10889afb80 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 11:07:35 +0200 Subject: [PATCH 637/662] variables with table changed to collection --- pype/modules/ftrack/ftrack_server/lib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/lib.py b/pype/modules/ftrack/ftrack_server/lib.py index ee6b1216dc..3a1c742ae8 100644 --- a/pype/modules/ftrack/ftrack_server/lib.py +++ b/pype/modules/ftrack/ftrack_server/lib.py @@ -153,9 +153,9 @@ class StorerEventHub(SocketBaseEventHub): class ProcessEventHub(SocketBaseEventHub): hearbeat_msg = b"processor" - uri, port, database, table_name = get_ftrack_event_mongo_info() + uri, port, database, collection_name = get_ftrack_event_mongo_info() - is_table_created = False + is_collection_created = False pypelog = Logger().get_logger("Session Processor") def __init__(self, *args, **kwargs): @@ -163,7 +163,7 @@ class ProcessEventHub(SocketBaseEventHub): self.uri, self.database, self.port, - self.table_name + self.collection_name ) super(ProcessEventHub, self).__init__(*args, **kwargs) @@ -184,7 +184,7 @@ class ProcessEventHub(SocketBaseEventHub): "Error with Mongo access, probably permissions." "Check if exist database with name \"{}\"" " and collection \"{}\" inside." - ).format(self.database, self.table_name)) + ).format(self.database, self.collection_name)) self.sock.sendall(b"MongoError") sys.exit(0) From 15172d32e3295b2f404c18cdabb32eeac800e85c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 11:12:23 +0200 Subject: [PATCH 638/662] modified imports inside ftrack module to be explicit --- pype/modules/ftrack/__init__.py | 12 +++++++++++- pype/modules/ftrack/ftrack_server/__init__.py | 6 ++++++ pype/modules/ftrack/ftrack_server/lib.py | 2 +- .../modules/ftrack/ftrack_server/sub_event_storer.py | 10 ++++++---- pype/modules/ftrack/lib/ftrack_base_handler.py | 6 +++--- pype/modules/ftrack/tray/login_dialog.py | 2 +- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/pype/modules/ftrack/__init__.py b/pype/modules/ftrack/__init__.py index aa8f04bffb..fad771f084 100644 --- a/pype/modules/ftrack/__init__.py +++ b/pype/modules/ftrack/__init__.py @@ -1,2 +1,12 @@ -from .lib import * +from . import ftrack_server from .ftrack_server import FtrackServer, check_ftrack_url +from .lib import BaseHandler, BaseEvent, BaseAction + +__all__ = ( + "ftrack_server", + "FtrackServer", + "check_ftrack_url", + "BaseHandler", + "BaseEvent", + "BaseAction" +) diff --git a/pype/modules/ftrack/ftrack_server/__init__.py b/pype/modules/ftrack/ftrack_server/__init__.py index fcae4e0690..9e3920b500 100644 --- a/pype/modules/ftrack/ftrack_server/__init__.py +++ b/pype/modules/ftrack/ftrack_server/__init__.py @@ -1,2 +1,8 @@ from .ftrack_server import FtrackServer from .lib import check_ftrack_url + + +__all__ = ( + "FtrackServer", + "check_ftrack_url" +) diff --git a/pype/modules/ftrack/ftrack_server/lib.py b/pype/modules/ftrack/ftrack_server/lib.py index 3a1c742ae8..79b708b17a 100644 --- a/pype/modules/ftrack/ftrack_server/lib.py +++ b/pype/modules/ftrack/ftrack_server/lib.py @@ -26,7 +26,7 @@ from pype.api import ( compose_url ) -from pype.modules.ftrack.lib.custom_db_connector import CustomDbConnector +from .custom_db_connector import CustomDbConnector TOPIC_STATUS_SERVER = "pype.event.server.status" diff --git a/pype/modules/ftrack/ftrack_server/sub_event_storer.py b/pype/modules/ftrack/ftrack_server/sub_event_storer.py index 1635f6cea3..2f4395c8db 100644 --- a/pype/modules/ftrack/ftrack_server/sub_event_storer.py +++ b/pype/modules/ftrack/ftrack_server/sub_event_storer.py @@ -12,7 +12,9 @@ from pype.modules.ftrack.ftrack_server.lib import ( get_ftrack_event_mongo_info, TOPIC_STATUS_SERVER, TOPIC_STATUS_SERVER_RESULT ) -from pype.modules.ftrack.lib.custom_db_connector import CustomDbConnector +from pype.modules.ftrack.ftrack_server.custom_db_connector import ( + CustomDbConnector +) from pype.api import Logger log = Logger().get_logger("Event storer") @@ -23,8 +25,8 @@ class SessionFactory: session = None -uri, port, database, table_name = get_ftrack_event_mongo_info() -dbcon = CustomDbConnector(uri, database, port, table_name) +uri, port, database, collection_name = get_ftrack_event_mongo_info() +dbcon = CustomDbConnector(uri, database, port, collection_name) # ignore_topics = ["ftrack.meta.connected"] ignore_topics = [] @@ -200,7 +202,7 @@ def main(args): "Error with Mongo access, probably permissions." "Check if exist database with name \"{}\"" " and collection \"{}\" inside." - ).format(database, table_name)) + ).format(database, collection_name)) sock.sendall(b"MongoError") finally: diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index ce6607d6bf..d322fbaf23 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -2,7 +2,7 @@ import functools import time from pype.api import Logger import ftrack_api -from pype.modules.ftrack.ftrack_server.lib import SocketSession +from pype.modules.ftrack import ftrack_server class MissingPermision(Exception): @@ -41,7 +41,7 @@ class BaseHandler(object): self.log = Logger().get_logger(self.__class__.__name__) if not( isinstance(session, ftrack_api.session.Session) or - isinstance(session, SocketSession) + isinstance(session, ftrack_server.lib.SocketSession) ): raise Exception(( "Session object entered with args is instance of \"{}\"" @@ -49,7 +49,7 @@ class BaseHandler(object): ).format( str(type(session)), str(ftrack_api.session.Session), - str(SocketSession) + str(ftrack_server.lib.SocketSession) )) self._session = session diff --git a/pype/modules/ftrack/tray/login_dialog.py b/pype/modules/ftrack/tray/login_dialog.py index 7730ee1609..aeed82671f 100644 --- a/pype/modules/ftrack/tray/login_dialog.py +++ b/pype/modules/ftrack/tray/login_dialog.py @@ -1,7 +1,7 @@ import os import requests from avalon import style -from pype.modules.ftrack import credentials +from pype.modules.ftrack.lib import credentials from . import login_tools from pype.api import resources from Qt import QtCore, QtGui, QtWidgets From 689c483631a42dd39079bf02851e6e1f9d05225c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 11:12:31 +0200 Subject: [PATCH 639/662] formatting changes --- pype/modules/ftrack/lib/avalon_sync.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/modules/ftrack/lib/avalon_sync.py b/pype/modules/ftrack/lib/avalon_sync.py index 03124ab10d..292ce752cf 100644 --- a/pype/modules/ftrack/lib/avalon_sync.py +++ b/pype/modules/ftrack/lib/avalon_sync.py @@ -1022,7 +1022,7 @@ class SyncEntitiesFactory: continue ent_path_items = [ent["name"] for ent in entity["link"]] - parents = ent_path_items[1:len(ent_path_items)-1:] + parents = ent_path_items[1:len(ent_path_items) - 1:] hierarchy = "" if len(parents) > 0: hierarchy = os.path.sep.join(parents) @@ -1141,7 +1141,7 @@ class SyncEntitiesFactory: if not is_right and not else_match_better: entity = entity_dict["entity"] ent_path_items = [ent["name"] for ent in entity["link"]] - parents = ent_path_items[1:len(ent_path_items)-1:] + parents = ent_path_items[1:len(ent_path_items) - 1:] av_parents = av_ent_by_mongo_id["data"]["parents"] if av_parents == parents: is_right = True From bb77c72b98d204b39d7d4bd953df289eeab5b18e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 11:30:21 +0200 Subject: [PATCH 640/662] fix thread stopping in ftrack login --- pype/modules/ftrack/tray/login_dialog.py | 2 ++ pype/modules/ftrack/tray/login_tools.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/pype/modules/ftrack/tray/login_dialog.py b/pype/modules/ftrack/tray/login_dialog.py index aeed82671f..94ad29e478 100644 --- a/pype/modules/ftrack/tray/login_dialog.py +++ b/pype/modules/ftrack/tray/login_dialog.py @@ -238,6 +238,8 @@ class CredentialsDialog(QtWidgets.QDialog): # If there is an existing server thread running we need to stop it. if self._login_server_thread: + if self._login_server_thread.isAlive(): + self._login_server_thread.stop() self._login_server_thread.join() self._login_server_thread = None diff --git a/pype/modules/ftrack/tray/login_tools.py b/pype/modules/ftrack/tray/login_tools.py index e7d22fbc19..d3297eaa76 100644 --- a/pype/modules/ftrack/tray/login_tools.py +++ b/pype/modules/ftrack/tray/login_tools.py @@ -61,12 +61,17 @@ class LoginServerThread(threading.Thread): def __init__(self, url, callback): self.url = url self.callback = callback + self._server = None super(LoginServerThread, self).__init__() def _handle_login(self, api_user, api_key): '''Login to server with *api_user* and *api_key*.''' self.callback(api_user, api_key) + def stop(self): + if self._server: + self._server.server_close() + def run(self): '''Listen for events.''' self._server = HTTPServer( From c9f381e60b6b1fc4956c1bfb718d49f8180c2478 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 11:46:23 +0200 Subject: [PATCH 641/662] hound fixes --- pype/modules/ftrack/ftrack_server/custom_db_connector.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pype/modules/ftrack/ftrack_server/custom_db_connector.py b/pype/modules/ftrack/ftrack_server/custom_db_connector.py index 232481e6f4..8a8ba4ccbb 100644 --- a/pype/modules/ftrack/ftrack_server/custom_db_connector.py +++ b/pype/modules/ftrack/ftrack_server/custom_db_connector.py @@ -167,7 +167,9 @@ class CustomDbConnector: @auto_reconnect def insert_one(self, item, **options): assert isinstance(item, dict), "item must be of type " - return self._database[self.active_collection].insert_one(item, **options) + return self._database[self.active_collection].insert_one( + item, **options + ) @check_active_collection @auto_reconnect @@ -178,7 +180,9 @@ class CustomDbConnector: assert isinstance(item, dict), "`item` must be of type " options["ordered"] = ordered - return self._database[self.active_collection].insert_many(items, **options) + return self._database[self.active_collection].insert_many( + items, **options + ) @check_active_collection @auto_reconnect From f16d601a8a1c00d48404909662f90ed1010dd378 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 12:22:17 +0200 Subject: [PATCH 642/662] changed default port to 8098 --- 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 ec6785625a..daf4b03103 100644 --- a/pype/modules/websocket_server/websocket_server.py +++ b/pype/modules/websocket_server/websocket_server.py @@ -37,7 +37,7 @@ class WebSocketServer(): parsed = urllib.parse.urlparse(websocket_url) port = parsed.port if not port: - port = 8099 # fallback + port = 8098 # fallback self.app = web.Application() From b7211626b05dc3fba8cf213b9cc235d76d2bc874 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 30 Sep 2020 12:40:13 +0200 Subject: [PATCH 643/662] fix(sp): adding "clip" family to better filter editorial instances --- .../standalonepublisher/publish/collect_clip_instances.py | 4 ++-- .../standalonepublisher/publish/extract_shot_data.py | 2 +- .../publish/validate_editorial_resources.py | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pype/plugins/standalonepublisher/publish/collect_clip_instances.py b/pype/plugins/standalonepublisher/publish/collect_clip_instances.py index a7af8df143..def0c13a78 100644 --- a/pype/plugins/standalonepublisher/publish/collect_clip_instances.py +++ b/pype/plugins/standalonepublisher/publish/collect_clip_instances.py @@ -17,13 +17,13 @@ class CollectClipInstances(pyblish.api.InstancePlugin): subsets = { "referenceMain": { "family": "review", - "families": ["review", "ftrack"], + "families": ["clip", "ftrack"], # "ftrackFamily": "review", "extension": ".mp4" }, "audioMain": { "family": "audio", - "families": ["ftrack"], + "families": ["clip", "ftrack"], # "ftrackFamily": "audio", "extension": ".wav", # "version": 1 diff --git a/pype/plugins/standalonepublisher/publish/extract_shot_data.py b/pype/plugins/standalonepublisher/publish/extract_shot_data.py index c39247d6d6..d5af7638ee 100644 --- a/pype/plugins/standalonepublisher/publish/extract_shot_data.py +++ b/pype/plugins/standalonepublisher/publish/extract_shot_data.py @@ -10,7 +10,7 @@ class ExtractShotData(pype.api.Extractor): label = "Extract Shot Data" hosts = ["standalonepublisher"] - families = ["review", "audio"] + families = ["clip"] # presets diff --git a/pype/plugins/standalonepublisher/publish/validate_editorial_resources.py b/pype/plugins/standalonepublisher/publish/validate_editorial_resources.py index ebc449c4ec..7e1694fbd1 100644 --- a/pype/plugins/standalonepublisher/publish/validate_editorial_resources.py +++ b/pype/plugins/standalonepublisher/publish/validate_editorial_resources.py @@ -1,5 +1,3 @@ -import os - import pyblish.api import pype.api @@ -9,10 +7,14 @@ class ValidateEditorialResources(pyblish.api.InstancePlugin): label = "Validate Editorial Resources" hosts = ["standalonepublisher"] - families = ["audio", "review"] + families = ["clip"] + order = pype.api.ValidateContentsOrder def process(self, instance): + self.log.debug( + f"Instance: {instance}, Families: " + f"{[instance.data['family']] + instance.data['families']}") check_file = instance.data["editorialVideoPath"] msg = f"Missing \"{check_file}\"." assert check_file, msg From d384fb9a45afa0c0b065ed977eced85a6269002a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 13:21:24 +0200 Subject: [PATCH 644/662] Qt is not used in avalon_apps module if tray_init is not triggered --- pype/modules/avalon_apps/avalon_app.py | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/pype/modules/avalon_apps/avalon_app.py b/pype/modules/avalon_apps/avalon_app.py index 7ed651f82b..de10268304 100644 --- a/pype/modules/avalon_apps/avalon_app.py +++ b/pype/modules/avalon_apps/avalon_app.py @@ -1,16 +1,27 @@ -from Qt import QtWidgets -from avalon.tools import libraryloader from pype.api import Logger -from pype.tools.launcher import LauncherWindow, actions class AvalonApps: def __init__(self, main_parent=None, parent=None): self.log = Logger().get_logger(__name__) - self.main_parent = main_parent + + self.tray_init(main_parent, parent) + + def tray_init(self, main_parent, parent): + from avalon.tools.libraryloader import app + from avalon import style + from pype.tools.launcher import LauncherWindow, actions + self.parent = parent + self.main_parent = main_parent self.app_launcher = LauncherWindow() + self.libraryloader = app.Window( + icon=self.parent.icon, + show_projects=True, + show_libraries=True + ) + self.libraryloader.setStyleSheet(style.load_stylesheet()) # actions.register_default_actions() actions.register_config_actions() @@ -23,6 +34,7 @@ class AvalonApps: # Definition of Tray menu def tray_menu(self, parent_menu=None): + from Qt import QtWidgets # Actions if parent_menu is None: if self.parent is None: @@ -52,9 +64,11 @@ class AvalonApps: self.app_launcher.activateWindow() def show_library_loader(self): - libraryloader.show( - parent=self.main_parent, - icon=self.parent.icon, - show_projects=True, - show_libraries=True - ) + self.libraryloader.show() + + # Raise and activate the window + # for MacOS + self.libraryloader.raise_() + # for Windows + self.libraryloader.activateWindow() + self.libraryloader.refresh() From 6951e046de4a531a635a80ca8909f601cac076c9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 15:13:19 +0200 Subject: [PATCH 645/662] clockify modules does not use Qt unless tray_init is triggered --- pype/modules/clockify/clockify.py | 75 +++++++++++++++++-------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/pype/modules/clockify/clockify.py b/pype/modules/clockify/clockify.py index fea15a1bea..24f1b0b39d 100644 --- a/pype/modules/clockify/clockify.py +++ b/pype/modules/clockify/clockify.py @@ -1,9 +1,8 @@ import os import threading +import time + from pype.api import Logger -from avalon import style -from Qt import QtWidgets -from .widgets import ClockifySettings, MessageWidget from .clockify_api import ClockifyAPI from .constants import CLOCKIFY_FTRACK_USER_PATH @@ -17,11 +16,21 @@ class ClockifyModule: os.environ["CLOCKIFY_WORKSPACE"] = self.workspace_name + self.timer_manager = None + self.MessageWidgetClass = None + + self.clockapi = ClockifyAPI(master_parent=self) + self.log = Logger().get_logger(self.__class__.__name__, "PypeTray") + self.tray_init(main_parent, parent) + + def tray_init(self, main_parent, parent): + from .widgets import ClockifySettings, MessageWidget + + self.MessageWidgetClass = MessageWidget self.main_parent = main_parent self.parent = parent - self.clockapi = ClockifyAPI(master_parent=self) self.message_widget = None self.widget_settings = ClockifySettings(main_parent, self) self.widget_settings_required = None @@ -78,12 +87,12 @@ class ClockifyModule: self.stop_timer() def timer_started(self, data): - if hasattr(self, 'timer_manager'): + if self.timer_manager: self.timer_manager.start_timers(data) def timer_stopped(self): self.bool_timer_run = False - if hasattr(self, 'timer_manager'): + if self.timer_manager: self.timer_manager.stop_timers() def start_timer_check(self): @@ -102,7 +111,7 @@ class ClockifyModule: self.thread_timer_check = None def check_running(self): - import time + while self.bool_thread_check_running is True: bool_timer_run = False if self.clockapi.get_in_progress() is not None: @@ -156,15 +165,14 @@ class ClockifyModule: self.timer_stopped() def signed_in(self): - if hasattr(self, 'timer_manager'): - if not self.timer_manager: - return + if not self.timer_manager: + return - if not self.timer_manager.last_task: - return + if not self.timer_manager.last_task: + return - if self.timer_manager.is_running: - self.start_timer_manager(self.timer_manager.last_task) + if self.timer_manager.is_running: + self.start_timer_manager(self.timer_manager.last_task) def start_timer(self, input_data): # If not api key is not entered then skip @@ -197,11 +205,12 @@ class ClockifyModule: "

Please inform your Project Manager." ).format(project_name, str(self.clockapi.workspace_name)) - self.message_widget = MessageWidget( - self.main_parent, msg, "Clockify - Info Message" - ) - self.message_widget.closed.connect(self.on_message_widget_close) - self.message_widget.show() + if self.MessageWidgetClass: + self.message_widget = self.MessageWidgetClass( + self.main_parent, msg, "Clockify - Info Message" + ) + self.message_widget.closed.connect(self.on_message_widget_close) + self.message_widget.show() return @@ -227,31 +236,29 @@ class ClockifyModule: # Definition of Tray menu def tray_menu(self, parent_menu): # Menu for Tray App - self.menu = QtWidgets.QMenu('Clockify', parent_menu) - self.menu.setProperty('submenu', 'on') - self.menu.setStyleSheet(style.load_stylesheet()) + from Qt import QtWidgets + menu = QtWidgets.QMenu("Clockify", parent_menu) + menu.setProperty("submenu", "on") # Actions - self.aShowSettings = QtWidgets.QAction( - "Settings", self.menu - ) - self.aStopTimer = QtWidgets.QAction( - "Stop timer", self.menu - ) + action_show_settings = QtWidgets.QAction("Settings", menu) + action_stop_timer = QtWidgets.QAction("Stop timer", menu) - self.menu.addAction(self.aShowSettings) - self.menu.addAction(self.aStopTimer) + menu.addAction(action_show_settings) + menu.addAction(action_stop_timer) - self.aShowSettings.triggered.connect(self.show_settings) - self.aStopTimer.triggered.connect(self.stop_timer) + action_show_settings.triggered.connect(self.show_settings) + action_stop_timer.triggered.connect(self.stop_timer) + + self.action_stop_timer = action_stop_timer self.set_menu_visibility() - parent_menu.addMenu(self.menu) + parent_menu.addMenu(menu) def show_settings(self): self.widget_settings.input_api_key.setText(self.clockapi.get_api_key()) self.widget_settings.show() def set_menu_visibility(self): - self.aStopTimer.setVisible(self.bool_timer_run) + self.action_stop_timer.setVisible(self.bool_timer_run) From d8eec091c316dc6bdbec09d9093a2778f77281ff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 15:19:31 +0200 Subject: [PATCH 646/662] fix hound --- pype/modules/clockify/clockify.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pype/modules/clockify/clockify.py b/pype/modules/clockify/clockify.py index 24f1b0b39d..4309bff9f2 100644 --- a/pype/modules/clockify/clockify.py +++ b/pype/modules/clockify/clockify.py @@ -66,11 +66,10 @@ class ClockifyModule: ) if 'AvalonApps' in modules: - from launcher import lib - actions_path = os.path.sep.join([ + actions_path = os.path.join( os.path.dirname(__file__), 'launcher_actions' - ]) + ) current = os.environ.get('AVALON_ACTIONS', '') if current: current += os.pathsep @@ -209,7 +208,9 @@ class ClockifyModule: self.message_widget = self.MessageWidgetClass( self.main_parent, msg, "Clockify - Info Message" ) - self.message_widget.closed.connect(self.on_message_widget_close) + self.message_widget.closed.connect( + self.on_message_widget_close + ) self.message_widget.show() return From 4785cf26c4afdf1e9cbe82806515a35e405c773e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 30 Sep 2020 15:24:31 +0200 Subject: [PATCH 647/662] muster is not using Qt until tray_init is triggered --- pype/modules/muster/muster.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/pype/modules/muster/muster.py b/pype/modules/muster/muster.py index 629fb12635..beb30690ac 100644 --- a/pype/modules/muster/muster.py +++ b/pype/modules/muster/muster.py @@ -1,10 +1,7 @@ -import appdirs -from avalon import style -from Qt import QtWidgets import os import json -from .widget_login import MusterLogin -from avalon.vendor import requests +import appdirs +import requests class MusterModule: @@ -21,6 +18,11 @@ class MusterModule: self.cred_path = os.path.join( self.cred_folder_path, self.cred_filename ) + self.tray_init(main_parent, parent) + + def tray_init(self, main_parent, parent): + from .widget_login import MusterLogin + self.main_parent = main_parent self.parent = parent self.widget_login = MusterLogin(main_parent, self) @@ -38,10 +40,6 @@ class MusterModule: pass def process_modules(self, modules): - - def api_callback(): - self.aShowLogin.trigger() - if "RestApiServer" in modules: def api_show_login(): self.aShowLogin.trigger() @@ -51,13 +49,12 @@ class MusterModule: # Definition of Tray menu def tray_menu(self, parent): - """ - Add **change credentials** option to tray menu. - """ + """Add **change credentials** option to tray menu.""" + from Qt import QtWidgets + # Menu for Tray App self.menu = QtWidgets.QMenu('Muster', parent) self.menu.setProperty('submenu', 'on') - self.menu.setStyleSheet(style.load_stylesheet()) # Actions self.aShowLogin = QtWidgets.QAction( @@ -91,9 +88,9 @@ class MusterModule: if not MUSTER_REST_URL: raise AttributeError("Muster REST API url not set") params = { - 'username': username, - 'password': password - } + 'username': username, + 'password': password + } api_entry = '/api/login' response = self._requests_post( MUSTER_REST_URL + api_entry, params=params) From d8deb18b52558a7678596ab9e3c6dbb19fbd6514 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 30 Sep 2020 18:41:07 +0200 Subject: [PATCH 648/662] fix(SP): not correct filtering of activated assets in hierarchy --- .../publish/extract_hierarchy_avalon.py | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/pype/plugins/global/publish/extract_hierarchy_avalon.py b/pype/plugins/global/publish/extract_hierarchy_avalon.py index 4253c35929..eb791184ed 100644 --- a/pype/plugins/global/publish/extract_hierarchy_avalon.py +++ b/pype/plugins/global/publish/extract_hierarchy_avalon.py @@ -1,6 +1,6 @@ import pyblish.api from avalon import io - +from copy import deepcopy class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): """Create entities in Avalon based on collected data.""" @@ -14,14 +14,12 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): if "hierarchyContext" not in context.data: self.log.info("skipping IntegrateHierarchyToAvalon") return + hierarchy_context = deepcopy(context.data["hierarchyContext"]) if not io.Session: io.install() active_assets = [] - hierarchy_context = context.data["hierarchyContext"] - hierarchy_assets = self._get_assets(hierarchy_context) - # filter only the active publishing insatnces for instance in context: if instance.data.get("publish") is False: @@ -32,13 +30,13 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): active_assets.append(instance.data["asset"]) - # filter out only assets which are activated as isntances - new_hierarchy_assets = {k: v for k, v in hierarchy_assets.items() - if k in active_assets} + # remove duplicity in list + self.active_assets = list(set(active_assets)) + self.log.debug("__ self.active_assets: {}".format(self.active_assets)) - # modify the hierarchy context so there are only fitred assets - self._set_assets(hierarchy_context, new_hierarchy_assets) + hierarchy_context = self._get_assets(hierarchy_context) + self.log.debug("__ hierarchy_context: {}".format(hierarchy_context)) input_data = context.data["hierarchyContext"] = hierarchy_context self.project = None @@ -178,14 +176,21 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): Usually the last part of deep dictionary which is not having any children """ + input_dict_copy = deepcopy(input_dict) + for key in input_dict.keys(): + self.log.debug("__ key: {}".format(key)) # check if child key is available if input_dict[key].get("childs"): # loop deeper - return self._get_assets(input_dict[key]["childs"]) + input_dict_copy[key]["childs"] = self._get_assets( + input_dict[key]["childs"]) else: - # give the dictionary with assets - return input_dict + # filter out unwanted assets + if key not in self.active_assets: + input_dict_copy.pop(key, None) + + return input_dict_copy def _set_assets(self, input_dict, new_assets=None): """ Modify the hierarchy context dictionary. From 56ca9b804c0e33d3461c1ef35ef9695889bc4812 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 30 Sep 2020 18:41:52 +0200 Subject: [PATCH 649/662] clean(SP): old code cleanup --- .../publish/extract_hierarchy_avalon.py | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/pype/plugins/global/publish/extract_hierarchy_avalon.py b/pype/plugins/global/publish/extract_hierarchy_avalon.py index eb791184ed..5d11eae058 100644 --- a/pype/plugins/global/publish/extract_hierarchy_avalon.py +++ b/pype/plugins/global/publish/extract_hierarchy_avalon.py @@ -191,27 +191,3 @@ class ExtractHierarchyToAvalon(pyblish.api.ContextPlugin): input_dict_copy.pop(key, None) return input_dict_copy - - def _set_assets(self, input_dict, new_assets=None): - """ Modify the hierarchy context dictionary. - It will replace the asset dictionary with only the filtred one. - """ - for key in input_dict.keys(): - # check if child key is available - if input_dict[key].get("childs"): - # return if this is just for testing purpose and no - # new_assets property is avalable - if not new_assets: - return True - - # test for deeper inner children availabelity - if self._set_assets(input_dict[key]["childs"]): - # if one level deeper is still children available - # then process farther - self._set_assets(input_dict[key]["childs"], new_assets) - else: - # or just assign the filtred asset ditionary - input_dict[key]["childs"] = new_assets - else: - # test didnt find more childs in input dictionary - return None From a09b74369e616f6a0f65e8dfb04432b65cc6ca81 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Wed, 30 Sep 2020 18:51:18 +0200 Subject: [PATCH 650/662] fix clashing namespace of called functions --- pype/hosts/harmony/__init__.py | 37 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/pype/hosts/harmony/__init__.py b/pype/hosts/harmony/__init__.py index 7310e91e9b..f920e38765 100644 --- a/pype/hosts/harmony/__init__.py +++ b/pype/hosts/harmony/__init__.py @@ -1,5 +1,6 @@ import os import sys +from uuid import uuid4 from avalon import api, io, harmony from avalon.vendor import Qt @@ -8,8 +9,11 @@ import pyblish.api from pype import lib +signature = str(uuid4()) + + def set_scene_settings(settings): - func = """function func(args) + func = """function %s_func(args) { if (args[0]["fps"]) { @@ -36,8 +40,8 @@ def set_scene_settings(settings): ) } } - func - """ + %s_func + """ % (signature, signature) harmony.send({"function": func, "args": [settings]}) @@ -107,15 +111,15 @@ def check_inventory(): outdated_containers.append(container) # Colour nodes. - func = """function func(args){ + func = """function %s_func(args){ for( var i =0; i <= args[0].length - 1; ++i) { var red_color = new ColorRGBA(255, 0, 0, 255); node.setColor(args[0][i], red_color); } } - func - """ + %s_func + """ % (signature, signature) outdated_nodes = [] for container in outdated_containers: if container["loader"] == "ImageSequenceLoader": @@ -144,7 +148,7 @@ def application_launch(): def export_template(backdrops, nodes, filepath): - func = """function func(args) + func = """function %s_func(args) { var temp_node = node.add("Top", "temp_note", "NOTE", 0, 0, 0); @@ -179,8 +183,8 @@ def export_template(backdrops, nodes, filepath): Action.perform("onActionUpToParent()", "Node View"); node.deleteNode(template_group, true, true); } - func - """ + %s_func + """ % (signature, signature) harmony.send({ "function": func, "args": [ @@ -221,12 +225,15 @@ def install(): def on_pyblish_instance_toggled(instance, old_value, new_value): """Toggle node enabling on instance toggles.""" - func = """function func(args) + func = """function %s_func(args) { node.setEnable(args[0], args[1]) } - func - """ - harmony.send( - {"function": func, "args": [instance[0], new_value]} - ) + %s_func + """ % (signature, signature) + try: + harmony.send( + {"function": func, "args": [instance[0], new_value]} + ) + except IndexError: + print(f"Instance '{instance}' is missing node") From fa541d1ddb5ff7a46dc9cbeaddf751f3651fa3e2 Mon Sep 17 00:00:00 2001 From: Milan Date: Wed, 30 Sep 2020 18:44:09 +0100 Subject: [PATCH 651/662] fix(SP): adding collect for plate and render family --- .../publish/collect_instance_data.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 pype/plugins/standalonepublisher/publish/collect_instance_data.py diff --git a/pype/plugins/standalonepublisher/publish/collect_instance_data.py b/pype/plugins/standalonepublisher/publish/collect_instance_data.py new file mode 100644 index 0000000000..1b32ea9144 --- /dev/null +++ b/pype/plugins/standalonepublisher/publish/collect_instance_data.py @@ -0,0 +1,29 @@ +""" +Requires: + Nothing + +Provides: + Instance +""" + +import pyblish.api +from pprint import pformat + + +class CollectInstanceData(pyblish.api.InstancePlugin): + """ + Collector with only one reason for its existence - remove 'ftrack' + family implicitly added by Standalone Publisher + """ + + label = "Collect instance data" + order = pyblish.api.CollectorOrder + 0.49 + families = ["render", "plate"] + hosts = ["standalonepublisher"] + + def process(self, instance): + fps = instance.data["assetEntity"]["data"]["fps"] + instance.data.update({ + "fps": fps + }) + self.log.debug(f"instance.data: {pformat(instance.data)}") From 5c9327fe867b76d082c0e87cdba17976d9c852e7 Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 1 Oct 2020 09:32:25 +0100 Subject: [PATCH 652/662] fixing space in path --- pype/tools/standalonepublish/widgets/widget_drop_frame.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pype/tools/standalonepublish/widgets/widget_drop_frame.py b/pype/tools/standalonepublish/widgets/widget_drop_frame.py index e13f701b30..a7abe1b24c 100644 --- a/pype/tools/standalonepublish/widgets/widget_drop_frame.py +++ b/pype/tools/standalonepublish/widgets/widget_drop_frame.py @@ -268,9 +268,10 @@ class DropDataFrame(QtWidgets.QFrame): args = [ ffprobe_path, '-v', 'quiet', - '-print_format', 'json', + '-print_format json', '-show_format', - '-show_streams', filepath + '-show_streams', + '"{}"'.format(filepath) ] ffprobe_p = subprocess.Popen( ' '.join(args), From 4fc5fa46ddde884b0ff2a98f8e86020006e2adde Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 1 Oct 2020 10:15:18 +0100 Subject: [PATCH 653/662] nondestructive reformating if input res odd number --- pype/plugins/global/publish/extract_review.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 0bae1b2ddc..9f638712a7 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -453,6 +453,7 @@ class ExtractReview(pyblish.api.InstancePlugin): if audio_filters: all_args.append("-filter:a {}".format(",".join(audio_filters))) + all_args.append('-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"') all_args.extend(output_args) return all_args From 945a6d88b9b5ec1b071ab73658693c3e7ea5c40f Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 1 Oct 2020 10:15:56 +0100 Subject: [PATCH 654/662] fix(burnin): space in path was crashing --- pype/scripts/otio_burnin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 156896a759..6607726c73 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -15,7 +15,7 @@ ffprobe_path = pype.lib.get_ffmpeg_tool_path("ffprobe") FFMPEG = ( - '{} -loglevel panic -i %(input)s %(filters)s %(args)s%(output)s' + '{} -loglevel panic -i "%(input)s" %(filters)s %(args)s%(output)s' ).format(ffmpeg_path) FFPROBE = ( From dbf0881415b713cfb4e3c9d1b0bbf3e43ff95aca Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 1 Oct 2020 15:19:01 +0200 Subject: [PATCH 655/662] first video filter will add padding to input if has width or height with odd numbers --- pype/plugins/global/publish/extract_review.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 0bae1b2ddc..db81adfcf7 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -633,6 +633,26 @@ class ExtractReview(pyblish.api.InstancePlugin): input_width = int(input_data["width"]) input_height = int(input_data["height"]) + # Make sure input width and height is not an odd number + input_width_is_odd = bool(input_width % 2 != 0) + inputh_height_is_odd = bool(input_height % 2 != 0) + if input_width_is_odd or inputh_height_is_odd: + # Add padding to input and make sure this filter is at first place + filters.append("pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2") + + # Change input width or height as first filter will change them + if input_width_is_odd: + self.log.info(( + "Converting input width from odd to even number. {} -> {}" + ).format(input_width, input_width + 1)) + input_width += 1 + + if inputh_height_is_odd: + self.log.info(( + "Converting input height from odd to even number. {} -> {}" + ).format(input_height, input_height + 1)) + input_height += 1 + self.log.debug("pixel_aspect: `{}`".format(pixel_aspect)) self.log.debug("input_width: `{}`".format(input_width)) self.log.debug("input_height: `{}`".format(input_height)) From 70780cbc5309e1191375ccdbaf577a981d6bd30e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 1 Oct 2020 15:19:41 +0200 Subject: [PATCH 656/662] also make sure output width or height does not contain odd numbers --- pype/plugins/global/publish/extract_review.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index db81adfcf7..3febff0f16 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -674,6 +674,22 @@ class ExtractReview(pyblish.api.InstancePlugin): output_width = int(output_width) output_height = int(output_height) + # Make sure output width and height is not an odd number + # When this can happen: + # - if output definition has set width and height with odd number + # - `instance.data` contain width and height with odd numbeer + if output_width % 2 != 0: + self.log.warning(( + "Converting output width from odd to even number. {} -> {}" + ).format(output_width, output_width + 1)) + output_width += 1 + + if output_height % 2 != 0: + self.log.warning(( + "Converting output height from odd to even number. {} -> {}" + ).format(output_height, output_height + 1)) + output_height += 1 + self.log.debug( "Output resolution is {}x{}".format(output_width, output_height) ) From 2a14a586c867ee3253ecb159e13a3be3cfe343b8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 1 Oct 2020 17:05:34 +0200 Subject: [PATCH 657/662] fix(standalone): fixing space in path for thumbnailer --- pype/plugins/standalonepublisher/publish/extract_thumbnail.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py index cddc9c3a82..5882775083 100644 --- a/pype/plugins/standalonepublisher/publish/extract_thumbnail.py +++ b/pype/plugins/standalonepublisher/publish/extract_thumbnail.py @@ -64,6 +64,7 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin): else: # Convert to jpeg if not yet full_input_path = os.path.join(thumbnail_repre["stagingDir"], file) + full_input_path = '"{}"'.format(full_input_path) self.log.info("input {}".format(full_input_path)) full_thumbnail_path = tempfile.mkstemp(suffix=".jpg")[1] From 4b754eed90982407f2c8abef066921682c06c9b2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 1 Oct 2020 17:07:59 +0200 Subject: [PATCH 658/662] fix(global): removing reformating of odd resolution --- pype/plugins/global/publish/extract_review.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 9f638712a7..0bae1b2ddc 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -453,7 +453,6 @@ class ExtractReview(pyblish.api.InstancePlugin): if audio_filters: all_args.append("-filter:a {}".format(",".join(audio_filters))) - all_args.append('-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"') all_args.extend(output_args) return all_args From 2c6797e63a3cdeebfb047f16ef531c298aed6bbf Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 1 Oct 2020 17:11:06 +0200 Subject: [PATCH 659/662] fixed typo --- pype/plugins/global/publish/extract_review.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 3febff0f16..318c843b80 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -635,8 +635,8 @@ class ExtractReview(pyblish.api.InstancePlugin): # Make sure input width and height is not an odd number input_width_is_odd = bool(input_width % 2 != 0) - inputh_height_is_odd = bool(input_height % 2 != 0) - if input_width_is_odd or inputh_height_is_odd: + input_height_is_odd = bool(input_height % 2 != 0) + if input_width_is_odd or input_height_is_odd: # Add padding to input and make sure this filter is at first place filters.append("pad=width=ceil(iw/2)*2:height=ceil(ih/2)*2") @@ -647,7 +647,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ).format(input_width, input_width + 1)) input_width += 1 - if inputh_height_is_odd: + if input_height_is_odd: self.log.info(( "Converting input height from odd to even number. {} -> {}" ).format(input_height, input_height + 1)) From 88bbe2d156f8fd542afc0e04bad554660aae57a3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 1 Oct 2020 18:34:32 +0200 Subject: [PATCH 660/662] fix(ftrack): print not for p27 --- pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py index 0616382569..f6cb512518 100644 --- a/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py +++ b/pype/plugins/ftrack/publish/integrate_hierarchy_ftrack.py @@ -2,7 +2,6 @@ import sys import six import pyblish.api from avalon import io -from pprint import pformat try: from pype.modules.ftrack.lib.avalon_sync import CUST_ATTR_AUTO_SYNC @@ -46,9 +45,6 @@ class IntegrateHierarchyToFtrack(pyblish.api.ContextPlugin): hierarchy_context = self.context.data["hierarchyContext"] - self.log.debug( - f"__ hierarchy_context: `{pformat(hierarchy_context)}`") - self.session = self.context.data["ftrackSession"] project_name = self.context.data["projectEntity"]["name"] query = 'Project where full_name is "{}"'.format(project_name) From 20b74ec2341fcf3e3dcc8399d8fddf956bec5598 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 1 Oct 2020 18:34:46 +0200 Subject: [PATCH 661/662] fix(nks): space in path crashing --- .../nukestudio/publish/extract_review_cutup_video.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pype/plugins/nukestudio/publish/extract_review_cutup_video.py b/pype/plugins/nukestudio/publish/extract_review_cutup_video.py index a4fbf90bed..d1ce3675b1 100644 --- a/pype/plugins/nukestudio/publish/extract_review_cutup_video.py +++ b/pype/plugins/nukestudio/publish/extract_review_cutup_video.py @@ -76,7 +76,7 @@ class ExtractReviewCutUpVideo(pype.api.Extractor): # check if audio stream is in input video file ffprob_cmd = ( - "{ffprobe_path} -i {full_input_path} -show_streams " + "{ffprobe_path} -i \"{full_input_path}\" -show_streams " "-select_streams a -loglevel error" ).format(**locals()) self.log.debug("ffprob_cmd: {}".format(ffprob_cmd)) @@ -106,7 +106,7 @@ class ExtractReviewCutUpVideo(pype.api.Extractor): # try to get video native resolution data try: resolution_output = pype.api.subprocess(( - "{ffprobe_path} -i {full_input_path} -v error " + "{ffprobe_path} -i \"{full_input_path}\" -v error " "-select_streams v:0 -show_entries " "stream=width,height -of csv=s=x:p=0" ).format(**locals())) @@ -193,7 +193,7 @@ class ExtractReviewCutUpVideo(pype.api.Extractor): # append ffmpeg input video clip input_args.append("-ss {:0.2f}".format(start_sec)) input_args.append("-t {:0.2f}".format(duration_sec)) - input_args.append("-i {}".format(full_input_path)) + input_args.append("-i \"{}\"".format(full_input_path)) # add copy audio video codec if only shortening clip if ("_cut-bigger" in tags) and (not empty_add): @@ -203,8 +203,7 @@ class ExtractReviewCutUpVideo(pype.api.Extractor): output_args.append("-intra") # output filename - output_args.append("-y") - output_args.append(full_output_path) + output_args.append("-y \"{}\"".format(full_output_path)) mov_args = [ ffmpeg_path, From d27be1914da9a52074d8fdb1348c493de6dfd501 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 2 Oct 2020 10:06:02 +0200 Subject: [PATCH 662/662] feat(hiero): adding icon --- pype/resources/app_icons/hiero.png | Bin 0 -> 46366 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pype/resources/app_icons/hiero.png diff --git a/pype/resources/app_icons/hiero.png b/pype/resources/app_icons/hiero.png new file mode 100644 index 0000000000000000000000000000000000000000..04bbf6265bb63f0615c2b98ab48891d03483f6b2 GIT binary patch literal 46366 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 literal 0 HcmV?d00001