diff --git a/Qt-Color-Widgets b/Qt-Color-Widgets
deleted file mode 160000
index eb6da62d..00000000
--- a/Qt-Color-Widgets
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit eb6da62d65c75f40437ed4964a8d4a18850f4d7f
diff --git a/Qt-Color-Widgets/COPYING b/Qt-Color-Widgets/COPYING
new file mode 100644
index 00000000..65c5ca88
--- /dev/null
+++ b/Qt-Color-Widgets/COPYING
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/Qt-Color-Widgets/LICENSE-EXCEPTION b/Qt-Color-Widgets/LICENSE-EXCEPTION
new file mode 100644
index 00000000..06698128
--- /dev/null
+++ b/Qt-Color-Widgets/LICENSE-EXCEPTION
@@ -0,0 +1,14 @@
+Linking this library statically or dynamically with other modules is making a
+combined work based on this library. Thus, the terms and conditions of the
+GNU Lesser General Public License version 3 cover the whole combination.
+
+As a special exception, the copyright holders of this library give you
+permission to combine this library with independent
+modules to produce an executable, and to copy and distribute the resulting
+executable under terms of any of the GNU General Public licenses, as published
+by the Free Software Foundation, provided that you also meet,
+for each linked independent module, the terms and conditions of the license of
+that module. An independent module is a module which is not derived from or
+based on this library. If you modify this library, you may extend this
+exception to your version of the library, but you are not obliged to do so.
+If you do not wish to do so, delete this exception statement from your version.
diff --git a/Qt-Color-Widgets/README.md b/Qt-Color-Widgets/README.md
new file mode 100644
index 00000000..b3c0b2a5
--- /dev/null
+++ b/Qt-Color-Widgets/README.md
@@ -0,0 +1,64 @@
+Color Widgets
+=============
+
+Here is a color dialog that is more user-friendly than the default QColorDialog
+and several other color-related widgets
+
+The provided widgets are:
+
+* ColorWheel, An analog widget used to select a color
+* ColorPreview, A simple widget that displays a color
+* GradientSlider, A slider that has a gradient background
+* HueSlider, A variant of GradientSlider that has a rainbow background
+* ColorSelector, A ColorPreview that shows a ColorDialog when clicked
+* ColorDialog, A dialog that uses the above widgets to provide a better user experience than QColorDialog
+* ColorListWidget, A widget to edit a list of colors
+* Swatch, A widget to display a color palette
+* ColorPaletteWidget, A widget to use and manage a list of palettes
+* Color2DSlider, An analog widget used to select 2 color components
+* ColorLineEdit, A widget to manipulate a string representing a color
+
+they are all in the color_widgets namespace.
+
+See [the gallery](gallery/README.md) for more information and screenshots.
+
+
+Using it in a project
+---------------------
+
+For QMake-based projects, include color_widgets.pri in the QMake project file.
+For CMake-based projects, add this as subdirectory, it will be compiled as a
+library and you can link the required targets to ColorWidgets-qt5.
+All the required files are in ./src and ./include.
+
+
+Installing as a Qt Designer/Creator Plugin
+------------------------------------------
+
+The sources for the designer plugin are in ./color_widgets_designer_plugin
+
+Compile the library and install in
+(Qt SDK)/Tools/QtCreator/bin/designer/
+(Qt SDK)/(Qt Version)/(Toolchain)/plugins/designer
+
+cd build && cmake .. && make ColorWidgetsPlugin && make install
+
+
+Latest Version
+--------------
+
+The latest version of the sources can be found at the following locations:
+
+* https://github.com/mbasaglia/Qt-Color-Widgets
+* git://github.com/mbasaglia/Qt-Color-Widgets.git
+
+
+License
+-------
+
+LGPLv3+, See COPYING.
+As a special exception, this library can be included in any project under the
+terms of any of the GNU liceses, distributing the whole project under a
+different GNU license, see LICENSE-EXCEPTION for details.
+
+Copyright (C) 2013-2017 Mattia Basaglia
diff --git a/Qt-Color-Widgets/color_widgets.pri b/Qt-Color-Widgets/color_widgets.pri
new file mode 100644
index 00000000..65e05eeb
--- /dev/null
+++ b/Qt-Color-Widgets/color_widgets.pri
@@ -0,0 +1,32 @@
+# Copyright (C) 2013-2017 Mattia Basaglia
+#
+#
+# This software is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with Color Widgets. If not, see .
+
+CONFIG += c++11
+
+INCLUDEPATH += $$PWD/src $$PWD/include
+
+SOURCES += \
+ $$PWD/src/color_wheel.cpp \
+ $$PWD/src/color_utils.cpp
+
+HEADERS += \
+ $$PWD/include/color_wheel.hpp \
+ $$PWD/include/colorwidgets_global.hpp \
+ $$PWD/src/color_utils.hpp
+
+RESOURCES += \
+ $$PWD/src/color_widgets.qrc
+
diff --git a/Qt-Color-Widgets/color_widgets.pro b/Qt-Color-Widgets/color_widgets.pro
new file mode 100644
index 00000000..4241ac2d
--- /dev/null
+++ b/Qt-Color-Widgets/color_widgets.pro
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2013-2017 Mattia Basaglia
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+#
+TEMPLATE=lib
+CONFIG += dll
+QT += core gui widgets
+DEFINES += QTCOLORWIDGETS_LIBRARY
+
+TARGET=ColorWidgets-qt5
+
+VERSION=1.0.0
+
+OBJECTS_DIR = out/obj
+MOC_DIR = out/generated
+UI_DIR = out/generated
+RCC_DIR = out/generated
+
+include(color_widgets.pri)
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+unix {
+ LIB_TARGET = lib$${TARGET}.so
+}
+win32 {
+ LIB_TARGET = $${TARGET}.dll
+}
+
+isEmpty(PREFIX) {
+ PREFIX = /usr/local
+}
+target.path = $$PREFIX/lib
+headers.path = $$PREFIX/include/QtColorWidgets
+headers.files = $$HEADERS
+
+INSTALLS += target headers
+
diff --git a/Qt-Color-Widgets/include/ColorWheel b/Qt-Color-Widgets/include/ColorWheel
new file mode 100644
index 00000000..ed17f683
--- /dev/null
+++ b/Qt-Color-Widgets/include/ColorWheel
@@ -0,0 +1 @@
+#include "color_wheel.hpp"
diff --git a/Qt-Color-Widgets/include/color_wheel.hpp b/Qt-Color-Widgets/include/color_wheel.hpp
new file mode 100644
index 00000000..2725c609
--- /dev/null
+++ b/Qt-Color-Widgets/include/color_wheel.hpp
@@ -0,0 +1,171 @@
+/**
+ * \file
+ *
+ * \author Mattia Basaglia
+ *
+ * \copyright Copyright (C) 2013-2017 Mattia Basaglia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ */
+#ifndef COLOR_WHEEL_HPP
+#define COLOR_WHEEL_HPP
+
+#include "colorwidgets_global.hpp"
+
+#include
+
+namespace color_widgets {
+
+/**
+ * \brief Display an analog widget that allows the selection of a HSV color
+ *
+ * It has an outer wheel to select the Hue and an intenal square to select
+ * Saturation and Lightness.
+ */
+class QCP_EXPORT ColorWheel : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged DESIGNABLE true STORED false )
+ Q_PROPERTY(qreal hue READ hue WRITE setHue DESIGNABLE false )
+ Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation DESIGNABLE false )
+ Q_PROPERTY(qreal value READ value WRITE setValue DESIGNABLE false )
+ Q_PROPERTY(unsigned wheelWidth READ wheelWidth WRITE setWheelWidth DESIGNABLE true )
+ Q_PROPERTY(DisplayFlags displayFlags READ displayFlags WRITE setDisplayFlags NOTIFY displayFlagsChanged DESIGNABLE true )
+
+public:
+ enum DisplayEnum
+ {
+ SHAPE_DEFAULT = 0x000, ///< Use the default shape
+ SHAPE_TRIANGLE = 0x001, ///< A triangle
+ SHAPE_SQUARE = 0x002, ///< A square
+ SHAPE_FLAGS = 0x00f, ///< Mask for the shape flags
+
+ ANGLE_DEFAULT = 0x000, ///< Use the default rotation style
+ ANGLE_FIXED = 0x010, ///< The inner part doesn't rotate
+ ANGLE_ROTATING = 0x020, ///< The inner part follows the hue selector
+ ANGLE_FLAGS = 0x0f0, ///< Mask for the angle flags
+
+ COLOR_DEFAULT = 0x000, ///< Use the default colorspace
+ COLOR_HSV = 0x100, ///< Use the HSV color space
+ COLOR_HSL = 0x200, ///< Use the HSL color space
+ COLOR_LCH = 0x400, ///< Use Luma Chroma Hue (Y_601')
+ COLOR_FLAGS = 0xf00, ///< Mask for the color space flags
+
+ FLAGS_DEFAULT = 0x000, ///< Use all defaults
+ FLAGS_ALL = 0xfff ///< Mask matching all flags
+ };
+ Q_DECLARE_FLAGS(DisplayFlags, DisplayEnum)
+ Q_FLAGS(DisplayFlags)
+
+ explicit ColorWheel(QWidget *parent = 0);
+ ~ColorWheel();
+
+ /// Get current color
+ QColor color() const;
+
+ virtual QSize sizeHint() const Q_DECL_OVERRIDE;
+
+ /// Get current hue in the range [0-1]
+ qreal hue() const;
+
+ /// Get current saturation in the range [0-1]
+ qreal saturation() const;
+
+ /// Get current value in the range [0-1]
+ qreal value() const;
+
+ /// Get the width in pixels of the outer wheel
+ unsigned int wheelWidth() const;
+
+ /// Set the width in pixels of the outer wheel
+ void setWheelWidth(unsigned int w);
+
+ /// Get display flags
+ DisplayFlags displayFlags(DisplayFlags mask = FLAGS_ALL) const;
+
+ /// Set the default display flags
+ static void setDefaultDisplayFlags(DisplayFlags flags);
+
+ /// Get default display flags
+ static DisplayFlags defaultDisplayFlags(DisplayFlags mask = FLAGS_ALL);
+
+ /**
+ * @brief Set a specific display flag
+ * @param flag Flag replacing the mask
+ * @param mask Mask to be cleared
+ */
+ void setDisplayFlag(DisplayFlags flag, DisplayFlags mask);
+
+public Q_SLOTS:
+
+ /// Set current color
+ void setColor(QColor c);
+
+ /**
+ * @param h Hue [0-1]
+ */
+ void setHue(qreal h);
+
+ /**
+ * @param s Saturation [0-1]
+ */
+ void setSaturation(qreal s);
+
+ /**
+ * @param v Value [0-1]
+ */
+ void setValue(qreal v);
+
+ /**
+ * @brief Set the display flags
+ * @param flags which will replace the current ones
+ */
+ void setDisplayFlags(ColorWheel::DisplayFlags flags);
+
+Q_SIGNALS:
+ /**
+ * Emitted when the user selects a color or setColor is called
+ */
+ void colorChanged(QColor);
+
+ /**
+ * Emitted when the user selects a color
+ */
+ void colorSelected(QColor);
+
+ void displayFlagsChanged(ColorWheel::DisplayFlags flags);
+
+ void mouseReleaseOnColor(QColor);
+
+protected:
+ void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
+ void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE;
+ void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE;
+ void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE;
+ void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE;
+ void dragEnterEvent(QDragEnterEvent* event) Q_DECL_OVERRIDE;
+ void dropEvent(QDropEvent* event) Q_DECL_OVERRIDE;
+
+private:
+ class Private;
+ Private * const p;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ColorWheel::DisplayFlags)
+
+} // namespace color_widgets
+
+#endif // COLOR_WHEEL_HPP
diff --git a/Qt-Color-Widgets/include/colorwidgets_global.hpp b/Qt-Color-Widgets/include/colorwidgets_global.hpp
new file mode 100644
index 00000000..13add22d
--- /dev/null
+++ b/Qt-Color-Widgets/include/colorwidgets_global.hpp
@@ -0,0 +1,14 @@
+#ifndef QT_COLOR_WIDGETS_GLOBAL_H
+#define QT_COLOR_WIDGETS_GLOBAL_H
+
+#include
+
+#if defined(QTCOLORWIDGETS_LIBRARY)
+# define QCP_EXPORT Q_DECL_EXPORT
+#elif defined(QTCOLORWIDGETS_STATICALLY_LINKED)
+# define QCP_EXPORT
+#else
+# define QCP_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // QT_COLOR_WIDGETS_GLOBAL_H
diff --git a/Qt-Color-Widgets/src/alphaback.png b/Qt-Color-Widgets/src/alphaback.png
new file mode 100644
index 00000000..62d5c6e5
Binary files /dev/null and b/Qt-Color-Widgets/src/alphaback.png differ
diff --git a/Qt-Color-Widgets/src/color_utils.cpp b/Qt-Color-Widgets/src/color_utils.cpp
new file mode 100644
index 00000000..e0bdb793
--- /dev/null
+++ b/Qt-Color-Widgets/src/color_utils.cpp
@@ -0,0 +1,83 @@
+/**
+ * \file
+ *
+ * \author Mattia Basaglia
+ *
+ * \copyright Copyright (C) 2013-2017 Mattia Basaglia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ */
+#include "color_utils.hpp"
+
+namespace color_widgets {
+namespace detail {
+
+QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha )
+{
+ qreal h1 = hue*6;
+ qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1));
+ QColor col;
+ if ( h1 >= 0 && h1 < 1 )
+ col = QColor::fromRgbF(chroma,x,0);
+ else if ( h1 < 2 )
+ col = QColor::fromRgbF(x,chroma,0);
+ else if ( h1 < 3 )
+ col = QColor::fromRgbF(0,chroma,x);
+ else if ( h1 < 4 )
+ col = QColor::fromRgbF(0,x,chroma);
+ else if ( h1 < 5 )
+ col = QColor::fromRgbF(x,0,chroma);
+ else if ( h1 < 6 )
+ col = QColor::fromRgbF(chroma,0,x);
+
+ qreal m = luma - color_lumaF(col);
+
+ return QColor::fromRgbF(
+ qBound(0.0,col.redF()+m,1.0),
+ qBound(0.0,col.greenF()+m,1.0),
+ qBound(0.0,col.blueF()+m,1.0),
+ alpha);
+}
+
+QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha )
+{
+ qreal chroma = (1 - qAbs(2*lig-1))*sat;
+ qreal h1 = hue*6;
+ qreal x = chroma*(1-qAbs(std::fmod(h1,2)-1));
+ QColor col;
+ if ( h1 >= 0 && h1 < 1 )
+ col = QColor::fromRgbF(chroma,x,0);
+ else if ( h1 < 2 )
+ col = QColor::fromRgbF(x,chroma,0);
+ else if ( h1 < 3 )
+ col = QColor::fromRgbF(0,chroma,x);
+ else if ( h1 < 4 )
+ col = QColor::fromRgbF(0,x,chroma);
+ else if ( h1 < 5 )
+ col = QColor::fromRgbF(x,0,chroma);
+ else if ( h1 < 6 )
+ col = QColor::fromRgbF(chroma,0,x);
+
+ qreal m = lig-chroma/2;
+
+ return QColor::fromRgbF(
+ qBound(0.0,col.redF()+m,1.0),
+ qBound(0.0,col.greenF()+m,1.0),
+ qBound(0.0,col.blueF()+m,1.0),
+ alpha);
+}
+
+} // namespace detail
+} // namespace color_widgets
diff --git a/Qt-Color-Widgets/src/color_utils.hpp b/Qt-Color-Widgets/src/color_utils.hpp
new file mode 100644
index 00000000..5e61cdc9
--- /dev/null
+++ b/Qt-Color-Widgets/src/color_utils.hpp
@@ -0,0 +1,70 @@
+/**
+ * \file
+ *
+ * \author Mattia Basaglia
+ *
+ * \copyright Copyright (C) 2013-2017 Mattia Basaglia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ */
+#include
+#include
+
+namespace color_widgets {
+namespace detail {
+
+
+inline qreal color_chromaF(const QColor& c)
+{
+ qreal max = qMax(c.redF(), qMax(c.greenF(), c.blueF()));
+ qreal min = qMin(c.redF(), qMin(c.greenF(), c.blueF()));
+ return max - min;
+}
+
+inline qreal color_lumaF(const QColor& c)
+{
+ return 0.30 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF();
+}
+QColor color_from_lch(qreal hue, qreal chroma, qreal luma, qreal alpha = 1 );
+
+inline QColor rainbow_lch(qreal hue)
+{
+ return color_from_lch(hue,1,1);
+}
+
+inline QColor rainbow_hsv(qreal hue)
+{
+ return QColor::fromHsvF(hue,1,1);
+}
+
+inline qreal color_lightnessF(const QColor& c)
+{
+ return ( qMax(c.redF(),qMax(c.greenF(),c.blueF())) +
+ qMin(c.redF(),qMin(c.greenF(),c.blueF())) ) / 2;
+}
+
+inline qreal color_HSL_saturationF(const QColor& col)
+{
+ qreal c = color_chromaF(col);
+ qreal l = color_lightnessF(col);
+ if ( qFuzzyCompare(l+1,1) || qFuzzyCompare(l+1,2) )
+ return 0;
+ return c / (1-qAbs(2*l-1));
+}
+
+QColor color_from_hsl(qreal hue, qreal sat, qreal lig, qreal alpha = 1 );
+
+} // namespace detail
+} // namespace color_widgets
diff --git a/Qt-Color-Widgets/src/color_wheel.cpp b/Qt-Color-Widgets/src/color_wheel.cpp
new file mode 100644
index 00000000..3a66c6ea
--- /dev/null
+++ b/Qt-Color-Widgets/src/color_wheel.cpp
@@ -0,0 +1,562 @@
+/**
+ * \file
+ *
+ * \author Mattia Basaglia
+ *
+ * \copyright Copyright (C) 2013-2017 Mattia Basaglia
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ */
+#include "color_wheel.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "color_utils.hpp"
+
+namespace color_widgets {
+
+enum MouseStatus
+{
+ Nothing,
+ DragCircle,
+ DragSquare
+};
+
+static const ColorWheel::DisplayFlags hard_default_flags = ColorWheel::SHAPE_TRIANGLE|ColorWheel::ANGLE_ROTATING|ColorWheel::COLOR_HSV;
+static ColorWheel::DisplayFlags default_flags = hard_default_flags;
+static const double selector_radius = 6;
+
+class ColorWheel::Private
+{
+private:
+ ColorWheel * const w;
+
+public:
+ qreal hue, sat, val;
+ unsigned int wheel_width;
+ MouseStatus mouse_status;
+ QPixmap hue_ring;
+ QImage inner_selector;
+ DisplayFlags display_flags;
+ QColor (*color_from)(qreal,qreal,qreal,qreal);
+ QColor (*rainbow_from_hue)(qreal);
+ int max_size = 128;
+
+ Private(ColorWheel *widget)
+ : w(widget), hue(0), sat(0), val(0),
+ wheel_width(20), mouse_status(Nothing),
+ display_flags(FLAGS_DEFAULT),
+ color_from(&QColor::fromHsvF), rainbow_from_hue(&detail::rainbow_hsv)
+ { }
+
+ /// Calculate outer wheel radius from idget center
+ qreal outer_radius() const
+ {
+ return qMin(w->geometry().width(), w->geometry().height())/2;
+ }
+
+ /// Calculate inner wheel radius from idget center
+ qreal inner_radius() const
+ {
+ return outer_radius()-wheel_width;
+ }
+
+ /// Calculate the edge length of the inner square
+ qreal square_size() const
+ {
+ return inner_radius()*qSqrt(2);
+ }
+
+ /// Calculate the height of the inner triangle
+ qreal triangle_height() const
+ {
+ return inner_radius()*3/2;
+ }
+
+ /// Calculate the side of the inner triangle
+ qreal triangle_side() const
+ {
+ return inner_radius()*qSqrt(3);
+ }
+
+ /// return line from center to given point
+ QLineF line_to_point(const QPoint &p) const
+ {
+ return QLineF (w->geometry().width()/2, w->geometry().height()/2, p.x(), p.y());
+ }
+
+ void render_square()
+ {
+ int width = qMin(square_size(), max_size);
+ QSize size(width, width);
+ inner_selector = QImage(size, QImage::Format_RGB32);
+
+ for ( int y = 0; y < width; ++y )
+ {
+ for ( int x = 0; x < width; ++x )
+ {
+ inner_selector.setPixel( x, y,
+ color_from(hue,double(x)/width,double(y)/width,1).rgb());
+ }
+ }
+ }
+
+ /**
+ * \brief renders the selector as a triangle
+ * \note It's the same as a square with the edge with value=0 collapsed to a single point
+ */
+ void render_triangle()
+ {
+ QSizeF size = selector_size();
+ if ( size.height() > max_size )
+ size *= max_size / size.height();
+
+ qreal ycenter = size.height()/2;
+ inner_selector = QImage(size.toSize(), QImage::Format_RGB32);
+
+ for (int x = 0; x < inner_selector.width(); x++ )
+ {
+ qreal pval = x / size.height();
+ qreal slice_h = size.height() * pval;
+ for (int y = 0; y < inner_selector.height(); y++ )
+ {
+ qreal ymin = ycenter-slice_h/2;
+ qreal psat = qBound(0.0,(y-ymin)/slice_h,1.0);
+
+ inner_selector.setPixel(x,y,color_from(hue,psat,pval,1).rgb());
+ }
+ }
+ }
+
+ /// Updates the inner image that displays the saturation-value selector
+ void render_inner_selector()
+ {
+ if ( display_flags & ColorWheel::SHAPE_TRIANGLE )
+ render_triangle();
+ else
+ render_square();
+ }
+
+ /// Offset of the selector image
+ QPointF selector_image_offset()
+ {
+ if ( display_flags & SHAPE_TRIANGLE )
+ return QPointF(-inner_radius(),-triangle_side()/2);
+ return QPointF(-square_size()/2,-square_size()/2);
+ }
+
+ /**
+ * \brief Size of the selector when rendered to the screen
+ */
+ QSizeF selector_size()
+ {
+ if ( display_flags & SHAPE_TRIANGLE )
+ return QSizeF(triangle_height(), triangle_side());
+ return QSizeF(square_size(), square_size());
+ }
+
+
+ /// Rotation of the selector image
+ qreal selector_image_angle()
+ {
+ if ( display_flags & SHAPE_TRIANGLE )
+ {
+ if ( display_flags & ANGLE_ROTATING )
+ return -hue*360-60;
+ return -150;
+ }
+ else
+ {
+ if ( display_flags & ANGLE_ROTATING )
+ return -hue*360-45;
+ else
+ return 180;
+ }
+ }
+
+ /// Updates the outer ring that displays the hue selector
+ void render_ring()
+ {
+ hue_ring = QPixmap(outer_radius()*2,outer_radius()*2);
+ hue_ring.fill(Qt::transparent);
+ QPainter painter(&hue_ring);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+
+
+ const int hue_stops = 24;
+ QConicalGradient gradient_hue(0, 0, 0);
+ if ( gradient_hue.stops().size() < hue_stops )
+ {
+ for ( double a = 0; a < 1.0; a+=1.0/(hue_stops-1) )
+ {
+ gradient_hue.setColorAt(a,rainbow_from_hue(a));
+ }
+ gradient_hue.setColorAt(1,rainbow_from_hue(0));
+ }
+
+ painter.translate(outer_radius(),outer_radius());
+
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(QBrush(gradient_hue));
+ painter.drawEllipse(QPointF(0,0),outer_radius(),outer_radius());
+
+ painter.setBrush(Qt::transparent);//palette().background());
+ painter.drawEllipse(QPointF(0,0),inner_radius(),inner_radius());
+ }
+
+ void set_color(const QColor& c)
+ {
+ if ( display_flags & ColorWheel::COLOR_HSV )
+ {
+ hue = qMax(0.0, c.hsvHueF());
+ sat = c.hsvSaturationF();
+ val = c.valueF();
+ }
+ else if ( display_flags & ColorWheel::COLOR_HSL )
+ {
+ hue = qMax(0.0, c.hueF());
+ sat = detail::color_HSL_saturationF(c);
+ val = detail::color_lightnessF(c);
+ }
+ else if ( display_flags & ColorWheel::COLOR_LCH )
+ {
+ hue = qMax(0.0, c.hsvHueF());
+ sat = detail::color_chromaF(c);
+ val = detail::color_lumaF(c);
+ }
+ }
+};
+
+ColorWheel::ColorWheel(QWidget *parent) :
+ QWidget(parent), p(new Private(this))
+{
+ setDisplayFlags(FLAGS_DEFAULT);
+ setAcceptDrops(true);
+}
+
+ColorWheel::~ColorWheel()
+{
+ delete p;
+}
+
+QColor ColorWheel::color() const
+{
+ return p->color_from(p->hue, p->sat, p->val, 1);
+}
+
+QSize ColorWheel::sizeHint() const
+{
+ return QSize(p->wheel_width*5, p->wheel_width*5);
+}
+
+qreal ColorWheel::hue() const
+{
+ if ( (p->display_flags & COLOR_LCH) && p->sat > 0.01 )
+ return color().hueF();
+ return p->hue;
+}
+
+qreal ColorWheel::saturation() const
+{
+ return color().hsvSaturationF();
+}
+
+qreal ColorWheel::value() const
+{
+ return color().valueF();
+}
+
+unsigned int ColorWheel::wheelWidth() const
+{
+ return p->wheel_width;
+}
+
+void ColorWheel::setWheelWidth(unsigned int w)
+{
+ p->wheel_width = w;
+ p->render_inner_selector();
+ update();
+}
+
+void ColorWheel::paintEvent(QPaintEvent * )
+{
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.translate(geometry().width()/2,geometry().height()/2);
+
+ // hue wheel
+ if(p->hue_ring.isNull())
+ p->render_ring();
+
+ painter.drawPixmap(-p->outer_radius(), -p->outer_radius(), p->hue_ring);
+
+ // hue selector
+ painter.setPen(QPen(Qt::black,3));
+ painter.setBrush(Qt::NoBrush);
+ QLineF ray(0, 0, p->outer_radius(), 0);
+ ray.setAngle(p->hue*360);
+ QPointF h1 = ray.p2();
+ ray.setLength(p->inner_radius());
+ QPointF h2 = ray.p2();
+ painter.drawLine(h1,h2);
+
+ // lum-sat square
+ if(p->inner_selector.isNull())
+ p->render_inner_selector();
+
+ painter.rotate(p->selector_image_angle());
+ painter.translate(p->selector_image_offset());
+
+ QPointF selector_position;
+ if ( p->display_flags & SHAPE_SQUARE )
+ {
+ qreal side = p->square_size();
+ selector_position = QPointF(p->sat*side, p->val*side);
+ }
+ else if ( p->display_flags & SHAPE_TRIANGLE )
+ {
+ qreal side = p->triangle_side();
+ qreal height = p->triangle_height();
+ qreal slice_h = side * p->val;
+ qreal ymin = side/2-slice_h/2;
+
+ selector_position = QPointF(p->val*height, ymin + p->sat*slice_h);
+ QPolygonF triangle;
+ triangle.append(QPointF(0,side/2));
+ triangle.append(QPointF(height,0));
+ triangle.append(QPointF(height,side));
+ QPainterPath clip;
+ clip.addPolygon(triangle);
+ painter.setClipPath(clip);
+ }
+
+ painter.drawImage(QRectF(QPointF(0, 0), p->selector_size()), p->inner_selector);
+ painter.setClipping(false);
+
+ // lum-sat selector
+ painter.setPen(QPen(p->val > 0.5 ? Qt::black : Qt::white, 3));
+ painter.setBrush(Qt::NoBrush);
+ painter.drawEllipse(selector_position, selector_radius, selector_radius);
+
+}
+
+void ColorWheel::mouseMoveEvent(QMouseEvent *ev)
+{
+ if (p->mouse_status == DragCircle )
+ {
+ p->hue = p->line_to_point(ev->pos()).angle()/360.0;
+ p->render_inner_selector();
+
+ Q_EMIT colorSelected(color());
+ Q_EMIT colorChanged(color());
+ update();
+ }
+ else if(p->mouse_status == DragSquare)
+ {
+ QLineF glob_mouse_ln = p->line_to_point(ev->pos());
+ QLineF center_mouse_ln ( QPointF(0,0),
+ glob_mouse_ln.p2() - glob_mouse_ln.p1() );
+
+ center_mouse_ln.setAngle(center_mouse_ln.angle()+p->selector_image_angle());
+ center_mouse_ln.setP2(center_mouse_ln.p2()-p->selector_image_offset());
+
+ if ( p->display_flags & SHAPE_SQUARE )
+ {
+ p->sat = qBound(0.0, center_mouse_ln.x2()/p->square_size(), 1.0);
+ p->val = qBound(0.0, center_mouse_ln.y2()/p->square_size(), 1.0);
+ }
+ else if ( p->display_flags & SHAPE_TRIANGLE )
+ {
+ QPointF pt = center_mouse_ln.p2();
+
+ qreal side = p->triangle_side();
+ p->val = qBound(0.0, pt.x() / p->triangle_height(), 1.0);
+ qreal slice_h = side * p->val;
+
+ qreal ycenter = side/2;
+ qreal ymin = ycenter-slice_h/2;
+
+ if ( slice_h > 0 )
+ p->sat = qBound(0.0, (pt.y()-ymin)/slice_h, 1.0);
+ }
+
+ Q_EMIT colorSelected(color());
+ Q_EMIT colorChanged(color());
+ update();
+ }
+}
+
+void ColorWheel::mousePressEvent(QMouseEvent *ev)
+{
+ if ( ev->buttons() & Qt::LeftButton )
+ {
+ setFocus();
+ QLineF ray = p->line_to_point(ev->pos());
+ if ( ray.length() <= p->inner_radius() )
+ p->mouse_status = DragSquare;
+ else if ( ray.length() <= p->outer_radius() )
+ p->mouse_status = DragCircle;
+
+ // Update the color
+ mouseMoveEvent(ev);
+ }
+}
+
+void ColorWheel::mouseReleaseEvent(QMouseEvent *ev)
+{
+ mouseMoveEvent(ev);
+ p->mouse_status = Nothing;
+ Q_EMIT mouseReleaseOnColor(color());
+
+}
+
+void ColorWheel::resizeEvent(QResizeEvent *)
+{
+ p->render_ring();
+ p->render_inner_selector();
+}
+
+void ColorWheel::setColor(QColor c)
+{
+ qreal oldh = p->hue;
+ p->set_color(c);
+ if (!qFuzzyCompare(oldh+1, p->hue+1))
+ p->render_inner_selector();
+ update();
+ Q_EMIT colorChanged(c);
+}
+
+void ColorWheel::setHue(qreal h)
+{
+ p->hue = qBound(0.0, h, 1.0);
+ p->render_inner_selector();
+ update();
+}
+
+void ColorWheel::setSaturation(qreal s)
+{
+ p->sat = qBound(0.0, s, 1.0);
+ update();
+}
+
+void ColorWheel::setValue(qreal v)
+{
+ p->val = qBound(0.0, v, 1.0);
+ update();
+}
+
+
+void ColorWheel::setDisplayFlags(DisplayFlags flags)
+{
+ if ( ! (flags & COLOR_FLAGS) )
+ flags |= default_flags & COLOR_FLAGS;
+ if ( ! (flags & ANGLE_FLAGS) )
+ flags |= default_flags & ANGLE_FLAGS;
+ if ( ! (flags & SHAPE_FLAGS) )
+ flags |= default_flags & SHAPE_FLAGS;
+
+ if ( (flags & COLOR_FLAGS) != (p->display_flags & COLOR_FLAGS) )
+ {
+ QColor old_col = color();
+ if ( flags & ColorWheel::COLOR_HSL )
+ {
+ p->hue = old_col.hueF();
+ p->sat = detail::color_HSL_saturationF(old_col);
+ p->val = detail::color_lightnessF(old_col);
+ p->color_from = &detail::color_from_hsl;
+ p->rainbow_from_hue = &detail::rainbow_hsv;
+ }
+ else if ( flags & ColorWheel::COLOR_LCH )
+ {
+ p->hue = old_col.hueF();
+ p->sat = detail::color_chromaF(old_col);
+ p->val = detail::color_lumaF(old_col);
+ p->color_from = &detail::color_from_lch;
+ p->rainbow_from_hue = &detail::rainbow_lch;
+ }
+ else
+ {
+ p->hue = old_col.hsvHueF();
+ p->sat = old_col.hsvSaturationF();
+ p->val = old_col.valueF();
+ p->color_from = &QColor::fromHsvF;
+ p->rainbow_from_hue = &detail::rainbow_hsv;
+ }
+ p->render_ring();
+ }
+
+ p->display_flags = flags;
+ p->render_inner_selector();
+ update();
+ Q_EMIT displayFlagsChanged(flags);
+}
+
+ColorWheel::DisplayFlags ColorWheel::displayFlags(DisplayFlags mask) const
+{
+ return p->display_flags & mask;
+}
+
+void ColorWheel::setDefaultDisplayFlags(DisplayFlags flags)
+{
+ if ( !(flags & COLOR_FLAGS) )
+ flags |= hard_default_flags & COLOR_FLAGS;
+ if ( !(flags & ANGLE_FLAGS) )
+ flags |= hard_default_flags & ANGLE_FLAGS;
+ if ( !(flags & SHAPE_FLAGS) )
+ flags |= hard_default_flags & SHAPE_FLAGS;
+ default_flags = flags;
+}
+
+ColorWheel::DisplayFlags ColorWheel::defaultDisplayFlags(DisplayFlags mask)
+{
+ return default_flags & mask;
+}
+
+void ColorWheel::setDisplayFlag(DisplayFlags flag, DisplayFlags mask)
+{
+ setDisplayFlags((p->display_flags&~mask)|flag);
+}
+
+void ColorWheel::dragEnterEvent(QDragEnterEvent* event)
+{
+ if ( event->mimeData()->hasColor() ||
+ ( event->mimeData()->hasText() && QColor(event->mimeData()->text()).isValid() ) )
+ event->acceptProposedAction();
+}
+
+void ColorWheel::dropEvent(QDropEvent* event)
+{
+ if ( event->mimeData()->hasColor() )
+ {
+ setColor(event->mimeData()->colorData().value());
+ event->accept();
+ }
+ else if ( event->mimeData()->hasText() )
+ {
+ QColor col(event->mimeData()->text());
+ if ( col.isValid() )
+ {
+ setColor(col);
+ event->accept();
+ }
+ }
+}
+
+} // namespace color_widgets
diff --git a/Qt-Color-Widgets/src/color_widgets.qrc b/Qt-Color-Widgets/src/color_widgets.qrc
new file mode 100644
index 00000000..7b8cfcd3
--- /dev/null
+++ b/Qt-Color-Widgets/src/color_widgets.qrc
@@ -0,0 +1,5 @@
+
+
+ alphaback.png
+
+