Merge pull request #1055 from pypeclub/feature/label_wrap_for_all_entities

Label wrap for all entities
This commit is contained in:
Milan Kolar 2021-02-24 15:08:19 +01:00 committed by GitHub
commit e6d1b2812e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 247 additions and 159 deletions

View file

@ -695,6 +695,12 @@ class ItemEntity(BaseItemEntity):
is_dynamic_item (bool): Entity should behave like dynamically created
entity.
"""
_default_label_wrap = {
"use_label_wrap": False,
"collapsible": True,
"collapsed": False
}
def __init__(self, schema_data, parent, is_dynamic_item=False):
super(ItemEntity, self).__init__(schema_data)
@ -736,12 +742,50 @@ class ItemEntity(BaseItemEntity):
self.key = self.schema_data.get("key")
self.label = self.schema_data.get("label")
# GUI attributes
_default_label_wrap = self.__class__._default_label_wrap
for key, value in ItemEntity._default_label_wrap.items():
if key not in _default_label_wrap:
self.log.warning(
"Class {} miss default label wrap key \"{}\"".format(
self.__class__.__name__, key
)
)
_default_label_wrap[key] = value
use_label_wrap = self.schema_data.get("use_label_wrap")
if use_label_wrap is None:
if not self.label:
use_label_wrap = False
else:
use_label_wrap = _default_label_wrap["use_label_wrap"]
self.use_label_wrap = use_label_wrap
# Used only if `use_label_wrap` is set to True
self.collapsible = self.schema_data.get(
"collapsible",
_default_label_wrap["collapsible"]
)
self.collapsed = self.schema_data.get(
"collapsed",
_default_label_wrap["collapsed"]
)
self._item_initalization()
def save(self):
"""Call save on root item."""
self.root_item.save()
def schema_validations(self):
if not self.label and self.use_label_wrap:
raise ValueError((
"{} Entity has set `use_label_wrap` to true but"
" does not have set `label`."
).format(self.path))
super(ItemEntity, self).schema_validations()
def create_schema_object(self, *args, **kwargs):
"""Reference method for creation of entities defined in RootEntity."""
return self.root_item.create_schema_object(*args, **kwargs)

View file

@ -27,6 +27,11 @@ class DictImmutableKeysEntity(ItemEntity):
are not real settings values but entities representing the value.
"""
schema_types = ["dict"]
_default_label_wrap = {
"use_label_wrap": True,
"collapsible": True,
"collapsed": True
}
def __getitem__(self, key):
"""Return entity inder key."""
@ -169,11 +174,6 @@ class DictImmutableKeysEntity(ItemEntity):
"highlight_content", False
)
self.show_borders = self.schema_data.get("show_borders", True)
self.collapsible = self.schema_data.get("collapsible", True)
self.collapsed = self.schema_data.get("collapsed", True)
# Not yet implemented
self.use_label_wrap = self.schema_data.get("use_label_wrap") or True
def get_child_path(self, child_obj):
"""Get hierarchical path of child entity.

View file

@ -29,6 +29,12 @@ class DictMutableKeysEntity(EndpointEntity):
- clear callbacks
"""
schema_types = ["dict-modifiable"]
_default_label_wrap = {
"use_label_wrap": True,
"collapsible": True,
"collapsed": True
}
_miss_arg = object()
def __getitem__(self, key):
@ -174,8 +180,6 @@ class DictMutableKeysEntity(EndpointEntity):
self.hightlight_content = (
self.schema_data.get("highlight_content") or False
)
self.collapsible = self.schema_data.get("collapsible", True)
self.collapsed = self.schema_data.get("collapsed", True)
object_type = self.schema_data["object_type"]
if not isinstance(object_type, dict):

View file

