Merge pull request #536 from pypeclub/feature/dict_items_merge

Feature/dict items merge
This commit is contained in:
Milan Kolar 2020-09-22 09:44:21 +02:00 committed by GitHub
commit 8fe06d27f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 142 deletions

View file

@ -54,13 +54,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",
@ -73,6 +78,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)
@ -280,7 +309,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

View file

@ -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": [
{

View file

@ -152,7 +152,7 @@ QPushButton[btn-type="expand-toggle"] {
background: #141a1f;
}
#DictItemWidgetBody{
#DictAsWidgetBody{
background: transparent;
border: 2px solid #cccccc;
border-radius: 5px;

View file

@ -1199,101 +1199,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)
@ -2325,18 +2230,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
@ -2344,10 +2257,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)
@ -2370,9 +2279,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)
@ -2387,6 +2293,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)
@ -2473,8 +2395,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)
@ -2483,15 +2409,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)
@ -2501,37 +2433,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)
@ -2544,6 +2479,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
@ -3549,7 +3488,8 @@ TypeToKlass.types["raw-json"] = RawJsonWidget
TypeToKlass.types["list"] = ListWidget
TypeToKlass.types["list-strict"] = ListStrictWidget
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