From 47ef4b64f297186c6d929a8f56ecfb93dd0f44e8 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Tue, 15 Sep 2020 17:59:53 +0200 Subject: [PATCH 01/63] 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 625eebea25dd93c127c47d394fdfc3e3d02e5c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Fri, 18 Sep 2020 17:32:56 +0200 Subject: [PATCH 02/63] maya plugins and capture settings --- .../plugins/maya/maya/maya_capture.json | 108 +++++ .../plugins/maya/maya/publish.json | 21 + .../plugins/maya/maya/workfile_build.json | 1 + .../projects_schema/1_plugins_gui_schema.json | 101 +--- .../projects_schema/2_maya_capture.json | 433 ++++++++++++++++++ .../projects_schema/2_maya_plugins.json | 90 ++++ .../projects_schema/2_maya_workfiles.json | 6 + pype/tools/settings/settings/widgets/lib.py | 6 +- 8 files changed, 681 insertions(+), 85 deletions(-) create mode 100644 pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json create mode 100644 pype/settings/defaults/project_settings/plugins/maya/maya/publish.json create mode 100644 pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_plugins.json create mode 100644 pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_workfiles.json diff --git a/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json b/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json new file mode 100644 index 0000000000..b6c4893034 --- /dev/null +++ b/pype/settings/defaults/project_settings/plugins/maya/maya/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/settings/defaults/project_settings/plugins/maya/maya/publish.json b/pype/settings/defaults/project_settings/plugins/maya/maya/publish.json new file mode 100644 index 0000000000..486f0917e2 --- /dev/null +++ b/pype/settings/defaults/project_settings/plugins/maya/maya/publish.json @@ -0,0 +1,21 @@ +{ + "ValidateModelName": { + "enabled": true, + "material_file": { + "windows": "", + "darwin": "", + "linux": "" + }, + "regex": "" + }, + "ValidateAssemblyName": { + "enabled": true + }, + "ValidateShaderName": { + "enabled": true, + "regex": "(?P.*)_(.*)_SHD" + }, + "ValidateMeshHasOverlappingUVs": { + "enabled": true + } +} \ No newline at end of file diff --git a/pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json b/pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/pype/settings/defaults/project_settings/plugins/maya/maya/workfile_build.json @@ -0,0 +1 @@ +{} \ No newline at end of file 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..560d214877 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 @@ -353,94 +353,27 @@ } ] }, { - "type": "dict", + "type": "dict-invisible", "collapsable": true, "key": "maya", "label": "Maya", "children": [ - { - "type": "dict", - "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "key": "ValidateModelName", - "label": "Validate Model Name", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "material_file", - "label": "Material File" - }, { - "type": "text", - "key": "regex", - "label": "Validation regex" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ValidateAssemblyName", - "label": "Validate Assembly Name", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ValidateShaderName", - "label": "ValidateShaderName", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "regex", - "label": "Validation regex" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ValidateMeshHasOverlappingUVs", - "label": "ValidateMeshHasOverlappingUVs", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - } - ] - }, { - "type": "raw-json", - "key": "workfile_build", - "label": "Workfile Build logic", - "is_file": true - } + { + "type": "dict", + "collapsable": true, + "key": "maya", + "label": "Maya", + "children": [ + { + "type": "schema", + "children": [ + "2_maya_capture", + "2_maya_plugins", + "2_maya_workfiles" + ] + } + ] + } ] }, { "type": "dict", diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json new file mode 100644 index 0000000000..a7b44323d2 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json @@ -0,0 +1,433 @@ +{ + "type": "dict", + "collapsable": true, + "key": "maya_capture", + "label": "Maya Capture settings", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "Codec", + "label": "Codec", + "children": [ + { + "type": "text", + "key": "compression", + "label": "Compression type" + }, { + "type": "text", + "key": "format", + "label": "Data format" + }, { + "type": "number", + "key": "quality", + "label": "Quality", + "decimal": 0, + "minimum": 0, + "maximum": 100 + } + ] + }, { + "type": "dict", + "collapsable": true, + "key": "Display Options", + "label": "Display Options", + "children": [ + { + "type": "list", + "key": "background", + "label": "Background Color", + "object_type": "number", + "input_modifiers": { + "decimal": 3, + "minimum": 0, + "maximum": 1 + } + }, { + "type": "list", + "key": "backgroundBottom", + "label": "Bottom Background Color", + "object_type": "number", + "input_modifiers": { + "decimal": 3, + "minimum": 0, + "maximum": 1 + } + }, { + "type": "list", + "key": "backgroundTop", + "label": "Top Background Color", + "object_type": "number", + "input_modifiers": { + "decimal": 3, + "minimum": 0, + "maximum": 1 + } + }, { + "type": "boolean", + "key": "override_display", + "label": "Override display options" + } + ] + }, { + "type": "dict", + "collapsable": true, + "key": "Generic", + "label": "Generic", + "children": [ + { + "type": "boolean", + "key": "isolate_view", + "label": "Isolate view" + },{ + "type": "boolean", + "key": "off_screen", + "label": "Off Screen" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "IO", + "label": "IO", + "children": [ + { + "type": "text", + "key": "name", + "label": "Name" + },{ + "type": "boolean", + "key": "open_finished", + "label": "Open finished" + },{ + "type": "boolean", + "key": "raw_frame_numbers", + "label": "Raw frame numbers" + },{ + "type": "list", + "key": "recent_playblasts", + "label": "Recent playbacks", + "object_type": "text" + },{ + "type": "boolean", + "key": "save_file", + "label": "Save file" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "PanZoom", + "label": "Pan Zoom", + "children": [ + { + "type": "boolean", + "key": "pan_zoom", + "label": "Pan Zoom" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "Renderer", + "label": "Renderer", + "children": [ + { + "type": "text", + "key": "rendererName", + "label": "Renderer name" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "Resolution", + "label": "Resolution", + "children": [ + { + "type": "number", + "key": "width", + "label": "Width", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + },{ + "type": "number", + "key": "height", + "label": "Height", + "decimal": 0, + "minimum": 0, + "maximum": 99999 + },{ + "type": "number", + "key": "percent", + "label": "percent", + "decimal": 1, + "minimum": 0, + "maximum": 200 + },{ + "type": "text", + "key": "mode", + "label": "Mode" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "Time Range", + "label": "Time Range", + "children": [ + { + "type": "number", + "key": "start_frame", + "label": "Start frame", + "decimal": 0, + "minimum": 0, + "maximum": 999999 + },{ + "type": "number", + "key": "end_frame", + "label": "End frame", + "decimal": 0, + "minimum": 0, + "maximum": 999999 + },{ + "type": "text", + "key": "mode", + "label": "Mode" + },{ + "type": "text", + "key": "frame", + "label": "Frame" + },{ + "type": "text", + "key": "time", + "label": "Time" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "Viewport Options", + "label": "Viewport Options", + "children": [ + { + "type": "boolean", + "key": "cameras", + "label": "cameras" + },{ + "type": "boolean", + "key": "clipGhosts", + "label": "clipGhosts" + },{ + "type": "boolean", + "key": "controlVertices", + "label": "controlVertices" + },{ + "type": "boolean", + "key": "deformers", + "label": "deformers" + },{ + "type": "boolean", + "key": "dimensions", + "label": "dimensions" + },{ + "type": "number", + "key": "displayLights", + "label": "displayLights", + "decimal": 0, + "minimum": 0, + "maximum": 10 + },{ + "type": "boolean", + "key": "dynamicConstraints", + "label": "dynamicConstraints" + },{ + "type": "boolean", + "key": "dynamics", + "label": "dynamics" + },{ + "type": "boolean", + "key": "fluids", + "label": "fluids" + },{ + "type": "boolean", + "key": "follicles", + "label": "follicles" + },{ + "type": "boolean", + "key": "gpuCacheDisplayFilter", + "label": "gpuCacheDisplayFilter" + },{ + "type": "boolean", + "key": "greasePencils", + "label": "greasePencils" + },{ + "type": "boolean", + "key": "grid", + "label": "grid" + },{ + "type": "boolean", + "key": "hairSystems", + "label": "hairSystems" + },{ + "type": "boolean", + "key": "handles", + "label": "handles" + },{ + "type": "boolean", + "key": "high_quality", + "label": "high_quality" + },{ + "type": "boolean", + "key": "hud", + "label": "hud" + },{ + "type": "boolean", + "key": "hulls", + "label": "hulls" + },{ + "type": "boolean", + "key": "ikHandles", + "label": "ikHandles" + },{ + "type": "boolean", + "key": "imagePlane", + "label": "imagePlane" + },{ + "type": "boolean", + "key": "joints", + "label": "joints" + },{ + "type": "boolean", + "key": "lights", + "label": "lights" + },{ + "type": "boolean", + "key": "locators", + "label": "locators" + },{ + "type": "boolean", + "key": "manipulators", + "label": "manipulators" + },{ + "type": "boolean", + "key": "motionTrails", + "label": "motionTrails" + },{ + "type": "boolean", + "key": "nCloths", + "label": "nCloths" + },{ + "type": "boolean", + "key": "nParticles", + "label": "nParticles" + },{ + "type": "boolean", + "key": "nRigids", + "label": "nRigids" + },{ + "type": "boolean", + "key": "nurbsCurves", + "label": "nurbsCurves" + },{ + "type": "boolean", + "key": "nurbsSurfaces", + "label": "nurbsSurfaces" + },{ + "type": "boolean", + "key": "override_viewport_options", + "label": "override_viewport_options" + },{ + "type": "boolean", + "key": "particleInstancers", + "label": "particleInstancers" + },{ + "type": "boolean", + "key": "pivots", + "label": "pivots" + },{ + "type": "boolean", + "key": "planes", + "label": "planes" + },{ + "type": "boolean", + "key": "pluginShapes", + "label": "pluginShapes" + },{ + "type": "boolean", + "key": "polymeshes", + "label": "polymeshes" + },{ + "type": "boolean", + "key": "shadows", + "label": "shadows" + },{ + "type": "boolean", + "key": "strokes", + "label": "strokes" + },{ + "type": "boolean", + "key": "subdivSurfaces", + "label": "subdivSurfaces" + },{ + "type": "boolean", + "key": "textures", + "label": "textures" + },{ + "type": "boolean", + "key": "twoSidedLighting", + "label": "twoSidedLighting" + } + ] + },{ + "type": "dict", + "collapsable": true, + "key": "Camera Options", + "label": "Camera Options", + "children": [ + { + "type": "boolean", + "key": "displayGateMask", + "label": "displayGateMask" + },{ + "type": "boolean", + "key": "displayResolution", + "label": "displayResolution" + },{ + "type": "boolean", + "key": "displayFilmGate", + "label": "displayFilmGate" + },{ + "type": "boolean", + "key": "displayFieldChart", + "label": "displayFieldChart" + },{ + "type": "boolean", + "key": "displaySafeAction", + "label": "displaySafeAction" + },{ + "type": "boolean", + "key": "displaySafeTitle", + "label": "displaySafeTitle" + },{ + "type": "boolean", + "key": "displayFilmPivot", + "label": "displayFilmPivot" + },{ + "type": "boolean", + "key": "displayFilmOrigin", + "label": "displayFilmOrigin" + },{ + "type": "number", + "key": "overscan", + "label": "overscan", + "decimal": 1, + "minimum": 0, + "maximum": 10 + } + ] + } + ] +} diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_plugins.json b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_plugins.json new file mode 100644 index 0000000000..7ba9608610 --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_plugins.json @@ -0,0 +1,90 @@ +{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [ + { + "type": "dict", + "collapsable": true, + "key": "ValidateModelName", + "label": "Validate Model Name", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "label", + "label": "Path to material file defining list of material names to check. This is material name per line simple text file.
It will be checked against named group shader in your Validation regex.

For example:
^.*(?P=<shader>.+)_GEO

" + }, + { + "type": "path-widget", + "key": "material_file", + "label": "Material File", + "multiplatform": true, + "multipath": false + }, + { + "type": "text", + "key": "regex", + "label": "Validation regex" + } + ] + }, { + "type": "dict", + "collapsable": true, + "key": "ValidateAssemblyName", + "label": "Validate Assembly Name", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + }, { + "type": "dict", + "collapsable": true, + "key": "ValidateShaderName", + "label": "ValidateShaderName", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "label", + "label": "Shader name regex can use named capture group asset to validate against current asset name.

Example:
^.*(?P=<asset>.+)_SHD

" + + }, { + "type": "text", + "key": "regex", + "label": "Validation regex" + } + ] + }, { + "type": "dict", + "collapsable": true, + "key": "ValidateMeshHasOverlappingUVs", + "label": "ValidateMeshHasOverlappingUVs", + "checkbox_key": "enabled", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + } + ] + } + ] + } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_workfiles.json b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_workfiles.json new file mode 100644 index 0000000000..bae4d32abd --- /dev/null +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_workfiles.json @@ -0,0 +1,6 @@ +{ + "type": "raw-json", + "key": "workfile_build", + "label": "Workfile Build logic", + "is_file": true +} diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index e225d65417..24dc4b552c 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -300,7 +300,11 @@ def gui_schema(subfolder, main_schema_name): filepath = os.path.join(dirpath, filename) with open(filepath, "r") as json_stream: - schema_data = json.load(json_stream) + try: + schema_data = json.load(json_stream) + except Exception as e: + raise Exception((f"Unable to parse JSON file {json_stream}\n " + f" - {e}")) from e loaded_schemas[basename] = schema_data main_schema = _fill_inner_schemas( From 04fd74587804006c7d3df0fede102b9735692dc9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 12:37:38 +0200 Subject: [PATCH 03/63] implemented multiselection combobox --- .../widgets/multiselection_combobox.py | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 pype/tools/settings/settings/widgets/multiselection_combobox.py diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py new file mode 100644 index 0000000000..d77de9f0e3 --- /dev/null +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -0,0 +1,335 @@ +from Qt import QtCore, QtGui, QtWidgets + + +class ComboItemDelegate(QtWidgets.QStyledItemDelegate): + """ + Helper styled delegate (mostly based on existing private Qt's + delegate used by the QtWidgets.QComboBox). Used to style the popup like a + list view (e.g windows style). + """ + + def paint(self, painter, option, index): + option = QtWidgets.QStyleOptionViewItem(option) + option.showDecorationSelected = True + + # option.state &= ( + # ~QtWidgets.QStyle.State_HasFocus + # & ~QtWidgets.QStyle.State_MouseOver + # ) + super(ComboItemDelegate, self).paint(painter, option, index) + + +class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): + """ + Helper styled delegate (mostly based on existing private Qt's + delegate used by the QtWidgets.QComboBox). Used to style the popup like a + menu. (e.g osx aqua style). + """ + + def paint(self, painter, option, index): + menuopt = self._menu_style_option(option, index) + if option.widget is not None: + style = option.widget.style() + else: + style = QtWidgets.QApplication.style() + style.drawControl(QtWidgets.QStyle.CE_MenuItem, menuopt, painter, + option.widget) + + def sizeHint(self, option, index): + menuopt = self._menu_style_option(option, index) + if option.widget is not None: + style = option.widget.style() + else: + style = QtWidgets.QApplication.style() + return style.sizeFromContents( + QtWidgets.QStyle.CT_MenuItem, menuopt, menuopt.rect.size(), + option.widget + ) + + def _menu_style_option(self, option, index): + menuoption = QtWidgets.QStyleOptionMenuItem() + if option.widget: + palette_source = option.widget.palette("QMenu") + else: + palette_source = QtWidgets.QApplication.palette("QMenu") + + palette = option.palette.resolve(palette_source) + foreground = index.data(QtCore.Qt.ForegroundRole) + if isinstance(foreground, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): + foreground = QtGui.QBrush(foreground) + palette.setBrush(QtGui.QPalette.Text, foreground) + palette.setBrush(QtGui.QPalette.ButtonText, foreground) + palette.setBrush(QtGui.QPalette.WindowText, foreground) + + background = index.data(QtCore.Qt.BackgroundRole) + if isinstance(background, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): + background = QtGui.QBrush(background) + palette.setBrush(QtGui.QPalette.Background, background) + + menuoption.palette = palette + + decoration = index.data(QtCore.Qt.DecorationRole) + if isinstance(decoration, QtGui.QIcon): + menuoption.icon = decoration + + menuoption.menuItemType = QtWidgets.QStyleOptionMenuItem.Normal + + if index.flags() & QtCore.Qt.ItemIsUserCheckable: + menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NonExclusive + else: + menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NotCheckable + + check = index.data(QtCore.Qt.CheckStateRole) + menuoption.checked = check == QtCore.Qt.Checked + + if option.widget is not None: + menuoption.font = option.widget.font() + else: + menuoption.font = QtWidgets.QApplication.font("QMenu") + + menuoption.maxIconWidth = option.decorationSize.width() + 4 + menuoption.rect = option.rect + menuoption.menuRect = option.rect + + # menuoption.menuHasCheckableItems = True + menuoption.tabWidth = 0 + # TODO: self.displayText(QVariant, QLocale) + # TODO: Why is this not a QtWidgets.QStyledItemDelegate? + menuoption.text = str(index.data(QtCore.Qt.DisplayRole)) + + menuoption.fontMetrics = QtGui.QFontMetrics(menuoption.font) + state = option.state & ( + QtWidgets.QStyle.State_MouseOver + | QtWidgets.QStyle.State_Selected + | QtWidgets.QStyle.State_Active + ) + + if index.flags() & QtCore.Qt.ItemIsEnabled: + state = state | QtWidgets.QStyle.State_Enabled + menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Active) + else: + state = state & ~QtWidgets.QStyle.State_Enabled + menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) + + if menuoption.checked: + state = state | QtWidgets.QStyle.State_On + else: + state = state | QtWidgets.QStyle.State_Off + + menuoption.state = state + return menuoption + + +class CheckComboBox(QtWidgets.QComboBox): + ignored_keys = { + QtCore.Qt.Key_Up, + QtCore.Qt.Key_Down, + QtCore.Qt.Key_PageDown, + QtCore.Qt.Key_PageUp, + QtCore.Qt.Key_Home, + QtCore.Qt.Key_End + } + + def __init__( + self, parent=None, placeholder_text="", separator=", ", **kwargs + ): + super(CheckComboBox, self).__init__(parent=parent, **kwargs) + self.setFocusPolicy(QtCore.Qt.StrongFocus) + + self._popup_is_shown = False + # self.__supressPopupHide = False + self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) + self._initial_mouse_pos = None + self._separator = separator + self._placeholder_text = placeholder_text + self._update_item_delegate() + + def mousePressEvent(self, event): + """Reimplemented.""" + self._popup_is_shown = False + super(CheckComboBox, self).mousePressEvent(event) + if self._popup_is_shown: + self._initial_mouse_pos = self.mapToGlobal(event.pos()) + self._block_mouse_release_timer.start( + QtWidgets.QApplication.doubleClickInterval() + ) + + def changeEvent(self, event): + """Reimplemented.""" + if event.type() == QtCore.QEvent.StyleChange: + self._update_item_delegate() + super(CheckComboBox, self).changeEvent(event) + + def showPopup(self): + """Reimplemented.""" + super(CheckComboBox, self).showPopup() + view = self.view() + view.installEventFilter(self) + view.viewport().installEventFilter(self) + self._popup_is_shown = True + + def hidePopup(self): + """Reimplemented.""" + self.view().removeEventFilter(self) + self.view().viewport().removeEventFilter(self) + self._popup_is_shown = False + self._initial_mouse_pos = None + super(CheckComboBox, self).hidePopup() + self.view().clearFocus() + + def eventFilter(self, obj, event): + """Reimplemented.""" + if ( + self._popup_is_shown + and event.type() == QtCore.QEvent.MouseMove + and self.view().isVisible() + and self._initial_mouse_pos is not None + ): + diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos + if ( + diff.manhattanLength() > 9 + and self._block_mouse_release_timer.isActive() + ): + self._block_mouse_release_timer.stop() + + current_index = self.view().currentIndex() + if ( + self._popup_is_shown + and event.type() == QtCore.QEvent.MouseButtonRelease + and self.view().isVisible() + and self.view().rect().contains(event.pos()) + and current_index.isValid() + and current_index.flags() & QtCore.Qt.ItemIsSelectable + and current_index.flags() & QtCore.Qt.ItemIsEnabled + and current_index.flags() & QtCore.Qt.ItemIsUserCheckable + and self.view().visualRect(current_index).contains(event.pos()) + and not self._block_mouse_release_timer.isActive() + ): + model = self.model() + index = self.view().currentIndex() + state = model.data(index, QtCore.Qt.CheckStateRole) + if state == QtCore.Qt.Unchecked: + check_state = QtCore.Qt.Checked + else: + check_state = QtCore.Qt.Unchecked + + model.setData(index, check_state, QtCore.Qt.CheckStateRole) + self.view().update(index) + self.update() + return True + + if self._popup_is_shown and event.type() == QtCore.QEvent.KeyPress: + if event.key() == QtCore.Qt.Key_Space: + # toogle the current items check state + model = self.model() + index = self.view().currentIndex() + flags = model.flags(index) + state = model.data(index, QtCore.Qt.CheckStateRole) + if flags & QtCore.Qt.ItemIsUserCheckable and \ + flags & QtCore.Qt.ItemIsTristate: + state = QtCore.Qt.CheckState((int(state) + 1) % 3) + elif flags & QtCore.Qt.ItemIsUserCheckable: + state = ( + QtCore.Qt.Checked + if state != QtCore.Qt.Checked + else QtCore.Qt.Unchecked + ) + model.setData(index, state, QtCore.Qt.CheckStateRole) + self.view().update(index) + self.update() + return True + # TODO: handle QtCore.Qt.Key_Enter, Key_Return? + + return super(CheckComboBox, self).eventFilter(obj, event) + + def paintEvent(self, event): + """Reimplemented.""" + painter = QtWidgets.QStylePainter(self) + option = QtWidgets.QStyleOptionComboBox() + self.initStyleOption(option) + painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option) + # draw the icon and text + items = self.checked_items_text() + if not items: + option.currentText = self._placeholder_text + option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) + painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option) + return + + # body_rect = QtCore.QRectF(option.rect) + + side_padding = 3 + item_spacing = 5 + font_metricts = self.fontMetrics() + left_x = option.rect.left() + 2 + for item in items: + rect = font_metricts.boundingRect(item) + rect.moveTop(option.rect.y()) + + label_height = rect.height() + + rect.moveLeft(left_x) + rect.setHeight(option.rect.height()) + + bg_rect = QtCore.QRect(rect) + bg_rect.setWidth(rect.width() + (2 * side_padding)) + left_x = bg_rect.right() + item_spacing + + rect.moveLeft(rect.x() + side_padding) + + remainder_half = (option.rect.height() - label_height) / 2 + remainder_quarter = int(remainder_half / 2) + 1 + bg_rect.setHeight(label_height + remainder_half) + bg_rect.moveTop(bg_rect.top() + remainder_quarter) + + path = QtGui.QPainterPath() + path.addRoundedRect(bg_rect, 5, 5) + + painter.fillPath(path, QtGui.QColor("#38d39f")) + + painter.drawText( + rect, + QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, + item + ) + option.currentText = self._separator.join(items) + # option.currentIcon = QtGui.QIcon() + + def setItemCheckState(self, index, state): + self.setItemData(index, state, QtCore.Qt.CheckStateRole) + + def checked_items_text(self): + items = list() + for idx in range(self.count()): + state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) + if state == QtCore.Qt.Checked: + items.append(self.itemText(idx)) + return items + + def wheelEvent(self, event): + event.ignore() + + def keyPressEvent(self, event): + if ( + event.key() == QtCore.Qt.Key_Down + and event.modifiers() & QtCore.Qt.AltModifier + ): + self.showPopup() + return + + if event.key() in self.ignored_keys: + event.ignore() + return + + return super(CheckComboBox, self).keyPressEvent(event) + + def _update_item_delegate(self): + opt = QtWidgets.QStyleOptionComboBox() + opt.initFrom(self) + if self.style().styleHint( + QtWidgets.QStyle.SH_ComboBox_Popup, opt, self + ): + delegate = ComboMenuDelegate(self) + else: + delegate = ComboItemDelegate(self) + self.setItemDelegate(delegate) From 0ce16680044b8f17f6c3229ed95cd6a69e72d979 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 13:10:09 +0200 Subject: [PATCH 04/63] implemented basic combobox with custom modifications --- .../settings/settings/widgets/widgets.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 2a1f5fe804..616e605a35 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -25,6 +25,28 @@ class NumberSpinBox(QtWidgets.QDoubleSpinBox): return output +class ComboBox(QtWidgets.QComboBox): + value_changed = QtCore.Signal() + + def __init__(self, *args, **kwargs): + super(ComboBox, self).__init__(*args, **kwargs) + + self.currentIndexChanged.connect(self._on_change) + + def _on_change(self, *args, **kwargs): + self.value_changed.emit() + + def set_value(self, value): + for idx in range(self.count()): + _value = self.itemData(idx, role=QtCore.Qt.UserRole) + if _value == value: + self.setCurrentIndex(idx) + break + + def value(self): + return self.itemData(self.currentIndex(), role=QtCore.Qt.UserRole) + + class PathInput(QtWidgets.QLineEdit): def clear_end_path(self): value = self.text().strip() From 8aefe456ae4c97d543d11d77c4680ddacfd0716c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 13:10:30 +0200 Subject: [PATCH 05/63] multiselectio ncheckbox has methods for getting and setting value --- .../widgets/multiselection_combobox.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index d77de9f0e3..98e6048cce 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -121,6 +121,7 @@ class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): class CheckComboBox(QtWidgets.QComboBox): + value_changed = QtCore.Signal() ignored_keys = { QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, @@ -131,7 +132,7 @@ class CheckComboBox(QtWidgets.QComboBox): } def __init__( - self, parent=None, placeholder_text="", separator=", ", **kwargs + self, parent=None, placeholder="", separator=", ", **kwargs ): super(CheckComboBox, self).__init__(parent=parent, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) @@ -141,7 +142,7 @@ class CheckComboBox(QtWidgets.QComboBox): self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) self._initial_mouse_pos = None self._separator = separator - self._placeholder_text = placeholder_text + self._placeholder_text = placeholder self._update_item_delegate() def mousePressEvent(self, event): @@ -216,6 +217,7 @@ class CheckComboBox(QtWidgets.QComboBox): model.setData(index, check_state, QtCore.Qt.CheckStateRole) self.view().update(index) self.update() + self.value_changed.emit() return True if self._popup_is_shown and event.type() == QtCore.QEvent.KeyPress: @@ -298,6 +300,26 @@ class CheckComboBox(QtWidgets.QComboBox): def setItemCheckState(self, index, state): self.setItemData(index, state, QtCore.Qt.CheckStateRole) + def set_value(self, values): + for idx in range(self.count()): + value = self.itemData(idx, role=QtCore.Qt.UserRole) + state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) + if value in values: + check_state = QtCore.Qt.Checked + else: + check_state = QtCore.Qt.Unchecked + self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole) + + def value(self): + items = list() + for idx in range(self.count()): + state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) + if state == QtCore.Qt.Checked: + items.append( + self.itemData(idx, role=QtCore.Qt.UserRole) + ) + return items + def checked_items_text(self): items = list() for idx in range(self.count()): From b700de57ddb5993ae91cc920ff09559b9f776ba3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 13:10:49 +0200 Subject: [PATCH 06/63] implemented enumerator item --- .../settings/settings/widgets/item_types.py | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e589b89c0f..634b14ab0e 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -6,8 +6,10 @@ from .widgets import ( ExpandingWidget, NumberSpinBox, PathInput, - GridLabelWidget + GridLabelWidget, + ComboBox ) +from .multiselection_combobox import CheckComboBox from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome @@ -827,6 +829,107 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): return self.checkbox.isChecked() +class EnumeratorWidget(QtWidgets.QWidget, InputObject): + 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(EnumeratorWidget, self).__init__(parent_widget) + + self.initial_attributes(input_data, parent, as_widget) + self.multiselection = input_data.get("multiselection") + self.enum_items = input_data["enum_items"] + if not self.enum_items: + raise ValueError( + "Attribute `enum_items` is not defined." + ) + + 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) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + + if self.multiselection: + placeholder = input_data.get("placeholder") + self.input_field = CheckComboBox( + placeholder=placeholder, parent=self + ) + else: + self.input_field = ComboBox(self) + + first_value = None + for enum_item in self.enum_items: + for value, label in enum_item.items(): + if first_value is None: + first_value = value + self.input_field.addItem(label, value) + + self._first_value = first_value + + layout.addWidget(self.input_field, 0) + + self.setFocusProxy(self.input_field) + + self.input_field.value_changed.connect(self._on_value_change) + + @property + def default_input_value(self): + if self.multiselection: + return [] + return self._first_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 + self.input_field.set_value(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): + return self.input_field.value() + + class NumberWidget(QtWidgets.QWidget, InputObject): default_input_value = 0 value_changed = QtCore.Signal(object) @@ -3494,6 +3597,7 @@ TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget TypeToKlass.types["list-strict"] = ListStrictWidget +TypeToKlass.types["enum"] = EnumeratorWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict # DEPRECATED - remove when removed from schemas TypeToKlass.types["dict-item"] = DictWidget From 4954a3dba0f9d793f5fb319e84aa39894da6147e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:04:15 +0200 Subject: [PATCH 07/63] fix checkables in multiselection --- pype/tools/settings/settings/widgets/item_types.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 634b14ab0e..274aeff86a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -877,6 +877,11 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): first_value = value self.input_field.addItem(label, value) + if self.multiselection: + model = self.input_field.model() + for idx in range(self.input_field.count()): + model.item(idx).setCheckable(True) + self._first_value = first_value layout.addWidget(self.input_field, 0) From 918ff9eefa91b814d4f0312010738568e7745653 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:04:36 +0200 Subject: [PATCH 08/63] changed bg_rect to QRectF --- .../settings/settings/widgets/multiselection_combobox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 98e6048cce..029f577032 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -273,7 +273,7 @@ class CheckComboBox(QtWidgets.QComboBox): rect.moveLeft(left_x) rect.setHeight(option.rect.height()) - bg_rect = QtCore.QRect(rect) + bg_rect = QtCore.QRectF(rect) bg_rect.setWidth(rect.width() + (2 * side_padding)) left_x = bg_rect.right() + item_spacing @@ -287,7 +287,7 @@ class CheckComboBox(QtWidgets.QComboBox): path = QtGui.QPainterPath() path.addRoundedRect(bg_rect, 5, 5) - painter.fillPath(path, QtGui.QColor("#38d39f")) + painter.fillPath(path, QtGui.QColor("#555555")) painter.drawText( rect, From f6f75c6fb33a6880a5e6b68b171f4d86ad4cf42f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:04:49 +0200 Subject: [PATCH 09/63] added enum to examples --- .../gui_schemas/system_schema/1_examples.json | 19 +++++++++++++++++++ 1 file changed, 19 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 0578968508..00aef304a9 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 @@ -9,6 +9,25 @@ "type": "dict-invisible", "children": [ { + "type": "enum", + "key": "test_enum_singleselection", + "label": "Enum Single Selection", + "enum_items": [ + {"value_1": "Label 1"}, + {"value_2": "Label 2"}, + {"value_3": "Label 3"} + ] + }, { + "type": "enum", + "key": "test_enum_multiselection", + "label": "Enum Multi Selection", + "multiselection": true, + "enum_items": [ + {"value_1": "Label 1"}, + {"value_2": "Label 2"}, + {"value_3": "Label 3"} + ] + }, { "type": "boolean", "key": "bool", "label": "Boolean checkbox" From 6e49beb9c38e5e20d81333c4f8d62339935b2853 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 14:56:44 +0200 Subject: [PATCH 10/63] added style for combobox --- pype/tools/settings/settings/style/style.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 3f648abef8..c4fce7aa90 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -38,6 +38,14 @@ QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QPlainTextEdit:d QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QPlainTextEdit:focus, QTextEdit:focus { border: 1px solid #ffffff; } + +QComboBox { + border: 1px solid #aaaaaa; + border-radius: 3px; + padding: 2px 2px 4px 4px; + background: #1d272f; +} + QToolButton { background: transparent; } From 4b70f708566bc1a06ef6295ced0e3e4783266fff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:35:48 +0200 Subject: [PATCH 11/63] multiselection combobox expand size by its items --- .../widgets/multiselection_combobox.py | 140 +++++++++++++----- 1 file changed, 104 insertions(+), 36 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 029f577032..30b0c89d28 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -131,6 +131,13 @@ class CheckComboBox(QtWidgets.QComboBox): QtCore.Qt.Key_End } + padding = 2 + left_offset = 2 + h_margins = 2 + item_spacing = 5 + + item_bg_color = QtGui.QColor("#555555") + def __init__( self, parent=None, placeholder="", separator=", ", **kwargs ): @@ -142,9 +149,16 @@ class CheckComboBox(QtWidgets.QComboBox): self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) self._initial_mouse_pos = None self._separator = separator - self._placeholder_text = placeholder + self.placeholder_text = placeholder self._update_item_delegate() + self.lines = {} + self.item_height = ( + self.fontMetrics().height() + + (2 * self.padding) + + (2 * self.h_margins) + ) + def mousePressEvent(self, event): """Reimplemented.""" self._popup_is_shown = False @@ -216,7 +230,7 @@ class CheckComboBox(QtWidgets.QComboBox): model.setData(index, check_state, QtCore.Qt.CheckStateRole) self.view().update(index) - self.update() + self.update_size_hint() self.value_changed.emit() return True @@ -250,52 +264,106 @@ class CheckComboBox(QtWidgets.QComboBox): option = QtWidgets.QStyleOptionComboBox() self.initStyleOption(option) painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option) + # draw the icon and text items = self.checked_items_text() if not items: - option.currentText = self._placeholder_text + option.currentText = self.placeholder_text option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option) return - # body_rect = QtCore.QRectF(option.rect) - - side_padding = 3 - item_spacing = 5 font_metricts = self.fontMetrics() - left_x = option.rect.left() + 2 + for line, items in self.lines.items(): + top_y = option.rect.top() + (line * self.item_height) + left_x = option.rect.left() + self.left_offset + for item in items: + label_rect = font_metricts.boundingRect(item) + label_height = label_rect.height() + + label_rect.moveTop(top_y) + label_rect.moveLeft(left_x) + label_rect.setHeight(self.item_height) + + bg_rect = QtCore.QRectF(label_rect) + bg_rect.setWidth(label_rect.width() + (2 * self.padding)) + left_x = bg_rect.right() + self.item_spacing + + label_rect.moveLeft(label_rect.x() + self.padding) + + bg_rect.setHeight(label_height + (2 * self.padding)) + bg_rect.moveTop(bg_rect.top() + self.h_margins) + + path = QtGui.QPainterPath() + path.addRoundedRect(bg_rect, 5, 5) + + painter.fillPath(path, self.item_bg_color) + + painter.drawText( + label_rect, + QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, + item + ) + + def resizeEvent(self, *args, **kwargs): + super(CheckComboBox, self).resizeEvent(*args, **kwargs) + self.update_size_hint() + + def update_size_hint(self): + previous_lines = len(self.lines) + + self.lines = {} + + items = self.checked_items_text() + if not items: + self.update() + return + + option = QtWidgets.QStyleOptionComboBox() + self.initStyleOption(option) + btn_rect = self.style().subControlRect( + QtWidgets.QStyle.CC_ComboBox, + option, + QtWidgets.QStyle.SC_ComboBoxArrow + ) + total_width = self.width() - btn_rect.width() + font_metricts = self.fontMetrics() + + line = 0 + self.lines = {line: []} + + font_metricts = self.fontMetrics() + left_x = None for item in items: + if left_x is None: + left_x = 0 + self.left_offset rect = font_metricts.boundingRect(item) - rect.moveTop(option.rect.y()) + width = rect.width() + (2 * self.padding) + right_x = left_x + width + if right_x > total_width: + if self.lines.get(line): + line += 1 + left_x = None + self.lines[line] = [item] + else: + self.lines[line] = [item] + line += 1 + left_x = None + else: + self.lines[line].append(item) + left_x = left_x + width + self.item_spacing - label_height = rect.height() + self.update() + if len(self.lines) != previous_lines: + self.updateGeometry() - rect.moveLeft(left_x) - rect.setHeight(option.rect.height()) - - bg_rect = QtCore.QRectF(rect) - bg_rect.setWidth(rect.width() + (2 * side_padding)) - left_x = bg_rect.right() + item_spacing - - rect.moveLeft(rect.x() + side_padding) - - remainder_half = (option.rect.height() - label_height) / 2 - remainder_quarter = int(remainder_half / 2) + 1 - bg_rect.setHeight(label_height + remainder_half) - bg_rect.moveTop(bg_rect.top() + remainder_quarter) - - path = QtGui.QPainterPath() - path.addRoundedRect(bg_rect, 5, 5) - - painter.fillPath(path, QtGui.QColor("#555555")) - - painter.drawText( - rect, - QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, - item - ) - option.currentText = self._separator.join(items) - # option.currentIcon = QtGui.QIcon() + def sizeHint(self): + value = super(CheckComboBox, self).sizeHint() + lines = len(self.lines) + if lines == 0: + lines = 1 + value.setHeight(lines * self.item_height) + return value def setItemCheckState(self, index, state): self.setItemData(index, state, QtCore.Qt.CheckStateRole) From e779375b9b3e61d5d9e1810cdb7ca6f67d1d7f8b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:55:31 +0200 Subject: [PATCH 12/63] renamed CheckComboBox to MultiSelectionComboBox --- .../settings/settings/widgets/item_types.py | 4 ++-- .../widgets/multiselection_combobox.py | 20 +++++++++---------- 2 files 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 274aeff86a..33585773f9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -9,7 +9,7 @@ from .widgets import ( GridLabelWidget, ComboBox ) -from .multiselection_combobox import CheckComboBox +from .multiselection_combobox import MultiSelectionComboBox from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome @@ -864,7 +864,7 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): if self.multiselection: placeholder = input_data.get("placeholder") - self.input_field = CheckComboBox( + self.input_field = MultiSelectionComboBox( placeholder=placeholder, parent=self ) else: diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 30b0c89d28..d49ebeb45a 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -120,7 +120,7 @@ class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): return menuoption -class CheckComboBox(QtWidgets.QComboBox): +class MultiSelectionComboBox(QtWidgets.QComboBox): value_changed = QtCore.Signal() ignored_keys = { QtCore.Qt.Key_Up, @@ -141,7 +141,7 @@ class CheckComboBox(QtWidgets.QComboBox): def __init__( self, parent=None, placeholder="", separator=", ", **kwargs ): - super(CheckComboBox, self).__init__(parent=parent, **kwargs) + super(MultiSelectionComboBox, self).__init__(parent=parent, **kwargs) self.setFocusPolicy(QtCore.Qt.StrongFocus) self._popup_is_shown = False @@ -162,7 +162,7 @@ class CheckComboBox(QtWidgets.QComboBox): def mousePressEvent(self, event): """Reimplemented.""" self._popup_is_shown = False - super(CheckComboBox, self).mousePressEvent(event) + super(MultiSelectionComboBox, self).mousePressEvent(event) if self._popup_is_shown: self._initial_mouse_pos = self.mapToGlobal(event.pos()) self._block_mouse_release_timer.start( @@ -173,11 +173,11 @@ class CheckComboBox(QtWidgets.QComboBox): """Reimplemented.""" if event.type() == QtCore.QEvent.StyleChange: self._update_item_delegate() - super(CheckComboBox, self).changeEvent(event) + super(MultiSelectionComboBox, self).changeEvent(event) def showPopup(self): """Reimplemented.""" - super(CheckComboBox, self).showPopup() + super(MultiSelectionComboBox, self).showPopup() view = self.view() view.installEventFilter(self) view.viewport().installEventFilter(self) @@ -189,7 +189,7 @@ class CheckComboBox(QtWidgets.QComboBox): self.view().viewport().removeEventFilter(self) self._popup_is_shown = False self._initial_mouse_pos = None - super(CheckComboBox, self).hidePopup() + super(MultiSelectionComboBox, self).hidePopup() self.view().clearFocus() def eventFilter(self, obj, event): @@ -256,7 +256,7 @@ class CheckComboBox(QtWidgets.QComboBox): return True # TODO: handle QtCore.Qt.Key_Enter, Key_Return? - return super(CheckComboBox, self).eventFilter(obj, event) + return super(MultiSelectionComboBox, self).eventFilter(obj, event) def paintEvent(self, event): """Reimplemented.""" @@ -306,7 +306,7 @@ class CheckComboBox(QtWidgets.QComboBox): ) def resizeEvent(self, *args, **kwargs): - super(CheckComboBox, self).resizeEvent(*args, **kwargs) + super(MultiSelectionComboBox, self).resizeEvent(*args, **kwargs) self.update_size_hint() def update_size_hint(self): @@ -358,7 +358,7 @@ class CheckComboBox(QtWidgets.QComboBox): self.updateGeometry() def sizeHint(self): - value = super(CheckComboBox, self).sizeHint() + value = super(MultiSelectionComboBox, self).sizeHint() lines = len(self.lines) if lines == 0: lines = 1 @@ -411,7 +411,7 @@ class CheckComboBox(QtWidgets.QComboBox): event.ignore() return - return super(CheckComboBox, self).keyPressEvent(event) + return super(MultiSelectionComboBox, self).keyPressEvent(event) def _update_item_delegate(self): opt = QtWidgets.QStyleOptionComboBox() From 13576aeedcf07646b72294cb9adcb75d73ca54f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:58:52 +0200 Subject: [PATCH 13/63] added a little bit more atomicity to padding and margins --- .../widgets/multiselection_combobox.py | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index d49ebeb45a..d7179f07f0 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -131,9 +131,10 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): QtCore.Qt.Key_End } - padding = 2 + top_bottom_padding = 2 + left_right_padding = 3 left_offset = 2 - h_margins = 2 + top_bottom_margins = 2 item_spacing = 5 item_bg_color = QtGui.QColor("#555555") @@ -155,8 +156,8 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.lines = {} self.item_height = ( self.fontMetrics().height() - + (2 * self.padding) - + (2 * self.h_margins) + + (2 * self.top_bottom_padding) + + (2 * self.top_bottom_margins) ) def mousePressEvent(self, event): @@ -275,7 +276,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): font_metricts = self.fontMetrics() for line, items in self.lines.items(): - top_y = option.rect.top() + (line * self.item_height) + top_y = ( + option.rect.top() + + (line * self.item_height) + + self.top_bottom_margins + ) left_x = option.rect.left() + self.left_offset for item in items: label_rect = font_metricts.boundingRect(item) @@ -286,13 +291,16 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): label_rect.setHeight(self.item_height) bg_rect = QtCore.QRectF(label_rect) - bg_rect.setWidth(label_rect.width() + (2 * self.padding)) + bg_rect.setWidth( + label_rect.width() + + (2 * self.left_right_padding) + ) left_x = bg_rect.right() + self.item_spacing - label_rect.moveLeft(label_rect.x() + self.padding) + label_rect.moveLeft(label_rect.x() + self.left_right_padding) - bg_rect.setHeight(label_height + (2 * self.padding)) - bg_rect.moveTop(bg_rect.top() + self.h_margins) + bg_rect.setHeight(label_height + (2 * self.top_bottom_padding)) + bg_rect.moveTop(bg_rect.top() + self.top_bottom_margins) path = QtGui.QPainterPath() path.addRoundedRect(bg_rect, 5, 5) @@ -338,7 +346,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): if left_x is None: left_x = 0 + self.left_offset rect = font_metricts.boundingRect(item) - width = rect.width() + (2 * self.padding) + width = rect.width() + (2 * self.left_right_padding) right_x = left_x + width if right_x > total_width: if self.lines.get(line): @@ -362,7 +370,10 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): lines = len(self.lines) if lines == 0: lines = 1 - value.setHeight(lines * self.item_height) + value.setHeight( + (lines * self.item_height) + + (2 * self.top_bottom_margins) + ) return value def setItemCheckState(self, index, state): From 016ea3146bd55f2809173731371121fd5fc8aa5c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 16:59:08 +0200 Subject: [PATCH 14/63] added style for multiselection combobox --- pype/tools/settings/settings/style/style.css | 4 ++++ .../settings/settings/widgets/multiselection_combobox.py | 1 + 2 files changed, 5 insertions(+) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index c4fce7aa90..796efa22a6 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -110,6 +110,10 @@ QPushButton[btn-type="expand-toggle"] { font-weight: bold; } +#MultiSelectionComboBox { + font-size: 12px; +} + #DictKey[state="studio"] {border-color: #bfccd6;} #DictKey[state="modified"] {border-color: #137cbd;} #DictKey[state="overriden"] {border-color: #00f;} diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index d7179f07f0..ddd4f65e65 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -143,6 +143,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self, parent=None, placeholder="", separator=", ", **kwargs ): super(MultiSelectionComboBox, self).__init__(parent=parent, **kwargs) + self.setObjectName("MultiSelectionComboBox") self.setFocusPolicy(QtCore.Qt.StrongFocus) self._popup_is_shown = False From 1c1676f6f8924dcd826d2832ef0fdb41c446d7a7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 17:06:54 +0200 Subject: [PATCH 15/63] final touches --- .../settings/settings/widgets/multiselection_combobox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index ddd4f65e65..b02d19f9c4 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -133,11 +133,11 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): top_bottom_padding = 2 left_right_padding = 3 - left_offset = 2 + left_offset = 4 top_bottom_margins = 2 item_spacing = 5 - item_bg_color = QtGui.QColor("#555555") + item_bg_color = QtGui.QColor("#31424e") def __init__( self, parent=None, placeholder="", separator=", ", **kwargs From 49ac226f30a6c99ad8dce87f5ac19190af6695c9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 17:32:21 +0200 Subject: [PATCH 16/63] line width is calculated right --- .../widgets/multiselection_combobox.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index b02d19f9c4..85dd538cd0 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -32,8 +32,9 @@ class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): style = option.widget.style() else: style = QtWidgets.QApplication.style() - style.drawControl(QtWidgets.QStyle.CE_MenuItem, menuopt, painter, - option.widget) + style.drawControl( + QtWidgets.QStyle.CE_MenuItem, menuopt, painter, option.widget + ) def sizeHint(self, option, index): menuopt = self._menu_style_option(option, index) @@ -335,36 +336,34 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): option, QtWidgets.QStyle.SC_ComboBoxArrow ) - total_width = self.width() - btn_rect.width() + total_width = option.rect.width() - btn_rect.width() font_metricts = self.fontMetrics() line = 0 self.lines = {line: []} font_metricts = self.fontMetrics() - left_x = None + default_left_x = 0 + self.left_offset + left_x = int(default_left_x) for item in items: - if left_x is None: - left_x = 0 + self.left_offset rect = font_metricts.boundingRect(item) width = rect.width() + (2 * self.left_right_padding) right_x = left_x + width if right_x > total_width: + left_x = int(default_left_x) if self.lines.get(line): line += 1 - left_x = None self.lines[line] = [item] + left_x += width else: self.lines[line] = [item] line += 1 - left_x = None else: self.lines[line].append(item) left_x = left_x + width + self.item_spacing self.update() - if len(self.lines) != previous_lines: - self.updateGeometry() + self.updateGeometry() def sizeHint(self): value = super(MultiSelectionComboBox, self).sizeHint() From 85e67b6ce25da02919ebc16b56323489fd6fef1d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 17:35:23 +0200 Subject: [PATCH 17/63] fix stretch --- pype/tools/settings/settings/widgets/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/base.py b/pype/tools/settings/settings/widgets/base.py index ee4762de14..404d7b700b 100644 --- a/pype/tools/settings/settings/widgets/base.py +++ b/pype/tools/settings/settings/widgets/base.py @@ -266,7 +266,7 @@ class SystemWidget(QtWidgets.QWidget): klass = lib.TypeToKlass.types.get(item_type) item = klass(child_configuration, self) self.input_fields.append(item) - self.content_layout.addWidget(item) + self.content_layout.addWidget(item, 0) # Add spacer to stretch children guis spacer = QtWidgets.QWidget(self.content_widget) @@ -532,7 +532,7 @@ class ProjectWidget(QtWidgets.QWidget): klass = lib.TypeToKlass.types.get(item_type) item = klass(child_configuration, self) self.input_fields.append(item) - self.content_layout.addWidget(item) + self.content_layout.addWidget(item, 0) # Add spacer to stretch children guis spacer = QtWidgets.QWidget(self.content_widget) From 34d16bb0960789b4a3e994e25c490a698f04b8a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:21:26 +0200 Subject: [PATCH 18/63] small cleanup --- pype/tools/settings/settings/style/style.css | 4 ++++ .../settings/settings/widgets/multiselection_combobox.py | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 796efa22a6..ebea87203d 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -46,6 +46,10 @@ QComboBox { background: #1d272f; } +QComboBox QAbstractItemView::item { + padding: 3px; +} + QToolButton { background: transparent; } diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 85dd538cd0..0c2d57aed8 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -148,7 +148,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.setFocusPolicy(QtCore.Qt.StrongFocus) self._popup_is_shown = False - # self.__supressPopupHide = False self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True) self._initial_mouse_pos = None self._separator = separator From 102a8ead4c0ddf95844cffce37d610d355947ec9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:30:55 +0200 Subject: [PATCH 19/63] added enumerator to ExtractReview --- .../projects_schema/1_plugins_gui_schema.json | 11 +++++++++-- 1 file changed, 9 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 f357b51dc5..2fefe8df2d 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 @@ -202,8 +202,15 @@ }, { "key": "tags", "label": "Tags", - "type": "list", - "object_type": "text" + "type": "enum", + "multiselection": true, + "enum_items": [ + {"burnin": "Add burnins"}, + {"ftrackreview": "Add to Ftrack"}, + {"delete": "Delete output"}, + {"slate-frame": "Add slate frame"}, + {"no-hnadles": "Skip handle frames"} + ] }, { "key": "ffmpeg_args", "label": "FFmpeg arguments", From 223ed557520c3938162fe719f87abb88b41b15c2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:34:55 +0200 Subject: [PATCH 20/63] project override values are not propagated in right way if dict is used as widget --- pype/tools/settings/settings/widgets/item_types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e589b89c0f..c477a7986a 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2442,7 +2442,9 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self._state = None self._child_state = None - if not self.as_widget: + if self.as_widget: + override_values = parent_values + else: metadata = {} groups = tuple() override_values = NOT_SET From 5410bab315df471f5f68b161b8e3d1f9fcd77bd6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:40:32 +0200 Subject: [PATCH 21/63] added readme --- pype/tools/settings/settings/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 47bbf28ba5..9492d8bc7b 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -168,6 +168,29 @@ } ``` +### enum +- returns value of single on multiple items from predefined values +- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`) +- values are defined under value of key `"enum_items"` as list + - each item in list is simple dictionary where value is label and key is value which will be stored + - should be possible to enter single dictionary if order of items doesn't matter + +``` +{ + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [ + {"burnin": "Add burnins"}, + {"ftrackreview": "Add to Ftrack"}, + {"delete": "Delete output"}, + {"slate-frame": "Add slate frame"}, + {"no-hnadles": "Skip handle frames"} + ] +} +``` + ## Inputs for setting value using Pure inputs - these inputs also have required `"key"` and `"label"` - they use Pure inputs "as widgets" From 9ed5778b51e6df049a9c6d29213576244b695b0f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:46:13 +0200 Subject: [PATCH 22/63] removed unused variables --- .../tools/settings/settings/widgets/multiselection_combobox.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 0c2d57aed8..0106051cc4 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -319,8 +319,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self.update_size_hint() def update_size_hint(self): - previous_lines = len(self.lines) - self.lines = {} items = self.checked_items_text() @@ -381,7 +379,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): def set_value(self, values): for idx in range(self.count()): value = self.itemData(idx, role=QtCore.Qt.UserRole) - state = self.itemData(idx, role=QtCore.Qt.CheckStateRole) if value in values: check_state = QtCore.Qt.Checked else: From 06dba918f7de483b710eeaab4e295bcf21c55c84 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:50:19 +0200 Subject: [PATCH 23/63] label is offset by two pixels down to fake nice view --- pype/tools/settings/settings/widgets/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 2a1f5fe804..522f606baa 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -243,10 +243,11 @@ class GridLabelWidget(QtWidgets.QWidget): self.properties = {} layout = QtWidgets.QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) + layout.setContentsMargins(0, 2, 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) From cc3d5bcc4165402d9c75c3bda6da8ef254b1aaa2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Tue, 22 Sep 2020 18:50:29 +0200 Subject: [PATCH 24/63] label and proxy widget are transparent now --- pype/tools/settings/settings/widgets/widgets.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 522f606baa..d6d28b3e43 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -266,6 +266,9 @@ class GridLabelWidget(QtWidgets.QWidget): layout.addWidget(label_proxy, 0) layout.addWidget(spacer_widget_v, 1) + label_proxy.setAttribute(QtCore.Qt.WA_TranslucentBackground) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.label_widget = label_widget def setProperty(self, name, value): From 3aaf4433274fd322aac1656feaec17620443b034 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:04:56 +0200 Subject: [PATCH 25/63] moved enumerator --- .../settings/settings/widgets/item_types.py | 212 +++++++++--------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 33585773f9..6e169b07b1 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -829,112 +829,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): return self.checkbox.isChecked() -class EnumeratorWidget(QtWidgets.QWidget, InputObject): - 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(EnumeratorWidget, self).__init__(parent_widget) - - self.initial_attributes(input_data, parent, as_widget) - self.multiselection = input_data.get("multiselection") - self.enum_items = input_data["enum_items"] - if not self.enum_items: - raise ValueError( - "Attribute `enum_items` is not defined." - ) - - 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) - label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - layout.addWidget(label_widget, 0) - self.label_widget = label_widget - - if self.multiselection: - placeholder = input_data.get("placeholder") - self.input_field = MultiSelectionComboBox( - placeholder=placeholder, parent=self - ) - else: - self.input_field = ComboBox(self) - - first_value = None - for enum_item in self.enum_items: - for value, label in enum_item.items(): - if first_value is None: - first_value = value - self.input_field.addItem(label, value) - - if self.multiselection: - model = self.input_field.model() - for idx in range(self.input_field.count()): - model.item(idx).setCheckable(True) - - self._first_value = first_value - - layout.addWidget(self.input_field, 0) - - self.setFocusProxy(self.input_field) - - self.input_field.value_changed.connect(self._on_value_change) - - @property - def default_input_value(self): - if self.multiselection: - return [] - return self._first_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 - self.input_field.set_value(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): - return self.input_field.value() - - class NumberWidget(QtWidgets.QWidget, InputObject): default_input_value = 0 value_changed = QtCore.Signal(object) @@ -1180,6 +1074,112 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): return self.path_input.text() +class EnumeratorWidget(QtWidgets.QWidget, InputObject): + 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(EnumeratorWidget, self).__init__(parent_widget) + + self.initial_attributes(input_data, parent, as_widget) + self.multiselection = input_data.get("multiselection") + self.enum_items = input_data["enum_items"] + if not self.enum_items: + raise ValueError( + "Attribute `enum_items` is not defined." + ) + + 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) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(label_widget, 0) + self.label_widget = label_widget + + if self.multiselection: + placeholder = input_data.get("placeholder") + self.input_field = MultiSelectionComboBox( + placeholder=placeholder, parent=self + ) + else: + self.input_field = ComboBox(self) + + first_value = None + for enum_item in self.enum_items: + for value, label in enum_item.items(): + if first_value is None: + first_value = value + self.input_field.addItem(label, value) + + if self.multiselection: + model = self.input_field.model() + for idx in range(self.input_field.count()): + model.item(idx).setCheckable(True) + + self._first_value = first_value + + layout.addWidget(self.input_field, 0) + + self.setFocusProxy(self.input_field) + + self.input_field.value_changed.connect(self._on_value_change) + + @property + def default_input_value(self): + if self.multiselection: + return [] + return self._first_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 + self.input_field.set_value(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): + return self.input_field.value() + + class RawJsonInput(QtWidgets.QPlainTextEdit): tab_length = 4 From dfaa62ef952758d51076fec4ff142bf8d9018bd2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:19:35 +0200 Subject: [PATCH 26/63] enum has better style changes --- .../settings/settings/widgets/item_types.py | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 6e169b07b1..647ec96c58 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1090,9 +1090,7 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.multiselection = input_data.get("multiselection") self.enum_items = input_data["enum_items"] if not self.enum_items: - raise ValueError( - "Attribute `enum_items` is not defined." - ) + raise ValueError("Attribute `enum_items` is not defined.") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -1105,7 +1103,7 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): label_widget = QtWidgets.QLabel(label) label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(label_widget, 0) - self.label_widget = label_widget + self.label_widget = label_widget if self.multiselection: placeholder = input_data.get("placeholder") @@ -1121,14 +1119,13 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): if first_value is None: first_value = value self.input_field.addItem(label, value) + self._first_value = first_value if self.multiselection: model = self.input_field.model() for idx in range(self.input_field.count()): model.item(idx).setCheckable(True) - self._first_value = first_value - layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) @@ -1147,16 +1144,13 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.input_field.set_value(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 - ) + if self.as_widget: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) else: state = self.style_state( self.has_studio_override, @@ -1164,17 +1158,16 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): 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 + self.input_field.setProperty("input-state", state) + self.input_field.style().polish(self.input_field) + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) def item_value(self): return self.input_field.value() From 83c0010320c63045f5129d34cc6ce871e3786f71 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:22:26 +0200 Subject: [PATCH 27/63] removed ComboMenuDelegate as not used --- .../widgets/multiselection_combobox.py | 122 +----------------- 1 file changed, 2 insertions(+), 120 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 0106051cc4..9e5bc815b4 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -19,108 +19,6 @@ class ComboItemDelegate(QtWidgets.QStyledItemDelegate): super(ComboItemDelegate, self).paint(painter, option, index) -class ComboMenuDelegate(QtWidgets.QAbstractItemDelegate): - """ - Helper styled delegate (mostly based on existing private Qt's - delegate used by the QtWidgets.QComboBox). Used to style the popup like a - menu. (e.g osx aqua style). - """ - - def paint(self, painter, option, index): - menuopt = self._menu_style_option(option, index) - if option.widget is not None: - style = option.widget.style() - else: - style = QtWidgets.QApplication.style() - style.drawControl( - QtWidgets.QStyle.CE_MenuItem, menuopt, painter, option.widget - ) - - def sizeHint(self, option, index): - menuopt = self._menu_style_option(option, index) - if option.widget is not None: - style = option.widget.style() - else: - style = QtWidgets.QApplication.style() - return style.sizeFromContents( - QtWidgets.QStyle.CT_MenuItem, menuopt, menuopt.rect.size(), - option.widget - ) - - def _menu_style_option(self, option, index): - menuoption = QtWidgets.QStyleOptionMenuItem() - if option.widget: - palette_source = option.widget.palette("QMenu") - else: - palette_source = QtWidgets.QApplication.palette("QMenu") - - palette = option.palette.resolve(palette_source) - foreground = index.data(QtCore.Qt.ForegroundRole) - if isinstance(foreground, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): - foreground = QtGui.QBrush(foreground) - palette.setBrush(QtGui.QPalette.Text, foreground) - palette.setBrush(QtGui.QPalette.ButtonText, foreground) - palette.setBrush(QtGui.QPalette.WindowText, foreground) - - background = index.data(QtCore.Qt.BackgroundRole) - if isinstance(background, (QtGui.QBrush, QtGui.QColor, QtGui.QPixmap)): - background = QtGui.QBrush(background) - palette.setBrush(QtGui.QPalette.Background, background) - - menuoption.palette = palette - - decoration = index.data(QtCore.Qt.DecorationRole) - if isinstance(decoration, QtGui.QIcon): - menuoption.icon = decoration - - menuoption.menuItemType = QtWidgets.QStyleOptionMenuItem.Normal - - if index.flags() & QtCore.Qt.ItemIsUserCheckable: - menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NonExclusive - else: - menuoption.checkType = QtWidgets.QStyleOptionMenuItem.NotCheckable - - check = index.data(QtCore.Qt.CheckStateRole) - menuoption.checked = check == QtCore.Qt.Checked - - if option.widget is not None: - menuoption.font = option.widget.font() - else: - menuoption.font = QtWidgets.QApplication.font("QMenu") - - menuoption.maxIconWidth = option.decorationSize.width() + 4 - menuoption.rect = option.rect - menuoption.menuRect = option.rect - - # menuoption.menuHasCheckableItems = True - menuoption.tabWidth = 0 - # TODO: self.displayText(QVariant, QLocale) - # TODO: Why is this not a QtWidgets.QStyledItemDelegate? - menuoption.text = str(index.data(QtCore.Qt.DisplayRole)) - - menuoption.fontMetrics = QtGui.QFontMetrics(menuoption.font) - state = option.state & ( - QtWidgets.QStyle.State_MouseOver - | QtWidgets.QStyle.State_Selected - | QtWidgets.QStyle.State_Active - ) - - if index.flags() & QtCore.Qt.ItemIsEnabled: - state = state | QtWidgets.QStyle.State_Enabled - menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Active) - else: - state = state & ~QtWidgets.QStyle.State_Enabled - menuoption.palette.setCurrentColorGroup(QtGui.QPalette.Disabled) - - if menuoption.checked: - state = state | QtWidgets.QStyle.State_On - else: - state = state | QtWidgets.QStyle.State_Off - - menuoption.state = state - return menuoption - - class MultiSelectionComboBox(QtWidgets.QComboBox): value_changed = QtCore.Signal() ignored_keys = { @@ -152,7 +50,8 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): self._initial_mouse_pos = None self._separator = separator self.placeholder_text = placeholder - self._update_item_delegate() + self.delegate = ComboItemDelegate(self) + self.setItemDelegate(self.delegate) self.lines = {} self.item_height = ( @@ -171,12 +70,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): QtWidgets.QApplication.doubleClickInterval() ) - def changeEvent(self, event): - """Reimplemented.""" - if event.type() == QtCore.QEvent.StyleChange: - self._update_item_delegate() - super(MultiSelectionComboBox, self).changeEvent(event) - def showPopup(self): """Reimplemented.""" super(MultiSelectionComboBox, self).showPopup() @@ -419,14 +312,3 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): return return super(MultiSelectionComboBox, self).keyPressEvent(event) - - def _update_item_delegate(self): - opt = QtWidgets.QStyleOptionComboBox() - opt.initFrom(self) - if self.style().styleHint( - QtWidgets.QStyle.SH_ComboBox_Popup, opt, self - ): - delegate = ComboMenuDelegate(self) - else: - delegate = ComboItemDelegate(self) - self.setItemDelegate(delegate) From ddd1637bd345f0135b6781a27d0c690b9a65689e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:46:35 +0200 Subject: [PATCH 28/63] reorganized eventFilter --- .../widgets/multiselection_combobox.py | 116 +++++++++--------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 9e5bc815b4..2c4c910770 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -87,69 +87,73 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): super(MultiSelectionComboBox, self).hidePopup() self.view().clearFocus() - def eventFilter(self, obj, event): - """Reimplemented.""" - if ( - self._popup_is_shown - and event.type() == QtCore.QEvent.MouseMove - and self.view().isVisible() - and self._initial_mouse_pos is not None - ): - diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos - if ( - diff.manhattanLength() > 9 - and self._block_mouse_release_timer.isActive() - ): - self._block_mouse_release_timer.stop() + def _event_popup_shown(self, obj, event): + if not self._popup_is_shown: + return current_index = self.view().currentIndex() - if ( - self._popup_is_shown - and event.type() == QtCore.QEvent.MouseButtonRelease - and self.view().isVisible() - and self.view().rect().contains(event.pos()) - and current_index.isValid() - and current_index.flags() & QtCore.Qt.ItemIsSelectable - and current_index.flags() & QtCore.Qt.ItemIsEnabled - and current_index.flags() & QtCore.Qt.ItemIsUserCheckable - and self.view().visualRect(current_index).contains(event.pos()) - and not self._block_mouse_release_timer.isActive() - ): - model = self.model() - index = self.view().currentIndex() - state = model.data(index, QtCore.Qt.CheckStateRole) - if state == QtCore.Qt.Unchecked: - check_state = QtCore.Qt.Checked - else: - check_state = QtCore.Qt.Unchecked + model = self.model() - model.setData(index, check_state, QtCore.Qt.CheckStateRole) - self.view().update(index) + if event.type() == QtCore.QEvent.MouseMove: + if ( + self.view().isVisible() + and self._initial_mouse_pos is not None + and self._block_mouse_release_timer.isActive() + ): + diff = obj.mapToGlobal(event.pos()) - self._initial_mouse_pos + if diff.manhattanLength() > 9: + self._block_mouse_release_timer.stop() + return + + index_flags = current_index.flags() + state = current_index.data(QtCore.Qt.CheckStateRole) + new_state = None + + if event.type() == QtCore.QEvent.MouseButtonRelease: + if ( + self._block_mouse_release_timer.isActive() + or not current_index.isValid() + or not self.view().isVisible() + or not self.view().rect().contains(event.pos()) + or not index_flags & QtCore.Qt.ItemIsSelectable + or not index_flags & QtCore.Qt.ItemIsEnabled + or not index_flags & QtCore.Qt.ItemIsUserCheckable + ): + return + + if state == QtCore.Qt.Unchecked: + new_state = QtCore.Qt.Checked + else: + new_state = QtCore.Qt.Unchecked + + elif event.type() == QtCore.QEvent.KeyPress: + # TODO: handle QtCore.Qt.Key_Enter, Key_Return? + if event.key() == QtCore.Qt.Key_Space: + # toogle the current items check state + if ( + index_flags & QtCore.Qt.ItemIsUserCheckable + and index_flags & QtCore.Qt.ItemIsTristate + ): + new_state = QtCore.Qt.CheckState((int(state) + 1) % 3) + + elif index_flags & QtCore.Qt.ItemIsUserCheckable: + if state != QtCore.Qt.Checked: + new_state = QtCore.Qt.Checked + else: + new_state = QtCore.Qt.Unchecked + + if new_state is not None: + model.setData(current_index, new_state, QtCore.Qt.CheckStateRole) + self.view().update(current_index) self.update_size_hint() self.value_changed.emit() return True - if self._popup_is_shown and event.type() == QtCore.QEvent.KeyPress: - if event.key() == QtCore.Qt.Key_Space: - # toogle the current items check state - model = self.model() - index = self.view().currentIndex() - flags = model.flags(index) - state = model.data(index, QtCore.Qt.CheckStateRole) - if flags & QtCore.Qt.ItemIsUserCheckable and \ - flags & QtCore.Qt.ItemIsTristate: - state = QtCore.Qt.CheckState((int(state) + 1) % 3) - elif flags & QtCore.Qt.ItemIsUserCheckable: - state = ( - QtCore.Qt.Checked - if state != QtCore.Qt.Checked - else QtCore.Qt.Unchecked - ) - model.setData(index, state, QtCore.Qt.CheckStateRole) - self.view().update(index) - self.update() - return True - # TODO: handle QtCore.Qt.Key_Enter, Key_Return? + def eventFilter(self, obj, event): + """Reimplemented.""" + result = self._event_popup_shown(obj, event) + if result is not None: + return result return super(MultiSelectionComboBox, self).eventFilter(obj, event) From 028b754f59bd5c2175153f74a7b6a1427b920e3b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:47:49 +0200 Subject: [PATCH 29/63] fixed set_value method for discard changes etc. --- pype/tools/settings/settings/widgets/multiselection_combobox.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 2c4c910770..159b2d16dc 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -281,6 +281,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): else: check_state = QtCore.Qt.Unchecked self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole) + self.update_size_hint() def value(self): items = list() From b2cd99cbcca73fb926983b3f6f333c2cd9bb517e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:50:46 +0200 Subject: [PATCH 30/63] skip setting item as checkable for multiselection input --- pype/tools/settings/settings/widgets/item_types.py | 5 ----- .../settings/settings/widgets/multiselection_combobox.py | 7 ++----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 647ec96c58..e495cfc8aa 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1121,11 +1121,6 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.input_field.addItem(label, value) self._first_value = first_value - if self.multiselection: - model = self.input_field.model() - for idx in range(self.input_field.count()): - model.item(idx).setCheckable(True) - layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 159b2d16dc..17750f909e 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -117,7 +117,6 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): or not self.view().rect().contains(event.pos()) or not index_flags & QtCore.Qt.ItemIsSelectable or not index_flags & QtCore.Qt.ItemIsEnabled - or not index_flags & QtCore.Qt.ItemIsUserCheckable ): return @@ -309,11 +308,9 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): event.key() == QtCore.Qt.Key_Down and event.modifiers() & QtCore.Qt.AltModifier ): - self.showPopup() - return + return self.showPopup() if event.key() in self.ignored_keys: - event.ignore() - return + return event.ignore() return super(MultiSelectionComboBox, self).keyPressEvent(event) From ba785f748bfa580a5cd44343b589e8c3b62bdbde Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 10:53:18 +0200 Subject: [PATCH 31/63] made None as valid value --- 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 e495cfc8aa..9ddfa5acab 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1113,10 +1113,10 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): else: self.input_field = ComboBox(self) - first_value = None + first_value = NOT_SET for enum_item in self.enum_items: for value, label in enum_item.items(): - if first_value is None: + if first_value is NOT_SET: first_value = value self.input_field.addItem(label, value) self._first_value = first_value From 614234f2f6a0bad9682fb08a65d4af67e42579ae Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 11:33:17 +0200 Subject: [PATCH 32/63] all items has attribute `label_widget` which may be set to None --- .../settings/settings/widgets/item_types.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e589b89c0f..468ef6e1b0 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -775,7 +775,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): label_widget = QtWidgets.QLabel(label) label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(label_widget, 0) - self.label_widget = label_widget + self.label_widget = label_widget self.checkbox = QtWidgets.QCheckBox(self) spacer = QtWidgets.QWidget(self) @@ -861,7 +861,7 @@ class NumberWidget(QtWidgets.QWidget, InputObject): label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) - self.label_widget = label_widget + self.label_widget = label_widget layout.addWidget(self.input_field, 1) @@ -946,7 +946,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0, **layout_kwargs) - self.label_widget = label_widget + self.label_widget = label_widget layout.addWidget(self.text_input, 1, **layout_kwargs) @@ -1021,7 +1021,7 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0) - self.label_widget = label_widget + self.label_widget = label_widget self.path_input = PathInput(self) self.setFocusProxy(self.path_input) @@ -1156,8 +1156,9 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): label = input_data["label"] label_widget = QtWidgets.QLabel(label) layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) - self.label_widget = label_widget - layout.addWidget(self.text_input, 1, alignment=QtCore.Qt.AlignTop) + self.label_widget = label_widget + + layout.addWidget(self.input_field, 1, alignment=QtCore.Qt.AlignTop) self.text_input.textChanged.connect(self._on_value_change) @@ -2014,6 +2015,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): if as_widget: body_widget = None + self.label_widget = label_widget else: body_widget = ExpandingWidget(input_data["label"], self) main_layout.addWidget(body_widget) @@ -2903,7 +2905,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): label_widget = QtWidgets.QLabel(label) label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(label_widget, 0, alignment=QtCore.Qt.AlignTop) - self.label_widget = label_widget + self.label_widget = label_widget self.content_widget = QtWidgets.QWidget(self) self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) From 733c64831743d01fa94ae595b8385f238a241784 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 11:33:54 +0200 Subject: [PATCH 33/63] implemented `update_style` for all input objects the same --- .../settings/settings/widgets/item_types.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 468ef6e1b0..40b2035e25 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -681,6 +681,36 @@ class InputObject(SettingObject): def hierarchical_style_update(self): self.update_style() + def _style_state(self): + if self.as_widget: + 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 + ) + return state + + def update_style(self): + state = self._style_state() + if self._state == state: + return + + self._state = state + + self.input_field.setProperty("input-state", state) + self.input_field.style().polish(self.input_field) + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + def remove_overrides(self): self._is_overriden = False self._is_modified = False From a3b6c5c027a9fdadcdf9e4bde5ba3907d3d354f5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 11:35:37 +0200 Subject: [PATCH 34/63] removed `update_style` from most of inputs --- .../settings/settings/widgets/item_types.py | 155 ------------------ 1 file changed, 155 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 40b2035e25..308c2ef65c 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -823,35 +823,6 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): # 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): return self.checkbox.isChecked() @@ -900,37 +871,6 @@ class NumberWidget(QtWidgets.QWidget, InputObject): def set_value(self, value): self.input_field.setValue(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" - widget = self.input_field - else: - property_name = "state" - widget = self.label_widget - - widget.setProperty(property_name, state) - widget.style().polish(widget) - def item_value(self): return self.input_field.value() @@ -988,37 +928,6 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.text_input.setText(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" - 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): if self.multiline: @@ -1066,38 +975,6 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): self.path_input.clear_end_path() super(PathInput, self).focusOutEvent(event) - 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" - 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() @@ -1203,38 +1080,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): self._is_invalid = self.text_input.has_invalid_value() return super(RawJsonWidget, self)._on_value_change(*args, **kwargs) - 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" - 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): if self.is_invalid: return NOT_SET From 19138839428d4bb929fff45237df342596314782 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 11:36:27 +0200 Subject: [PATCH 35/63] all inputs object has attribute `input_field` --- .../settings/settings/widgets/item_types.py | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 308c2ef65c..289690250f 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -798,7 +798,7 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self._as_widget: + if not self.as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] @@ -807,25 +807,24 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): layout.addWidget(label_widget, 0) self.label_widget = label_widget - self.checkbox = QtWidgets.QCheckBox(self) + self.input_field = QtWidgets.QCheckBox(self) spacer = QtWidgets.QWidget(self) - layout.addWidget(self.checkbox, 0) - layout.addWidget(spacer, 1) - spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground) - self.setFocusProxy(self.checkbox) + layout.addWidget(self.input_field, 0) + layout.addWidget(spacer, 1) - self.checkbox.stateChanged.connect(self._on_value_change) + self.setFocusProxy(self.input_field) + + self.input_field.stateChanged.connect(self._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) - + self.input_field.setChecked(value) def item_value(self): - return self.checkbox.isChecked() + return self.input_field.isChecked() class NumberWidget(QtWidgets.QWidget, InputObject): @@ -897,14 +896,14 @@ class TextWidget(QtWidgets.QWidget, InputObject): layout.setSpacing(5) if self.multiline: - self.text_input = QtWidgets.QPlainTextEdit(self) + self.input_field = QtWidgets.QPlainTextEdit(self) else: - self.text_input = QtWidgets.QLineEdit(self) + self.input_field = QtWidgets.QLineEdit(self) if placeholder: - self.text_input.setPlaceholderText(placeholder) + self.input_field.setPlaceholderText(placeholder) - self.setFocusProxy(self.text_input) + self.setFocusProxy(self.input_field) layout_kwargs = {} if self.multiline: @@ -918,22 +917,21 @@ class TextWidget(QtWidgets.QWidget, InputObject): layout.addWidget(label_widget, 0, **layout_kwargs) self.label_widget = label_widget - layout.addWidget(self.text_input, 1, **layout_kwargs) + layout.addWidget(self.input_field, 1, **layout_kwargs) - self.text_input.textChanged.connect(self._on_value_change) + self.input_field.textChanged.connect(self._on_value_change) def set_value(self, value): if self.multiline: - self.text_input.setPlainText(value) + self.input_field.setPlainText(value) else: - self.text_input.setText(value) - + self.input_field.setText(value) def item_value(self): if self.multiline: - return self.text_input.toPlainText() + return self.input_field.toPlainText() else: - return self.text_input.text() + return self.input_field.text() class PathInputWidget(QtWidgets.QWidget, InputObject): @@ -962,21 +960,21 @@ class PathInputWidget(QtWidgets.QWidget, InputObject): 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.input_field = PathInput(self) + self.setFocusProxy(self.input_field) + layout.addWidget(self.input_field, 1) - self.path_input.textChanged.connect(self._on_value_change) + self.input_field.textChanged.connect(self._on_value_change) def set_value(self, value): - self.path_input.setText(value) + self.input_field.setText(value) def focusOutEvent(self, event): - self.path_input.clear_end_path() + self.input_field.clear_end_path() super(PathInput, self).focusOutEvent(event) def item_value(self): - return self.path_input.text() + return self.input_field.text() class RawJsonInput(QtWidgets.QPlainTextEdit): @@ -1049,15 +1047,15 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - self.text_input = RawJsonInput(self) - self.text_input.setSizePolicy( + self.input_field = RawJsonInput(self) + self.input_field.setSizePolicy( QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding ) - self.setFocusProxy(self.text_input) + self.setFocusProxy(self.input_field) - if not self._as_widget: + if not self.as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] @@ -1067,17 +1065,17 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): layout.addWidget(self.input_field, 1, alignment=QtCore.Qt.AlignTop) - self.text_input.textChanged.connect(self._on_value_change) + self.input_field.textChanged.connect(self._on_value_change) def update_studio_values(self, parent_values): - self._is_invalid = self.text_input.has_invalid_value() + self._is_invalid = self.input_field.has_invalid_value() return super(RawJsonWidget, self).update_studio_values(parent_values) def set_value(self, value): - self.text_input.set_value(value) + self.input_field.set_value(value) def _on_value_change(self, *args, **kwargs): - self._is_invalid = self.text_input.has_invalid_value() + self._is_invalid = self.input_field.has_invalid_value() return super(RawJsonWidget, self)._on_value_change(*args, **kwargs) def item_value(self): From eadf08f0bbcd6981877d2afa203a80d151039a0d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 11:36:59 +0200 Subject: [PATCH 36/63] updated methed `update_style` for inputs where it is more complex --- .../settings/settings/widgets/item_types.py | 97 ++++++------------- 1 file changed, 29 insertions(+), 68 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 289690250f..e262960655 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1469,29 +1469,16 @@ class ListWidget(QtWidgets.QWidget, InputObject): 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 not self.label_widget: + return + + state = self._style_state() if self._state == state: return - if self.label_widget: - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + self._state = state + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) def item_value(self): output = [] @@ -1648,30 +1635,17 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): 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 not self.label_widget: + return + + state = self._style_state() if self._state == state: return - if self.label_widget: - self.label_widget.setProperty("state", state) - self.label_widget.style().polish(self.label_widget) + self._state = state + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) def item_value(self): output = [] @@ -1990,42 +1964,29 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): 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 - ) + state = self._style_state() + if self._state == state: return + self._state = state + + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + if not self.body_widget: + return + if state: child_state = "child-{}".format(state) else: child_state = "" - 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) - self.label_widget.style().polish(self.label_widget) - - self._state = 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 + ) def all_item_values(self): output = {} From b193cc3b519d9c399c459b96f725c9cb556a358f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 23 Sep 2020 12:37:05 +0200 Subject: [PATCH 37/63] 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 38/63] 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 8f959eb73844e54e8a9a1eb470a97b21adaa4722 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 12:45:14 +0200 Subject: [PATCH 39/63] expandable widget can have widget before and after label now --- .../settings/settings/widgets/widgets.py | 68 +++++++------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 2a1f5fe804..355c297e5e 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -71,33 +71,51 @@ class ExpandingWidget(QtWidgets.QWidget): top_part = ClickableWidget(parent=self) + side_line_widget = QtWidgets.QWidget(top_part) + side_line_widget.setObjectName("SideLineWidget") + button_size = QtCore.QSize(5, 5) - button_toggle = QtWidgets.QToolButton(parent=top_part) + button_toggle = QtWidgets.QToolButton(parent=side_line_widget) 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 = QtWidgets.QLabel(label, parent=side_line_widget) label_widget.setObjectName("DictLabel") - side_line_widget = QtWidgets.QWidget(top_part) - side_line_widget.setObjectName("SideLineWidget") + before_label_widget = QtWidgets.QWidget(side_line_widget) + before_label_layout = QtWidgets.QVBoxLayout(before_label_widget) + before_label_layout.setContentsMargins(0, 0, 0, 0) + + after_label_widget = QtWidgets.QWidget(side_line_widget) + after_label_layout = QtWidgets.QVBoxLayout(after_label_widget) + after_label_layout.setContentsMargins(0, 0, 0, 0) + + spacer_widget = QtWidgets.QWidget(side_line_widget) + 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(before_label_widget) side_line_layout.addWidget(label_widget) + side_line_layout.addWidget(after_label_widget) + side_line_layout.addWidget(spacer_widget, 1) top_part_layout = QtWidgets.QHBoxLayout(top_part) top_part_layout.setContentsMargins(0, 0, 0, 0) top_part_layout.addWidget(side_line_widget) + before_label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + after_label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) self.top_part_ending = None - self.after_label_layout = None - self.end_of_layout = None + self.after_label_layout = after_label_layout + self.before_label_layout = before_label_layout self.side_line_widget = side_line_widget self.side_line_layout = side_line_layout @@ -146,45 +164,11 @@ class ExpandingWidget(QtWidgets.QWidget): 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 + def add_widget_before_label(self, widget): + self.before_label_layout.addWidget(widget) - 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) From 86ed514b5a34451c39eb80eaf07cbf0a2a476a31 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 12:45:26 +0200 Subject: [PATCH 40/63] dict item adds checkbox before label instead of after --- 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 e589b89c0f..60208cedaf 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2360,7 +2360,7 @@ class DictWidget(QtWidgets.QWidget, SettingObject): ) item.value_changed.connect(self._on_value_change) - self.body_widget.add_widget_after_label(item) + self.body_widget.add_widget_before_label(item) self.checkbox_widget = item self.input_fields.append(item) return item From 89b99479afbe35b7a644cf66de08c46f19e3fd68 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 12:46:29 +0200 Subject: [PATCH 41/63] formatting fix --- pype/tools/settings/settings/widgets/widgets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 355c297e5e..cab50bc7b9 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -169,7 +169,6 @@ class ExpandingWidget(QtWidgets.QWidget): def add_widget_before_label(self, widget): self.before_label_layout.addWidget(widget) - def resizeEvent(self, event): super(ExpandingWidget, self).resizeEvent(event) self.content_widget.updateGeometry() From 145b34425581758649dfa7fa0ab1f6e2e0d1e373 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 12:49:34 +0200 Subject: [PATCH 42/63] added validation of type for checkbox_key --- pype/tools/settings/settings/widgets/item_types.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 60208cedaf..58520d9d24 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2333,7 +2333,13 @@ class DictWidget(QtWidgets.QWidget, SettingObject): 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) + if child_configuration["type"] != "boolean": + self.log.warning(( + "SCHEMA BUG: Dictionary item has set as checkbox" + " item invalid type \"{}\". Expected \"boolean\"." + ).format(child_configuration["type"])) + else: + return self._add_checkbox_child(child_configuration) label_widget = None if not klass.expand_in_grid: From 7cc52fe28a332f9af3b27377e7a425d356745252 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 23 Sep 2020 12:55:02 +0200 Subject: [PATCH 43/63] 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 c2d9a66b8cff8321a1de68a36e560f2db636d4f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 12:59:06 +0200 Subject: [PATCH 44/63] fix default checkboxes in multiselection --- pype/tools/settings/settings/widgets/item_types.py | 5 +++++ .../settings/settings/widgets/multiselection_combobox.py | 1 + 2 files changed, 6 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 9ddfa5acab..dc6cde2407 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1121,6 +1121,11 @@ class EnumeratorWidget(QtWidgets.QWidget, InputObject): self.input_field.addItem(label, value) self._first_value = first_value + if self.multiselection: + model = self.input_field.model() + for idx in range(self.input_field.count()): + model.item(idx).setCheckable(True) + layout.addWidget(self.input_field, 0) self.setFocusProxy(self.input_field) diff --git a/pype/tools/settings/settings/widgets/multiselection_combobox.py b/pype/tools/settings/settings/widgets/multiselection_combobox.py index 17750f909e..9a99561ea8 100644 --- a/pype/tools/settings/settings/widgets/multiselection_combobox.py +++ b/pype/tools/settings/settings/widgets/multiselection_combobox.py @@ -117,6 +117,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox): or not self.view().rect().contains(event.pos()) or not index_flags & QtCore.Qt.ItemIsSelectable or not index_flags & QtCore.Qt.ItemIsEnabled + or not index_flags & QtCore.Qt.ItemIsUserCheckable ): return From f7104a1f7ecb9dd509478c638eaafaeade854f08 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 16:49:28 +0200 Subject: [PATCH 45/63] 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 46/63] 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 47/63] 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 d91f67a799a4faf8a8251047242d37aafa19e414 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:47:57 +0200 Subject: [PATCH 48/63] ListItem and ModifiableDictItem expect one argument less --- pype/tools/settings/settings/widgets/item_types.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 0419c48c5c..406565c950 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1190,8 +1190,7 @@ class ListItem(QtWidgets.QWidget, SettingObject): value_changed = QtCore.Signal(object) def __init__( - self, object_type, input_modifiers, config_parent, parent, - is_strict=False + self, item_schema, config_parent, parent, is_strict=False ): super(ListItem, self).__init__(parent) @@ -1243,9 +1242,9 @@ class ListItem(QtWidgets.QWidget, SettingObject): layout.addWidget(self.add_btn, 0) layout.addWidget(self.remove_btn, 0) - ItemKlass = TypeToKlass.types[object_type] + ItemKlass = TypeToKlass.types[item_schema["type"]] self.value_input = ItemKlass( - input_modifiers, + item_schema, self, as_widget=True, label_widget=None @@ -1759,7 +1758,7 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, input_modifiers, config_parent, parent): + def __init__(self, item_schema, config_parent, parent): super(ModifiableDictItem, self).__init__(parent) self._set_default_attributes() @@ -1779,13 +1778,13 @@ class ModifiableDictItem(QtWidgets.QWidget, SettingObject): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(3) - ItemKlass = TypeToKlass.types[object_type] + ItemKlass = TypeToKlass.types[item_schema["type"]] self.key_input = QtWidgets.QLineEdit(self) self.key_input.setObjectName("DictKey") self.value_input = ItemKlass( - input_modifiers, + item_schema, self, as_widget=True, label_widget=None From ddc1042d6cf3d1f33a923f67167212b23d5c3a07 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:48:09 +0200 Subject: [PATCH 49/63] use pype logger inside --- 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 406565c950..6f092b4bd8 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1,5 +1,4 @@ import json -import logging import collections from Qt import QtWidgets, QtCore, QtGui from .widgets import ( @@ -11,6 +10,7 @@ from .widgets import ( ) from .multiselection_combobox import MultiSelectionComboBox from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET +from pype.api import Logger from avalon.vendor import qtawesome @@ -111,7 +111,7 @@ class SettingObject: def log(self): """Auto created logger for debugging.""" if self._log is None: - self._log = logging.getLogger(self.__class__.__name__) + self._log = Logger().get_logger(self.__class__.__name__) return self._log @property From 83eab6b2ca5f5776d630b1b6f1f12cd93e55dfc2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:49:14 +0200 Subject: [PATCH 50/63] ModifiableDict and List are able to handle new way of their item definition with backwards compatibility --- .../settings/settings/widgets/item_types.py | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 6f092b4bd8..ba343b3979 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1381,8 +1381,21 @@ class ListWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(input_data, parent, as_widget) - self.object_type = input_data["object_type"] - self.input_modifiers = input_data.get("input_modifiers") or {} + object_type = input_data["object_type"] + if isinstance(object_type, dict): + self.item_schema = object_type + else: + self.item_schema = { + "type": object_type + } + # Backwards compatibility + input_modifiers = input_data.get("input_modifiers") or {} + if input_modifiers: + self.log.info(( + "Used deprecated key `input_modifiers` to define item." + " Rather use `object_type` as dictionary with modifiers." + )) + self.item_schema.update(input_modifiers) self.input_fields = [] @@ -1949,6 +1962,22 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.key = input_data["key"] + object_type = input_data["object_type"] + if isinstance(object_type, dict): + self.item_schema = object_type + else: + # Backwards compatibility + self.item_schema = { + "type": object_type + } + input_modifiers = input_data.get("input_modifiers") or {} + if input_modifiers: + self.log.info(( + "Used deprecated key `input_modifiers` to define item." + " Rather use `object_type` as dictionary with modifiers." + )) + self.item_schema.update(input_modifiers) + if input_data.get("highlight_content", False): content_state = "hightlighted" bottom_margin = 5 From a1715355a35b1874b3ebda32f08ba27d150fb492 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:50:22 +0200 Subject: [PATCH 51/63] List and ModifiableDict are creating new items in right way --- pype/tools/settings/settings/widgets/item_types.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index ba343b3979..d6858d390b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1464,9 +1464,7 @@ 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, self.inputs_widget - ) + item_widget = ListItem(self.item_schema, self, self.inputs_widget) previous_field = None next_field = None @@ -1652,11 +1650,8 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): children_item_mapping = [] for child_configuration in input_data["object_types"]: - object_type = child_configuration["type"] - item_widget = ListItem( - object_type, child_configuration, self, self.inputs_widget, - is_strict=True + child_configuration, self, self.inputs_widget, is_strict=True ) self.input_fields.append(item_widget) @@ -2030,9 +2025,6 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): self.setAttribute(QtCore.Qt.WA_TranslucentBackground) - self.object_type = input_data["object_type"] - self.input_modifiers = input_data.get("input_modifiers") or {} - self.add_row(is_empty=True) def count(self): @@ -2132,7 +2124,7 @@ class ModifiableDict(QtWidgets.QWidget, 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.content_widget + self.item_schema, self, self.content_widget ) if is_empty: item_widget.set_as_empty() From d241a450375f6fd0ce45885777d214e78035e0b5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:51:59 +0200 Subject: [PATCH 52/63] info changed to warning --- 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 d6858d390b..ed8a5d6305 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1391,7 +1391,7 @@ class ListWidget(QtWidgets.QWidget, InputObject): # Backwards compatibility input_modifiers = input_data.get("input_modifiers") or {} if input_modifiers: - self.log.info(( + self.log.warning(( "Used deprecated key `input_modifiers` to define item." " Rather use `object_type` as dictionary with modifiers." )) @@ -1967,7 +1967,7 @@ class ModifiableDict(QtWidgets.QWidget, InputObject): } input_modifiers = input_data.get("input_modifiers") or {} if input_modifiers: - self.log.info(( + self.log.warning(( "Used deprecated key `input_modifiers` to define item." " Rather use `object_type` as dictionary with modifiers." )) From 069f25f1cbf8ab570878b148adf805f50dee742a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:56:34 +0200 Subject: [PATCH 53/63] skip input modifiers in anatomy --- 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 6d7b3292ce..e1a726187c 100644 --- a/pype/tools/settings/settings/widgets/anatomy_types.py +++ b/pype/tools/settings/settings/widgets/anatomy_types.py @@ -271,9 +271,9 @@ class RootsWidget(QtWidgets.QWidget, SettingObject): ) multiroot_data = { "key": self.key, - "object_type": "path-widget", "expandable": False, - "input_modifiers": { + "object_type": { + "type": "path-widget", "multiplatform": True } } From 8cc5a906ffdca51f1fcdbda8468732e06be07902 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:57:07 +0200 Subject: [PATCH 54/63] modified schema to use new object_type definition --- .../projects_schema/1_plugins_gui_schema.json | 8 ++++---- .../gui_schemas/system_schema/1_examples.json | 16 ++++++++-------- .../system_schema/1_modules_gui_schema.json | 18 +++++++++--------- 3 files changed, 21 insertions(+), 21 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 2fefe8df2d..f70d9345e5 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,8 +172,8 @@ "type": "list", "key": "profiles", "label": "Profiles", - "object_type": "dict", - "input_modifiers": { + "object_type": { + "type": "dict", "children": [ { "key": "families", @@ -192,8 +192,8 @@ "label": "Output Definitions", "type": "dict-modifiable", "highlight_content": true, - "object_type": "dict", - "input_modifiers": { + "object_type": { + "type": "dict", "children": [ { "key": "ext", 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 00aef304a9..dd0f7f20d1 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 @@ -67,16 +67,16 @@ "type": "list", "key": "list_item_of_multiline_texts", "label": "List of multiline texts", - "object_type": "text", - "input_modifiers": { + "object_type": { + "type": "text", "multiline": true } }, { "type": "list", "key": "list_item_of_floats", "label": "List of floats", - "object_type": "number", - "input_modifiers": { + "object_type": { + "type": "number", "decimal": 3, "minimum": 1000, "maximum": 2000 @@ -85,8 +85,8 @@ "type": "dict-modifiable", "key": "modifiable_dict_of_integers", "label": "Modifiable dict of integers", - "object_type": "number", - "input_modifiers": { + "object_type": { + "type": "number", "decimal": 0, "minimum": 10, "maximum": 100 @@ -213,8 +213,8 @@ "type": "list", "key": "dict_item", "label": "DictItem in List", - "object_type": "dict-item", - "input_modifiers": { + "object_type": { + "type": "dict-item", "children": [ { "key": "families", 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 index 7b3d8cdd13..d78c11838a 100644 --- 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 @@ -80,8 +80,8 @@ "type": "list", "key": "statuses_name_change", "label": "Status name change", - "object_type": "text", - "input_modifiers": { + "object_type": { + "type": "text", "multiline": false } }] @@ -96,9 +96,9 @@ "type": "dict-modifiable", "key": "status_update", "label": "Status Updates", - "object_type": "list", - "input_modifiers": { - "object_type": "text" + "object_type": { + "type": "list", + "object_type": "text" } }, { @@ -133,10 +133,10 @@ }, { "type": "list", - "object_type": "number", "key": "exclude_ports", "label": "Exclude ports", - "input_modifiers": { + "object_type": { + "type": "number", "minimum": 1, "maximum": 65535 } @@ -213,8 +213,8 @@ "label": "Muster Resl URL" },{ "type": "dict-modifiable", - "object_type": "number", - "input_modifiers": { + "object_type": { + "type": "number", "minimum": 0, "maximum": 300 }, From 7c80946cef55ea803fed79d76286b482cf3117b3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 17:57:15 +0200 Subject: [PATCH 55/63] modified readme --- pype/tools/settings/settings/README.md | 52 ++++++++++++++++++++------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 9492d8bc7b..e8b7fcdb57 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -84,8 +84,8 @@ "type": "list", "key": "profiles", "label": "Profiles", - "object_type": "dict-item", - "input_modifiers": { + "object_type": { + "type": "dict-item", "children": [ { "key": "families", @@ -199,37 +199,53 @@ - 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 of items is defined with key `"object_type"` +- there are 2 possible ways how to set the type: + 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) + 2.) item type name as string without modifiers (e.g. `text`) +1.) with item modifiers ``` { "type": "list", - "object_type": "number", "key": "exclude_ports", "label": "Exclude ports", - "input_modifiers": { - "minimum": 1, - "maximum": 65535 + "object_type": { + "type": "number", # number item type + "minimum": 1, # minimum modifier + "maximum": 65535 # maximum modifier } } ``` +2.) without modifiers +``` +{ + "type": "list", + "key": "exclude_ports", + "label": "Exclude ports", + "object_type": "text" +} +``` + ### 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"` +- type of items is defined with key `"object_type"` +- there are 2 possible ways how to set the type: + 1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below) + 2.) item type name as string without modifiers (e.g. `text`) - 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`) +1.) with item modifiers ``` { "type": "dict-modifiable", - "object_type": "number", - "input_modifiers": { + "object_type": { + "type": "number", "minimum": 0, "maximum": 300 }, @@ -240,6 +256,18 @@ } ``` +2.) without modifiers +``` +{ + "type": "dict-modifiable", + "object_type": "text", + "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"` From 0f05901ac7979b84d2b6f624dd8bf23163d07b48 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 19:11:03 +0200 Subject: [PATCH 56/63] simplified PathWidget with usage of dict as widget --- .../settings/settings/widgets/item_types.py | 146 +++++++----------- 1 file changed, 56 insertions(+), 90 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 0419c48c5c..9512680a39 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2835,13 +2835,13 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self.multiplatform = input_data.get("multiplatform", False) self.multipath = input_data.get("multipath", False) - self.input_fields = [] + self.input_field = None layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - if not self._as_widget: + if not self.as_widget: self.key = input_data["key"] if not label_widget: label = input_data["label"] @@ -2882,45 +2882,49 @@ class PathWidget(QtWidgets.QWidget, SettingObject): ) self.setFocusProxy(path_input) self.content_layout.addWidget(path_input) - self.input_fields.append(path_input) + self.input_field = 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 + item_schema = { + "key": self.key, + "object_type": "path-input" + } input_widget = ListWidget( - input_data_for_list, self, label_widget=self.label_widget + item_schema, self, label_widget=self.label_widget ) self.setFocusProxy(input_widget) self.content_layout.addWidget(input_widget) - self.input_fields.append(input_widget) + self.input_field = 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) + item_schema = { + "type": "dict", + "show_borders": False, + "children": [] + } for platform_key in self.platforms: platform_label = self.platform_labels_mapping[platform_key] - label_widget = QtWidgets.QLabel(platform_label, proxy_widget) + child_item = { + "key": platform_key, + "label": platform_label + } if self.multipath: - input_data_for_list["key"] = platform_key - input_widget = ListWidget( - input_data_for_list, self, label_widget=label_widget - ) + child_item["type"] = "list" + child_item["object_type"] = "path-input" 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) + child_item["type"] = "path-input" - self.setFocusProxy(self.input_fields[0]) - self.content_layout.addWidget(proxy_widget) + item_schema["children"].append(child_item) + + input_widget = DictWidget( + item_schema, self, as_widget=True, label_widget=self.label_widget + ) + self.content_layout.addWidget(input_widget) + self.input_field = input_widget + input_widget.value_changed.connect(self._on_value_change) def update_default_values(self, parent_values): self._state = None @@ -2960,11 +2964,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._has_studio_override = False self._had_studio_override = False - if not self.multiplatform: - self.input_fields[0].update_default_values(value) - else: - for input_field in self.input_fields: - input_field.update_default_values(value) + # TODO handle invalid value type + self.input_field.update_default_values(value) def update_studio_values(self, parent_values): self._state = None @@ -2989,11 +2990,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._had_studio_override = False 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) + # TODO handle invalid value type + self.input_field.update_studio_values(value) def apply_overrides(self, parent_values): self._is_modified = False @@ -3012,11 +3010,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): 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: - for input_field in self.input_fields: - input_field.apply_overrides(override_values) + # TODO handle invalid value type + self.input_field.update_studio_values(override_values) if not self._is_overriden: self._is_overriden = ( @@ -3029,12 +3024,13 @@ class PathWidget(QtWidgets.QWidget, SettingObject): def set_value(self, value): if not self.multiplatform: - self.input_fields[0].set_value(value) + return self.input_field.set_value(value) - else: - for input_field in self.input_fields: - _value = value[input_field.key] - input_field.set_value(_value) + for _input_field in self.input_field.input_fields: + _value = value.get(_input_field.key, NOT_SET) + if _value is NOT_SET: + continue + _input_field.set_value(_value) def _on_value_change(self, item=None): if self.ignore_value_changes: @@ -3095,17 +3091,14 @@ class PathWidget(QtWidgets.QWidget, SettingObject): def remove_overrides(self): self._is_overriden = False self._is_modified = False - for input_field in self.input_fields: - input_field.remove_overrides() + self.input_field.remove_overrides() def reset_to_pype_default(self): - for input_field in self.input_fields: - input_field.reset_to_pype_default() + self.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() + self.input_field.set_studio_default() if self.is_group: self._has_studio_override = True @@ -3114,8 +3107,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._is_modified = False self._is_overriden = self._was_overriden - for input_field in self.input_fields: - input_field.discard_changes() + self.input_field.discard_changes() self._is_modified = self.child_modified @@ -3124,51 +3116,29 @@ class PathWidget(QtWidgets.QWidget, SettingObject): @property def child_has_studio_override(self): - for input_field in self.input_fields: - if ( - input_field.has_studio_override - or input_field.child_has_studio_override - ): - return True - return False + return ( + self.input_field.has_studio_override + or self.input_field.child_has_studio_override + ) @property def child_modified(self): - for input_field in self.input_fields: - if input_field.child_modified: - return True - return False + return self.input_field.child_modified @property def child_overriden(self): - for input_field in self.input_fields: - if input_field.child_overriden: - return True - return False + return self.input_field.child_overriden @property def child_invalid(self): - for input_field in self.input_fields: - if input_field.child_invalid: - return True - return False + return self.input_field.child_invalid def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() + self.input_field.hierarchical_style_update() self.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 + return self.input_field.item_value() def studio_overrides(self): if ( @@ -3178,18 +3148,14 @@ class PathWidget(QtWidgets.QWidget, SettingObject): ): return NOT_SET, False - value = self.item_value() - if not self.multiplatform: - value = {self.key: value} + value = {self.key: self.item_value()} return value, self.is_group 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} + value = {self.key: self.item_value()} return value, self.is_group From 3a6c8e32eb518b74e1b56ebb0217b5641155eeb1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 19:14:20 +0200 Subject: [PATCH 57/63] DictWidget used as widget has ability to not add borders around the widget --- 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 9512680a39..fd284bb339 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2244,6 +2244,8 @@ class DictWidget(QtWidgets.QWidget, SettingObject): def _ui_as_widget(self, input_data): body = QtWidgets.QWidget(self) body.setObjectName("DictAsWidgetBody") + show_borders = str(int(input_data.get("show_borders", True))) + body.setProperty("show_borders", show_borders) content_layout = QtWidgets.QGridLayout(body) content_layout.setContentsMargins(5, 5, 5, 5) From 36a2edf2fbae8636c0684ffba7517cfbec279929 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 19:14:39 +0200 Subject: [PATCH 58/63] modified styles for dict widget --- pype/tools/settings/settings/style/style.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index ebea87203d..dcc7a5effe 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -168,8 +168,10 @@ QPushButton[btn-type="expand-toggle"] { background: #141a1f; } -#DictAsWidgetBody{ +#DictAsWidgetBody { background: transparent; +} +#DictAsWidgetBody[show_borders="1"] { border: 2px solid #cccccc; border-radius: 5px; } From c51daf918b706416cdb2bbb65cbce0e0af295bce Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 19:40:29 +0200 Subject: [PATCH 59/63] fixed a lot of in path widget --- .../settings/settings/widgets/item_types.py | 58 +++++++++---------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fd284bb339..379f058fab 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2873,14 +2873,14 @@ class PathWidget(QtWidgets.QWidget, SettingObject): platform: value_type() for platform in self.platforms } - else: - return value_type() + return value_type() 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 + input_data, self, + as_widget=True, label_widget=self.label_widget ) self.setFocusProxy(path_input) self.content_layout.addWidget(path_input) @@ -2894,7 +2894,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): "object_type": "path-input" } input_widget = ListWidget( - item_schema, self, label_widget=self.label_widget + item_schema, self, + as_widget=True, label_widget=self.label_widget ) self.setFocusProxy(input_widget) self.content_layout.addWidget(input_widget) @@ -2934,21 +2935,15 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._is_modified = False value = NOT_SET - if self._as_widget: + if self.as_widget: value = parent_values elif parent_values is not NOT_SET: - if not self.multiplatform: - value = parent_values - else: - value = parent_values.get(self.key, NOT_SET) + value = parent_values.get(self.key, NOT_SET) if value is NOT_SET: if self.develop_mode: - 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 + value = self.default_input_value if value is NOT_SET: raise NotImplementedError(( "{} Does not have implemented" @@ -2975,13 +2970,10 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._is_modified = False value = NOT_SET - if self._as_widget: + if self.as_widget: value = parent_values elif parent_values is not NOT_SET: - if not self.multiplatform: - value = parent_values - else: - value = parent_values.get(self.key, NOT_SET) + value = parent_values.get(self.key, NOT_SET) self.studio_value = value if value is not NOT_SET: @@ -2990,7 +2982,6 @@ class PathWidget(QtWidgets.QWidget, SettingObject): else: self._has_studio_override = False self._had_studio_override = False - value = self.default_value # TODO handle invalid value type self.input_field.update_studio_values(value) @@ -3004,10 +2995,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): if self._as_widget: override_values = parent_values elif parent_values is not NOT_SET: - if not self.multiplatform: - override_values = parent_values - else: - override_values = parent_values.get(self.key, NOT_SET) + 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) @@ -3075,7 +3063,7 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self.style().polish(self) self._child_state = child_state - if not self._as_widget: + if self.label_widget: state = self.style_state( child_has_studio_override, child_invalid, @@ -3106,30 +3094,36 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._has_studio_override = True def discard_changes(self): - self._is_modified = False self._is_overriden = self._was_overriden + self._has_studio_override = self._had_studio_override self.input_field.discard_changes() - self._is_modified = self.child_modified + if not self.is_overidable: + 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 + + self._is_modified = False + self._is_overriden = self._was_overriden def set_as_overriden(self): self._is_overriden = True @property def child_has_studio_override(self): - return ( - self.input_field.has_studio_override - or self.input_field.child_has_studio_override - ) + return self.has_studio_override @property def child_modified(self): - return self.input_field.child_modified + return self.is_modified @property def child_overriden(self): - return self.input_field.child_overriden + return self.is_overriden @property def child_invalid(self): From 4f61d84612bbcb1c3705611b6657fa6e7c3015a7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 23 Sep 2020 19:41:34 +0200 Subject: [PATCH 60/63] fix raw json item_value method --- 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 0419c48c5c..ec315acaf5 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1182,7 +1182,7 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): def item_value(self): if self.is_invalid: return NOT_SET - return self.text_input.json_value() + return self.input_field.json_value() class ListItem(QtWidgets.QWidget, SettingObject): From ce29b1e8623e3dba1436db4fc96d3d3d1ea9b86e Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 24 Sep 2020 10:38:18 +0200 Subject: [PATCH 61/63] 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 62/63] 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 53dc5e20dd8953726f0ee6ed0f679cde8093430d Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 24 Sep 2020 14:55:54 +0200 Subject: [PATCH 63/63] switch maya capture to invidible dictionary --- .../plugins/maya/maya/maya_capture.json | 26 +- .../projects_schema/1_plugins_gui_schema.json | 1149 ++++++++--------- .../projects_schema/2_maya_capture.json | 193 ++- 3 files changed, 693 insertions(+), 675 deletions(-) diff --git a/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json b/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json index b6c4893034..02e6a9b95d 100644 --- a/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json +++ b/pype/settings/defaults/project_settings/plugins/maya/maya/maya_capture.json @@ -6,19 +6,19 @@ }, "Display Options": { "background": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 + 0.714, + 0.714, + 0.714 ], "backgroundBottom": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 + 0.714, + 0.714, + 0.714 ], "backgroundTop": [ - 0.7137254901960784, - 0.7137254901960784, - 0.7137254901960784 + 0.714, + 0.714, + 0.714 ], "override_display": true }, @@ -40,15 +40,15 @@ "rendererName": "vp2Renderer" }, "Resolution": { + "width": 1920, "height": 1080, - "mode": "Custom", "percent": 1.0, - "width": 1920 + "mode": "Custom" }, "Time Range": { + "start_frame": 0, "end_frame": 25, "frame": "", - "start_frame": 0, "time": "Time Slider" }, "Viewport Options": { @@ -105,4 +105,4 @@ "displayFilmOrigin": false, "overscan": 1.0 } -} +} \ No newline at end of file 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 ea015edfc5..87912cfdc0 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 @@ -3,683 +3,612 @@ "collapsable": true, "key": "plugins", "label": "Plugins", - "children": [ - { + "children": [{ "type": "dict", "collapsable": true, "key": "celaction", "label": "CelAction", - "children": [ - { + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ "type": "dict", "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractCelactionDeadline", - "label": "ExtractCelactionDeadline", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "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" - } - ] - } - ] - } - ] + "checkbox_key": "enabled", + "key": "ExtractCelactionDeadline", + "label": "ExtractCelactionDeadline", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "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": "dict", "collapsable": true, "key": "ftrack", "label": "Ftrack", - "children": [ - { + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ "type": "dict", "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "IntegrateFtrackNote", - "label": "IntegrateFtrackNote", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "note_with_intent_template", - "label": "Note with intent template" - }, { - "type": "list", - "object_type": "text", - "key": "note_labels", - "label": "Note labels" - } - ] - } - ] - } - ] + "checkbox_key": "enabled", + "key": "IntegrateFtrackNote", + "label": "IntegrateFtrackNote", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text", + "key": "note_with_intent_template", + "label": "Note with intent template" + }, { + "type": "list", + "object_type": "text", + "key": "note_labels", + "label": "Note labels" + }] + }] + }] }, { "type": "dict", "collapsable": true, "key": "global", "label": "Global", - "children": [ - { + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ "type": "dict", "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "IntegrateMasterVersion", - "label": "IntegrateMasterVersion", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] + "checkbox_key": "enabled", + "key": "IntegrateMasterVersion", + "label": "IntegrateMasterVersion", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractJpegEXR", + "label": "ExtractJpegEXR", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "dict-invisible", + "key": "ffmpeg_args", + "children": [{ + "type": "list", + "object_type": "text", + "key": "input", + "label": "FFmpeg input arguments" }, { + "type": "list", + "object_type": "text", + "key": "output", + "label": "FFmpeg output arguments" + }] + }] + }, { + "type": "dict", + "collapsable": true, + "key": "ExtractReview", + "label": "ExtractReview", + "checkbox_key": "enabled", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": { "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractJpegEXR", - "label": "ExtractJpegEXR", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "dict-invisible", - "key": "ffmpeg_args", - "children": [ - { - "type": "list", - "object_type": "text", - "key": "input", - "label": "FFmpeg input arguments" - }, { - "type": "list", - "object_type": "text", - "key": "output", - "label": "FFmpeg output arguments" - } - ] - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ExtractReview", - "label": "ExtractReview", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": { - "type": "dict", - "children": [ + "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": { + "type": "dict", + "children": [{ + "key": "ext", + "label": "Output extension", + "type": "text" + }, { + "key": "tags", + "label": "Tags", + "type": "enum", + "multiselection": true, + "enum_items": [{ + "burnin": "Add burnins" + }, { - "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": { - "type": "dict", - "children": [ - { - "key": "ext", - "label": "Output extension", - "type": "text" - }, { - "key": "tags", - "label": "Tags", - "type": "enum", - "multiselection": true, - "enum_items": [ - {"burnin": "Add burnins"}, - {"ftrackreview": "Add to Ftrack"}, - {"delete": "Delete output"}, - {"slate-frame": "Add slate frame"}, - {"no-hnadles": "Skip handle frames"} - ] - }, { - "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" - } - ] - } - ] - } + "ftrackreview": "Add to Ftrack" + }, + { + "delete": "Delete output" + }, + { + "slate-frame": "Add slate frame" + }, + { + "no-hnadles": "Skip handle frames" } ] - } + }, { + "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" + }] + }] } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ExtractBurnin", - "label": "ExtractBurnin", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "dict", - "collapsable": true, - "key": "options", - "label": "Burnin formating options", - "children": [ - { - "type": "number", - "key": "font_size", - "label": "Font size" - }, { - "type": "number", - "key": "opacity", - "label": "Font opacity" - }, { - "type": "number", - "key": "bg_opacity", - "label": "Background opacity" - }, { - "type": "number", - "key": "x_offset", - "label": "X Offset" - }, { - "type": "number", - "key": "y_offset", - "label": "Y Offset" - }, { - "type": "number", - "key": "bg_padding", - "label": "Padding aroung text" - } - ] - }, { - "type": "raw-json", - "key": "profiles", - "label": "Burnin profiles" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "IntegrateAssetNew", - "label": "IntegrateAssetNew", - "is_group": true, - "children": [ - { - "type": "raw-json", - "key": "template_name_profiles", - "label": "template_name_profiles" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ProcessSubmittedJobOnFarm", - "label": "ProcessSubmittedJobOnFarm", - "checkbox_key": "enabled", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "text", - "key": "deadline_department", - "label": "Deadline department" - }, { - "type": "text", - "key": "deadline_pool", - "label": "Deadline Pool" - }, { - "type": "text", - "key": "deadline_group", - "label": "Deadline Group" - } - ] + }] } - ] - } - ] + }] + }, { + "type": "dict", + "collapsable": true, + "key": "ExtractBurnin", + "label": "ExtractBurnin", + "checkbox_key": "enabled", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "dict", + "collapsable": true, + "key": "options", + "label": "Burnin formating options", + "children": [{ + "type": "number", + "key": "font_size", + "label": "Font size" + }, { + "type": "number", + "key": "opacity", + "label": "Font opacity" + }, { + "type": "number", + "key": "bg_opacity", + "label": "Background opacity" + }, { + "type": "number", + "key": "x_offset", + "label": "X Offset" + }, { + "type": "number", + "key": "y_offset", + "label": "Y Offset" + }, { + "type": "number", + "key": "bg_padding", + "label": "Padding aroung text" + }] + }, { + "type": "raw-json", + "key": "profiles", + "label": "Burnin profiles" + }] + }, { + "type": "dict", + "collapsable": true, + "key": "IntegrateAssetNew", + "label": "IntegrateAssetNew", + "is_group": true, + "children": [{ + "type": "raw-json", + "key": "template_name_profiles", + "label": "template_name_profiles" + }] + }, { + "type": "dict", + "collapsable": true, + "key": "ProcessSubmittedJobOnFarm", + "label": "ProcessSubmittedJobOnFarm", + "checkbox_key": "enabled", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "text", + "key": "deadline_department", + "label": "Deadline department" + }, { + "type": "text", + "key": "deadline_pool", + "label": "Deadline Pool" + }, { + "type": "text", + "key": "deadline_group", + "label": "Deadline Group" + }] + }] + }] }, { "type": "dict-invisible", "collapsable": true, "key": "maya", "label": "Maya", - "children": [ - { - "type": "dict", - "collapsable": true, - "key": "maya", - "label": "Maya", - "children": [ + "children": [{ + "type": "dict", + "collapsable": true, + "key": "maya", + "label": "Maya", + "children": [ + { - "type": "schema", - "children": [ - "2_maya_capture", - "2_maya_plugins", - "2_maya_workfiles" - ] + "type": "schema", + "name": "2_maya_capture" + }, + { + "type": "schema", + "name": "2_maya_plugins" + }, + { + "type": "schema", + "name": "2_maya_workfiles" } ] - } - ] + }] }, { "type": "dict", "collapsable": true, "key": "nuke", "label": "Nuke", - "children": [ - { + "children": [{ + "type": "dict", + "collapsable": true, + "key": "create", + "label": "Create plugins", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": false, + "key": "CreateWriteRender", + "label": "CreateWriteRender", + "is_group": true, + "children": [{ + "type": "text", + "key": "fpath_template", + "label": "Path template" + }] + }, { + "type": "dict", + "collapsable": false, + "key": "CreateWritePrerender", + "label": "CreateWritePrerender", + "is_group": true, + "children": [{ + "type": "text", + "key": "fpath_template", + "label": "Path template" + }] + }] + }, { + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ "type": "dict", "collapsable": true, - "key": "create", - "label": "Create plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": false, - "key": "CreateWriteRender", - "label": "CreateWriteRender", - "is_group": true, - "children": [ - { - "type": "text", - "key": "fpath_template", - "label": "Path template" - } - ] - }, { - "type": "dict", - "collapsable": false, - "key": "CreateWritePrerender", - "label": "CreateWritePrerender", - "is_group": true, - "children": [ - { - "type": "text", - "key": "fpath_template", - "label": "Path template" - } - ] - } - ] + "checkbox_key": "enabled", + "key": "ExtractThumbnail", + "label": "ExtractThumbnail", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "raw-json", + "key": "nodes", + "label": "Nodes" + }] }, { "type": "dict", "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractThumbnail", - "label": "ExtractThumbnail", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "raw-json", - "key": "nodes", - "label": "Nodes" - } - ] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ValidateNukeWriteKnobs", - "label": "ValidateNukeWriteKnobs", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "raw-json", - "key": "knobs", - "label": "Knobs" - } - ] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractReviewDataLut", - "label": "ExtractReviewDataLut", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractReviewDataMov", - "label": "ExtractReviewDataMov", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "boolean", - "key": "viewer_lut_raw", - "label": "Viewer LUT raw" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "ExtractSlateFrame", - "label": "ExtractSlateFrame", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "viewer_lut_raw", - "label": "Viewer LUT raw" - } - ] - }, { - "type": "dict", - "collapsable": true, - "key": "NukeSubmitDeadline", - "label": "NukeSubmitDeadline", - "is_group": true, - "children": [ - { - "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": "number", - "key": "deadline_chunk_size", - "label": "deadline_chunk_size" - } - ] - } - ] + "checkbox_key": "enabled", + "key": "ValidateNukeWriteKnobs", + "label": "ValidateNukeWriteKnobs", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "raw-json", + "key": "knobs", + "label": "Knobs" + }] }, { - "type": "raw-json", - "key": "workfile_build", - "label": "Workfile Build logic", - "is_file": true - } - ] + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractReviewDataLut", + "label": "ExtractReviewDataLut", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractReviewDataMov", + "label": "ExtractReviewDataMov", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw" + }] + }, { + "type": "dict", + "collapsable": true, + "key": "ExtractSlateFrame", + "label": "ExtractSlateFrame", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "viewer_lut_raw", + "label": "Viewer LUT raw" + }] + }, { + "type": "dict", + "collapsable": true, + "key": "NukeSubmitDeadline", + "label": "NukeSubmitDeadline", + "is_group": true, + "children": [{ + "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": "number", + "key": "deadline_chunk_size", + "label": "deadline_chunk_size" + }] + }] + }, { + "type": "raw-json", + "key": "workfile_build", + "label": "Workfile Build logic", + "is_file": true + }] }, { "type": "dict", "collapsable": true, "key": "nukestudio", "label": "NukeStudio", - "children": [ - { + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "children": [{ "type": "dict", "collapsable": true, - "key": "publish", - "label": "Publish plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "CollectInstanceVersion", - "label": "Collect Instance Version", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - } - ] - }, { - "type": "dict", - "collapsable": true, - "checkbox_key": "enabled", - "key": "ExtractReviewCutUpVideo", - "label": "Extract Review Cut Up Video", - "is_group": true, - "children": [ - { - "type": "boolean", - "key": "enabled", - "label": "Enabled" - }, { - "type": "list", - "object_type": "text", - "key": "tags_addition", - "label": "Tags addition" - } - ] - } - ] - } - ] + "checkbox_key": "enabled", + "key": "CollectInstanceVersion", + "label": "Collect Instance Version", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }] + }, { + "type": "dict", + "collapsable": true, + "checkbox_key": "enabled", + "key": "ExtractReviewCutUpVideo", + "label": "Extract Review Cut Up Video", + "is_group": true, + "children": [{ + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, { + "type": "list", + "object_type": "text", + "key": "tags_addition", + "label": "Tags addition" + }] + }] + }] }, { "type": "dict", "collapsable": true, "key": "resolve", "label": "DaVinci Resolve", - "children": [ - { - "type": "dict", - "collapsable": true, - "key": "create", - "label": "Creator plugins", - "is_file": true, - "children": [ - { - "type": "dict", - "collapsable": true, - "key": "CreateShotClip", - "label": "Create Shot Clip", - "is_group": true, - "children": [ - { - "type": "text", - "key": "clipName", - "label": "Clip name template" - }, { - "type": "text", - "key": "folder", - "label": "Folder" - }, { - "type": "number", - "key": "steps", - "label": "Steps" - } - ] - } + "children": [{ + "type": "dict", + "collapsable": true, + "key": "create", + "label": "Creator plugins", + "is_file": true, + "children": [{ + "type": "dict", + "collapsable": true, + "key": "CreateShotClip", + "label": "Create Shot Clip", + "is_group": true, + "children": [{ + "type": "text", + "key": "clipName", + "label": "Clip name template" + }, { + "type": "text", + "key": "folder", + "label": "Folder" + }, { + "type": "number", + "key": "steps", + "label": "Steps" + }] + } - ] - } - ] + ] + }] }, { "type": "dict", "collapsable": true, "key": "standalonepublisher", "label": "Standalone Publisher", - "children": [ - { + "children": [{ + "type": "dict", + "collapsable": true, + "key": "publish", + "label": "Publish plugins", + "is_file": true, + "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" - } - ] - } - ] - } - ] - } - ] + "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" + } + ] + }] + }] + }] } ] } diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json index a7b44323d2..836ad90404 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/2_maya_capture.json @@ -6,11 +6,15 @@ "is_file": true, "children": [ { - "type": "dict", - "collapsable": true, + "type": "dict-invisible", "key": "Codec", "label": "Codec", + "collapsable": false, "children": [ + { + "type": "label", + "label": "Codec" + }, { "type": "text", "key": "compression", @@ -26,72 +30,137 @@ "decimal": 0, "minimum": 0, "maximum": 100 + }, + + { + "type": "splitter" } ] }, { - "type": "dict", - "collapsable": true, + "type": "dict-invisible", "key": "Display Options", "label": "Display Options", + "collapsable": false, "children": [ { - "type": "list", + "type": "label", + "label": "Display Options" + }, + { + "type": "list-strict", "key": "background", - "label": "Background Color", - "object_type": "number", - "input_modifiers": { - "decimal": 3, - "minimum": 0, - "maximum": 1 - } - }, { - "type": "list", - "key": "backgroundBottom", - "label": "Bottom Background Color", - "object_type": "number", - "input_modifiers": { - "decimal": 3, - "minimum": 0, - "maximum": 1 - } - }, { - "type": "list", - "key": "backgroundTop", - "label": "Top Background Color", - "object_type": "number", - "input_modifiers": { - "decimal": 3, - "minimum": 0, - "maximum": 1 - } - }, { + "label": "Background Color: ", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + }, { + "type": "list-strict", + "key": "backgroundBottom", + "label": "Background Bottom: ", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + }, { + "type": "list-strict", + "key": "backgroundTop", + "label": "Background Top: ", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 3 + } + ] + }, { "type": "boolean", "key": "override_display", "label": "Override display options" } ] - }, { - "type": "dict", + }, + { + "type": "splitter" + } , + { + "type": "dict-invisible", "collapsable": true, "key": "Generic", "label": "Generic", "children": [ + { + "type": "label", + "label": "Generic" + }, { "type": "boolean", "key": "isolate_view", - "label": "Isolate view" + "label": " Isolate view" },{ "type": "boolean", "key": "off_screen", - "label": "Off Screen" + "label": " Off Screen" } ] },{ - "type": "dict", + "type": "dict-invisible", "collapsable": true, "key": "IO", "label": "IO", "children": [ + { + "type": "label", + "label": "IO" + }, { "type": "text", "key": "name", @@ -107,7 +176,7 @@ },{ "type": "list", "key": "recent_playblasts", - "label": "Recent playbacks", + "label": "Recent Playblasts", "object_type": "text" },{ "type": "boolean", @@ -116,7 +185,7 @@ } ] },{ - "type": "dict", + "type": "dict-invisible", "collapsable": true, "key": "PanZoom", "label": "Pan Zoom", @@ -124,31 +193,47 @@ { "type": "boolean", "key": "pan_zoom", - "label": "Pan Zoom" + "label": " Pan Zoom" } ] + }, + { + "type": "splitter" },{ - "type": "dict", + "type": "dict-invisible", "collapsable": true, "key": "Renderer", "label": "Renderer", "children": [ + + { + "type": "label", + "label": "Renderer" + }, { "type": "text", "key": "rendererName", - "label": "Renderer name" + "label": " Renderer name" } ] },{ - "type": "dict", + "type": "dict-invisible", "collapsable": true, "key": "Resolution", "label": "Resolution", "children": [ + + { + "type": "splitter" + }, + { + "type": "label", + "label": "Resolution" + }, { "type": "number", "key": "width", - "label": "Width", + "label": " Width", "decimal": 0, "minimum": 0, "maximum": 99999 @@ -172,16 +257,24 @@ "label": "Mode" } ] - },{ - "type": "dict", + }, + { + "type": "splitter" + }, + { + "type": "dict-invisible", "collapsable": true, "key": "Time Range", "label": "Time Range", "children": [ + { + "type": "label", + "label": "Time Range" + }, { "type": "number", "key": "start_frame", - "label": "Start frame", + "label": " Start frame", "decimal": 0, "minimum": 0, "maximum": 999999 @@ -192,10 +285,6 @@ "decimal": 0, "minimum": 0, "maximum": 999999 - },{ - "type": "text", - "key": "mode", - "label": "Mode" },{ "type": "text", "key": "frame",