diff --git a/plugins/python/CMakeLists.txt b/plugins/python/CMakeLists.txt
--- a/plugins/python/CMakeLists.txt
+++ b/plugins/python/CMakeLists.txt
@@ -94,6 +94,7 @@
install_pykrita_plugin(comics_project_management_tools)
install_pykrita_plugin(krita_script_starter)
install_pykrita_plugin(plugin_importer)
+install_pykrita_plugin(mixer_slider_docker)
# if(PYTHON_VERSION_MAJOR VERSION_EQUAL 3)
# install_pykrita_plugin(cmake_utils)
diff --git a/plugins/python/mixer_slider_docker/Manual.html b/plugins/python/mixer_slider_docker/Manual.html
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/Manual.html
@@ -0,0 +1,22 @@
+
+
+
+
+
Krita-docker-color-slider Plugin Manual
+
+
+
+Mixer Slider Docker
+A docker which allows you to choose from the gradient between two colors.
+Basic Usage
+Go to Settings -> Configure Krita -> Python Plugin Manager.
+ Enable "Mixer Slider docker."
+Right-click on menu bar, and enable "Mixer Slider Docker." A docker will appear in the window.
+The button on the left with the text "S" is for settings. Click on it to set the number of slider lines.
+The right part of the docker contains the sliders. Each line has a left color, a slider bar, and a right color.
+Click the left/right color to set it to the current foreground color. Click and move on the slider to set
+ the current foreground color to the color your mouse is hovering. An indicator will appear to show the color
+you just selected.
+
+
+
diff --git a/plugins/python/mixer_slider_docker/__init__.py b/plugins/python/mixer_slider_docker/__init__.py
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/__init__.py
@@ -0,0 +1,19 @@
+'''
+ Copyright (C) 2019 Tusooa Zhu
+
+ This file is part of Krita-docker-color-slider.
+
+ Krita-docker-color-slider is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Krita-docker-color-slider is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Krita-docker-color-slider. If not, see .
+'''
+from .mixer_slider_docker import *
diff --git a/plugins/python/mixer_slider_docker/color_slider.py b/plugins/python/mixer_slider_docker/color_slider.py
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/color_slider.py
@@ -0,0 +1,135 @@
+'''
+ Copyright (C) 2019 Tusooa Zhu
+
+ This file is part of Krita-docker-color-slider.
+
+ Krita-docker-color-slider is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Krita-docker-color-slider is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Krita-docker-color-slider. If not, see .
+'''
+from PyQt5.QtWidgets import QWidget
+from PyQt5.QtGui import QPixmap, QPainter, QColor, QBrush, QPolygon
+from PyQt5.QtCore import QPoint
+from krita import ManagedColor
+
+
+class ColorSlider(QWidget):
+ default_color = ManagedColor("", "", "")
+
+ def __init__(self, docker, left_color=default_color, right_color=default_color, parent=None):
+ super(ColorSlider, self).__init__(parent)
+ self.docker = docker
+ self.left_color = left_color
+ self.right_color = right_color
+ self.slider_pixmap = None
+ self.value_x = None
+ self.cursor_fill_color = QColor.fromRgbF(1, 1, 1, 1)
+ self.cursor_outline_color = QColor.fromRgbF(0, 0, 0, 1)
+ self.need_redraw = True
+
+ def set_color(self, pos, color):
+ if pos == 'left':
+ if self.left_color is not color:
+ self.left_color = color
+ self.need_redraw = True
+ else:
+ if self.right_color is not color:
+ self.right_color = color
+ self.need_redraw = True
+
+ def update_slider(self):
+ '''
+ Update the slider to a gradient between the two colors.
+
+ The painting of the slider comes from the program Krita. The original code can be accessed
+ at the following URL.
+ https://github.com/KDE/krita/blob/master/plugins/dockers/advancedcolorselector/kis_shade_selector_line.cpp
+ '''
+ if self.need_redraw:
+ patch_count = self.width()
+ base_hsva = self.docker.managedcolor_to_qcolor(self.left_color).getHsvF()
+ dest_hsva = self.docker.managedcolor_to_qcolor(self.right_color).getHsvF()
+ diff_hsva = [(dest_hsva[i] - base_hsva[i]) for i in range(4)]
+ if dest_hsva[0] == -1.0:
+ diff_hsva[0] = 0
+ elif diff_hsva[0] > 0.5: # make sure the sliding goes through a minor arc
+ diff_hsva[0] = diff_hsva[0] - 1.0
+ elif diff_hsva[0] < -0.5:
+ diff_hsva[0] = diff_hsva[0] + 1.0
+
+ step_hsva = [x / patch_count for x in diff_hsva]
+
+ self.slider_pixmap = QPixmap(self.width(), self.height())
+ painter = QPainter(self.slider_pixmap)
+
+ for i in range(patch_count):
+ hue = base_hsva[0] + i * step_hsva[0]
+ while hue < 0.0:
+ hue += 1.0
+
+ while hue > 1.0:
+ hue -= 1.0
+
+ saturation = base_hsva[1] + i * step_hsva[1]
+ value = base_hsva[2] + i * step_hsva[2]
+ cur_color = QColor.fromHsvF(hue, saturation, value)
+ painter.fillRect(i, 0, 1, self.height(), cur_color)
+
+ painter.end()
+
+ self.need_redraw = False
+
+ widget_painter = QPainter(self)
+ self.rendered_image = self.slider_pixmap.toImage()
+
+ widget_painter.drawImage(0, 0, self.rendered_image)
+ if self.value_x is not None:
+ start_x = self.value_x
+ start_y = self.height() / 2
+ delta_x = self.height() / 3
+ delta_y = self.height() / 3
+ points = [QPoint(start_x, start_y),
+ QPoint(start_x - delta_x, start_y + delta_y),
+ QPoint(start_x + delta_x, start_y + delta_y)]
+ widget_painter.setBrush(QBrush(self.cursor_fill_color))
+ widget_painter.setPen(self.cursor_outline_color)
+ widget_painter.drawPolygon(QPolygon(points))
+
+ def paintEvent(self, event):
+ self.update_slider()
+
+ def resizeEvent(self, event): # after resizing the widget, force-redraw the underlying slider
+ self.need_redraw = True
+
+ def adjust_pos_x(self, x): # adjust the x to make it in the range of [0, width - 1]
+ if x < 0:
+ return 0
+ if x >= self.width():
+ return self.width() - 1
+ return x
+
+ def mouseMoveEvent(self, event):
+ pos = event.pos()
+ self.value_x = self.adjust_pos_x(pos.x())
+ self.update()
+
+ def mouseReleaseEvent(self, event):
+ pos = event.pos()
+ self.value_x = self.adjust_pos_x(pos.x())
+ y = int(self.height() / 2)
+ fixed_pos = QPoint(self.value_x, y)
+ color = self.rendered_image.pixelColor(fixed_pos)
+ mc = self.docker.qcolor_to_managedcolor(color)
+ if self.docker.canvas() is not None:
+ if self.docker.canvas().view() is not None:
+ self.docker.canvas().view().setForeGroundColor(mc)
+ self.update()
diff --git a/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop b/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/kritapykrita_mixer_slider_docker.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Krita/PythonPlugin
+X-KDE-Library=mixer_slider_docker
+X-Python-2-Compatible=false
+X-Krita-Manual=Manual.html
+Name=Mixer Slider docker
+Comment=A color slider.
diff --git a/plugins/python/mixer_slider_docker/mixer_slider_docker.py b/plugins/python/mixer_slider_docker/mixer_slider_docker.py
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/mixer_slider_docker.py
@@ -0,0 +1,129 @@
+'''
+ Copyright (C) 2019 Tusooa Zhu
+
+ This file is part of Krita-docker-color-slider.
+
+ Krita-docker-color-slider is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Krita-docker-color-slider is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Krita-docker-color-slider. If not, see .
+'''
+from PyQt5.QtGui import QColor
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton
+
+from krita import Krita, DockWidget, ManagedColor, DockWidgetFactory, DockWidgetFactoryBase
+
+from .slider_line import SliderLine
+from .ui_mixer_slider_docker import UIMixerSliderDocker
+
+
+class MixerSliderDocker(DockWidget):
+ # Init the docker
+
+ def __init__(self):
+ super(MixerSliderDocker, self).__init__()
+
+ main_program = Krita.instance()
+ settings = main_program.readSetting("", "MixerSliderColors",
+ "RGBA,U8,sRGB-elle-V2-srgbtrc.icc,1,0.8,0.4,1," +
+ "RGBA,U8,sRGB-elle-V2-srgbtrc.icc,0,0,0,1") # alpha=1 == non-transparent
+
+ self.default_left_color = self.qcolor_to_managedcolor(QColor.fromRgbF(0.4, 0.8, 1, 1))
+ self.default_right_color = self.qcolor_to_managedcolor(QColor.fromRgbF(0, 0, 0, 1))
+
+ # make base-widget and layout
+ self.widget = QWidget()
+ self.sliders = []
+ self.top_layout = QVBoxLayout()
+ self.main_layout = QHBoxLayout()
+ self.top_layout.addLayout(self.main_layout)
+ self.top_layout.addStretch(0)
+ # The text on the button for settings
+ self.settings_button = QPushButton(i18n('S'))
+ self.settings_button.setToolTip(i18n('Change settings'))
+ self.settings_button.setMaximumSize(30, 30)
+ self.main_layout.addWidget(self.settings_button)
+ self.layout = QVBoxLayout()
+ self.layout.setSpacing(0)
+ self.main_layout.addLayout(self.layout)
+ for line in settings.split(";"):
+ colors = line.split(',')
+ left_color = self.parse_color(colors[0:7])
+ right_color = self.parse_color(colors[7:])
+ widget = SliderLine(left_color, right_color, self)
+ self.sliders.append(widget)
+ self.layout.addWidget(widget)
+
+ self.widget.setLayout(self.top_layout)
+ self.setWindowTitle(i18n("Mixer Slider Docker"))
+ self.setWidget(self.widget)
+ [x.show() for x in self.sliders]
+
+ self.settings_button.clicked.connect(self.init_ui)
+
+ def settings_changed(self):
+ if self.ui.line_edit is not None:
+ num_sliders = int(self.ui.line_edit.text())
+ if len(self.sliders) > num_sliders:
+ for extra_line in self.sliders[num_sliders:]:
+ self.layout.removeWidget(extra_line)
+ extra_line.setParent(None)
+
+ self.sliders = self.sliders[0:num_sliders]
+ elif len(self.sliders) < num_sliders:
+ for i in range(num_sliders - len(self.sliders)):
+ widget = SliderLine(self.default_left_color, self.default_right_color, self)
+ self.sliders.append(widget)
+ self.layout.addWidget(widget)
+ self.write_settings()
+
+ def get_color_space(self):
+ if self.canvas() is not None:
+ if self.canvas().view() is not None:
+ canvas_color = self.canvas().view().foregroundColor()
+ return ManagedColor(canvas_color.colorModel(), canvas_color.colorDepth(), canvas_color.colorProfile())
+ return ManagedColor('RGBA', 'U8', 'sRGB-elle-V2-srgbtrc.icc')
+
+ def init_ui(self):
+ self.ui = UIMixerSliderDocker()
+ self.ui.initialize(self)
+
+ def write_settings(self):
+ main_program = Krita.instance()
+ setting = ';'.join(
+ [self.color_to_settings(line.left) + ',' + self.color_to_settings(line.right)
+ for line in self.sliders])
+
+ main_program.writeSetting("", "MixerSliderColors", setting)
+
+ def color_to_settings(self, managedcolor):
+ return ','.join([managedcolor.colorModel(),
+ managedcolor.colorDepth(),
+ managedcolor.colorProfile()] +
+ [str(c) for c in managedcolor.components()])
+
+ def parse_color(self, array):
+ color = ManagedColor(array[0], array[1], array[2])
+ color.setComponents([float(x) for x in array[3:]])
+ return color
+
+ def canvasChanged(self, canvas):
+ pass
+
+ def qcolor_to_managedcolor(self, qcolor):
+ mc = self.get_color_space()
+ mc.setComponents([qcolor.blueF(), qcolor.greenF(), qcolor.redF(), qcolor.alphaF()])
+ return mc
+
+ def managedcolor_to_qcolor(self, managedcolor):
+ return managedcolor.colorForCanvas(self.canvas())
+
+Application.addDockWidgetFactory(DockWidgetFactory("mixer_slider_docker", DockWidgetFactoryBase.DockRight, MixerSliderDocker))
diff --git a/plugins/python/mixer_slider_docker/settings_dialog.py b/plugins/python/mixer_slider_docker/settings_dialog.py
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/settings_dialog.py
@@ -0,0 +1,34 @@
+'''
+ Copyright (C) 2019 Tusooa Zhu
+
+ This file is part of Krita-docker-color-slider.
+
+ Krita-docker-color-slider is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Krita-docker-color-slider is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Krita-docker-color-slider. If not, see .
+'''
+from PyQt5.QtWidgets import QDialog
+
+
+class SettingsDialog(QDialog):
+ def __init__(self, ui_mixer_slider, parent=None):
+ super(SettingsDialog, self).__init__(parent)
+
+ self.ui_mixer_slider = ui_mixer_slider
+
+ def accept(self):
+ self.ui_mixer_slider.docker.settings_changed()
+
+ super(SettingsDialog, self).accept()
+
+ def closeEvent(self, event):
+ event.accept()
diff --git a/plugins/python/mixer_slider_docker/slider_line.py b/plugins/python/mixer_slider_docker/slider_line.py
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/slider_line.py
@@ -0,0 +1,103 @@
+'''
+ Copyright (C) 2019 Tusooa Zhu
+
+ This file is part of Krita-docker-color-slider.
+
+ Krita-docker-color-slider is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Krita-docker-color-slider is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Krita-docker-color-slider. If not, see .
+'''
+from PyQt5.QtWidgets import QHBoxLayout, QWidget
+from PyQt5.QtGui import QPixmap, QPainter
+from PyQt5.Qt import pyqtSlot, pyqtSignal
+
+from .color_slider import ColorSlider
+
+
+class SliderBtn(QWidget):
+ clicked = pyqtSignal()
+
+ def __init__(self, parent=None):
+ super(SliderBtn, self).__init__(parent)
+
+ def set_color(self, qcolor):
+ self.color = qcolor
+ self.update()
+
+ def update_color(self):
+ color_sq = QPixmap(self.width(), self.height())
+ color_sq.fill(self.color)
+ image = color_sq.toImage()
+
+ painter = QPainter(self)
+ painter.drawImage(0, 0, image)
+
+ def paintEvent(self, event):
+ self.update_color()
+
+ def mouseReleaseEvent(self, event):
+ self.clicked.emit()
+
+
+class SliderLine(QWidget):
+ def __init__(self, left_color, right_color, docker, parent=None):
+ super(SliderLine, self).__init__(parent)
+ self.left_button = SliderBtn()
+ self.right_button = SliderBtn()
+ self.docker = docker
+ self.color_slider = ColorSlider(docker)
+ self.layout = QHBoxLayout()
+ self.layout.setContentsMargins(2, 2, 2, 2)
+ self.setLayout(self.layout)
+ self.layout.addWidget(self.left_button)
+ self.layout.addWidget(self.color_slider)
+ self.layout.addWidget(self.right_button)
+ self.left_button.clicked.connect(self.slot_update_left_color)
+ self.right_button.clicked.connect(self.slot_update_right_color)
+ self.set_color('left', left_color)
+ self.set_color('right', right_color)
+ self.left_button.setMinimumSize(30, 30)
+ self.left_button.setMaximumSize(30, 30)
+ self.right_button.setMinimumSize(30, 30)
+ self.right_button.setMaximumSize(30, 30)
+ self.color_slider.setMaximumHeight(30)
+
+ def set_color(self, pos, color):
+ button_to_set = None
+ if pos == 'left':
+ self.left = color
+ button_to_set = self.left_button
+ else:
+ self.right = color
+ button_to_set = self.right_button
+
+ self.color_slider.set_color(pos, color)
+
+ button_to_set.set_color(self.docker.managedcolor_to_qcolor(color))
+
+ @pyqtSlot()
+ def slot_update_left_color(self):
+ if self.docker.canvas() is not None:
+ if self.docker.canvas().view() is not None:
+ self.set_color('left', self.docker.canvas().view().foregroundColor())
+ self.color_slider.value_x = 0 # set the cursor to the left-most
+ self.color_slider.update()
+ self.docker.write_settings()
+
+ @pyqtSlot()
+ def slot_update_right_color(self):
+ if self.docker.canvas() is not None:
+ if self.docker.canvas().view() is not None:
+ self.set_color('right', self.docker.canvas().view().foregroundColor())
+ self.color_slider.value_x = self.color_slider.width() - 1
+ self.color_slider.update()
+ self.docker.write_settings()
diff --git a/plugins/python/mixer_slider_docker/ui_mixer_slider_docker.py b/plugins/python/mixer_slider_docker/ui_mixer_slider_docker.py
new file mode 100644
--- /dev/null
+++ b/plugins/python/mixer_slider_docker/ui_mixer_slider_docker.py
@@ -0,0 +1,56 @@
+'''
+ Copyright (C) 2019 Tusooa Zhu
+
+ This file is part of Krita-docker-color-slider.
+
+ Krita-docker-color-slider is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Krita-docker-color-slider is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Krita-docker-color-slider. If not, see .
+'''
+from PyQt5.QtWidgets import QDialogButtonBox, QLabel, QVBoxLayout, QHBoxLayout, QLineEdit
+from PyQt5.QtGui import QIntValidator
+from PyQt5.QtCore import Qt
+import krita
+
+from .settings_dialog import SettingsDialog
+
+
+class UIMixerSliderDocker(object):
+ def __init__(self):
+ self.krita_instance = krita.Krita.instance()
+ self.main_dialog = SettingsDialog(self, self.krita_instance.activeWindow().qwindow())
+
+ self.button_box = QDialogButtonBox(self.main_dialog)
+ self.vbox = QVBoxLayout(self.main_dialog)
+ self.hbox = QHBoxLayout(self.main_dialog)
+ self.line_edit = None
+
+ self.button_box.accepted.connect(self.main_dialog.accept)
+ self.button_box.rejected.connect(self.main_dialog.reject)
+
+ self.button_box.setOrientation(Qt.Horizontal)
+ self.button_box.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+
+ def initialize(self, docker):
+ self.docker = docker
+
+ self.vbox.addLayout(self.hbox)
+ self.hbox.addWidget(QLabel(i18n('Number of slider lines: ')))
+ self.line_edit = QLineEdit(str(len(docker.sliders)))
+ self.line_edit.setValidator(QIntValidator(1, 8))
+ self.hbox.addWidget(self.line_edit)
+
+ self.vbox.addWidget(self.button_box)
+
+ self.main_dialog.show()
+ self.main_dialog.activateWindow()
+ self.main_dialog.exec_()