From 0c96044ed05ec7b14b003921800b654b6efd8eb5 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Oct 2020 23:04:13 +0200 Subject: [PATCH 1/5] implemented new nice checkbox widget --- .../settings/settings/widgets/widgets.py | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index b0bcf059a5..0d2960f86a 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -288,3 +288,188 @@ class GridLabelWidget(QtWidgets.QWidget): if self.input_field: return self.input_field.show_actions_menu(event) return super(GridLabelWidget, self).mouseReleaseEvent(event) + + +class NiceCheckboxMoveWidget(QtWidgets.QFrame): + def __init__(self, height, border_width, parent): + super(NiceCheckboxMoveWidget, self).__init__(parent=parent) + + self.checkstate = False + + self.half_size = int(height / 2) + self.full_size = self.half_size * 2 + self.border_width = border_width + self.setFixedHeight(self.full_size) + self.setFixedWidth(self.full_size) + + self.setStyleSheet(( + "background: #444444;border-style: none;" + "border-radius: {};border-width:{}px;" + ).format(self.half_size, self.border_width)) + + def update_position(self): + parent_rect = self.parent().rect() + if self.checkstate is True: + pos_x = ( + parent_rect.x() + + parent_rect.width() + - self.full_size + - self.border_width + ) + else: + pos_x = parent_rect.x() + self.border_width + + pos_y = parent_rect.y() + int( + parent_rect.height() / 2 - self.half_size + ) + self.setGeometry(pos_x, pos_y, self.width(), self.height()) + + def state_offset(self): + diff_x = ( + self.parent().rect().width() + - self.full_size + - (2 * self.border_width) + ) + return QtCore.QPoint(diff_x, 0) + + def change_position(self, checkstate): + self.checkstate = checkstate + + self.update_position() + + def resizeEvent(self, event): + super().resizeEvent(event) + self.update_position() + + +class NiceCheckbox(QtWidgets.QFrame): + stateChanged = QtCore.Signal(int) + checked_bg_color = QtGui.QColor(69, 128, 86) + unchecked_bg_color = QtGui.QColor(170, 80, 80) + + def set_bg_color(self, color): + self._bg_color = color + self.setStyleSheet(self._stylesheet_template.format( + color.red(), color.green(), color.blue() + )) + + def bg_color(self): + return self._bg_color + + bgcolor = QtCore.Property(QtGui.QColor, bg_color, set_bg_color) + + def __init__(self, checked=True, height=30, *args, **kwargs): + super(NiceCheckbox, self).__init__(*args, **kwargs) + + self._checkstate = checked + if checked: + bg_color = self.checked_bg_color + else: + bg_color = self.unchecked_bg_color + + self.half_height = int(height / 2) + height = self.half_height * 2 + tenth_height = int(height / 10) + + self.setFixedHeight(height) + self.setFixedWidth((height - tenth_height) * 2) + + move_item_size = height - (2 * tenth_height) + + self.move_item = NiceCheckboxMoveWidget( + move_item_size, tenth_height, self + ) + self.move_item.change_position(self._checkstate) + + self._stylesheet_template = ( + "border-radius: {}px;" + "border-width: {}px;" + "background: #333333;" + "border-style: solid;" + "border-color: #555555;" + ).format(self.half_height, tenth_height) + self._stylesheet_template += "background: rgb({},{},{});" + + self.set_bg_color(bg_color) + + def resizeEvent(self, event): + super(NiceCheckbox, self).resizeEvent(event) + self.move_item.update_position() + + def show(self, *args, **kwargs): + super(NiceCheckbox, self).show(*args, **kwargs) + self.move_item.update_position() + + def checkState(self): + if self._checkstate: + return QtCore.Qt.Checked + else: + return QtCore.Qt.Unchecked + + def _on_checkstate_change(self): + move_start_value = self.move_item.pos() + offset = self.move_item.state_offset() + if self._checkstate is True: + move_end_value = move_start_value + offset + else: + move_end_value = move_start_value - offset + move_animation = QtCore.QPropertyAnimation( + self.move_item, b"pos", self + ) + move_animation.setDuration(150) + move_animation.setEasingCurve(QtCore.QEasingCurve.OutQuad) + move_animation.setStartValue(move_start_value) + move_animation.setEndValue(move_end_value) + + color_animation = QtCore.QPropertyAnimation( + self, b"bgcolor" + ) + color_animation.setDuration(150) + if self._checkstate is True: + color_animation.setStartValue(self.unchecked_bg_color) + color_animation.setEndValue(self.checked_bg_color) + else: + color_animation.setStartValue(self.checked_bg_color) + color_animation.setEndValue(self.unchecked_bg_color) + + anim_group = QtCore.QParallelAnimationGroup(self) + anim_group.addAnimation(move_animation) + anim_group.addAnimation(color_animation) + + def _finished(): + self.move_item.change_position(self._checkstate) + self.stateChanged.emit(self.checkState()) + + anim_group.finished.connect(_finished) + anim_group.start() + + def isChecked(self): + return self._checkstate + + def setChecked(self, checked): + self._checkstate = checked + self._on_checkstate_change() + + def setCheckState(self, state=None): + if state is None: + checkstate = not self._checkstate + elif state == QtCore.Qt.Checked: + checkstate = True + elif state == QtCore.Qt.Unchecked: + checkstate = False + else: + return + + if checkstate == self._checkstate: + return + + self._checkstate = checkstate + + self._on_checkstate_change() + + def mouseReleaseEvent(self, event): + if event.button() == QtCore.Qt.LeftButton: + self.setCheckState() + event.accept() + return + return super(NiceCheckbox, self).mouseReleaseEvent(event) From 28eccb4d1f3d43265693d345e8c16aa622419123 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Oct 2020 23:04:27 +0200 Subject: [PATCH 2/5] new checkbox widget used in boolean item --- pype/tools/settings/settings/widgets/item_types.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index f3d51e3f1f..551b91e911 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -6,7 +6,8 @@ from .widgets import ( NumberSpinBox, PathInput, GridLabelWidget, - ComboBox + ComboBox, + NiceCheckbox ) from .multiselection_combobox import MultiSelectionComboBox from .lib import NOT_SET, METADATA_KEY, TypeToKlass, CHILD_OFFSET @@ -910,7 +911,11 @@ class BooleanWidget(QtWidgets.QWidget, InputObject): layout.addWidget(label_widget, 0) self.label_widget = label_widget - self.input_field = QtWidgets.QCheckBox(self) + checkbox_height = self.style().pixelMetric( + QtWidgets.QStyle.PM_IndicatorHeight + ) + self.input_field = NiceCheckbox(height=checkbox_height, parent=self) + spacer = QtWidgets.QWidget(self) spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground) From ba18d81448574305c2cc143b81d3871dee10b7d1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Oct 2020 23:11:02 +0200 Subject: [PATCH 3/5] few minor fixes --- pype/tools/settings/settings/widgets/widgets.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pype/tools/settings/settings/widgets/widgets.py b/pype/tools/settings/settings/widgets/widgets.py index 0d2960f86a..b64b1aa8ac 100644 --- a/pype/tools/settings/settings/widgets/widgets.py +++ b/pype/tools/settings/settings/widgets/widgets.py @@ -407,6 +407,8 @@ class NiceCheckbox(QtWidgets.QFrame): return QtCore.Qt.Unchecked def _on_checkstate_change(self): + self.stateChanged.emit(self.checkState()) + move_start_value = self.move_item.pos() offset = self.move_item.state_offset() if self._checkstate is True: @@ -438,7 +440,6 @@ class NiceCheckbox(QtWidgets.QFrame): def _finished(): self.move_item.change_position(self._checkstate) - self.stateChanged.emit(self.checkState()) anim_group.finished.connect(_finished) anim_group.start() @@ -447,6 +448,8 @@ class NiceCheckbox(QtWidgets.QFrame): return self._checkstate def setChecked(self, checked): + if checked == self._checkstate: + return self._checkstate = checked self._on_checkstate_change() From 91fd0066305172c340e62d91a2c41d627d17159c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Oct 2020 23:32:22 +0200 Subject: [PATCH 4/5] environments metadata are added in `config_value` not in `item_value` --- pype/tools/settings/settings/widgets/item_types.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index f3d51e3f1f..7f22f804a7 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -1302,14 +1302,16 @@ class RawJsonWidget(QtWidgets.QWidget, InputObject): output = {} for key, value in value.items(): output[key.upper()] = value - - output[METADATA_KEY] = { - "environments": { - self.env_group_key: list(output.keys()) - } - } return output + def config_value(self): + value = self.item_value() + value[METADATA_KEY] = { + "environments": { + self.env_group_key: list(value.keys()) + } + } + return {self.key: value} class ListItem(QtWidgets.QWidget, SettingObject): _btn_size = 20 From baf89fa6c604574fc33c8fc5a5026a10bea6756a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 2 Oct 2020 23:33:07 +0200 Subject: [PATCH 5/5] fixed discard changes --- .../settings/settings/widgets/item_types.py | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/pype/tools/settings/settings/widgets/item_types.py b/pype/tools/settings/settings/widgets/item_types.py index 7f22f804a7..8e1ef57942 100644 --- a/pype/tools/settings/settings/widgets/item_types.py +++ b/pype/tools/settings/settings/widgets/item_types.py @@ -850,6 +850,7 @@ class InputObject(SettingObject): self._is_overriden = False return + self._state = None self._is_modified = False self._is_overriden = self._was_overriden @@ -2517,13 +2518,22 @@ class DictWidget(QtWidgets.QWidget, SettingObject): self._has_studio_override = True def discard_changes(self): - self._is_overriden = self._was_overriden self._is_modified = False + self._is_overriden = self._was_overriden + self._has_studio_override = self._had_studio_override for input_field in self.input_fields: input_field.discard_changes() self._is_modified = self.child_modified + if not self.is_overidable and self.as_widget: + if self.has_studio_override: + self._is_modified = self.studio_value != self.item_value() + else: + self._is_modified = self.default_value != self.item_value() + + self._state = None + self._is_overriden = self._was_overriden def set_as_overriden(self): if self.is_overriden: @@ -2925,11 +2935,20 @@ class DictInvisible(QtWidgets.QWidget, SettingObject): def discard_changes(self): self._is_modified = False self._is_overriden = self._was_overriden + self._has_studio_override = self._had_studio_override for input_field in self.input_fields: input_field.discard_changes() self._is_modified = self.child_modified + if not self.is_overidable and self.as_widget: + if self.has_studio_override: + self._is_modified = self.studio_value != self.item_value() + else: + self._is_modified = self.default_value != self.item_value() + + self._state = None + self._is_overriden = self._was_overriden def set_as_overriden(self): if self.is_overriden: @@ -3331,20 +3350,20 @@ class PathWidget(QtWidgets.QWidget, SettingObject): self._has_studio_override = True def discard_changes(self): + self._is_modified = False self._is_overriden = self._was_overriden self._has_studio_override = self._had_studio_override self.input_field.discard_changes() - if not self.is_overidable: + self._is_modified = self.child_modified + if not self.is_overidable and self.as_widget: if self.has_studio_override: self._is_modified = self.studio_value != self.item_value() else: self._is_modified = self.default_value != self.item_value() - self._is_overriden = False - return - self._is_modified = False + self._state = None self._is_overriden = self._was_overriden def set_as_overriden(self): @@ -3460,11 +3479,20 @@ class DictFormWidget(QtWidgets.QWidget, SettingObject): def discard_changes(self): self._is_modified = False self._is_overriden = self._was_overriden + self._has_studio_override = self._had_studio_override - for item in self.input_fields: - item.discard_changes() + for input_field in self.input_fields: + input_field.discard_changes() self._is_modified = self.child_modified + if not self.is_overidable and self.as_widget: + if self.has_studio_override: + self._is_modified = self.studio_value != self.item_value() + else: + self._is_modified = self.default_value != self.item_value() + + self._state = None + self._is_overriden = self._was_overriden def remove_overrides(self): self._is_overriden = False