Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Collapsible wrapper in settings #767

Merged
merged 6 commits into from
Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions pype/tools/settings/settings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,11 +436,9 @@
## Proxy wrappers
- should wraps multiple inputs only visually
- these does not have `"key"` key and do not allow to have `"is_file"` or `"is_group"` modifiers enabled
- can't be used as widget (first item in e.g. `list`, `dict-modifiable`, etc.)

### form
- DEPRECATED
- may be used only in `dict` and `dict-invisible` where is currently used grid layout so form is not needed
- item is kept as still may be used in specific cases
- wraps inputs into form look layout
- should be used only for Pure inputs

Expand All @@ -462,3 +460,24 @@
]
}
```


### collapsible-wrap
- wraps inputs into collapsible widget
- looks like `dict` but does not hold `"key"`
- should be used only for Pure inputs

```
{
"type": "collapsible-wrap",
"label": "Collapsible example"
"children": [
{
"type": "text",
"key": "_example_input_collapsible",
"label": "Example input in collapsible wrapper"
}, {
...
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,16 @@
]
}
]
}, {
"type": "collapsible-wrap",
"label": "Collapsible Wrapper without key",
"children": [
{
"type": "text",
"key": "_example_input_collapsible",
"label": "Example input in collapsible wrapper"
}
]
}
]
}
Expand Down
258 changes: 202 additions & 56 deletions pype/tools/settings/settings/widgets/item_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3505,14 +3505,7 @@ def overrides(self):
return value, self.is_group


# Proxy for form layout
class FormLabel(QtWidgets.QLabel):
def __init__(self, *args, **kwargs):
super(FormLabel, self).__init__(*args, **kwargs)
self.item = None


class DictFormWidget(QtWidgets.QWidget, SettingObject):
class WrapperItemWidget(QtWidgets.QWidget, SettingObject):
value_changed = QtCore.Signal(object)
allow_actions = False
expand_in_grid = True
Expand All @@ -3523,63 +3516,43 @@ def __init__(
):
if parent_widget is None:
parent_widget = parent
super(DictFormWidget, self).__init__(parent_widget)

self.initial_attributes(schema_data, parent, as_widget)

self._as_widget = False
self._is_group = False
super(WrapperItemWidget, self).__init__(parent_widget)

self.input_fields = []

def create_ui(self, label_widget=None):
self.content_layout = QtWidgets.QFormLayout(self)
self.content_layout.setContentsMargins(0, 0, 0, 0)

for child_data in self.schema_data.get("children", []):
self.add_children_gui(child_data)

self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

any_visible = False
for input_field in self.input_fields:
if not input_field.hidden_by_role:
any_visible = True
break

if not any_visible:
self.hide()
self.initial_attributes(schema_data, parent, as_widget)

def add_children_gui(self, child_configuration):
item_type = child_configuration["type"]
# Pop label to not be set in child
label = child_configuration["label"]
if self.as_widget:
raise TypeError(
"Wrapper items ({}) can't be used as widgets.".format(
self.__class__.__name__
)
)

klass = TypeToKlass.types.get(item_type)
if self.is_group:
raise TypeError(
"Wrapper items ({}) can't be used as groups.".format(
self.__class__.__name__
)
)

label_widget = FormLabel(label, self)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

item = klass(child_configuration, self)
item.create_ui(label_widget=label_widget)
label_widget.item = item
self.wrapper_initial_attributes(schema_data)

if item.hidden_by_role:
label_widget.hide()
def wrapper_initial_attributes(self, schema_data):
"""Initialization of attributes for specific wrapper."""
return

item.value_changed.connect(self._on_value_change)
self.content_layout.addRow(label_widget, item)
self.input_fields.append(item)
return item
def create_ui(self, label_widget=None):
"""UI implementation."""
raise NotImplementedError(
"Method `create_ui` not implemented."
)

def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.RightButton:
position = self.mapFromGlobal(QtGui.QCursor().pos())
widget = self.childAt(position)
if widget and isinstance(widget, FormLabel):
widget.item.mouseReleaseEvent(event)
event.accept()
return
super(DictFormWidget, self).mouseReleaseEvent(event)
def update_style(self):
"""Update items styles."""
return

def apply_overrides(self, parent_values):
for item in self.input_fields:
Expand Down Expand Up @@ -3647,6 +3620,7 @@ def _on_value_change(self, item=None):
self.value_changed.emit(self)
if self.any_parent_is_group:
self.hierarchical_style_update()
self.update_style()

@property
def child_has_studio_override(self):
Expand Down Expand Up @@ -3688,6 +3662,7 @@ def get_invalid(self):
def hierarchical_style_update(self):
for input_field in self.input_fields:
input_field.hierarchical_style_update()
self.update_style()

