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

Commit

Permalink
Merge pull request #767 from pypeclub/feature/collapsable_wrapper
Browse files Browse the repository at this point in the history
Collapsible wrapper in settings
  • Loading branch information
mkolar authored Dec 1, 2020
2 parents 650ffb5 + 6b73060 commit a7a46a7
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 59 deletions.
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 @@ -3532,14 +3532,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 @@ -3550,63 +3543,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 @@ -3674,6 +3647,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 @@ -3715,6 +3689,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 @@ -3768,6 +3743,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 @@ -3837,7 +3979,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

0 comments on commit a7a46a7

Please sign in to comment.