@ -15,6 +15,11 @@ from .exceptions import (
class ListEntity(EndpointEntity):
schema_types = ["list"]
_default_label_wrap = {
"use_label_wrap": False,
"collapsible": True,
"collapsed": False
}
def __iter__(self):
for item in self.children:
@ -139,12 +144,6 @@ class ListEntity(EndpointEntity):
# Value that was set on set_override_state
self.initial_value = []
# GUI attributes
self.use_label_wrap = self.schema_data.get("use_label_wrap") or False
# Used only if `use_label_wrap` is set to True
self.collapsible = self.schema_data.get("collapsible") or True
self.collapsed = self.schema_data.get("collapsed") or False
def schema_validations(self):
super(ListEntity, self).schema_validations()

View file

@ -14,15 +14,10 @@
"name": "schema_global_tools"
},
{
"type": "collapsible-wrap",
"type": "raw-json",
"label": "Project Folder Structure",
"children": [
{
"type": "raw-json",
"label": " ",
"key": "project_folder_structure"
}
]
"key": "project_folder_structure",
"use_label_wrap": true
},
{
"type": "schema",

View file

@ -1,4 +1,6 @@
from Qt import QtWidgets, QtGui, QtCore
from .lib import CHILD_OFFSET
from .widgets import ExpandingWidget
class BaseWidget(QtWidgets.QWidget):
@ -161,27 +163,92 @@ class BaseWidget(QtWidgets.QWidget):
class InputWidget(BaseWidget):
def create_ui(self):
if self.entity.use_label_wrap:
label = None
self._create_label_wrap_ui()
else:
label = self.entity.label
self.label_widget = None
self.body_widget = None
self.content_widget = self
self.content_layout = self._create_layout(self)
self._add_inputs_to_layout()
self.entity_widget.add_widget_to_layout(self, label)
def _create_label_wrap_ui(self):
content_widget = QtWidgets.QWidget(self)
content_widget.setObjectName("ContentWidget")
content_widget.setProperty("content_state", "")
content_layout_margins = (CHILD_OFFSET, 5, 0, 0)
body_widget = ExpandingWidget(self.entity.label, self)
label_widget = body_widget.label_widget
body_widget.set_content_widget(content_widget)
content_layout = self._create_layout(content_widget)
content_layout.setContentsMargins(*content_layout_margins)
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
main_layout.addWidget(body_widget)
self.label_widget = label_widget
self.body_widget = body_widget
self.content_widget = content_widget
self.content_layout = content_layout
def _create_layout(self, parent_widget):
layout = QtWidgets.QHBoxLayout(parent_widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
return layout
def _add_inputs_to_layout(self):
raise NotImplementedError(
"Method `_add_inputs_to_layout` not implemented {}".format(
self.__class__.__name__
)
)
def update_style(self):
has_unsaved_changes = self.entity.has_unsaved_changes
if not has_unsaved_changes and self.entity.group_item:
has_unsaved_changes = self.entity.group_item.has_unsaved_changes
state = self.get_style_state(
style_state = self.get_style_state(
self.is_invalid,
has_unsaved_changes,
self.entity.has_project_override,
self.entity.has_studio_override
)
if self._style_state == state:
if self._style_state == style_state:
return
self._style_state = state
self._style_state = style_state
self.input_field.setProperty("input-state", state)
self.input_field.setProperty("input-state", style_state)
self.input_field.style().polish(self.input_field)
if self.label_widget:
self.label_widget.setProperty("state", state)
self.label_widget.setProperty("state", style_state)
self.label_widget.style().polish(self.label_widget)
if self.body_widget:
if style_state:
child_style_state = "child-{}".format(style_state)
else:
child_style_state = ""
self.body_widget.side_line_widget.setProperty(
"state", child_style_state
)
self.body_widget.side_line_widget.style().polish(
self.body_widget.side_line_widget
)
@property
def child_invalid(self):
return self.is_invalid

View file

@ -24,18 +24,27 @@ from .lib import CHILD_OFFSET
class DictImmutableKeysWidget(BaseWidget):
def create_ui(self):
self._child_style_state = ""
self.input_fields = []
self.checkbox_child = None
if not self.entity.is_dynamic_item and not self.entity.label:
self._ui_item_without_label()
self.label_widget = None
self.body_widget = None
self.content_widget = None
self.content_layout = None
label = None
if self.entity.is_dynamic_item:
self._ui_as_dynamic_item()
elif self.entity.use_label_wrap:
self._ui_label_wrap()
self.checkbox_child = self.entity.non_gui_children.get(
self.entity.checkbox_key
)
else:
self._ui_item_or_as_widget()
if not self.entity.is_dynamic_item:
self.checkbox_child = self.entity.non_gui_children.get(
self.entity.checkbox_key
)
self._ui_item_base()
label = self.entity.label
self._parent_widget_by_entity_id = {}
self._added_wrapper_ids = set()
@ -50,7 +59,7 @@ class DictImmutableKeysWidget(BaseWidget):
)
)
self.entity_widget.add_widget_to_layout(self)
self.entity_widget.add_widget_to_layout(self, label)
def _prepare_entity_layouts(self, children, widget):
for child in children:
@ -74,68 +83,73 @@ class DictImmutableKeysWidget(BaseWidget):
self._prepare_entity_layouts(child["children"], wrapper)
def _ui_item_without_label(self):
def _ui_item_base(self):
self.setObjectName("DictInvisible")
self.body_widget = None
self.content_widget = self
self.content_layout = QtWidgets.QGridLayout(self)
self.content_layout.setContentsMargins(0, 0, 0, 0)
self.content_layout.setSpacing(5)
def _ui_item_or_as_widget(self):
def _ui_as_dynamic_item(self):
content_widget = QtWidgets.QWidget(self)
content_widget.setObjectName("DictAsWidgetBody")
if self.entity.is_dynamic_item:
content_widget.setObjectName("DictAsWidgetBody")
show_borders = str(int(self.entity.show_borders))
content_widget.setProperty("show_borders", show_borders)
content_layout_margins = (5, 5, 5, 5)
main_layout_spacing = 5
body_widget = None
label_widget = QtWidgets.QLabel(self.entity.label)
show_borders = str(int(self.entity.show_borders))
content_widget.setProperty("show_borders", show_borders)
label_widget = QtWidgets.QLabel(self.entity.label)
content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(5, 5, 5, 5)
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(5)
main_layout.addWidget(content_widget)
self.label_widget = label_widget
self.content_widget = content_widget
self.content_layout = content_layout
def _ui_label_wrap(self):
content_widget = QtWidgets.QWidget(self)
content_widget.setObjectName("ContentWidget")
if self.entity.highlight_content:
content_state = "hightlighted"
bottom_margin = 5
else:
content_widget.setObjectName("ContentWidget")
if self.entity.highlight_content:
content_state = "hightlighted"
bottom_margin = 5
else:
content_state = ""
bottom_margin = 0
content_widget.setProperty("content_state", content_state)
content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin)
main_layout_spacing = 0
content_state = ""
bottom_margin = 0
content_widget.setProperty("content_state", content_state)
content_layout_margins = (CHILD_OFFSET, 5, 0, bottom_margin)
body_widget = ExpandingWidget(self.entity.label, self)
label_widget = body_widget.label_widget
body_widget.set_content_widget(content_widget)
body_widget = ExpandingWidget(self.entity.label, self)
label_widget = body_widget.label_widget
body_widget.set_content_widget(content_widget)
content_layout = QtWidgets.QGridLayout(content_widget)
content_layout.setContentsMargins(*content_layout_margins)
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(main_layout_spacing)
if not body_widget:
main_layout.addWidget(content_widget)
else:
main_layout.addWidget(body_widget)
main_layout.setSpacing(0)
main_layout.addWidget(body_widget)
self.label_widget = label_widget
self.body_widget = body_widget
self.content_widget = content_widget
self.content_layout = content_layout
if body_widget:
if len(self.input_fields) == 1 and self.checkbox_widget:
body_widget.hide_toolbox(hide_content=True)
if len(self.input_fields) == 1 and self.checkbox_widget:
body_widget.hide_toolbox(hide_content=True)
elif self.entity.collapsible:
if not self.entity.collapsed:
body_widget.toggle_content()
else:
body_widget.hide_toolbox(hide_content=False)
elif self.entity.collapsible:
if not self.entity.collapsed:
body_widget.toggle_content()
else:
body_widget.hide_toolbox(hide_content=False)
def add_widget_to_layout(self, widget, label=None):
if self.checkbox_child and widget.entity is self.checkbox_child:
@ -174,7 +188,7 @@ class DictImmutableKeysWidget(BaseWidget):
for input_field in self.input_fields:
input_field.hierarchical_style_update()
def update_style(self, is_overriden=None):
def update_style(self):
if not self.body_widget and not self.label_widget:
return
@ -188,36 +202,8 @@ class DictImmutableKeysWidget(BaseWidget):
has_project_override = self.entity.has_project_override
has_studio_override = self.entity.has_studio_override
is_invalid = self.is_invalid
if self.body_widget:
child_style_state = self.get_style_state(
is_invalid,
has_unsaved_changes,
has_project_override,
has_studio_override
)
if child_style_state:
child_style_state = "child-{}".format(child_style_state)
if self._child_style_state != child_style_state:
self.body_widget.side_line_widget.setProperty(
"state", child_style_state
)
self.body_widget.side_line_widget.style().polish(
self.body_widget.side_line_widget
)
self._child_style_state = child_style_state
# There is nothing to care if there is no label
if not self.label_widget:
return
# Don't change label if is not group or under group item
if not self.entity.is_group and not self.entity.group_item:
return
style_state = self.get_style_state(
is_invalid,
self.is_invalid,
has_unsaved_changes,
has_project_override,
has_studio_override
@ -225,11 +211,32 @@ class DictImmutableKeysWidget(BaseWidget):
if self._style_state == style_state:
return
self._style_state = style_state
if self.body_widget:
if style_state:
child_style_state = "child-{}".format(style_state)
else:
child_style_state = ""
self.body_widget.side_line_widget.setProperty(
"state", child_style_state
)
self.body_widget.side_line_widget.style().polish(
self.body_widget.side_line_widget
)
# There is nothing to care if there is no label
if not self.label_widget:
return
# Don't change label if is not group or under group item
if not self.entity.is_group and not self.entity.group_item:
return
self.label_widget.setProperty("state", style_state)
self.label_widget.style().polish(self.label_widget)
self._style_state = style_state
def _on_entity_change(self):
pass
@ -252,26 +259,23 @@ class DictImmutableKeysWidget(BaseWidget):
class BoolWidget(InputWidget):
def create_ui(self):
def _add_inputs_to_layout(self):
checkbox_height = self.style().pixelMetric(
QtWidgets.QStyle.PM_IndicatorHeight
)
self.input_field = NiceCheckbox(height=checkbox_height, parent=self)
self.input_field = NiceCheckbox(
height=checkbox_height, parent=self.content_widget
)
spacer = QtWidgets.QWidget(self)
spacer = QtWidgets.QWidget(self.content_widget)
spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground)
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
layout.addWidget(self.input_field, 0)
layout.addWidget(spacer, 1)
self.content_layout.addWidget(self.input_field, 0)
self.content_layout.addWidget(spacer, 1)
self.setFocusProxy(self.input_field)
self.input_field.stateChanged.connect(self._on_value_change)
self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_field.isChecked():
@ -287,12 +291,12 @@ class BoolWidget(InputWidget):
class TextWidget(InputWidget):
def create_ui(self):
def _add_inputs_to_layout(self):
multiline = self.entity.multiline
if multiline:
self.input_field = QtWidgets.QPlainTextEdit(self)
self.input_field = QtWidgets.QPlainTextEdit(self.content_widget)
else:
self.input_field = QtWidgets.QLineEdit(self)
self.input_field = QtWidgets.QLineEdit(self.content_widget)
placeholder_text = self.entity.placeholder_text
if placeholder_text:
@ -304,15 +308,10 @@ class TextWidget(InputWidget):
if multiline:
layout_kwargs["alignment"] = QtCore.Qt.AlignTop
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
layout.addWidget(self.input_field, 1, **layout_kwargs)
self.content_layout.addWidget(self.input_field, 1, **layout_kwargs)
self.input_field.textChanged.connect(self._on_value_change)
self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_value():
self.set_entity_value()
@ -337,26 +336,20 @@ class TextWidget(InputWidget):
class NumberWidget(InputWidget):
def create_ui(self):
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
def _add_inputs_to_layout(self):
kwargs = {
"minimum": self.entity.minimum,
"maximum": self.entity.maximum,
"decimal": self.entity.decimal
}
self.input_field = NumberSpinBox(self, **kwargs)
self.input_field = NumberSpinBox(self.content_widget, **kwargs)
self.setFocusProxy(self.input_field)
layout.addWidget(self.input_field, 1)
self.content_layout.addWidget(self.input_field, 1)
self.input_field.valueChanged.connect(self._on_value_change)
self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_field.value():
self.set_entity_value()
@ -421,12 +414,8 @@ class RawJsonInput(QtWidgets.QPlainTextEdit):
class RawJsonWidget(InputWidget):
def create_ui(self):
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
self.input_field = RawJsonInput(self)
def _add_inputs_to_layout(self):
self.input_field = RawJsonInput(self.content_widget)
self.input_field.setSizePolicy(
QtWidgets.QSizePolicy.Minimum,
QtWidgets.QSizePolicy.MinimumExpanding
@ -434,10 +423,11 @@ class RawJsonWidget(InputWidget):
self.setFocusProxy(self.input_field)
layout.addWidget(self.input_field, 1, alignment=QtCore.Qt.AlignTop)
self.content_layout.addWidget(
self.input_field, 1, alignment=QtCore.Qt.AlignTop
)
self.input_field.textChanged.connect(self._on_value_change)
self.entity_widget.add_widget_to_layout(self, self.entity.label)
def set_entity_value(self):
self.input_field.set_value(self.entity.value)
@ -465,31 +455,26 @@ class RawJsonWidget(InputWidget):
class EnumeratorWidget(InputWidget):
def create_ui(self):
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
def _add_inputs_to_layout(self):
if self.entity.multiselection:
self.input_field = MultiSelectionComboBox(
placeholder=self.entity.placeholder, parent=self
placeholder=self.entity.placeholder, parent=self.content_widget
)
model = self.input_field.model()
for idx in range(self.input_field.count()):
model.item(idx).setCheckable(True)
else:
self.input_field = ComboBox(self)
self.input_field = ComboBox(self.content_widget)
for enum_item in self.entity.enum_items:
for value, label in enum_item.items():
self.input_field.addItem(label, value)
layout.addWidget(self.input_field, 0)
self.content_layout.addWidget(self.input_field, 0)
self.setFocusProxy(self.input_field)
self.input_field.value_changed.connect(self._on_value_change)
self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_field.value():
@ -574,12 +559,8 @@ class PathWidget(BaseWidget):
class PathInputWidget(InputWidget):
def create_ui(self, label_widget=None):
layout = QtWidgets.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(5)
self.input_field = QtWidgets.QLineEdit(self)
def _add_inputs_to_layout(self):
self.input_field = QtWidgets.QLineEdit(self.content_widget)
self.args_input_field = None
if self.entity.with_arguments:
self.input_field.setPlaceholderText("Executable path")
@ -587,15 +568,13 @@ class PathInputWidget(InputWidget):
self.args_input_field.setPlaceholderText("Arguments")
self.setFocusProxy(self.input_field)
layout.addWidget(self.input_field, 8)
self.content_layout.addWidget(self.input_field, 8)
self.input_field.textChanged.connect(self._on_value_change)
if self.args_input_field:
layout.addWidget(self.args_input_field, 2)
self.content_layout.addWidget(self.args_input_field, 2)
self.args_input_field.textChanged.connect(self._on_value_change)
self.entity_widget.add_widget_to_layout(self, self.entity.label)
def _on_entity_change(self):
if self.entity.value != self.input_value():
self.set_entity_value()