File indexing completed on 2024-05-26 04:34:17

0001 '''
0002     SPDX-FileCopyrightText: 2019 Tusooa Zhu <tusooa@vista.aero>
0003 
0004     This file is part of Krita-docker-color-slider.
0005 
0006     SPDX-License-Identifier: GPL-3.0-or-later
0007 '''
0008 from PyQt5.QtWidgets import QWidget
0009 from PyQt5.QtGui import QPixmap, QPainter, QColor, QBrush, QPolygon
0010 from PyQt5.QtCore import QPoint
0011 from krita import ManagedColor
0012 
0013 
0014 class ColorSlider(QWidget):
0015     default_color = ManagedColor("", "", "")
0016 
0017     def __init__(self, docker, left_color=default_color, right_color=default_color, parent=None):
0018         super(ColorSlider, self).__init__(parent)
0019         self.docker = docker
0020         self.left_color = left_color
0021         self.right_color = right_color
0022         self.slider_pixmap = None
0023         self.value_x = None
0024         self.cursor_fill_color = QColor.fromRgbF(1, 1, 1, 1)
0025         self.cursor_outline_color = QColor.fromRgbF(0, 0, 0, 1)
0026         self.need_redraw = True
0027 
0028     def set_color(self, pos, color):
0029         if pos == 'left':
0030             if self.left_color is not color:
0031                 self.left_color = color
0032                 self.need_redraw = True
0033         else:
0034             if self.right_color is not color:
0035                 self.right_color = color
0036                 self.need_redraw = True
0037 
0038     def update_slider(self):
0039         '''
0040         Update the slider to a gradient between the two colors.
0041 
0042         The painting of the slider comes from the program Krita. The original code can be accessed
0043         at the following URL.
0044         https://github.com/KDE/krita/blob/master/plugins/dockers/advancedcolorselector/kis_shade_selector_line.cpp
0045         '''
0046         if self.need_redraw:
0047             patch_count = self.width()
0048             base_hsva = list(self.docker.managedcolor_to_qcolor(self.left_color).getHsvF())
0049             dest_hsva = list(self.docker.managedcolor_to_qcolor(self.right_color).getHsvF())
0050             diff_hsva = [(dest_hsva[i] - base_hsva[i]) for i in range(4)]
0051             if dest_hsva[0] == -1.0:
0052                 diff_hsva[0] = 0
0053             elif base_hsva[0] == -1.0:
0054                 diff_hsva[0] = 0
0055                 base_hsva[0] = dest_hsva[0]
0056             elif diff_hsva[0] > 0.5:  # make sure the sliding goes through a minor arc
0057                 diff_hsva[0] = diff_hsva[0] - 1.0
0058             elif diff_hsva[0] < -0.5:
0059                 diff_hsva[0] = diff_hsva[0] + 1.0
0060 
0061             step_hsva = [x / patch_count for x in diff_hsva]
0062 
0063             self.slider_pixmap = QPixmap(self.width(), self.height())
0064             painter = QPainter(self.slider_pixmap)
0065 
0066             for i in range(patch_count):
0067                 hue = base_hsva[0] + i * step_hsva[0]
0068                 while hue < 0.0:
0069                     hue += 1.0
0070 
0071                 while hue > 1.0:
0072                     hue -= 1.0
0073 
0074                 saturation = base_hsva[1] + i * step_hsva[1]
0075                 value = base_hsva[2] + i * step_hsva[2]
0076                 cur_color = QColor.fromHsvF(hue, saturation, value)
0077                 painter.fillRect(i, 0, 1, self.height(), cur_color)
0078 
0079             painter.end()
0080 
0081             self.need_redraw = False
0082 
0083         widget_painter = QPainter(self)
0084         self.rendered_image = self.slider_pixmap.toImage()
0085 
0086         widget_painter.drawImage(0, 0, self.rendered_image)
0087         if self.value_x is not None:
0088             start_x = int(self.value_x)
0089             start_y = int(self.height() / 2)
0090             delta_x = int(self.height() / 3)
0091             delta_y = int(self.height() / 3)
0092             points = [QPoint(start_x, start_y),
0093                       QPoint(start_x - delta_x, start_y + delta_y),
0094                       QPoint(start_x + delta_x, start_y + delta_y)]
0095             widget_painter.setBrush(QBrush(self.cursor_fill_color))
0096             widget_painter.setPen(self.cursor_outline_color)
0097             widget_painter.drawPolygon(QPolygon(points))
0098 
0099     def paintEvent(self, event):
0100         self.update_slider()
0101 
0102     def resizeEvent(self, event):  # after resizing the widget, force-redraw the underlying slider
0103         self.need_redraw = True
0104 
0105     def adjust_pos_x(self, x):  # adjust the x to make it in the range of [0, width - 1]
0106         if x < 0:
0107             return 0
0108         if x >= self.width():
0109             return self.width() - 1
0110         return x
0111 
0112     def mouseMoveEvent(self, event):
0113         pos = event.pos()
0114         self.value_x = self.adjust_pos_x(pos.x())
0115         self.update()
0116 
0117     def mouseReleaseEvent(self, event):
0118         pos = event.pos()
0119         self.value_x = self.adjust_pos_x(pos.x())
0120         y = int(self.height() / 2)
0121         fixed_pos = QPoint(self.value_x, y)
0122         color = self.rendered_image.pixelColor(fixed_pos)
0123         mc = self.docker.qcolor_to_managedcolor(color)
0124         if self.docker.canvas() is not None:
0125             if self.docker.canvas().view() is not None:
0126                 self.docker.canvas().view().setForeGroundColor(mc)
0127         self.update()