File indexing completed on 2024-05-12 05:46:37

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