mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
Merge pull request #1542 from pypeclub/feature/color_entity
This commit is contained in:
commit
20615721da
16 changed files with 2860 additions and 26 deletions
|
|
@ -57,6 +57,7 @@ from .exceptions import (
|
|||
SchemaError,
|
||||
DefaultsNotDefined,
|
||||
StudioDefaultsNotDefined,
|
||||
BaseInvalidValueType,
|
||||
InvalidValueType,
|
||||
InvalidKeySymbols,
|
||||
SchemaMissingFileInfo,
|
||||
|
|
@ -96,7 +97,7 @@ from .input_entities import (
|
|||
PathInput,
|
||||
RawJsonEntity
|
||||
)
|
||||
|
||||
from .color_entity import ColorEntity
|
||||
from .enum_entity import (
|
||||
BaseEnumEntity,
|
||||
EnumEntity,
|
||||
|
|
@ -115,6 +116,7 @@ from .anatomy_entities import AnatomyEntity
|
|||
__all__ = (
|
||||
"DefaultsNotDefined",
|
||||
"StudioDefaultsNotDefined",
|
||||
"BaseInvalidValueType",
|
||||
"InvalidValueType",
|
||||
"InvalidKeySymbols",
|
||||
"SchemaMissingFileInfo",
|
||||
|
|
@ -146,6 +148,8 @@ __all__ = (
|
|||
"PathInput",
|
||||
"RawJsonEntity",
|
||||
|
||||
"ColorEntity",
|
||||
|
||||
"BaseEnumEntity",
|
||||
"EnumEntity",
|
||||
"AppsEnumEntity",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from .lib import (
|
|||
)
|
||||
|
||||
from .exceptions import (
|
||||
BaseInvalidValueType,
|
||||
InvalidValueType,
|
||||
SchemeGroupHierarchyBug,
|
||||
EntitySchemaError
|
||||
|
|
@ -377,7 +378,7 @@ class BaseItemEntity(BaseEntity):
|
|||
|
||||
try:
|
||||
new_value = self.convert_to_valid_type(value)
|
||||
except InvalidValueType:
|
||||
except BaseInvalidValueType:
|
||||
new_value = NOT_SET
|
||||
|
||||
if new_value is not NOT_SET:
|
||||
|
|
|
|||
54
openpype/settings/entities/color_entity.py
Normal file
54
openpype/settings/entities/color_entity.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
from .lib import STRING_TYPE
|
||||
from .input_entities import InputEntity
|
||||
from .exceptions import (
|
||||
BaseInvalidValueType,
|
||||
InvalidValueType
|
||||
)
|
||||
|
||||
|
||||
class ColorEntity(InputEntity):
|
||||
schema_types = ["color"]
|
||||
|
||||
def _item_initalization(self):
|
||||
self.valid_value_types = (list, )
|
||||
self.value_on_not_set = [0, 0, 0, 255]
|
||||
|
||||
def convert_to_valid_type(self, value):
|
||||
"""Conversion to valid type.
|
||||
|
||||
Complexity of entity requires to override BaseEntity implementation.
|
||||
"""
|
||||
# Convertion to valid value type `list`
|
||||
if isinstance(value, (set, tuple)):
|
||||
value = list(value)
|
||||
|
||||
# Skip other validations if is not `list`
|
||||
if not isinstance(value, list):
|
||||
raise InvalidValueType(
|
||||
self.valid_value_types, type(value), self.path
|
||||
)
|
||||
|
||||
# Allow list of len 3 (last aplha is set to max)
|
||||
if len(value) == 3:
|
||||
value.append(255)
|
||||
|
||||
if len(value) != 4:
|
||||
reason = "Color entity expect 4 items in list got {}".format(
|
||||
len(value)
|
||||
)
|
||||
raise BaseInvalidValueType(reason, self.path)
|
||||
|
||||
new_value = []
|
||||
for item in value:
|
||||
if not isinstance(item, int):
|
||||
if isinstance(item, (STRING_TYPE, float)):
|
||||
item = int(item)
|
||||
|
||||
is_valid = isinstance(item, int) and -1 < item < 256
|
||||
if not is_valid:
|
||||
reason = (
|
||||
"Color entity expect 4 integers in range 0-255 got {}"
|
||||
).format(value)
|
||||
raise BaseInvalidValueType(reason, self.path)
|
||||
new_value.append(item)
|
||||
return new_value
|
||||
|
|
@ -15,20 +15,22 @@ class StudioDefaultsNotDefined(Exception):
|
|||
super(StudioDefaultsNotDefined, self).__init__(msg)
|
||||
|
||||
|
||||
class InvalidValueType(Exception):
|
||||
msg_template = "{}"
|
||||
class BaseInvalidValueType(Exception):
|
||||
def __init__(self, reason, path):
|
||||
msg = "Path \"{}\". {}".format(path, reason)
|
||||
self.msg = msg
|
||||
super(BaseInvalidValueType, self).__init__(msg)
|
||||
|
||||
|
||||
class InvalidValueType(BaseInvalidValueType):
|
||||
def __init__(self, valid_types, invalid_type, path):
|
||||
msg = "Path \"{}\". ".format(path)
|
||||
|
||||
joined_types = ", ".join(
|
||||
[str(valid_type) for valid_type in valid_types]
|
||||
)
|
||||
msg += "Got invalid type \"{}\". Expected: {}".format(
|
||||
msg = "Got invalid type \"{}\". Expected: {}".format(
|
||||
invalid_type, joined_types
|
||||
)
|
||||
self.msg = msg
|
||||
super(InvalidValueType, self).__init__(msg)
|
||||
super(InvalidValueType, self).__init__(msg, path)
|
||||
|
||||
|
||||
class RequiredKeyModified(KeyError):
|
||||
|
|
|
|||
|
|
@ -420,6 +420,18 @@
|
|||
}
|
||||
```
|
||||
|
||||
### color
|
||||
- preimplemented entity to store and load color values
|
||||
- entity store and expect list of 4 integers in range 0-255
|
||||
- integers represents rgba [Red, Green, Blue, Alpha]
|
||||
|
||||
```
|
||||
{
|
||||
"type": "color",
|
||||
"key": "bg_color",
|
||||
"label": "Background Color"
|
||||
}
|
||||
```
|
||||
|
||||
## Noninteractive widgets
|
||||
- have nothing to do with data
|
||||
|
|
|
|||
|
|
@ -228,14 +228,9 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_rgba_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Fill Color",
|
||||
"name": "fill_color"
|
||||
}
|
||||
]
|
||||
"type": "color",
|
||||
"label": "Fill Color",
|
||||
"key": "fill_color"
|
||||
},
|
||||
{
|
||||
"key": "line_thickness",
|
||||
|
|
@ -245,14 +240,9 @@
|
|||
"maximum": 1000
|
||||
},
|
||||
{
|
||||
"type": "schema_template",
|
||||
"name": "template_rgba_color",
|
||||
"template_data": [
|
||||
{
|
||||
"label": "Line Color",
|
||||
"name": "line_color"
|
||||
}
|
||||
]
|
||||
"type": "color",
|
||||
"label": "Line Color",
|
||||
"key": "line_color"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
"type": "dict",
|
||||
"is_file": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "color",
|
||||
"label": "Color input",
|
||||
"type": "color"
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "schema_template_exaples",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ from openpype.settings.entities import (
|
|||
TextEntity,
|
||||
PathInput,
|
||||
RawJsonEntity,
|
||||
ColorEntity,
|
||||
|
||||
DefaultsNotDefined,
|
||||
StudioDefaultsNotDefined,
|
||||
|
|
@ -44,7 +45,7 @@ from .item_widgets import (
|
|||
PathWidget,
|
||||
PathInputWidget
|
||||
)
|
||||
|
||||
from .color_widget import ColorWidget
|
||||
from avalon.vendor import qtawesome
|
||||
|
||||
|
||||
|
|
@ -113,6 +114,9 @@ class SettingsCategoryWidget(QtWidgets.QWidget):
|
|||
elif isinstance(entity, RawJsonEntity):
|
||||
return RawJsonWidget(*args)
|
||||
|
||||
elif isinstance(entity, ColorEntity):
|
||||
return ColorWidget(*args)
|
||||
|
||||
elif isinstance(entity, BaseEnumEntity):
|
||||
return EnumeratorWidget(*args)
|
||||
|
||||
|
|
|
|||
171
openpype/tools/settings/settings/color_widget.py
Normal file
171
openpype/tools/settings/settings/color_widget.py
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from .item_widgets import InputWidget
|
||||
|
||||
from openpype.widgets.color_widgets import (
|
||||
ColorPickerWidget,
|
||||
draw_checkerboard_tile
|
||||
)
|
||||
|
||||
|
||||
class ColorWidget(InputWidget):
|
||||
def _add_inputs_to_layout(self):
|
||||
self.input_field = ColorViewer(self.content_widget)
|
||||
|
||||
self.setFocusProxy(self.input_field)
|
||||
|
||||
self.content_layout.addWidget(self.input_field, 1)
|
||||
|
||||
self.input_field.clicked.connect(self._on_click)
|
||||
|
||||
self._dialog = None
|
||||
|
||||
def _on_click(self):
|
||||
if self._dialog:
|
||||
self._dialog.open()
|
||||
return
|
||||
|
||||
dialog = ColorDialog(self.input_field.color(), self)
|
||||
self._dialog = dialog
|
||||
|
||||
dialog.open()
|
||||
dialog.finished.connect(self._on_dialog_finish)
|
||||
|
||||
def _on_dialog_finish(self, *_args):
|
||||
if not self._dialog:
|
||||
return
|
||||
|
||||
color = self._dialog.result()
|
||||
if color is not None:
|
||||
self.input_field.set_color(color)
|
||||
self._on_value_change()
|
||||
|
||||
self._dialog.deleteLater()
|
||||
self._dialog = None
|
||||
|
||||
def _on_entity_change(self):
|
||||
if self.entity.value != self.input_value():
|
||||
self.set_entity_value()
|
||||
|
||||
def set_entity_value(self):
|
||||
self.input_field.set_color(*self.entity.value)
|
||||
|
||||
def input_value(self):
|
||||
color = self.input_field.color()
|
||||
return [color.red(), color.green(), color.blue(), color.alpha()]
|
||||
|
||||
def _on_value_change(self):
|
||||
if self.ignore_input_changes:
|
||||
return
|
||||
|
||||
self.entity.set(self.input_value())
|
||||
|
||||
|
||||
class ColorViewer(QtWidgets.QWidget):
|
||||
clicked = QtCore.Signal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ColorViewer, self).__init__(parent)
|
||||
|
||||
self.setMinimumSize(10, 10)
|
||||
|
||||
self.actual_pen = QtGui.QPen()
|
||||
self.actual_color = QtGui.QColor()
|
||||
self._checkerboard = None
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
if event.button() == QtCore.Qt.LeftButton:
|
||||
self.clicked.emit()
|
||||
super(ColorViewer, self).mouseReleaseEvent(event)
|
||||
|
||||
def checkerboard(self):
|
||||
if not self._checkerboard:
|
||||
self._checkerboard = draw_checkerboard_tile(self.height() / 4)
|
||||
return self._checkerboard
|
||||
|
||||
def color(self):
|
||||
return self.actual_color
|
||||
|
||||
def set_color(self, *args):
|
||||
# Create copy of entered color
|
||||
self.actual_color = QtGui.QColor(*args)
|
||||
# Repaint
|
||||
self.update()
|
||||
|
||||
def set_alpha(self, alpha):
|
||||
# Change alpha of current color
|
||||
self.actual_color.setAlpha(alpha)
|
||||
# Repaint
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
rect = event.rect()
|
||||
|
||||
painter = QtGui.QPainter(self)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
radius = rect.height() / 2
|
||||
rounded_rect = QtGui.QPainterPath()
|
||||
rounded_rect.addRoundedRect(QtCore.QRectF(rect), radius, radius)
|
||||
painter.setClipPath(rounded_rect)
|
||||
|
||||
pen = QtGui.QPen(QtGui.QColor(255, 255, 255, 67))
|
||||
pen.setWidth(1)
|
||||
painter.setPen(pen)
|
||||
painter.drawTiledPixmap(rect, self.checkerboard())
|
||||
painter.fillRect(rect, self.actual_color)
|
||||
painter.drawPath(rounded_rect)
|
||||
|
||||
painter.end()
|
||||
|
||||
|
||||
class ColorDialog(QtWidgets.QDialog):
|
||||
def __init__(self, color=None, parent=None):
|
||||
super(ColorDialog, self).__init__(parent)
|
||||
|
||||
self.setWindowTitle("Color picker dialog")
|
||||
|
||||
picker_widget = ColorPickerWidget(color, self)
|
||||
|
||||
footer_widget = QtWidgets.QWidget(self)
|
||||
|
||||
ok_btn = QtWidgets.QPushButton("Ok", footer_widget)
|
||||
cancel_btn = QtWidgets.QPushButton("Cancel", footer_widget)
|
||||
|
||||
footer_layout = QtWidgets.QHBoxLayout(footer_widget)
|
||||
footer_layout.setContentsMargins(0, 0, 0, 0)
|
||||
footer_layout.addStretch(1)
|
||||
footer_layout.addWidget(ok_btn)
|
||||
footer_layout.addWidget(cancel_btn)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
layout.addWidget(picker_widget, 1)
|
||||
layout.addWidget(footer_widget, 0)
|
||||
|
||||
ok_btn.clicked.connect(self.on_ok_clicked)
|
||||
cancel_btn.clicked.connect(self.on_cancel_clicked)
|
||||
|
||||
self.picker_widget = picker_widget
|
||||
self.ok_btn = ok_btn
|
||||
self.cancel_btn = cancel_btn
|
||||
|
||||
self._result = None
|
||||
|
||||
def showEvent(self, event):
|
||||
super(ColorDialog, self).showEvent(event)
|
||||
|
||||
btns_width = max(self.ok_btn.width(), self.cancel_btn.width())
|
||||
self.ok_btn.setFixedWidth(btns_width)
|
||||
self.cancel_btn.setFixedWidth(btns_width)
|
||||
|
||||
def on_ok_clicked(self):
|
||||
self._result = self.picker_widget.color()
|
||||
self.close()
|
||||
|
||||
def on_cancel_clicked(self):
|
||||
self._result = None
|
||||
self.close()
|
||||
|
||||
def result(self):
|
||||
return self._result
|
||||
14
openpype/widgets/color_widgets/__init__.py
Normal file
14
openpype/widgets/color_widgets/__init__.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from .color_picker_widget import (
|
||||
ColorPickerWidget
|
||||
)
|
||||
|
||||
from .color_view import (
|
||||
draw_checkerboard_tile
|
||||
)
|
||||
|
||||
|
||||
__all__ = (
|
||||
"ColorPickerWidget",
|
||||
|
||||
"draw_checkerboard_tile"
|
||||
)
|
||||
639
openpype/widgets/color_widgets/color_inputs.py
Normal file
639
openpype/widgets/color_widgets/color_inputs.py
Normal file
|
|
@ -0,0 +1,639 @@
|
|||
import re
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from .color_view import draw_checkerboard_tile
|
||||
|
||||
|
||||
slide_style = """
|
||||
QSlider::groove:horizontal {
|
||||
background: qlineargradient(
|
||||
x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #000, stop: 1 #fff
|
||||
);
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0, x2:1, y2:1, stop:0 #ddd, stop:1 #bbb
|
||||
);
|
||||
border: 1px solid #777;
|
||||
width: 8px;
|
||||
margin-top: -1px;
|
||||
margin-bottom: -1px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal:hover {
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ddd
|
||||
);
|
||||
border: 1px solid #444;ff
|
||||
border-radius: 4px;
|
||||
}"""
|
||||
|
||||
|
||||
class AlphaSlider(QtWidgets.QSlider):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AlphaSlider, self).__init__(*args, **kwargs)
|
||||
self._mouse_clicked = False
|
||||
self.setSingleStep(1)
|
||||
self.setMinimum(0)
|
||||
self.setMaximum(255)
|
||||
self.setValue(255)
|
||||
|
||||
self._checkerboard = None
|
||||
|
||||
def checkerboard(self):
|
||||
if self._checkerboard is None:
|
||||
self._checkerboard = draw_checkerboard_tile(
|
||||
3, QtGui.QColor(173, 173, 173), QtGui.QColor(27, 27, 27)
|
||||
)
|
||||
return self._checkerboard
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
self._mouse_clicked = True
|
||||
if event.button() == QtCore.Qt.LeftButton:
|
||||
self._set_value_to_pos(event.pos().x())
|
||||
return event.accept()
|
||||
return super(AlphaSlider, self).mousePressEvent(event)
|
||||
|
||||
def _set_value_to_pos(self, pos_x):
|
||||
value = (
|
||||
self.maximum() - self.minimum()
|
||||
) * pos_x / self.width() + self.minimum()
|
||||
self.setValue(value)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self._mouse_clicked:
|
||||
self._set_value_to_pos(event.pos().x())
|
||||
super(AlphaSlider, self).mouseMoveEvent(event)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
self._mouse_clicked = True
|
||||
super(AlphaSlider, self).mouseReleaseEvent(event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QtGui.QPainter(self)
|
||||
opt = QtWidgets.QStyleOptionSlider()
|
||||
self.initStyleOption(opt)
|
||||
|
||||
painter.fillRect(event.rect(), QtCore.Qt.transparent)
|
||||
|
||||
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform)
|
||||
rect = self.style().subControlRect(
|
||||
QtWidgets.QStyle.CC_Slider,
|
||||
opt,
|
||||
QtWidgets.QStyle.SC_SliderGroove,
|
||||
self
|
||||
)
|
||||
final_height = 9
|
||||
offset_top = 0
|
||||
if rect.height() > final_height:
|
||||
offset_top = int((rect.height() - final_height) / 2)
|
||||
rect = QtCore.QRect(
|
||||
rect.x(),
|
||||
offset_top,
|
||||
rect.width(),
|
||||
final_height
|
||||
)
|
||||
|
||||
pix_rect = QtCore.QRect(event.rect())
|
||||
pix_rect.setX(rect.x())
|
||||
pix_rect.setWidth(rect.width() - (2 * rect.x()))
|
||||
pix = QtGui.QPixmap(pix_rect.width(), pix_rect.height())
|
||||
pix_painter = QtGui.QPainter(pix)
|
||||
pix_painter.drawTiledPixmap(pix_rect, self.checkerboard())
|
||||
gradient = QtGui.QLinearGradient(rect.topLeft(), rect.bottomRight())
|
||||
gradient.setColorAt(0, QtCore.Qt.transparent)
|
||||
gradient.setColorAt(1, QtCore.Qt.white)
|
||||
pix_painter.fillRect(pix_rect, gradient)
|
||||
pix_painter.end()
|
||||
|
||||
brush = QtGui.QBrush(pix)
|
||||
painter.save()
|
||||
painter.setPen(QtCore.Qt.NoPen)
|
||||
painter.setBrush(brush)
|
||||
ratio = rect.height() / 2
|
||||
painter.drawRoundedRect(rect, ratio, ratio)
|
||||
painter.restore()
|
||||
|
||||
_handle_rect = self.style().subControlRect(
|
||||
QtWidgets.QStyle.CC_Slider,
|
||||
opt,
|
||||
QtWidgets.QStyle.SC_SliderHandle,
|
||||
self
|
||||
)
|
||||
|
||||
handle_rect = QtCore.QRect(rect)
|
||||
if offset_top > 1:
|
||||
height = handle_rect.height()
|
||||
handle_rect.setY(handle_rect.y() - 1)
|
||||
handle_rect.setHeight(height + 2)
|
||||
handle_rect.setX(_handle_rect.x())
|
||||
handle_rect.setWidth(handle_rect.height())
|
||||
|
||||
painter.save()
|
||||
|
||||
gradient = QtGui.QRadialGradient()
|
||||
radius = handle_rect.height() / 2
|
||||
center_x = handle_rect.width() / 2 + handle_rect.x()
|
||||
center_y = handle_rect.height()
|
||||
gradient.setCenter(center_x, center_y)
|
||||
gradient.setCenterRadius(radius)
|
||||
gradient.setFocalPoint(center_x, center_y)
|
||||
|
||||
gradient.setColorAt(0.9, QtGui.QColor(127, 127, 127))
|
||||
gradient.setColorAt(1, QtCore.Qt.transparent)
|
||||
|
||||
painter.setPen(QtCore.Qt.NoPen)
|
||||
painter.setBrush(gradient)
|
||||
painter.drawEllipse(handle_rect)
|
||||
|
||||
painter.restore()
|
||||
|
||||
|
||||
class AlphaInputs(QtWidgets.QWidget):
|
||||
alpha_changed = QtCore.Signal(int)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(AlphaInputs, self).__init__(parent)
|
||||
|
||||
self._block_changes = False
|
||||
self.alpha_value = None
|
||||
|
||||
percent_input = QtWidgets.QDoubleSpinBox(self)
|
||||
percent_input.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
percent_input.setMinimum(0)
|
||||
percent_input.setMaximum(100)
|
||||
percent_input.setDecimals(2)
|
||||
|
||||
int_input = QtWidgets.QSpinBox(self)
|
||||
int_input.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
int_input.setMinimum(0)
|
||||
int_input.setMaximum(255)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(int_input)
|
||||
layout.addWidget(QtWidgets.QLabel("0-255"))
|
||||
layout.addWidget(percent_input)
|
||||
layout.addWidget(QtWidgets.QLabel("%"))
|
||||
|
||||
percent_input.valueChanged.connect(self._on_percent_change)
|
||||
int_input.valueChanged.connect(self._on_int_change)
|
||||
|
||||
self.percent_input = percent_input
|
||||
self.int_input = int_input
|
||||
|
||||
self.set_alpha(255)
|
||||
|
||||
def set_alpha(self, alpha):
|
||||
if alpha == self.alpha_value:
|
||||
return
|
||||
self.alpha_value = alpha
|
||||
|
||||
self.update_alpha()
|
||||
|
||||
def _on_percent_change(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.alpha_value = int(self.percent_input.value() * 255 / 100)
|
||||
self.alpha_changed.emit(self.alpha_value)
|
||||
self.update_alpha()
|
||||
|
||||
def _on_int_change(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
|
||||
self.alpha_value = self.int_input.value()
|
||||
self.alpha_changed.emit(self.alpha_value)
|
||||
self.update_alpha()
|
||||
|
||||
def update_alpha(self):
|
||||
self._block_changes = True
|
||||
if self.int_input.value() != self.alpha_value:
|
||||
self.int_input.setValue(self.alpha_value)
|
||||
|
||||
percent = round(100 * self.alpha_value / 255, 2)
|
||||
if self.percent_input.value() != percent:
|
||||
self.percent_input.setValue(percent)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
|
||||
class RGBInputs(QtWidgets.QWidget):
|
||||
value_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, color, parent=None):
|
||||
super(RGBInputs, self).__init__(parent)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
self.color = color
|
||||
|
||||
input_red = QtWidgets.QSpinBox(self)
|
||||
input_green = QtWidgets.QSpinBox(self)
|
||||
input_blue = QtWidgets.QSpinBox(self)
|
||||
|
||||
input_red.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_green.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_blue.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
|
||||
input_red.setMinimum(0)
|
||||
input_green.setMinimum(0)
|
||||
input_blue.setMinimum(0)
|
||||
|
||||
input_red.setMaximum(255)
|
||||
input_green.setMaximum(255)
|
||||
input_blue.setMaximum(255)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(input_red, 1)
|
||||
layout.addWidget(input_green, 1)
|
||||
layout.addWidget(input_blue, 1)
|
||||
|
||||
input_red.valueChanged.connect(self._on_red_change)
|
||||
input_green.valueChanged.connect(self._on_green_change)
|
||||
input_blue.valueChanged.connect(self._on_blue_change)
|
||||
|
||||
self.input_red = input_red
|
||||
self.input_green = input_green
|
||||
self.input_blue = input_blue
|
||||
|
||||
def _on_red_change(self, value):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.color.setRed(value)
|
||||
self._on_change()
|
||||
|
||||
def _on_green_change(self, value):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.color.setGreen(value)
|
||||
self._on_change()
|
||||
|
||||
def _on_blue_change(self, value):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.color.setBlue(value)
|
||||
self._on_change()
|
||||
|
||||
def _on_change(self):
|
||||
self.value_changed.emit()
|
||||
|
||||
def color_changed(self):
|
||||
if (
|
||||
self.input_red.value() == self.color.red()
|
||||
and self.input_green.value() == self.color.green()
|
||||
and self.input_blue.value() == self.color.blue()
|
||||
):
|
||||
return
|
||||
|
||||
self._block_changes = True
|
||||
|
||||
self.input_red.setValue(self.color.red())
|
||||
self.input_green.setValue(self.color.green())
|
||||
self.input_blue.setValue(self.color.blue())
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
|
||||
class CMYKInputs(QtWidgets.QWidget):
|
||||
value_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, color, parent=None):
|
||||
super(CMYKInputs, self).__init__(parent)
|
||||
|
||||
self.color = color
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
input_cyan = QtWidgets.QSpinBox(self)
|
||||
input_magenta = QtWidgets.QSpinBox(self)
|
||||
input_yellow = QtWidgets.QSpinBox(self)
|
||||
input_black = QtWidgets.QSpinBox(self)
|
||||
|
||||
input_cyan.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_magenta.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_yellow.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_black.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
|
||||
input_cyan.setMinimum(0)
|
||||
input_magenta.setMinimum(0)
|
||||
input_yellow.setMinimum(0)
|
||||
input_black.setMinimum(0)
|
||||
|
||||
input_cyan.setMaximum(255)
|
||||
input_magenta.setMaximum(255)
|
||||
input_yellow.setMaximum(255)
|
||||
input_black.setMaximum(255)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(input_cyan, 1)
|
||||
layout.addWidget(input_magenta, 1)
|
||||
layout.addWidget(input_yellow, 1)
|
||||
layout.addWidget(input_black, 1)
|
||||
|
||||
input_cyan.valueChanged.connect(self._on_change)
|
||||
input_magenta.valueChanged.connect(self._on_change)
|
||||
input_yellow.valueChanged.connect(self._on_change)
|
||||
input_black.valueChanged.connect(self._on_change)
|
||||
|
||||
self.input_cyan = input_cyan
|
||||
self.input_magenta = input_magenta
|
||||
self.input_yellow = input_yellow
|
||||
self.input_black = input_black
|
||||
|
||||
def _on_change(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.color.setCmyk(
|
||||
self.input_cyan.value(),
|
||||
self.input_magenta.value(),
|
||||
self.input_yellow.value(),
|
||||
self.input_black.value()
|
||||
)
|
||||
self.value_changed.emit()
|
||||
|
||||
def color_changed(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
_cur_color = QtGui.QColor()
|
||||
_cur_color.setCmyk(
|
||||
self.input_cyan.value(),
|
||||
self.input_magenta.value(),
|
||||
self.input_yellow.value(),
|
||||
self.input_black.value()
|
||||
)
|
||||
if (
|
||||
_cur_color.red() == self.color.red()
|
||||
and _cur_color.green() == self.color.green()
|
||||
and _cur_color.blue() == self.color.blue()
|
||||
):
|
||||
return
|
||||
|
||||
c, m, y, k, _ = self.color.getCmyk()
|
||||
self._block_changes = True
|
||||
|
||||
self.input_cyan.setValue(c)
|
||||
self.input_magenta.setValue(m)
|
||||
self.input_yellow.setValue(y)
|
||||
self.input_black.setValue(k)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
|
||||
class HEXInputs(QtWidgets.QWidget):
|
||||
hex_regex = re.compile("^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$")
|
||||
value_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, color, parent=None):
|
||||
super(HEXInputs, self).__init__(parent)
|
||||
self.color = color
|
||||
|
||||
input_field = QtWidgets.QLineEdit(self)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(input_field, 1)
|
||||
|
||||
input_field.textChanged.connect(self._on_change)
|
||||
|
||||
self.input_field = input_field
|
||||
|
||||
def _on_change(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
input_value = self.input_field.text()
|
||||
# TODO what if does not match?
|
||||
if self.hex_regex.match(input_value):
|
||||
self.color.setNamedColor(input_value)
|
||||
self.value_changed.emit()
|
||||
|
||||
def color_changed(self):
|
||||
input_value = self.input_field.text()
|
||||
if self.hex_regex.match(input_value):
|
||||
_cur_color = QtGui.QColor()
|
||||
_cur_color.setNamedColor(input_value)
|
||||
if (
|
||||
_cur_color.red() == self.color.red()
|
||||
and _cur_color.green() == self.color.green()
|
||||
and _cur_color.blue() == self.color.blue()
|
||||
):
|
||||
return
|
||||
self._block_changes = True
|
||||
|
||||
self.input_field.setText(self.color.name())
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
|
||||
class HSVInputs(QtWidgets.QWidget):
|
||||
value_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, color, parent=None):
|
||||
super(HSVInputs, self).__init__(parent)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
self.color = color
|
||||
|
||||
input_hue = QtWidgets.QSpinBox(self)
|
||||
input_sat = QtWidgets.QSpinBox(self)
|
||||
input_val = QtWidgets.QSpinBox(self)
|
||||
|
||||
input_hue.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_sat.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_val.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
|
||||
input_hue.setMinimum(0)
|
||||
input_sat.setMinimum(0)
|
||||
input_val.setMinimum(0)
|
||||
|
||||
input_hue.setMaximum(359)
|
||||
input_sat.setMaximum(255)
|
||||
input_val.setMaximum(255)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(input_hue, 1)
|
||||
layout.addWidget(input_sat, 1)
|
||||
layout.addWidget(input_val, 1)
|
||||
|
||||
input_hue.valueChanged.connect(self._on_change)
|
||||
input_sat.valueChanged.connect(self._on_change)
|
||||
input_val.valueChanged.connect(self._on_change)
|
||||
|
||||
self.input_hue = input_hue
|
||||
self.input_sat = input_sat
|
||||
self.input_val = input_val
|
||||
|
||||
def _on_change(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.color.setHsv(
|
||||
self.input_hue.value(),
|
||||
self.input_sat.value(),
|
||||
self.input_val.value()
|
||||
)
|
||||
self.value_changed.emit()
|
||||
|
||||
def color_changed(self):
|
||||
_cur_color = QtGui.QColor()
|
||||
_cur_color.setHsv(
|
||||
self.input_hue.value(),
|
||||
self.input_sat.value(),
|
||||
self.input_val.value()
|
||||
)
|
||||
if (
|
||||
_cur_color.red() == self.color.red()
|
||||
and _cur_color.green() == self.color.green()
|
||||
and _cur_color.blue() == self.color.blue()
|
||||
):
|
||||
return
|
||||
|
||||
self._block_changes = True
|
||||
h, s, v, _ = self.color.getHsv()
|
||||
|
||||
self.input_hue.setValue(h)
|
||||
self.input_sat.setValue(s)
|
||||
self.input_val.setValue(v)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
|
||||
class HSLInputs(QtWidgets.QWidget):
|
||||
value_changed = QtCore.Signal()
|
||||
|
||||
def __init__(self, color, parent=None):
|
||||
super(HSLInputs, self).__init__(parent)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
self.color = color
|
||||
|
||||
input_hue = QtWidgets.QSpinBox(self)
|
||||
input_sat = QtWidgets.QSpinBox(self)
|
||||
input_light = QtWidgets.QSpinBox(self)
|
||||
|
||||
input_hue.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_sat.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
input_light.setButtonSymbols(QtWidgets.QSpinBox.NoButtons)
|
||||
|
||||
input_hue.setMinimum(0)
|
||||
input_sat.setMinimum(0)
|
||||
input_light.setMinimum(0)
|
||||
|
||||
input_hue.setMaximum(359)
|
||||
input_sat.setMaximum(255)
|
||||
input_light.setMaximum(255)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(input_hue, 1)
|
||||
layout.addWidget(input_sat, 1)
|
||||
layout.addWidget(input_light, 1)
|
||||
|
||||
input_hue.valueChanged.connect(self._on_change)
|
||||
input_sat.valueChanged.connect(self._on_change)
|
||||
input_light.valueChanged.connect(self._on_change)
|
||||
|
||||
self.input_hue = input_hue
|
||||
self.input_sat = input_sat
|
||||
self.input_light = input_light
|
||||
|
||||
def _on_change(self):
|
||||
if self._block_changes:
|
||||
return
|
||||
self.color.setHsl(
|
||||
self.input_hue.value(),
|
||||
self.input_sat.value(),
|
||||
self.input_light.value()
|
||||
)
|
||||
self.value_changed.emit()
|
||||
|
||||
def color_changed(self):
|
||||
_cur_color = QtGui.QColor()
|
||||
_cur_color.setHsl(
|
||||
self.input_hue.value(),
|
||||
self.input_sat.value(),
|
||||
self.input_light.value()
|
||||
)
|
||||
if (
|
||||
_cur_color.red() == self.color.red()
|
||||
and _cur_color.green() == self.color.green()
|
||||
and _cur_color.blue() == self.color.blue()
|
||||
):
|
||||
return
|
||||
|
||||
self._block_changes = True
|
||||
h, s, l, _ = self.color.getHsl()
|
||||
|
||||
self.input_hue.setValue(h)
|
||||
self.input_sat.setValue(s)
|
||||
self.input_light.setValue(l)
|
||||
|
||||
self._block_changes = False
|
||||
|
||||
|
||||
class ColorInputsWidget(QtWidgets.QWidget):
|
||||
color_changed = QtCore.Signal(QtGui.QColor)
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
super(ColorInputsWidget, self).__init__(parent)
|
||||
|
||||
color = QtGui.QColor()
|
||||
|
||||
input_fields = []
|
||||
|
||||
if kwargs.get("use_hex", True):
|
||||
input_fields.append(HEXInputs(color, self))
|
||||
|
||||
if kwargs.get("use_rgb", True):
|
||||
input_fields.append(RGBInputs(color, self))
|
||||
|
||||
if kwargs.get("use_hsl", True):
|
||||
input_fields.append(HSLInputs(color, self))
|
||||
|
||||
if kwargs.get("use_hsv", True):
|
||||
input_fields.append(HSVInputs(color, self))
|
||||
|
||||
if kwargs.get("use_cmyk", True):
|
||||
input_fields.append(CMYKInputs(color, self))
|
||||
|
||||
inputs_widget = QtWidgets.QWidget(self)
|
||||
inputs_layout = QtWidgets.QVBoxLayout(inputs_widget)
|
||||
|
||||
for input_field in input_fields:
|
||||
inputs_layout.addWidget(input_field)
|
||||
input_field.value_changed.connect(self._on_value_change)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(inputs_widget, 0)
|
||||
spacer = QtWidgets.QWidget(self)
|
||||
layout.addWidget(spacer, 1)
|
||||
|
||||
self.input_fields = input_fields
|
||||
|
||||
self.color = color
|
||||
|
||||
def set_color(self, color):
|
||||
if (
|
||||
color.red() == self.color.red()
|
||||
and color.green() == self.color.green()
|
||||
and color.blue() == self.color.blue()
|
||||
):
|
||||
return
|
||||
self.color.setRed(color.red())
|
||||
self.color.setGreen(color.green())
|
||||
self.color.setBlue(color.blue())
|
||||
self._on_value_change()
|
||||
|
||||
def _on_value_change(self):
|
||||
for input_field in self.input_fields:
|
||||
input_field.color_changed()
|
||||
self.color_changed.emit(self.color)
|
||||
176
openpype/widgets/color_widgets/color_picker_widget.py
Normal file
176
openpype/widgets/color_widgets/color_picker_widget.py
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
import os
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
from .color_triangle import QtColorTriangle
|
||||
from .color_view import ColorViewer
|
||||
from .color_screen_pick import PickScreenColorWidget
|
||||
from .color_inputs import (
|
||||
AlphaSlider,
|
||||
AlphaInputs,
|
||||
HEXInputs,
|
||||
RGBInputs,
|
||||
HSLInputs,
|
||||
HSVInputs
|
||||
)
|
||||
|
||||
|
||||
class ColorPickerWidget(QtWidgets.QWidget):
|
||||
color_changed = QtCore.Signal(QtGui.QColor)
|
||||
|
||||
def __init__(self, color=None, parent=None):
|
||||
super(ColorPickerWidget, self).__init__(parent)
|
||||
|
||||
# Color triangle
|
||||
color_triangle = QtColorTriangle(self)
|
||||
|
||||
alpha_slider_proxy = QtWidgets.QWidget(self)
|
||||
alpha_slider = AlphaSlider(QtCore.Qt.Horizontal, alpha_slider_proxy)
|
||||
|
||||
alpha_slider_layout = QtWidgets.QHBoxLayout(alpha_slider_proxy)
|
||||
alpha_slider_layout.setContentsMargins(5, 5, 5, 5)
|
||||
alpha_slider_layout.addWidget(alpha_slider, 1)
|
||||
|
||||
# Eye picked widget
|
||||
pick_widget = PickScreenColorWidget()
|
||||
pick_widget.setMaximumHeight(50)
|
||||
|
||||
# Color pick button
|
||||
btn_pick_color = QtWidgets.QPushButton(self)
|
||||
icon_path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"eyedropper.png"
|
||||
)
|
||||
btn_pick_color.setIcon(QtGui.QIcon(icon_path))
|
||||
btn_pick_color.setToolTip("Pick a color")
|
||||
|
||||
# Color preview
|
||||
color_view = ColorViewer(self)
|
||||
color_view.setMaximumHeight(50)
|
||||
|
||||
alpha_inputs = AlphaInputs(self)
|
||||
|
||||
color_inputs_color = QtGui.QColor()
|
||||
col_inputs_by_label = [
|
||||
("HEX", HEXInputs(color_inputs_color, self)),
|
||||
("RGB", RGBInputs(color_inputs_color, self)),
|
||||
("HSL", HSLInputs(color_inputs_color, self)),
|
||||
("HSV", HSVInputs(color_inputs_color, self))
|
||||
]
|
||||
|
||||
layout = QtWidgets.QGridLayout(self)
|
||||
empty_col = 1
|
||||
label_col = empty_col + 1
|
||||
input_col = label_col + 1
|
||||
empty_widget = QtWidgets.QWidget(self)
|
||||
empty_widget.setFixedWidth(10)
|
||||
layout.addWidget(empty_widget, 0, empty_col)
|
||||
|
||||
row = 0
|
||||
layout.addWidget(btn_pick_color, row, label_col)
|
||||
layout.addWidget(color_view, row, input_col)
|
||||
row += 1
|
||||
|
||||
color_input_fields = []
|
||||
for label, input_field in col_inputs_by_label:
|
||||
layout.addWidget(QtWidgets.QLabel(label, self), row, label_col)
|
||||
layout.addWidget(input_field, row, input_col)
|
||||
input_field.value_changed.connect(
|
||||
self._on_color_input_value_change
|
||||
)
|
||||
color_input_fields.append(input_field)
|
||||
row += 1
|
||||
|
||||
layout.addWidget(color_triangle, 0, 0, row + 1, 1)
|
||||
layout.setRowStretch(row, 1)
|
||||
row += 1
|
||||
|
||||
layout.addWidget(alpha_slider_proxy, row, 0)
|
||||
|
||||
layout.addWidget(QtWidgets.QLabel("Alpha", self), row, label_col)
|
||||
layout.addWidget(alpha_inputs, row, input_col)
|
||||
row += 1
|
||||
layout.setRowStretch(row, 1)
|
||||
|
||||
color_view.set_color(color_triangle.cur_color)
|
||||
|
||||
color_triangle.color_changed.connect(self.triangle_color_changed)
|
||||
alpha_slider.valueChanged.connect(self._on_alpha_slider_change)
|
||||
pick_widget.color_selected.connect(self.on_color_change)
|
||||
alpha_inputs.alpha_changed.connect(self._on_alpha_inputs_changed)
|
||||
btn_pick_color.released.connect(self.pick_color)
|
||||
|
||||
self.color_input_fields = color_input_fields
|
||||
self.color_inputs_color = color_inputs_color
|
||||
|
||||
self.pick_widget = pick_widget
|
||||
|
||||
self.color_triangle = color_triangle
|
||||
self.alpha_slider = alpha_slider
|
||||
|
||||
self.color_view = color_view
|
||||
self.alpha_inputs = alpha_inputs
|
||||
self.btn_pick_color = btn_pick_color
|
||||
|
||||
self._minimum_size_set = False
|
||||
|
||||
if color:
|
||||
self.set_color(color)
|
||||
self.alpha_changed(color.alpha())
|
||||
|
||||
def showEvent(self, event):
|
||||
super(ColorPickerWidget, self).showEvent(event)
|
||||
if self._minimum_size_set:
|
||||
return
|
||||
|
||||
triangle_size = max(int(self.width() / 5 * 3), 180)
|
||||
self.color_triangle.setMinimumWidth(triangle_size)
|
||||
self.color_triangle.setMinimumHeight(triangle_size)
|
||||
self._minimum_size_set = True
|
||||
|
||||
def color(self):
|
||||
return self.color_view.color()
|
||||
|
||||
def set_color(self, color):
|
||||
self.alpha_inputs.set_alpha(color.alpha())
|
||||
self.on_color_change(color)
|
||||
|
||||
def pick_color(self):
|
||||
self.pick_widget.pick_color()
|
||||
|
||||
def triangle_color_changed(self, color):
|
||||
self.color_view.set_color(color)
|
||||
if self.color_inputs_color != color:
|
||||
self.color_inputs_color.setRgb(
|
||||
color.red(), color.green(), color.blue()
|
||||
)
|
||||
for color_input in self.color_input_fields:
|
||||
color_input.color_changed()
|
||||
|
||||
def on_color_change(self, color):
|
||||
self.color_view.set_color(color)
|
||||
self.color_triangle.set_color(color)
|
||||
if self.color_inputs_color != color:
|
||||
self.color_inputs_color.setRgb(
|
||||
color.red(), color.green(), color.blue()
|
||||
)
|
||||
for color_input in self.color_input_fields:
|
||||
color_input.color_changed()
|
||||
|
||||
def _on_color_input_value_change(self):
|
||||
for input_field in self.color_input_fields:
|
||||
input_field.color_changed()
|
||||
self.on_color_change(QtGui.QColor(self.color_inputs_color))
|
||||
|
||||
def alpha_changed(self, value):
|
||||
self.color_view.set_alpha(value)
|
||||
if self.alpha_slider.value() != value:
|
||||
self.alpha_slider.setValue(value)
|
||||
|
||||
if self.alpha_inputs.alpha_value != value:
|
||||
self.alpha_inputs.set_alpha(value)
|
||||
|
||||
def _on_alpha_inputs_changed(self, value):
|
||||
self.alpha_changed(value)
|
||||
|
||||
def _on_alpha_slider_change(self, value):
|
||||
self.alpha_changed(value)
|
||||
248
openpype/widgets/color_widgets/color_screen_pick.py
Normal file
248
openpype/widgets/color_widgets/color_screen_pick.py
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
import Qt
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
|
||||
class PickScreenColorWidget(QtWidgets.QWidget):
|
||||
color_selected = QtCore.Signal(QtGui.QColor)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(PickScreenColorWidget, self).__init__(parent)
|
||||
self.labels = []
|
||||
self.magnification = 2
|
||||
|
||||
self._min_magnification = 1
|
||||
self._max_magnification = 10
|
||||
|
||||
def add_magnification_delta(self, delta):
|
||||
_delta = abs(delta / 1000)
|
||||
if delta > 0:
|
||||
self.magnification += _delta
|
||||
else:
|
||||
self.magnification -= _delta
|
||||
|
||||
if self.magnification > self._max_magnification:
|
||||
self.magnification = self._max_magnification
|
||||
elif self.magnification < self._min_magnification:
|
||||
self.magnification = self._min_magnification
|
||||
|
||||
def pick_color(self):
|
||||
if self.labels:
|
||||
if self.labels[0].isVisible():
|
||||
return
|
||||
self.labels = []
|
||||
|
||||
for screen in QtWidgets.QApplication.screens():
|
||||
label = PickLabel(self)
|
||||
label.pick_color(screen)
|
||||
label.color_selected.connect(self.on_color_select)
|
||||
label.close_session.connect(self.end_pick_session)
|
||||
self.labels.append(label)
|
||||
|
||||
def end_pick_session(self):
|
||||
for label in self.labels:
|
||||
label.close()
|
||||
self.labels = []
|
||||
|
||||
def on_color_select(self, color):
|
||||
self.color_selected.emit(color)
|
||||
self.end_pick_session()
|
||||
|
||||
|
||||
class PickLabel(QtWidgets.QLabel):
|
||||
color_selected = QtCore.Signal(QtGui.QColor)
|
||||
close_session = QtCore.Signal()
|
||||
|
||||
def __init__(self, pick_widget):
|
||||
super(PickLabel, self).__init__()
|
||||
self.setMouseTracking(True)
|
||||
|
||||
self.pick_widget = pick_widget
|
||||
|
||||
self.radius_pen = QtGui.QPen(QtGui.QColor(27, 27, 27), 2)
|
||||
self.text_pen = QtGui.QPen(QtGui.QColor(127, 127, 127), 4)
|
||||
self.text_bg = QtGui.QBrush(QtGui.QColor(27, 27, 27))
|
||||
self._mouse_over = False
|
||||
|
||||
self.radius = 100
|
||||
self.radius_ratio = 11
|
||||
|
||||
@property
|
||||
def magnification(self):
|
||||
return self.pick_widget.magnification
|
||||
|
||||
def pick_color(self, screen_obj):
|
||||
self.show()
|
||||
self.windowHandle().setScreen(screen_obj)
|
||||
geo = screen_obj.geometry()
|
||||
args = (
|
||||
QtWidgets.QApplication.desktop().winId(),
|
||||
geo.x(), geo.y(), geo.width(), geo.height()
|
||||
)
|
||||
if Qt.__binding__ in ("PyQt4", "PySide"):
|
||||
pix = QtGui.QPixmap.grabWindow(*args)
|
||||
else:
|
||||
pix = screen_obj.grabWindow(*args)
|
||||
|
||||
if pix.width() > pix.height():
|
||||
size = pix.height()
|
||||
else:
|
||||
size = pix.width()
|
||||
|
||||
self.radius = int(size / self.radius_ratio)
|
||||
|
||||
self.setPixmap(pix)
|
||||
self.showFullScreen()
|
||||
|
||||
def wheelEvent(self, event):
|
||||
y_delta = event.angleDelta().y()
|
||||
self.pick_widget.add_magnification_delta(y_delta)
|
||||
self.update()
|
||||
|
||||
def enterEvent(self, event):
|
||||
self._mouse_over = True
|
||||
super().enterEvent(event)
|
||||
|
||||
def leaveEvent(self, event):
|
||||
self._mouse_over = False
|
||||
super().leaveEvent(event)
|
||||
self.update()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
super().paintEvent(event)
|
||||
if not self._mouse_over:
|
||||
return
|
||||
|
||||
mouse_pos_to_widet = self.mapFromGlobal(QtGui.QCursor.pos())
|
||||
|
||||
magnified_half_size = self.radius / self.magnification
|
||||
magnified_size = magnified_half_size * 2
|
||||
|
||||
zoom_x_1 = mouse_pos_to_widet.x() - magnified_half_size
|
||||
zoom_x_2 = mouse_pos_to_widet.x() + magnified_half_size
|
||||
zoom_y_1 = mouse_pos_to_widet.y() - magnified_half_size
|
||||
zoom_y_2 = mouse_pos_to_widet.y() + magnified_half_size
|
||||
pix_width = magnified_size
|
||||
pix_height = magnified_size
|
||||
draw_pos_x = 0
|
||||
draw_pos_y = 0
|
||||
if zoom_x_1 < 0:
|
||||
draw_pos_x = abs(zoom_x_1)
|
||||
pix_width -= draw_pos_x
|
||||
zoom_x_1 = 1
|
||||
elif zoom_x_2 > self.pixmap().width():
|
||||
pix_width -= zoom_x_2 - self.pixmap().width()
|
||||
|
||||
if zoom_y_1 < 0:
|
||||
draw_pos_y = abs(zoom_y_1)
|
||||
pix_height -= draw_pos_y
|
||||
zoom_y_1 = 1
|
||||
elif zoom_y_2 > self.pixmap().height():
|
||||
pix_height -= zoom_y_2 - self.pixmap().height()
|
||||
|
||||
new_pix = QtGui.QPixmap(magnified_size, magnified_size)
|
||||
new_pix.fill(QtCore.Qt.transparent)
|
||||
new_pix_painter = QtGui.QPainter(new_pix)
|
||||
new_pix_painter.drawPixmap(
|
||||
QtCore.QRect(draw_pos_x, draw_pos_y, pix_width, pix_height),
|
||||
self.pixmap().copy(zoom_x_1, zoom_y_1, pix_width, pix_height)
|
||||
)
|
||||
new_pix_painter.end()
|
||||
|
||||
painter = QtGui.QPainter(self)
|
||||
|
||||
ellipse_rect = QtCore.QRect(
|
||||
mouse_pos_to_widet.x() - self.radius,
|
||||
mouse_pos_to_widet.y() - self.radius,
|
||||
self.radius * 2,
|
||||
self.radius * 2
|
||||
)
|
||||
ellipse_rect_f = QtCore.QRectF(ellipse_rect)
|
||||
path = QtGui.QPainterPath()
|
||||
path.addEllipse(ellipse_rect_f)
|
||||
painter.setClipPath(path)
|
||||
|
||||
new_pix_rect = QtCore.QRect(
|
||||
mouse_pos_to_widet.x() - self.radius + 1,
|
||||
mouse_pos_to_widet.y() - self.radius + 1,
|
||||
new_pix.width() * self.magnification,
|
||||
new_pix.height() * self.magnification
|
||||
)
|
||||
|
||||
painter.drawPixmap(new_pix_rect, new_pix)
|
||||
|
||||
painter.setClipping(False)
|
||||
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
painter.setPen(self.radius_pen)
|
||||
painter.drawEllipse(ellipse_rect_f)
|
||||
|
||||
image = self.pixmap().toImage()
|
||||
if image.valid(mouse_pos_to_widet):
|
||||
color = QtGui.QColor(image.pixel(mouse_pos_to_widet))
|
||||
else:
|
||||
color = QtGui.QColor()
|
||||
|
||||
color_text = "Red: {} - Green: {} - Blue: {}".format(
|
||||
color.red(), color.green(), color.blue()
|
||||
)
|
||||
font = painter.font()
|
||||
font.setPointSize(self.radius / 10)
|
||||
painter.setFont(font)
|
||||
|
||||
text_rect_height = int(painter.fontMetrics().height() + 10)
|
||||
text_rect = QtCore.QRect(
|
||||
ellipse_rect.x(),
|
||||
ellipse_rect.bottom(),
|
||||
ellipse_rect.width(),
|
||||
text_rect_height
|
||||
)
|
||||
if text_rect.bottom() > self.pixmap().height():
|
||||
text_rect.moveBottomLeft(ellipse_rect.topLeft())
|
||||
|
||||
rect_radius = text_rect_height / 2
|
||||
path = QtGui.QPainterPath()
|
||||
path.addRoundedRect(
|
||||
QtCore.QRectF(text_rect),
|
||||
rect_radius,
|
||||
rect_radius
|
||||
)
|
||||
painter.fillPath(path, self.text_bg)
|
||||
|
||||
painter.setPen(self.text_pen)
|
||||
painter.drawText(
|
||||
text_rect,
|
||||
QtCore.Qt.AlignLeft | QtCore.Qt.AlignCenter,
|
||||
color_text
|
||||
)
|
||||
|
||||
color_rect_x = ellipse_rect.x() - text_rect_height
|
||||
if color_rect_x < 0:
|
||||
color_rect_x += (text_rect_height + ellipse_rect.width())
|
||||
|
||||
color_rect = QtCore.QRect(
|
||||
color_rect_x,
|
||||
ellipse_rect.y(),
|
||||
text_rect_height,
|
||||
ellipse_rect.height()
|
||||
)
|
||||
path = QtGui.QPainterPath()
|
||||
path.addRoundedRect(
|
||||
QtCore.QRectF(color_rect),
|
||||
rect_radius,
|
||||
rect_radius
|
||||
)
|
||||
painter.fillPath(path, color)
|
||||
painter.drawRoundedRect(color_rect, rect_radius, rect_radius)
|
||||
painter.end()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
color = QtGui.QColor(self.pixmap().toImage().pixel(event.pos()))
|
||||
self.color_selected.emit(color)
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if event.key() == QtCore.Qt.Key_Escape:
|
||||
self.close_session.emit()
|
||||
1431
openpype/widgets/color_widgets/color_triangle.py
Normal file
1431
openpype/widgets/color_widgets/color_triangle.py
Normal file
File diff suppressed because it is too large
Load diff
83
openpype/widgets/color_widgets/color_view.py
Normal file
83
openpype/widgets/color_widgets/color_view.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
|
||||
def draw_checkerboard_tile(piece_size=None, color_1=None, color_2=None):
|
||||
if piece_size is None:
|
||||
piece_size = 7
|
||||
|
||||
if color_1 is None:
|
||||
color_1 = QtGui.QColor(188, 188, 188)
|
||||
|
||||
if color_2 is None:
|
||||
color_2 = QtGui.QColor(90, 90, 90)
|
||||
|
||||
pix = QtGui.QPixmap(piece_size * 2, piece_size * 2)
|
||||
pix_painter = QtGui.QPainter(pix)
|
||||
|
||||
rect = QtCore.QRect(
|
||||
0, 0, piece_size, piece_size
|
||||
)
|
||||
pix_painter.fillRect(rect, color_1)
|
||||
rect.moveTo(piece_size, piece_size)
|
||||
pix_painter.fillRect(rect, color_1)
|
||||
rect.moveTo(piece_size, 0)
|
||||
pix_painter.fillRect(rect, color_2)
|
||||
rect.moveTo(0, piece_size)
|
||||
pix_painter.fillRect(rect, color_2)
|
||||
pix_painter.end()
|
||||
|
||||
return pix
|
||||
|
||||
|
||||
class ColorViewer(QtWidgets.QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super(ColorViewer, self).__init__(parent)
|
||||
|
||||
self.setMinimumSize(10, 10)
|
||||
|
||||
self.alpha = 255
|
||||
self.actual_pen = QtGui.QPen()
|
||||
self.actual_color = QtGui.QColor()
|
||||
self._checkerboard = None
|
||||
|
||||
def checkerboard(self):
|
||||
if not self._checkerboard:
|
||||
self._checkerboard = draw_checkerboard_tile(4)
|
||||
return self._checkerboard
|
||||
|
||||
def color(self):
|
||||
return self.actual_color
|
||||
|
||||
def set_color(self, color):
|
||||
if color == self.actual_color:
|
||||
return
|
||||
|
||||
# Create copy of entered color
|
||||
self.actual_color = QtGui.QColor(color)
|
||||
# Set alpha by current alpha value
|
||||
self.actual_color.setAlpha(self.alpha)
|
||||
# Repaint
|
||||
self.update()
|
||||
|
||||
def set_alpha(self, alpha):
|
||||
if alpha == self.alpha:
|
||||
return
|
||||
# Change alpha of current color
|
||||
self.actual_color.setAlpha(alpha)
|
||||
# Store the value
|
||||
self.alpha = alpha
|
||||
# Repaint
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
clip_rect = event.rect()
|
||||
rect = clip_rect.adjusted(0, 0, -1, -1)
|
||||
|
||||
painter = QtGui.QPainter(self)
|
||||
painter.setClipRect(clip_rect)
|
||||
painter.drawTiledPixmap(rect, self.checkerboard())
|
||||
painter.setBrush(self.actual_color)
|
||||
pen = QtGui.QPen(QtGui.QColor(255, 255, 255, 67))
|
||||
painter.setPen(pen)
|
||||
painter.drawRect(rect)
|
||||
painter.end()
|
||||
BIN
openpype/widgets/color_widgets/eyedropper.png
Normal file
BIN
openpype/widgets/color_widgets/eyedropper.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue