From 75fd8c666ee0fc7b867386486a9a9ac13aa13bd1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:09:03 +0200 Subject: [PATCH 01/25] added possibility to set placeholder for text input --- pype/tools/settings/settings/widgets/item_types.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 68cebf6642..fea78b713b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -906,6 +906,7 @@ class TextWidget(QtWidgets.QWidget, InputObject): self.initial_attributes(input_data, parent, as_widget) self.multiline = input_data.get("multiline", False) + placeholder = input_data.get("placeholder") layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) @@ -916,6 +917,9 @@ class TextWidget(QtWidgets.QWidget, InputObject): else: self.text_input = QtWidgets.QLineEdit(self) + if placeholder: + self.text_input.setPlaceholderText(placeholder) + self.setFocusProxy(self.text_input) layout_kwargs = {} From a28e154580c4bb5eef3dcbc38c280a3bb8780c02 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:09:09 +0200 Subject: [PATCH 02/25] added info to README --- pype/tools/settings/settings/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..da8868199a 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -111,6 +111,7 @@ ### text - simple text input - key `"multiline"` allows to enter multiple lines of text (Default: `False`) + - key `"placeholder"` allows to show text inside input when is empty (Default: `None`) ``` { From 98569e4fed3469f7bb19a4b4923dfff1c2ae4add Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:14:45 +0200 Subject: [PATCH 03/25] schema item does not have key `children` but `name`, schema type can represent only one schema name --- pype/tools/settings/settings/widgets/lib.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/lib.py b/pype/tools/settings/settings/widgets/lib.py index e225d65417..f54989cfd7 100644 --- a/pype/tools/settings/settings/widgets/lib.py +++ b/pype/tools/settings/settings/widgets/lib.py @@ -69,12 +69,11 @@ def _fill_inner_schemas(schema_data, schema_collection): new_children.append(new_child) continue - for schema_name in child["children"]: - new_child = _fill_inner_schemas( - schema_collection[schema_name], - schema_collection - ) - new_children.append(new_child) + new_child = _fill_inner_schemas( + schema_collection[child["name"]], + schema_collection + ) + new_children.append(new_child) schema_data["children"] = new_children return schema_data From 44dc6805ade48fd2edd94bb1db1479afdc84f0a8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:14:56 +0200 Subject: [PATCH 04/25] modified current schemas --- .../projects_schema/0_project_gui_schema.json | 4 +--- .../system_schema/0_system_gui_schema.json | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json index fa7c6a366d..cf95bf4c45 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/0_project_gui_schema.json @@ -22,9 +22,7 @@ "children": [ { "type": "schema", - "children": [ - "1_plugins_gui_schema" - ] + "name": "1_plugins_gui_schema" } ] } diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json index b16545111c..456af7ac0f 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/0_system_gui_schema.json @@ -7,12 +7,16 @@ "key": "global", "children": [{ "type": "schema", - "children": [ - "1_tray_items", - "1_applications_gui_schema", - "1_tools_gui_schema", - "1_intents_gui_schema" - ] + "name": "1_tray_items" + }, { + "type": "schema", + "name": "1_applications_gui_schema" + }, { + "type": "schema", + "name": "1_tools_gui_schema" + }, { + "type": "schema", + "name": "1_intents_gui_schema" }] }, { "type": "dict-invisible", @@ -29,6 +33,9 @@ "label": "Muster - Templates mapping", "is_file": true }] + }, { + "type": "schema", + "name": "1_examples" } ] } From aa472d66de0eb674bad32cc31747a38710eeea09 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 14:15:02 +0200 Subject: [PATCH 05/25] modified README --- pype/tools/settings/settings/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..adacd62772 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -27,10 +27,7 @@ ``` { "type": "schema", - "children": [ - "my_schema_name", - "my_other_schema_name" - ] + "name": "my_schema_name" } ``` From 2ee94bd890d0f86052f4d6278f751383d688a82b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:33:07 +0200 Subject: [PATCH 06/25] ListItem can be set as strict --- .../settings/settings/widgets/item_types.py | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 68cebf6642..8c9fbd8640 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1291,11 +1291,16 @@ class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) - def __init__(self, object_type, input_modifiers, config_parent, parent): + def __init__( + self, object_type, input_modifiers, config_parent, parent, + is_strict=False + ): super(ListItem, self).__init__(parent) self._set_default_attributes() + self._is_strict = is_strict + self._parent = config_parent self._any_parent_is_group = True self._is_empty = False @@ -1307,34 +1312,38 @@ class ListItem(QtWidgets.QWidget, SettingObject): char_up = qtawesome.charmap("fa.angle-up") char_down = qtawesome.charmap("fa.angle-down") - self.add_btn = QtWidgets.QPushButton("+") - self.remove_btn = QtWidgets.QPushButton("-") - self.up_btn = QtWidgets.QPushButton(char_up) - self.down_btn = QtWidgets.QPushButton(char_down) + if not self._is_strict: + self.add_btn = QtWidgets.QPushButton("+") + self.remove_btn = QtWidgets.QPushButton("-") + self.up_btn = QtWidgets.QPushButton(char_up) + self.down_btn = QtWidgets.QPushButton(char_down) - font_up_down = qtawesome.font("fa", 13) - self.up_btn.setFont(font_up_down) - self.down_btn.setFont(font_up_down) + font_up_down = qtawesome.font("fa", 13) + self.up_btn.setFont(font_up_down) + self.down_btn.setFont(font_up_down) - self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - self.up_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - self.down_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.add_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.remove_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.up_btn.setFocusPolicy(QtCore.Qt.ClickFocus) + self.down_btn.setFocusPolicy(QtCore.Qt.ClickFocus) - self.add_btn.setFixedSize(self._btn_size, self._btn_size) - self.remove_btn.setFixedSize(self._btn_size, self._btn_size) - self.up_btn.setFixedSize(self._btn_size, self._btn_size) - self.down_btn.setFixedSize(self._btn_size, self._btn_size) + self.add_btn.setFixedSize(self._btn_size, self._btn_size) + self.remove_btn.setFixedSize(self._btn_size, self._btn_size) + self.up_btn.setFixedSize(self._btn_size, self._btn_size) + self.down_btn.setFixedSize(self._btn_size, self._btn_size) - self.add_btn.setProperty("btn-type", "tool-item") - self.remove_btn.setProperty("btn-type", "tool-item") - self.up_btn.setProperty("btn-type", "tool-item") - self.down_btn.setProperty("btn-type", "tool-item") + self.add_btn.setProperty("btn-type", "tool-item") + self.remove_btn.setProperty("btn-type", "tool-item") + self.up_btn.setProperty("btn-type", "tool-item") + self.down_btn.setProperty("btn-type", "tool-item") - self.add_btn.clicked.connect(self._on_add_clicked) - self.remove_btn.clicked.connect(self._on_remove_clicked) - self.up_btn.clicked.connect(self._on_up_clicked) - self.down_btn.clicked.connect(self._on_down_clicked) + self.add_btn.clicked.connect(self._on_add_clicked) + self.remove_btn.clicked.connect(self._on_remove_clicked) + self.up_btn.clicked.connect(self._on_up_clicked) + self.down_btn.clicked.connect(self._on_down_clicked) + + layout.addWidget(self.add_btn, 0) + layout.addWidget(self.remove_btn, 0) ItemKlass = TypeToKlass.types[object_type] self.value_input = ItemKlass( @@ -1344,18 +1353,17 @@ class ListItem(QtWidgets.QWidget, SettingObject): label_widget=None ) - self.spacer_widget = QtWidgets.QWidget(self) - self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - self.spacer_widget.setVisible(False) - - layout.addWidget(self.add_btn, 0) - layout.addWidget(self.remove_btn, 0) - layout.addWidget(self.value_input, 1) - layout.addWidget(self.spacer_widget, 1) - layout.addWidget(self.up_btn, 0) - layout.addWidget(self.down_btn, 0) + if not self._is_strict: + self.spacer_widget = QtWidgets.QWidget(self) + self.spacer_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + self.spacer_widget.setVisible(False) + + layout.addWidget(self.spacer_widget, 1) + + layout.addWidget(self.up_btn, 0) + layout.addWidget(self.down_btn, 0) self.value_input.value_changed.connect(self._on_value_change) From 0cccd9e3a7fe7a12866ba627f8d6770813838eca Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:44:55 +0200 Subject: [PATCH 07/25] implemented strict list --- .../settings/settings/widgets/item_types.py | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8c9fbd8640..7afa6fca18 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1705,6 +1705,153 @@ class ListWidget(QtWidgets.QWidget, InputObject): return output +class ListStrictWidget(QtWidgets.QWidget, InputObject): + value_changed = QtCore.Signal(object) + _default_input_value = None + + def __init__( + self, input_data, parent, + as_widget=False, label_widget=None, parent_widget=None + ): + if parent_widget is None: + parent_widget = parent + super(ListStrictWidget, self).__init__(parent_widget) + self.setObjectName("ListStrictWidget") + + horizontal = input_data.get("horizontal", True) + + self.initial_attributes(input_data, parent, as_widget) + + self.input_fields = [] + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 5) + layout.setSpacing(5) + + if not self.as_widget: + self.key = input_data["key"] + if not label_widget: + label_widget = QtWidgets.QLabel(input_data["label"], self) + layout.addWidget(label_widget, alignment=QtCore.Qt.AlignTop) + + self.label_widget = label_widget + + inputs_widget = QtWidgets.QWidget(self) + inputs_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + layout.addWidget(inputs_widget) + + if horizontal: + inputs_layout = QtWidgets.QHBoxLayout(inputs_widget) + else: + inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout.setContentsMargins(0, 0, 0, 0) + inputs_layout.setSpacing(3) + + self.inputs_widget = inputs_widget + self.inputs_layout = inputs_layout + + for child_configuration in input_data["object_types"]: + object_type = child_configuration["type"] + + proxy_widget = QtWidgets.QWidget(self) + proxy_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + item_widget = ListItem( + object_type, child_configuration, self, proxy_widget, + is_strict=True + ) + + self.input_fields.append(item_widget) + item_widget.value_changed.connect(self._on_value_change) + + proxy_layout = QtWidgets.QHBoxLayout(proxy_widget) + proxy_layout.setContentsMargins(0, 0, 0, 0) + proxy_layout.setSpacing(5) + + label = child_configuration.get("label") + label_widget = None + if label: + label_widget = QtWidgets.QLabel(label, self) + proxy_layout.addWidget(label_widget, 0) + + proxy_layout.addWidget(item_widget, 0) + + if not horizontal: + spacer_widget = QtWidgets.QWidget(proxy_widget) + proxy_layout.addWidget(spacer_widget, 1) + + self.inputs_layout.addWidget(proxy_widget) + + if horizontal: + spacer_widget = QtWidgets.QWidget(proxy_widget) + self.inputs_layout.addWidget(spacer_widget, 1) + + self.updateGeometry() + + @property + def default_input_value(self): + if self._default_input_value is None: + self.set_value(NOT_SET) + self._default_input_value = self.item_value() + return self._default_input_value + + def set_value(self, value): + if self._is_overriden: + method_name = "apply_overrides" + elif not self._has_studio_override: + method_name = "update_default_values" + else: + method_name = "update_studio_values" + + for idx, input_field in enumerate(self.input_fields): + if value is NOT_SET: + _value = value + else: + if idx > len(value) - 1: + _value = NOT_SET + else: + _value = value[idx] + _method = getattr(input_field, method_name) + _method(_value) + + def hierarchical_style_update(self): + for input_field in self.input_fields: + input_field.hierarchical_style_update() + self.update_style() + + def update_style(self): + if self._as_widget: + if not self.isEnabled(): + state = self.style_state(False, False, False, False) + else: + state = self.style_state( + False, + self._is_invalid, + False, + self._is_modified + ) + else: + state = self.style_state( + self.has_studio_override, + self.is_invalid, + self.is_overriden, + self.is_modified + ) + + if self._state == state: + return + + if self.label_widget: + self.label_widget.setProperty("state", state) + self.label_widget.style().polish(self.label_widget) + + def item_value(self): + output = [] + for item in self.input_fields: + output.append(item.config_value()) + return output + + class ModifiableDictItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) @@ -3360,6 +3507,7 @@ TypeToKlass.types["text"] = TextWidget TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget +TypeToKlass.types["list-strict"] = ListStrictWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict TypeToKlass.types["dict-item"] = DictItemWidget TypeToKlass.types["dict"] = DictWidget From a13755c341d67a91b9a70ce23440c16ce0d544d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:46:08 +0200 Subject: [PATCH 08/25] make sure defaults_not_set is set to False if defaults are available --- pype/tools/settings/settings/widgets/item_types.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 7afa6fca18..4a9e092a99 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -547,6 +547,7 @@ class InputObject(SettingObject): Class is for item types not creating or using other item types, most of methods has same code in that case. """ + def update_default_values(self, parent_values): self._state = None self._is_modified = False @@ -559,8 +560,8 @@ class InputObject(SettingObject): if value is NOT_SET: if self.develop_mode: - value = self.default_input_value self.defaults_not_set = True + value = self.default_input_value if value is NOT_SET: raise NotImplementedError(( "{} Does not have implemented" @@ -571,6 +572,8 @@ class InputObject(SettingObject): raise ValueError( "Default value is not set. This is implementation BUG." ) + else: + self.defaults_not_set = False self.default_value = value self._has_studio_override = False @@ -3024,6 +3027,8 @@ class PathWidget(QtWidgets.QWidget, SettingObject): raise ValueError( "Default value is not set. This is implementation BUG." ) + else: + self.defaults_not_set = False self.default_value = value self._has_studio_override = False From d3e61cea7dd01d4d950c9786d9184d20a0b59485 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:46:24 +0200 Subject: [PATCH 09/25] added strict list and dict-item to readme --- pype/tools/settings/settings/README.md | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..9d12467cc9 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -207,6 +207,85 @@ } ``` +### dict-item +- item represents dictionary with strict keys in and data types of its values +- can be used only as widget (in `list` or `dict-modifiable`) + - only key modifier is `children` which is list of it's keys +- USAGE: e.g. List of dictionaries where each dictionary have same structure. + +``` +{ + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ... + ] + } +} +``` + +### list-strict +- input for strict number of items in list +- each child item can be different type with different possible modifiers +- it is possible to display them in horizontal or vertical layout + - key `"horizontal"` as `True`/`False` (Default: `True`) +- each child may have defined `"label"` which is shown next to input + - label does not reflect modifications or overrides (TODO) +- children item are defined under key `"object_types"` which is list of dictionaries + - key `"children"` is not used because is used for hierarchy validations in schema +- USAGE: For colors, transformations, etc. Custom number and different modifiers + give ability to define if color is HUE or RGB, 0-255, 0-1, 0-100 etc. + +``` +{ + "type": "list-strict", + "key": "color", + "label": "Color", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] +} +``` + + ## Noninteractive widgets - have nothing to do with data From 060aa04f93f6999ddc9146ba762d81eb9ffeb8fa Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 17:49:16 +0200 Subject: [PATCH 10/25] added dict-item and list-strict to examples --- .../gui_schemas/system_schema/1_examples.json | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json index 73f72c875c..1284c9948b 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -72,6 +72,57 @@ "minimum": 10, "maximum": 100 } + }, { + "type": "list-strict", + "key": "strict_list", + "label": "StrictList (color)", + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] + }, { + "type": "list", + "key": "dict_item", + "label": "DictItem in List", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ] + } }, { "type": "path-widget", "key": "single_path_input", From 8f967c9d6df25f85bad8ef633890688f51a54aff Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:16:21 +0200 Subject: [PATCH 11/25] added more variants to list-strict --- .../gui_schemas/system_schema/1_examples.json | 91 ++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json index 1284c9948b..0578968508 100644 --- a/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json +++ b/pype/tools/settings/settings/gui_schemas/system_schema/1_examples.json @@ -74,8 +74,8 @@ } }, { "type": "list-strict", - "key": "strict_list", - "label": "StrictList (color)", + "key": "strict_list_labels_horizontal", + "label": "StrictList-labels-horizontal (color)", "object_types": [ { "label": "Red", @@ -103,6 +103,93 @@ "decimal": 6 } ] + }, { + "type": "list-strict", + "key": "strict_list_labels_vertical", + "label": "StrictList-labels-vertical (color)", + "horizontal": false, + "object_types": [ + { + "label": "Red", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Green", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Blue", + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "label": "Alpha", + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] + }, { + "type": "list-strict", + "key": "strict_list_nolabels_horizontal", + "label": "StrictList-nolabels-horizontal (color)", + "object_types": [ + { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] + }, { + "type": "list-strict", + "key": "strict_list_nolabels_vertical", + "label": "StrictList-nolabels-vertical (color)", + "horizontal": false, + "object_types": [ + { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 255, + "decimal": 0 + }, { + "type": "number", + "minimum": 0, + "maximum": 1, + "decimal": 6 + } + ] }, { "type": "list", "key": "dict_item", From 85a55b4f1b649c5d9d6bd3f27360ae2deaca6239 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:16:34 +0200 Subject: [PATCH 12/25] list-strict use grid layout now --- .../settings/settings/widgets/item_types.py | 90 ++++++++++++++----- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 4a9e092a99..01dab9ccc9 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1721,8 +1721,6 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): super(ListStrictWidget, self).__init__(parent_widget) self.setObjectName("ListStrictWidget") - horizontal = input_data.get("horizontal", True) - self.initial_attributes(input_data, parent, as_widget) self.input_fields = [] @@ -1739,58 +1737,91 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): self.label_widget = label_widget + self._add_children(layout, input_data) + + def _add_children(self, layout, input_data): inputs_widget = QtWidgets.QWidget(self) inputs_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) layout.addWidget(inputs_widget) + horizontal = input_data.get("horizontal", True) if horizontal: inputs_layout = QtWidgets.QHBoxLayout(inputs_widget) else: - inputs_layout = QtWidgets.QVBoxLayout(inputs_widget) + inputs_layout = QtWidgets.QGridLayout(inputs_widget) + inputs_layout.setContentsMargins(0, 0, 0, 0) inputs_layout.setSpacing(3) self.inputs_widget = inputs_widget self.inputs_layout = inputs_layout + children_item_mapping = [] for child_configuration in input_data["object_types"]: object_type = child_configuration["type"] - proxy_widget = QtWidgets.QWidget(self) - proxy_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground) - item_widget = ListItem( - object_type, child_configuration, self, proxy_widget, + object_type, child_configuration, self, self.inputs_widget, is_strict=True ) self.input_fields.append(item_widget) item_widget.value_changed.connect(self._on_value_change) - proxy_layout = QtWidgets.QHBoxLayout(proxy_widget) - proxy_layout.setContentsMargins(0, 0, 0, 0) - proxy_layout.setSpacing(5) - label = child_configuration.get("label") label_widget = None if label: label_widget = QtWidgets.QLabel(label, self) - proxy_layout.addWidget(label_widget, 0) - proxy_layout.addWidget(item_widget, 0) - - if not horizontal: - spacer_widget = QtWidgets.QWidget(proxy_widget) - proxy_layout.addWidget(spacer_widget, 1) - - self.inputs_layout.addWidget(proxy_widget) + children_item_mapping.append((label_widget, item_widget)) if horizontal: - spacer_widget = QtWidgets.QWidget(proxy_widget) - self.inputs_layout.addWidget(spacer_widget, 1) + self._add_children_horizontally(children_item_mapping) + else: + self._add_children_vertically(children_item_mapping) self.updateGeometry() + def _add_children_vertically(self, children_item_mapping): + any_has_label = False + for item_mapping in children_item_mapping: + if item_mapping[0]: + any_has_label = True + break + + row = self.inputs_layout.count() + if not any_has_label: + self.inputs_layout.setColumnStretch(1, 1) + for item_mapping in children_item_mapping: + item_widget = item_mapping[1] + self.inputs_layout.addWidget(item_widget, row, 0, 1, 1) + + spacer_widget = QtWidgets.QWidget(self.inputs_widget) + self.inputs_layout.addWidget(spacer_widget, row, 1, 1, 1) + row += 1 + + else: + self.inputs_layout.setColumnStretch(2, 1) + for label_widget, item_widget in children_item_mapping: + self.inputs_layout.addWidget( + label_widget, row, 0, 1, 1, + alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop + ) + self.inputs_layout.addWidget(item_widget, row, 1, 1, 1) + + spacer_widget = QtWidgets.QWidget(self.inputs_widget) + self.inputs_layout.addWidget(spacer_widget, row, 2, 1, 1) + row += 1 + + def _add_children_horizontally(self, children_item_mapping): + for label_widget, item_widget in children_item_mapping: + if label_widget: + self.inputs_layout.addWidget(label_widget, 0) + self.inputs_layout.addWidget(item_widget, 0) + + spacer_widget = QtWidgets.QWidget(self.inputs_widget) + self.inputs_layout.addWidget(spacer_widget, 1) + @property def default_input_value(self): if self._default_input_value is None: @@ -1840,7 +1871,7 @@ class ListStrictWidget(QtWidgets.QWidget, InputObject): self.is_overriden, self.is_modified ) - + if self._state == state: return @@ -2630,6 +2661,18 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return {self.key: values}, self.is_group +class GridLabel(QtWidgets.QLabel): + def __init__(self, *args, **kwargs): + super(GridLabel, self).__init__(*args, **kwargs) + self.input_field = None + + def mouseReleaseEvent(self, event): + if self.input_field: + print("here", self.input_field) + self.input_field.mouseReleaseEvent(event) + return super(GridLabel, self).mouseReleaseEvent(event) + + class DictInvisible(QtWidgets.QWidget, SettingObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) @@ -2679,7 +2722,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidgets.QLabel(label, self) + label_widget = GridLabel(label, self) self.content_layout.addWidget( label_widget, row, 0, 1, 1, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop @@ -2689,6 +2732,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item.value_changed.connect(self._on_value_change) if label_widget: + label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) From dcb0db7937a94e438568308d942cbd13e76d48bc Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:19:51 +0200 Subject: [PATCH 13/25] reverse testing changes --- .../tools/settings/settings/widgets/item_types.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 01dab9ccc9..3bbf352f8b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2661,18 +2661,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): return {self.key: values}, self.is_group -class GridLabel(QtWidgets.QLabel): - def __init__(self, *args, **kwargs): - super(GridLabel, self).__init__(*args, **kwargs) - self.input_field = None - - def mouseReleaseEvent(self, event): - if self.input_field: - print("here", self.input_field) - self.input_field.mouseReleaseEvent(event) - return super(GridLabel, self).mouseReleaseEvent(event) - - class DictInvisible(QtWidgets.QWidget, SettingObject): # TODO is not overridable by itself value_changed = QtCore.Signal(object) @@ -2722,7 +2710,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = GridLabel(label, self) + label_widget = QtWidget.QLabel(label, self) self.content_layout.addWidget( label_widget, row, 0, 1, 1, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop @@ -2732,7 +2720,6 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): item.value_changed.connect(self._on_value_change) if label_widget: - label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) From cc8faba5bffbabec5e6f0d6f7d253ebd4a59aa8d Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 18 Sep 2020 18:20:52 +0200 Subject: [PATCH 14/25] typo fix --- pype/tools/settings/settings/widgets/item_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 3bbf352f8b..bf9155f765 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2710,7 +2710,7 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidget.QLabel(label, self) + label_widget = QtWidgets.QLabel(label, self) self.content_layout.addWidget( label_widget, row, 0, 1, 1, alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop From bbab7178c7ca1637ccdbcf7291a9209ebcd5954b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:53:27 +0200 Subject: [PATCH 15/25] DictWidget can be used as widget --- .../settings/settings/widgets/item_types.py | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 68cebf6642..8a88fbf829 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2132,18 +2132,26 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self, input_data, parent, as_widget=False, label_widget=None, parent_widget=None ): - if as_widget: - raise TypeError("Can't use \"{}\" as widget item.".format( - self.__class__.__name__ - )) - if parent_widget is None: parent_widget = parent super(DictWidget, self).__init__(parent_widget) - self.setObjectName("DictWidget") self.initial_attributes(input_data, parent, as_widget) + self.input_fields = [] + + self.checkbox_widget = None + self.checkbox_key = input_data.get("checkbox_key") + + self.label_widget = label_widget + + if self.as_widget: + self._ui_as_widget(input_data) + else: + self._ui_as_item(input_data) + + def _ui_as_item(self, input_data): + self.key = input_data["key"] if input_data.get("highlight_content", False): content_state = "hightlighted" bottom_margin = 5 @@ -2151,10 +2159,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): content_state = "" bottom_margin = 0 - self.input_fields = [] - - self.key = input_data["key"] - main_layout = QtWidgets.QHBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) @@ -2177,9 +2181,6 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.label_widget = body_widget.label_widget - self.checkbox_widget = None - self.checkbox_key = input_data.get("checkbox_key") - for child_data in input_data.get("children", []): self.add_children_gui(child_data) @@ -2194,6 +2195,22 @@ class DictWidget(QtWidgets.QWidget, SettingObject): else: body_widget.hide_toolbox(hide_content=False) + def _ui_as_widget(self, input_data): + body = QtWidgets.QWidget(self) + body.setObjectName("DictAsWidgetBody") + + content_layout = QtWidgets.QGridLayout(body) + content_layout.setContentsMargins(5, 5, 5, 5) + self.content_layout = content_layout + + layout = QtWidgets.QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(5) + layout.addWidget(body) + + for child_configuration in input_data["children"]: + self.add_children_gui(child_configuration) + def add_children_gui(self, child_configuration): item_type = child_configuration["type"] klass = TypeToKlass.types.get(item_type) From bd5e1ae310168996eda083fc008b190d8f671a64 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:55:16 +0200 Subject: [PATCH 16/25] minor tweaks in DictWidget to be able used as widget --- .../settings/settings/widgets/item_types.py | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 8a88fbf829..83805d9948 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -2297,8 +2297,12 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item.set_as_overriden() def update_default_values(self, parent_values): + # Make sure this is set to False + self._state = None + self._child_state = None + value = NOT_SET - if self._as_widget: + if self.as_widget: value = parent_values elif parent_values is not NOT_SET: value = parent_values.get(self.key, NOT_SET) @@ -2307,15 +2311,21 @@ class DictWidget(QtWidgets.QWidget, SettingObject): item.update_default_values(value) def update_studio_values(self, parent_values): + # Make sure this is set to False + self._state = None + self._child_state = None value = NOT_SET - if parent_values is not NOT_SET: - value = parent_values.get(self.key, NOT_SET) + if self.as_widget: + value = parent_values + else: + if parent_values is not NOT_SET: + value = parent_values.get(self.key, NOT_SET) - self._has_studio_override = False - if self.is_group and value is not NOT_SET: - self._has_studio_override = True + self._has_studio_override = False + if self.is_group and value is not NOT_SET: + self._has_studio_override = True - self._had_studio_override = bool(self._has_studio_override) + self._had_studio_override = bool(self._has_studio_override) for item in self.input_fields: item.update_studio_values(value) @@ -2325,37 +2335,40 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self._state = None self._child_state = None - metadata = {} - groups = tuple() - override_values = NOT_SET - if parent_values is not NOT_SET: - metadata = parent_values.get(METADATA_KEY) or metadata - groups = metadata.get("groups") or groups - override_values = parent_values.get(self.key, override_values) + if not self.as_widget: + metadata = {} + groups = tuple() + override_values = NOT_SET + if parent_values is not NOT_SET: + metadata = parent_values.get(METADATA_KEY) or metadata + groups = metadata.get("groups") or groups + override_values = parent_values.get(self.key, override_values) - self._is_overriden = self.key in groups + self._is_overriden = self.key in groups for item in self.input_fields: item.apply_overrides(override_values) - if not self._is_overriden: - self._is_overriden = ( - self.is_group - and self.is_overidable - and self.child_overriden - ) - self._was_overriden = bool(self._is_overriden) + if not self.as_widget: + if not self._is_overriden: + self._is_overriden = ( + self.is_group + and self.is_overidable + and self.child_overriden + ) + self._was_overriden = bool(self._is_overriden) def _on_value_change(self, item=None): if self.ignore_value_changes: return - if self.is_group and not self.any_parent_as_widget: + if self.is_group and not (self.as_widget or self.any_parent_as_widget): if self.is_overidable: self._is_overriden = True else: self._has_studio_override = True + # TODO check if this is required self.hierarchical_style_update() self.value_changed.emit(self) @@ -2368,6 +2381,10 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self.update_style() def update_style(self, is_overriden=None): + # TODO add style update when used as widget + if self.as_widget: + return + child_has_studio_override = self.child_has_studio_override child_modified = self.child_modified child_invalid = self.child_invalid From cbbbefc76dd939cbd5e327086825f4eb5d508033 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:56:25 +0200 Subject: [PATCH 17/25] "dict-item" is set to DictWidget for backwards compatibility --- pype/tools/settings/settings/widgets/item_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 83805d9948..e6fb2d32e3 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -3387,7 +3387,8 @@ TypeToKlass.types["path-input"] = PathInputWidget TypeToKlass.types["raw-json"] = RawJsonWidget TypeToKlass.types["list"] = ListWidget TypeToKlass.types["dict-modifiable"] = ModifiableDict -TypeToKlass.types["dict-item"] = DictItemWidget +# DEPRECATED - remove when removed from schemas +TypeToKlass.types["dict-item"] = DictWidget TypeToKlass.types["dict"] = DictWidget TypeToKlass.types["dict-invisible"] = DictInvisible TypeToKlass.types["path-widget"] = PathWidget From 4bd7a6c4fa2ddabf5a90e0ec39d80c970e069da8 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:56:45 +0200 Subject: [PATCH 18/25] removed DictItemWidget as is not used --- .../settings/settings/widgets/item_types.py | 95 ------------------- 1 file changed, 95 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index e6fb2d32e3..3cf9cfcc74 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1192,101 +1192,6 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): return self.text_input.json_value() -class DictItemWidget(QtWidgets.QWidget, SettingObject): - default_input_value = True - value_changed = QtCore.Signal(object) - - def __init__( - self, input_data, parent, - as_widget=False, label_widget=None, parent_widget=None - ): - if parent_widget is None: - parent_widget = parent - super(DictItemWidget, self).__init__(parent_widget) - - self.initial_attributes(input_data, parent, as_widget) - - if not self._as_widget: - raise TypeError("{} can be used only as widget.".format( - self.__class__.__name__ - )) - - self.input_fields = [] - - body = QtWidgets.QWidget(self) - body.setObjectName("DictItemWidgetBody") - - content_layout = QtWidgets.QGridLayout(body) - content_layout.setContentsMargins(5, 5, 5, 5) - self.content_layout = content_layout - - layout = QtWidgets.QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(5) - layout.addWidget(body) - - self.label_widget = label_widget - - for child_configuration in input_data["children"]: - self.add_children_gui(child_configuration) - - def add_children_gui(self, child_configuration): - item_type = child_configuration["type"] - klass = TypeToKlass.types.get(item_type) - - row = self.content_layout.rowCount() - if not getattr(klass, "is_input_type", False): - item = klass(child_configuration, self) - self.content_layout.addWidget(item, row, 0, 1, 2) - return item - - label_widget = None - if not klass.expand_in_grid: - label = child_configuration.get("label") - if label is not None: - label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget( - label_widget, row, 0, 1, 1, - alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop - ) - - item = klass(child_configuration, self, label_widget=label_widget) - item.value_changed.connect(self._on_value_change) - - if label_widget: - self.content_layout.addWidget(item, row, 1, 1, 1) - else: - self.content_layout.addWidget(item, row, 0, 1, 2) - - self.input_fields.append(item) - return item - - def hierarchical_style_update(self): - for input_field in self.input_fields: - input_field.hierarchical_style_update() - - def _on_value_change(self, item=None): - self.value_changed.emit(self) - - def update_default_values(self, parent_values): - for input_field in self.input_fields: - input_field.update_default_values(parent_values) - - def update_studio_values(self, parent_values): - for input_field in self.input_fields: - input_field.update_studio_values(parent_values) - - def apply_overrides(self, parent_values): - for input_field in self.input_fields: - input_field.apply_overrides(parent_values) - - def item_value(self): - output = {} - for input_field in self.input_fields: - output.update(input_field.config_value()) - return output - - class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 value_changed = QtCore.Signal(object) From ba8b1b8015b5821996b1b4140d6d2831c1394f03 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:57:00 +0200 Subject: [PATCH 19/25] changed object name in styles --- pype/tools/settings/settings/style/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/style/style.css b/pype/tools/settings/settings/style/style.css index 221f297219..3f648abef8 100644 --- a/pype/tools/settings/settings/style/style.css +++ b/pype/tools/settings/settings/style/style.css @@ -152,7 +152,7 @@ QPushButton[btn-type="expand-toggle"] { background: #141a1f; } -#DictItemWidgetBody{ +#DictAsWidgetBody{ background: transparent; border: 2px solid #cccccc; border-radius: 5px; From 14a15c9a8cbedae0641583869b552a8a84af78b1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 11:57:35 +0200 Subject: [PATCH 20/25] current schemas in example does not have dict-item --- .../gui_schemas/projects_schema/1_plugins_gui_schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json index f70495017e..f357b51dc5 100644 --- a/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json +++ b/pype/tools/settings/settings/gui_schemas/projects_schema/1_plugins_gui_schema.json @@ -172,7 +172,7 @@ "type": "list", "key": "profiles", "label": "Profiles", - "object_type": "dict-item", + "object_type": "dict", "input_modifiers": { "children": [ { @@ -192,7 +192,7 @@ "label": "Output Definitions", "type": "dict-modifiable", "highlight_content": true, - "object_type": "dict-item", + "object_type": "dict", "input_modifiers": { "children": [ { From 83ff6bc85bd8c0016c97fca91e8ac07169ac4a58 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 12:03:57 +0200 Subject: [PATCH 21/25] removed dict-item from readme --- pype/tools/settings/settings/README.md | 31 -------------------------- 1 file changed, 31 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index 9d12467cc9..8fa0a4616a 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -207,37 +207,6 @@ } ``` -### dict-item -- item represents dictionary with strict keys in and data types of its values -- can be used only as widget (in `list` or `dict-modifiable`) - - only key modifier is `children` which is list of it's keys -- USAGE: e.g. List of dictionaries where each dictionary have same structure. - -``` -{ - "type": "list", - "key": "profiles", - "label": "Profiles", - "object_type": "dict-item", - "input_modifiers": { - "children": [ - { - "key": "families", - "label": "Families", - "type": "list", - "object_type": "text" - }, { - "key": "hosts", - "label": "Hosts", - "type": "list", - "object_type": "text" - } - ... - ] - } -} -``` - ### list-strict - input for strict number of items in list - each child item can be different type with different possible modifiers From 7361e86cb9341d9b92e092920711091a71342463 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 12:04:50 +0200 Subject: [PATCH 22/25] added new usage to readme --- pype/tools/settings/settings/README.md | 43 +++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/README.md b/pype/tools/settings/settings/README.md index db444eb3bd..969c9dc574 100644 --- a/pype/tools/settings/settings/README.md +++ b/pype/tools/settings/settings/README.md @@ -57,13 +57,18 @@ ## dict - this is another dictionary input wrapping more inputs but visually makes them different -- required keys are `"key"` under which will be stored and `"label"` which will be shown in GUI -- this input can be expandable - - that can be set with key `"expandable"` as `True`/`False` (Default: `True`) - - with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`) -- it is possible to add darker background with `"highlight_content"` (Default: `False`) - - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color +- item may be used as widget (in `list` or `dict-modifiable`) + - in that case the only key modifier is `children` which is list of it's keys + - USAGE: e.g. List of dictionaries where each dictionary have same structure. +- item options if is not used as widget + - required keys are `"key"` under which will be stored and `"label"` which will be shown in GUI + - this input can be expandable + - that can be set with key `"expandable"` as `True`/`False` (Default: `True`) + - with key `"expanded"` as `True`/`False` can be set that is expanded when GUI is opened (Default: `False`) + - it is possible to add darker background with `"highlight_content"` (Default: `False`) + - darker background has limits of maximum applies after 3-4 nested highlighted items there is not difference in the color ``` +# Example { "key": "applications", "type": "dict", @@ -76,6 +81,30 @@ ...ITEMS... ] } + +# When used as widget +{ + "type": "list", + "key": "profiles", + "label": "Profiles", + "object_type": "dict-item", + "input_modifiers": { + "children": [ + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, { + "key": "hosts", + "label": "Hosts", + "type": "list", + "object_type": "text" + } + ... + ] + } +} ``` ## Inputs for setting any kind of value (`Pure` inputs) @@ -234,7 +263,7 @@ - should wraps multiple inputs only visually - these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled -### dict-form +### form - DEPRECATED - may be used only in `dict` and `dict-invisible` where is currently used grid layout so form is not needed - item is kept as still may be used in specific cases From ac26fb31eb873ad784202d8575c4f56e7071e913 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 18:01:23 +0200 Subject: [PATCH 23/25] implemented label widget used in grid layout --- .../settings/settings/widgets/widgets.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 400b9371fd..2a1f5fe804 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -226,3 +226,56 @@ class UnsavedChangesDialog(QtWidgets.QDialog): def on_discard_pressed(self): self.done(2) + + +class SpacerWidget(QtWidgets.QWidget): + def __init__(self, parent=None): + super(SpacerWidget, self).__init__(parent) + self.setAttribute(QtCore.Qt.WA_TranslucentBackground) + + +class GridLabelWidget(QtWidgets.QWidget): + def __init__(self, label, parent=None): + super(GridLabelWidget, self).__init__(parent) + + self.input_field = None + + self.properties = {} + + layout = QtWidgets.QVBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + + label_proxy = QtWidgets.QWidget(self) + label_proxy_layout = QtWidgets.QHBoxLayout(label_proxy) + label_proxy_layout.setContentsMargins(0, 0, 0, 0) + label_proxy_layout.setSpacing(0) + + label_widget = QtWidgets.QLabel(label, label_proxy) + spacer_widget_h = SpacerWidget(label_proxy) + label_proxy_layout.addWidget( + spacer_widget_h, 0, alignment=QtCore.Qt.AlignRight + ) + label_proxy_layout.addWidget( + label_widget, 0, alignment=QtCore.Qt.AlignRight + ) + + spacer_widget_v = SpacerWidget(self) + + layout.addWidget(label_proxy, 0) + layout.addWidget(spacer_widget_v, 1) + + self.label_widget = label_widget + + def setProperty(self, name, value): + cur_value = self.properties.get(name) + if cur_value == value: + return + + self.label_widget.setProperty(name, value) + self.label_widget.style().polish(self.label_widget) + + def mouseReleaseEvent(self, event): + if self.input_field: + return self.input_field.show_actions_menu(event) + return super(GridLabelWidget, self).mouseReleaseEvent(event) From 65e9a6a2541f3cacc3f2a98c11c749a9798d50a4 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 18:01:54 +0200 Subject: [PATCH 24/25] `show_actions_menu` is separate method now triggered with right click on item --- .../settings/settings/widgets/item_types.py | 124 ++++++++++-------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index fea78b713b..9f7d951241 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -285,65 +285,75 @@ class SettingObject: return "-".join(items) or "" + def show_actions_menu(self, event=None): + if event and event.button() != QtCore.Qt.RightButton: + return + + if not self.allow_actions: + if event: + return self.mouseReleaseEvent(event) + return + + menu = QtWidgets.QMenu() + + actions_mapping = {} + if self.child_modified: + action = QtWidgets.QAction("Discard changes") + actions_mapping[action] = self._discard_changes + menu.addAction(action) + + if ( + self.is_overidable + and not self.is_overriden + and not self.any_parent_is_group + ): + action = QtWidgets.QAction("Set project override") + actions_mapping[action] = self._set_as_overriden + menu.addAction(action) + + if ( + not self.is_overidable + and ( + self.has_studio_override + ) + ): + action = QtWidgets.QAction("Reset to pype default") + actions_mapping[action] = self._reset_to_pype_default + menu.addAction(action) + + if ( + not self.is_overidable + and not self.is_overriden + and not self.any_parent_is_group + and not self._had_studio_override + ): + action = QtWidgets.QAction("Set studio default") + actions_mapping[action] = self._set_studio_default + menu.addAction(action) + + if ( + not self.any_parent_overriden() + and (self.is_overriden or self.child_overriden) + ): + # TODO better label + action = QtWidgets.QAction("Remove project override") + actions_mapping[action] = self._remove_overrides + menu.addAction(action) + + if not actions_mapping: + action = QtWidgets.QAction("< No action >") + actions_mapping[action] = None + menu.addAction(action) + + result = menu.exec_(QtGui.QCursor.pos()) + if result: + to_run = actions_mapping[result] + if to_run: + to_run() + def mouseReleaseEvent(self, event): if self.allow_actions and event.button() == QtCore.Qt.RightButton: - menu = QtWidgets.QMenu() - - actions_mapping = {} - if self.child_modified: - action = QtWidgets.QAction("Discard changes") - actions_mapping[action] = self._discard_changes - menu.addAction(action) - - if ( - self.is_overidable - and not self.is_overriden - and not self.any_parent_is_group - ): - action = QtWidgets.QAction("Set project override") - actions_mapping[action] = self._set_as_overriden - menu.addAction(action) - - if ( - not self.is_overidable - and ( - self.has_studio_override - ) - ): - action = QtWidgets.QAction("Reset to pype default") - actions_mapping[action] = self._reset_to_pype_default - menu.addAction(action) - - if ( - not self.is_overidable - and not self.is_overriden - and not self.any_parent_is_group - and not self._had_studio_override - ): - action = QtWidgets.QAction("Set studio default") - actions_mapping[action] = self._set_studio_default - menu.addAction(action) - - if ( - not self.any_parent_overriden() - and (self.is_overriden or self.child_overriden) - ): - # TODO better label - action = QtWidgets.QAction("Remove project override") - actions_mapping[action] = self._remove_overrides - menu.addAction(action) - - if not actions_mapping: - action = QtWidgets.QAction("< No action >") - actions_mapping[action] = None - menu.addAction(action) - - result = menu.exec_(QtGui.QCursor.pos()) - if result: - to_run = actions_mapping[result] - if to_run: - to_run() - return + return self.show_actions_menu() mro = type(self).mro() index = mro.index(self.__class__) From 0d2110a6cce03fafe1682c5189904120c7777013 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Sep 2020 18:03:28 +0200 Subject: [PATCH 25/25] GridLabelWidget is used in dict and dict-invisible --- .../settings/settings/widgets/item_types.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 9f7d951241..213bd00a1b 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -5,7 +5,8 @@ from Qt import QtWidgets, QtCore, QtGui from .widgets import ( ExpandingWidget, NumberSpinBox, - PathInput + PathInput, + GridLabelWidget ) from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET from avalon.vendor import qtawesome @@ -2227,16 +2228,14 @@ class DictWidget(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget( - label_widget, row, 0, 1, 1, - alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop - ) + label_widget = GridLabelWidget(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) if label_widget: + label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2) @@ -2535,16 +2534,14 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): if not klass.expand_in_grid: label = child_configuration.get("label") if label is not None: - label_widget = QtWidgets.QLabel(label, self) - self.content_layout.addWidget( - label_widget, row, 0, 1, 1, - alignment=QtCore.Qt.AlignRight | QtCore.Qt.AlignTop - ) + label_widget = GridLabelWidget(label, self) + self.content_layout.addWidget(label_widget, row, 0, 1, 1) item = klass(child_configuration, self, label_widget=label_widget) item.value_changed.connect(self._on_value_change) if label_widget: + label_widget.input_field = item self.content_layout.addWidget(item, row, 1, 1, 1) else: self.content_layout.addWidget(item, row, 0, 1, 2)