def item_value(self):
output = {}
Expand Down Expand Up @@ -3741,6 +3716,173 @@ def overrides(self):
return values, self.is_group


# Proxy for form layout
class FormLabel(QtWidgets.QLabel):
def __init__(self, input_field, *args, **kwargs):
super(FormLabel, self).__init__(*args, **kwargs)
self.input_field = input_field

def mouseReleaseEvent(self, event):
if self.input_field:
return self.input_field.show_actions_menu(event)
return super(FormLabel, self).mouseReleaseEvent(event)


class FormItemWidget(WrapperItemWidget):
def create_ui(self, label_widget=None):
self.content_layout = QtWidgets.QFormLayout(self)
self.content_layout.setContentsMargins(0, 0, 0, 0)

for child_data in self.schema_data["children"]:
self.add_children_gui(child_data)

any_visible = False
for input_field in self.input_fields:
if not input_field.hidden_by_role:
any_visible = True
break

if not any_visible:
self.hidden_by_role = True
self.hide()

def add_children_gui(self, child_configuration):
item_type = child_configuration["type"]
# Pop label to not be set in child
label = child_configuration["label"]

klass = TypeToKlass.types.get(item_type)

item = klass(child_configuration, self)

label_widget = FormLabel(item, label, self)

item.create_ui(label_widget=label_widget)

if item.hidden_by_role:
label_widget.hide()

item.value_changed.connect(self._on_value_change)
self.content_layout.addRow(label_widget, item)
self.input_fields.append(item)
return item


class CollapsibleWrapperItem(WrapperItemWidget):
def wrapper_initial_attributes(self, schema_data):
self.collapsable = schema_data.get("collapsable", True)
self.collapsed = schema_data.get("collapsed", True)

def create_ui(self, label_widget=None):
content_widget = QtWidgets.QWidget(self)
content_widget.setObjectName("ContentWidget")
content_widget.setProperty("content_state", "")

content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(CHILD_OFFSET, 5, 0, 0)

body_widget = ExpandingWidget(self.schema_data["label"], self)
body_widget.set_content_widget(content_widget)

label_widget = body_widget.label_widget

main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
if not body_widget:
main_layout.addWidget(content_widget)
else:
main_layout.addWidget(body_widget)

self.label_widget = label_widget
self.body_widget = body_widget
self.content_layout = content_layout

if self.collapsable:
if not self.collapsed:
body_widget.toggle_content()
else:
body_widget.hide_toolbox(hide_content=False)

for child_data in self.schema_data.get("children", []):
self.add_children_gui(child_data)

any_visible = False
for input_field in self.input_fields:
if not input_field.hidden_by_role:
any_visible = True
break

if not any_visible:
self.hide()

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
item = klass(child_configuration, self)
if not item.expand_in_grid:
label = child_configuration.get("label")
if label is not None:
label_widget = GridLabelWidget(label, self)
self.content_layout.addWidget(label_widget, row, 0, 1, 1)

item.create_ui(label_widget=label_widget)
item.value_changed.connect(self._on_value_change)

if label_widget:
if item.hidden_by_role:
label_widget.hide()
label_widget.input_field = item
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 update_style(self, is_overriden=None):
child_has_studio_override = self.child_has_studio_override
child_modified = self.child_modified
child_invalid = self.child_invalid
child_state = self.style_state(
child_has_studio_override,
child_invalid,
self.child_overriden,
child_modified
)
if child_state:
child_state = "child-{}".format(child_state)

if child_state != self._child_state:
self.body_widget.side_line_widget.setProperty("state", child_state)
self.body_widget.side_line_widget.style().polish(
self.body_widget.side_line_widget
)
self._child_state = child_state

state = self.style_state(
self.had_studio_override,
child_invalid,
self.is_overriden,
self.is_modified
)
if self._state == state:
return

self.label_widget.setProperty("state", state)
self.label_widget.style().polish(self.label_widget)

self._state = state


class LabelWidget(QtWidgets.QWidget):
is_input_type = False

Expand Down Expand Up @@ -3810,7 +3952,11 @@ def __init__(self, configuration, parent):
# ---------------------------------------------
TypeToKlass.types["dict"] = DictWidget
TypeToKlass.types["path-widget"] = PathWidget
TypeToKlass.types["form"] = DictFormWidget

# Wrappers
TypeToKlass.types["form"] = FormItemWidget
TypeToKlass.types["collapsible-wrap"] = CollapsibleWrapperItem

# UI items
TypeToKlass.types["label"] = LabelWidget
TypeToKlass.types["separator"] = SplitterWidget