Merge remote-tracking branch 'origin/develop' into feature/system_settings

This commit is contained in:
Milan Kolar 2020-09-22 10:04:40 +02:00
commit f1fa791127
13 changed files with 733 additions and 303 deletions

View file

@ -0,0 +1,4 @@
{
"studio_name": "",
"studio_code": ""
}

View file

@ -25,6 +25,15 @@
"In Progress": [
"_any_"
]
},
"intent": {
"items": {
"-": "-",
"wip": "WIP",
"final": "Final",
"test": "Test"
},
"default": "-"
}
},
"Rest Api": {
@ -38,7 +47,7 @@
},
"Clockify": {
"enabled": true,
"workspace_name": ""
"workspace_name": "studio name"
},
"Deadline": {
"enabled": true,
@ -48,23 +57,17 @@
"enabled": false,
"MUSTER_REST_URL": "",
"templates_mapping": {
"3delight": 41,
"arnold": 46,
"arnold_sf": 57,
"gelato": 30,
"harware": 3,
"krakatoa": 51,
"file_layers": 7,
"mentalray": 2,
"mentalray_sf": 6,
"redshift": 55,
"renderman": 29,
"software": 1,
"software_sf": 5,
"turtle": 10,
"vector": 4,
"vray": 37,
"ffmpeg": 48
"file_layers": 7,
"mentalray": 2,
"mentalray_sf": 6,
"redshift": 55,
"renderman": 29,
"software": 1,
"software_sf": 5,
"turtle": 10,
"vector": 4,
"vray": 37,
"ffmpeg": 48
}
},
"Logging": {
@ -82,4 +85,4 @@
"Idle Manager": {
"enabled": true
}
}
}

View file

@ -27,10 +27,7 @@
```
{
"type": "schema",
"children": [
"my_schema_name",
"my_other_schema_name"
]
"name": "my_schema_name"
}
```
@ -57,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",
@ -76,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)
@ -111,6 +137,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`)
```
{
@ -207,6 +234,54 @@
}
```
### 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
@ -234,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

@ -22,9 +22,7 @@
"children": [
{
"type": "schema",
"children": [
"1_plugins_gui_schema"
]
"name": "1_plugins_gui_schema"
}
]
}

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

@ -7,12 +7,16 @@
"key": "global",
"children": [{
"type": "schema",
"children": [
"1_modules_gui_schema",
"1_applications_gui_schema",
"1_tools_gui_schema",
"1_intents_gui_schema"
]
"name": "1_intents_gui_schema"
},{
"type": "schema",
"name": "1_modules_gui_schema"
}, {
"type": "schema",
"name": "1_applications_gui_schema"
}, {
"type": "schema",
"name": "1_tools_gui_schema"
}]
}
]

View file

@ -72,6 +72,144 @@
"minimum": 10,
"maximum": 100
}
}, {
"type": "list-strict",
"key": "strict_list_labels_horizontal",
"label": "StrictList-labels-horizontal (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-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",
"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",

View file

@ -1,20 +1,16 @@
{
"key": "intent",
"type": "dict",
"label": "Intent Setting",
"collapsable": true,
"is_group": true,
"is_file": true,
"children": [
{
"type": "dict-modifiable",
"object_type": "text",
"key": "items",
"label": "Intent Key/Label"
}, {
"type": "text",
"key": "default",
"label": "Default intent"
}
]
}
"key": "general",
"type": "dict",
"label": "General",
"collapsable": true,
"is_file": true,
"children": [{
"key": "studio_name",
"type": "text",
"label": "Studio Name"
},{
"key": "studio_code",
"type": "text",
"label": "Studio Short Code"
}
]}

View file

@ -100,7 +100,24 @@
"input_modifiers": {
"object_type": "text"
}
}
},
{
"key": "intent",
"type": "dict-invisible",
"children": [
{
"type": "dict-modifiable",
"object_type": "text",
"key": "items",
"label": "Intent Key/Label"
},
{
"key": "default",
"type": "text",
"label": "Defautl Intent"
}
]
}
]
}, {
"type": "dict",

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

@ -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
@ -285,65 +286,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__)
@ -547,6 +558,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 +571,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 +583,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
@ -906,6 +920,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 +931,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 = {}
@ -1192,110 +1210,20 @@ 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)
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 +1235,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 +1276,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)
@ -1697,6 +1628,184 @@ 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")
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
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.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"]
item_widget = ListItem(
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)
label = child_configuration.get("label")
label_widget = None
if label:
label_widget = QtWidgets.QLabel(label, self)
children_item_mapping.append((label_widget, item_widget))
if horizontal:
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:
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)
@ -2132,18 +2241,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 +2268,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 +2290,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 +2304,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)
@ -2213,16 +2339,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)
@ -2280,8 +2404,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)
@ -2290,15 +2418,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)
@ -2308,37 +2442,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)
@ -2351,6 +2488,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
@ -2521,16 +2662,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)
@ -2869,6 +3008,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
@ -3352,8 +3493,10 @@ 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
# 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

View file

@ -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

View file

@ -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)