From 4951c9442a86bc23bd8ffa40618fc9c9676a8c49 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:45:22 +0200 Subject: [PATCH 1/3] small enhancements in nice checkbox --- client/ayon_core/tools/utils/nice_checkbox.py | 200 +++++++++--------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/client/ayon_core/tools/utils/nice_checkbox.py b/client/ayon_core/tools/utils/nice_checkbox.py index 3d9d63b6bc..d1cc8d16f5 100644 --- a/client/ayon_core/tools/utils/nice_checkbox.py +++ b/client/ayon_core/tools/utils/nice_checkbox.py @@ -1,7 +1,8 @@ -from math import floor, sqrt, ceil +from math import floor, ceil + from qtpy import QtWidgets, QtCore, QtGui -from ayon_core.style import get_objected_colors +from ayon_core.style import load_stylesheet, get_objected_colors class NiceCheckbox(QtWidgets.QFrame): @@ -9,12 +10,15 @@ class NiceCheckbox(QtWidgets.QFrame): clicked = QtCore.Signal() _checked_bg_color = None + _checked_bg_color_disabled = None _unchecked_bg_color = None + _unchecked_bg_color_disabled = None _checker_color = None + _checker_color_disabled = None _checker_hover_color = None def __init__(self, checked=False, draw_icons=False, parent=None): - super(NiceCheckbox, self).__init__(parent) + super().__init__(parent) self.setObjectName("NiceCheckbox") self.setAttribute(QtCore.Qt.WA_TranslucentBackground) @@ -48,8 +52,6 @@ class NiceCheckbox(QtWidgets.QFrame): self._pressed = False self._under_mouse = False - self.icon_scale_factor = sqrt(2) / 2 - icon_path_stroker = QtGui.QPainterPathStroker() icon_path_stroker.setCapStyle(QtCore.Qt.RoundCap) icon_path_stroker.setJoinStyle(QtCore.Qt.RoundJoin) @@ -61,35 +63,6 @@ class NiceCheckbox(QtWidgets.QFrame): self._base_size = QtCore.QSize(90, 50) self._load_colors() - @classmethod - def _load_colors(cls): - if cls._checked_bg_color is not None: - return - - colors_info = get_objected_colors("nice-checkbox") - - cls._checked_bg_color = colors_info["bg-checked"].get_qcolor() - cls._unchecked_bg_color = colors_info["bg-unchecked"].get_qcolor() - - cls._checker_color = colors_info["bg-checker"].get_qcolor() - cls._checker_hover_color = colors_info["bg-checker-hover"].get_qcolor() - - @property - def checked_bg_color(self): - return self._checked_bg_color - - @property - def unchecked_bg_color(self): - return self._unchecked_bg_color - - @property - def checker_color(self): - return self._checker_color - - @property - def checker_hover_color(self): - return self._checker_hover_color - def setTristate(self, tristate=True): if self._is_tristate != tristate: self._is_tristate = tristate @@ -121,14 +94,14 @@ class NiceCheckbox(QtWidgets.QFrame): def setFixedHeight(self, *args, **kwargs): self._fixed_height_set = True - super(NiceCheckbox, self).setFixedHeight(*args, **kwargs) + super().setFixedHeight(*args, **kwargs) if not self._fixed_width_set: width = self.get_width_hint_by_height(self.height()) self.setFixedWidth(width) def setFixedWidth(self, *args, **kwargs): self._fixed_width_set = True - super(NiceCheckbox, self).setFixedWidth(*args, **kwargs) + super().setFixedWidth(*args, **kwargs) if not self._fixed_height_set: height = self.get_height_hint_by_width(self.width()) self.setFixedHeight(height) @@ -136,7 +109,7 @@ class NiceCheckbox(QtWidgets.QFrame): def setFixedSize(self, *args, **kwargs): self._fixed_height_set = True self._fixed_width_set = True - super(NiceCheckbox, self).setFixedSize(*args, **kwargs) + super().setFixedSize(*args, **kwargs) def steps(self): return self._steps @@ -242,7 +215,7 @@ class NiceCheckbox(QtWidgets.QFrame): if event.buttons() & QtCore.Qt.LeftButton: self._pressed = True self.repaint() - super(NiceCheckbox, self).mousePressEvent(event) + super().mousePressEvent(event) def mouseReleaseEvent(self, event): if self._pressed and not event.buttons() & QtCore.Qt.LeftButton: @@ -252,7 +225,7 @@ class NiceCheckbox(QtWidgets.QFrame): self.clicked.emit() event.accept() return - super(NiceCheckbox, self).mouseReleaseEvent(event) + super().mouseReleaseEvent(event) def mouseMoveEvent(self, event): if self._pressed: @@ -261,19 +234,19 @@ class NiceCheckbox(QtWidgets.QFrame): self._under_mouse = under_mouse self.repaint() - super(NiceCheckbox, self).mouseMoveEvent(event) + super().mouseMoveEvent(event) def enterEvent(self, event): self._under_mouse = True if self.isEnabled(): self.repaint() - super(NiceCheckbox, self).enterEvent(event) + super().enterEvent(event) def leaveEvent(self, event): self._under_mouse = False if self.isEnabled(): self.repaint() - super(NiceCheckbox, self).leaveEvent(event) + super().leaveEvent(event) def _on_animation_timeout(self): if self._checkstate == QtCore.Qt.Checked: @@ -302,24 +275,13 @@ class NiceCheckbox(QtWidgets.QFrame): @staticmethod def steped_color(color1, color2, offset_ratio): - red_dif = ( - color1.red() - color2.red() - ) - green_dif = ( - color1.green() - color2.green() - ) - blue_dif = ( - color1.blue() - color2.blue() - ) - red = int(color2.red() + ( - red_dif * offset_ratio - )) - green = int(color2.green() + ( - green_dif * offset_ratio - )) - blue = int(color2.blue() + ( - blue_dif * offset_ratio - )) + red_dif = color1.red() - color2.red() + green_dif = color1.green() - color2.green() + blue_dif = color1.blue() - color2.blue() + + red = int(color2.red() + (red_dif * offset_ratio)) + green = int(color2.green() + (green_dif * offset_ratio)) + blue = int(color2.blue() + (blue_dif * offset_ratio)) return QtGui.QColor(red, green, blue) @@ -334,20 +296,28 @@ class NiceCheckbox(QtWidgets.QFrame): painter = QtGui.QPainter(self) painter.setRenderHint(QtGui.QPainter.Antialiasing) + painter.setPen(QtCore.Qt.NoPen) # Draw inner background - if self._current_step == self._steps: - bg_color = self.checked_bg_color + if not self.isEnabled(): + bg_color = ( + self._checked_bg_color_disabled + if self._current_step == self._steps + else self._unchecked_bg_color_disabled + ) + + elif self._current_step == self._steps: + bg_color = self._checked_bg_color elif self._current_step == 0: - bg_color = self.unchecked_bg_color + bg_color = self._unchecked_bg_color else: offset_ratio = float(self._current_step) / self._steps # Animation bg bg_color = self.steped_color( - self.checked_bg_color, - self.unchecked_bg_color, + self._checked_bg_color, + self._unchecked_bg_color, offset_ratio ) @@ -378,14 +348,20 @@ class NiceCheckbox(QtWidgets.QFrame): -margin_size_c, -margin_size_c ) - if checkbox_rect.width() > checkbox_rect.height(): - radius = floor(checkbox_rect.height() * 0.5) - else: - radius = floor(checkbox_rect.width() * 0.5) + slider_rect = QtCore.QRect(checkbox_rect) + slider_offset = int( + ceil(min(slider_rect.width(), slider_rect.height())) * 0.08 + ) + if slider_offset < 1: + slider_offset = 1 + slider_rect.adjust( + slider_offset, slider_offset, + -slider_offset, -slider_offset + ) + radius = floor(min(slider_rect.width(), slider_rect.height()) * 0.5) - painter.setPen(QtCore.Qt.NoPen) painter.setBrush(bg_color) - painter.drawRoundedRect(checkbox_rect, radius, radius) + painter.drawRoundedRect(slider_rect, radius, radius) # Draw checker checker_size = size_without_margins - (margin_size_c * 2) @@ -394,9 +370,8 @@ class NiceCheckbox(QtWidgets.QFrame): - (margin_size_c * 2) - checker_size ) - if self._current_step == 0: - x_offset = 0 - else: + x_offset = 0 + if self._current_step != 0: x_offset = (float(area_width) / self._steps) * self._current_step pos_x = checkbox_rect.x() + x_offset + margin_size_c @@ -404,55 +379,80 @@ class NiceCheckbox(QtWidgets.QFrame): checker_rect = QtCore.QRect(pos_x, pos_y, checker_size, checker_size) - under_mouse = self.isEnabled() and self._under_mouse - if under_mouse: - checker_color = self.checker_hover_color - else: - checker_color = self.checker_color + checker_color = self._checker_color + if not self.isEnabled(): + checker_color = self._checker_color_disabled + elif self._under_mouse: + checker_color = self._checker_hover_color painter.setBrush(checker_color) painter.drawEllipse(checker_rect) if self._draw_icons: painter.setBrush(bg_color) - icon_path = self._get_icon_path(painter, checker_rect) + icon_path = self._get_icon_path(checker_rect) painter.drawPath(icon_path) - # Draw shadow overlay - if not self.isEnabled(): - level = 33 - alpha = 127 - painter.setPen(QtCore.Qt.transparent) - painter.setBrush(QtGui.QColor(level, level, level, alpha)) - painter.drawRoundedRect(checkbox_rect, radius, radius) - painter.end() - def _get_icon_path(self, painter, checker_rect): + @classmethod + def _load_colors(cls): + if cls._checked_bg_color is not None: + return + + colors_info = get_objected_colors("nice-checkbox") + + disabled_color = QtGui.QColor(33, 33, 33, 127) + + cls._checked_bg_color = colors_info["bg-checked"].get_qcolor() + cls._checked_bg_color_disabled = cls._merge_colors( + cls._checked_bg_color, disabled_color + ) + cls._unchecked_bg_color = colors_info["bg-unchecked"].get_qcolor() + cls._unchecked_bg_color_disabled = cls._merge_colors( + cls._unchecked_bg_color, disabled_color + ) + + cls._checker_color = colors_info["bg-checker"].get_qcolor() + cls._checker_color_disabled = cls._merge_colors( + cls._checker_color, disabled_color + ) + cls._checker_hover_color = colors_info["bg-checker-hover"].get_qcolor() + + @staticmethod + def _merge_colors(color_1, color_2): + a = color_2.alphaF() + return QtGui.QColor( + floor((color_1.red() + (color_2.red() * a)) * 0.5), + floor((color_1.green() + (color_2.green() * a)) * 0.5), + floor((color_1.blue() + (color_2.blue() * a)) * 0.5), + color_1.alpha() + ) + + def _get_icon_path(self, checker_rect): self.icon_path_stroker.setWidth(checker_rect.height() / 5) if self._current_step == self._steps: - return self._get_enabled_icon_path(painter, checker_rect) + return self._get_enabled_icon_path(checker_rect) if self._current_step == 0: - return self._get_disabled_icon_path(painter, checker_rect) + return self._get_disabled_icon_path(checker_rect) if self._current_step == self._middle_step: - return self._get_middle_circle_path(painter, checker_rect) + return self._get_middle_circle_path(checker_rect) disabled_step = self._steps - self._current_step enabled_step = self._steps - disabled_step half_steps = self._steps + 1 - ((self._steps + 1) % 2) if enabled_step > disabled_step: return self._get_enabled_icon_path( - painter, checker_rect, enabled_step, half_steps - ) - else: - return self._get_disabled_icon_path( - painter, checker_rect, disabled_step, half_steps + checker_rect, enabled_step, half_steps ) + return self._get_disabled_icon_path( + checker_rect, disabled_step, half_steps + ) - def _get_middle_circle_path(self, painter, checker_rect): + def _get_middle_circle_path(self, checker_rect): width = self.icon_path_stroker.width() path = QtGui.QPainterPath() path.addEllipse(checker_rect.center(), width, width) @@ -460,7 +460,7 @@ class NiceCheckbox(QtWidgets.QFrame): return path def _get_enabled_icon_path( - self, painter, checker_rect, step=None, half_steps=None + self, checker_rect, step=None, half_steps=None ): fifteenth = float(checker_rect.height()) / 15 # Left point @@ -509,7 +509,7 @@ class NiceCheckbox(QtWidgets.QFrame): return self.icon_path_stroker.createStroke(path) def _get_disabled_icon_path( - self, painter, checker_rect, step=None, half_steps=None + self, checker_rect, step=None, half_steps=None ): center_point = QtCore.QPointF( float(checker_rect.width()) / 2, From f4855402cf82e44554df9d471d82366c2637a2eb Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:50:38 +0200 Subject: [PATCH 2/3] remove unused import --- client/ayon_core/tools/utils/nice_checkbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/utils/nice_checkbox.py b/client/ayon_core/tools/utils/nice_checkbox.py index d1cc8d16f5..f16b62eb9c 100644 --- a/client/ayon_core/tools/utils/nice_checkbox.py +++ b/client/ayon_core/tools/utils/nice_checkbox.py @@ -2,7 +2,7 @@ from math import floor, ceil from qtpy import QtWidgets, QtCore, QtGui -from ayon_core.style import load_stylesheet, get_objected_colors +from ayon_core.style import get_objected_colors class NiceCheckbox(QtWidgets.QFrame): From 40e8384b1cb33c0771e62eba7b0dedaac9e28e94 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 14 Aug 2025 16:50:44 +0200 Subject: [PATCH 3/3] formatting fix --- client/ayon_core/tools/utils/nice_checkbox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/tools/utils/nice_checkbox.py b/client/ayon_core/tools/utils/nice_checkbox.py index f16b62eb9c..c33533b0e4 100644 --- a/client/ayon_core/tools/utils/nice_checkbox.py +++ b/client/ayon_core/tools/utils/nice_checkbox.py @@ -358,7 +358,7 @@ class NiceCheckbox(QtWidgets.QFrame): slider_offset, slider_offset, -slider_offset, -slider_offset ) - radius = floor(min(slider_rect.width(), slider_rect.height()) * 0.5) + radius = floor(min(slider_rect.width(), slider_rect.height()) * 0.5) painter.setBrush(bg_color) painter.drawRoundedRect(slider_rect, radius, radius)