From fb9f7dbd3cff907843704e5c706a642d445539a3 Mon Sep 17 00:00:00 2001 From: Michal_Marszalek <1aam2am1@gmail.com> Date: Wed, 2 Sep 2020 17:08:47 +0200 Subject: [PATCH] Added Color Picker Widget Signed-off-by: Michal_Marszalek <1aam2am1@gmail.com> --- .../TGUI/Renderers/ColorPickerRenderer.hpp | 105 +++ include/TGUI/Signal.hpp | 8 + include/TGUI/SignalImpl.hpp | 11 +- include/TGUI/TGUI.hpp | 1 + include/TGUI/Widgets/ColorPicker.hpp | 246 ++++++ src/TGUI/CMakeLists.txt | 2 + src/TGUI/Renderers/ColorPickerRenderer.cpp | 40 + src/TGUI/Signal.cpp | 13 + src/TGUI/Widgets/ColorPicker.cpp | 722 ++++++++++++++++++ 9 files changed, 1147 insertions(+), 1 deletion(-) create mode 100644 include/TGUI/Renderers/ColorPickerRenderer.hpp create mode 100644 include/TGUI/Widgets/ColorPicker.hpp create mode 100644 src/TGUI/Renderers/ColorPickerRenderer.cpp create mode 100644 src/TGUI/Widgets/ColorPicker.cpp diff --git a/include/TGUI/Renderers/ColorPickerRenderer.hpp b/include/TGUI/Renderers/ColorPickerRenderer.hpp new file mode 100644 index 000000000..b5cdcf87c --- /dev/null +++ b/include/TGUI/Renderers/ColorPickerRenderer.hpp @@ -0,0 +1,105 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2020 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef TGUI_COLOR_PICKER_RENDERER_HPP +#define TGUI_COLOR_PICKER_RENDERER_HPP + + +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui +{ + class TGUI_API ColorPickerRenderer : public ChildWindowRenderer + { + public: + + using ChildWindowRenderer::ChildWindowRenderer; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Sets the renderer data of the buttons which the color picker uses + /// + /// @param rendererData Data about how the buttons should look + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setButton(std::shared_ptr rendererData); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the renderer data of the buttons which the color picker uses + /// + /// @return Data about how the buttons looks + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::shared_ptr getButton() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Sets the renderer data of the labels which the color picker uses + /// + /// @param rendererData Data about how the labels should look + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setLabel(std::shared_ptr rendererData); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the renderer data of the labels which the color picker uses + /// + /// @return Data about how the labels looks + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::shared_ptr getLabel() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Sets the renderer data of the sliders which the color picker uses + /// + /// @param rendererData Data about how the sliders should look + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setSlider(std::shared_ptr rendererData); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the renderer data of the sliders which the color picker uses + /// + /// @return Data about how the sliders looks + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::shared_ptr getSlider() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // TGUI_COLOR_PICKER_RENDERER_HPP diff --git a/include/TGUI/Signal.hpp b/include/TGUI/Signal.hpp index ba81309b8..6d414e494 100644 --- a/include/TGUI/Signal.hpp +++ b/include/TGUI/Signal.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,12 @@ namespace tgui static constexpr const char* const EscapeKeyPressed = "EscapeKeyPressed"; ///< The escape key was pressed while the child window was focused. Optional parameter: pointer to the window }; + struct ColorPicker : public ChildWindow + { + static constexpr const char* const ColorChange = "ColorChanged"; ///< The color was changed. Optional parameter: color chosen + static constexpr const char* const OkPressed = "OkPressed"; ///< The ok key was pressed. Optional parameter: color chosen + }; + struct ComboBox : public Widget { static constexpr const char* const ItemSelected = "ItemSelected"; ///< An item was selected in the combo box. Optional parameter: selected item or its index @@ -458,6 +465,7 @@ namespace tgui TGUI_SIGNAL_VALUE_DECLARATION(Float, float) TGUI_SIGNAL_VALUE_DECLARATION(String, const sf::String&) TGUI_SIGNAL_VALUE_DECLARATION(Vector2f, Vector2f) + TGUI_SIGNAL_VALUE_DECLARATION(Color, Color) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/TGUI/SignalImpl.hpp b/include/TGUI/SignalImpl.hpp index e0353b408..9e68ad962 100644 --- a/include/TGUI/SignalImpl.hpp +++ b/include/TGUI/SignalImpl.hpp @@ -55,6 +55,8 @@ namespace tgui return static_cast(*static_cast(obj)); else if constexpr (std::is_same_v) // Signal handlers are allowed to have sf::Vector2f parameters while the signal sends tgui::Vector2f return static_cast(*static_cast(obj)); + else if constexpr (std::is_same_v) // Signal handlers are allowed to have sf::Color parameters while the signal sends tgui::Color + return static_cast(*static_cast(obj)); else return *static_cast*>(obj); } @@ -73,7 +75,14 @@ namespace tgui return static_cast(*static_cast(obj)); } - template ::value && !std::is_same::value>::type* = nullptr> + template ::value>::type* = nullptr> + decltype(auto) dereference(const void* obj) + { + // Signal handlers are allowed to have sf::Vector2f parameters while the signal sends tgui::Vector2f + return static_cast(*static_cast(obj)); + } + + template ::value && !std::is_same::value && !std::is_same::value>::type* = nullptr> decltype(auto) dereference(const void* obj) { return *static_cast::type*>(obj); diff --git a/include/TGUI/TGUI.hpp b/include/TGUI/TGUI.hpp index 70043e298..bc520252f 100644 --- a/include/TGUI/TGUI.hpp +++ b/include/TGUI/TGUI.hpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/include/TGUI/Widgets/ColorPicker.hpp b/include/TGUI/Widgets/ColorPicker.hpp new file mode 100644 index 000000000..82e296e5b --- /dev/null +++ b/include/TGUI/Widgets/ColorPicker.hpp @@ -0,0 +1,246 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2020 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef TGUI_COLOR_PICKER_HPP +#define TGUI_COLOR_PICKER_HPP + + +#include +#include +#include +#include +#include + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +namespace tgui +{ + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Color picker widget + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + class TGUI_API ColorPicker : public ChildWindow + { + public: + + typedef std::shared_ptr Ptr; ///< Shared widget pointer + typedef std::shared_ptr ConstPtr; ///< Shared constant widget pointer + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Default constructor + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPicker(); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Creates a new color picker widget + /// + /// @param title Title to display in the title bar of the color picker + /// @param color Default color to display + /// + /// @return The new color picker + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static ColorPicker::Ptr create(sf::String title = "", Color color = Color::Black); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Copy constructor + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPicker(const ColorPicker ©); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Move constructor + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPicker(ColorPicker &©); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Overload of copy assignment operator + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPicker &operator=(const ColorPicker &right); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Overload of move assignment operator + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPicker &operator=(ColorPicker &&right); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Makes a copy of another color picker + /// + /// @param messageBox The other color picker + /// + /// @return The new color picker + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static ColorPicker::Ptr copy(ColorPicker::ConstPtr colorPicker); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the renderer, which gives access to functions that determine how the widget is displayed + /// @return Temporary pointer to the renderer that may be shared with other widgets using the same renderer + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPickerRenderer *getSharedRenderer(); + + const ColorPickerRenderer *getSharedRenderer() const; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the renderer, which gives access to functions that determine how the widget is displayed + /// @return Temporary pointer to the renderer + /// @warning After calling this function, the widget has its own copy of the renderer and it will no longer be shared. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ColorPickerRenderer *getRenderer(); + + const ColorPickerRenderer *getRenderer() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Changes the color of Color Picker + /// + /// @param color The color picked by Color Picker + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setColor(const Color &color); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the picked color + /// + /// @return Color that is picked inside Color Picker + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Color getColor() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void leftMousePressed(Vector2f pos) override; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void leftMouseButtonNoLongerDown() override; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void mouseMoved(Vector2f pos) override; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + protected: + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Makes sure all widgets lie within the window and places them on the correct position. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void rearrange(); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Retrieves a signal based on its name + /// + /// @param signalName Name of the signal + /// + /// @return Signal that corresponds to the name + /// + /// @throw Exception when the name does not match any signal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Signal &getSignal(std::string signalName) override; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Function called when one of the properties of the renderer is changed + /// + /// @param property Lowercase name of the property that was changed + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void rendererChanged(const std::string &property) override; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Saves the widget as a tree node in order to save it to a file + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::unique_ptr save(SavingRenderersMap &renderers) const override; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Loads the widget from a tree of nodes + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void load(const std::unique_ptr &node, const LoadingRenderersMap &renderers) override; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Makes a copy of the widget + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Widget::Ptr clone() const override + { + return std::make_shared(*this); + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private: + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Figure and connect signals of widgets + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void identifyButtonsAndConnect(); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public: + + SignalColor onColorChange = {"ColorChanged"}; ///< Color was changed + SignalColor onOkPressed = {"OkPressed"}; ///< Ok was pressed + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + protected: + std::shared_ptr m_HSV; + + Canvas::Ptr m_canvas = Canvas::create({200, 200}); + + Slider::Ptr m_red = Slider::create(0, 255); + Slider::Ptr m_green = Slider::create(0, 255); + Slider::Ptr m_blue = Slider::create(0, 255); + Slider::Ptr m_alpha = Slider::create(0, 255); + + Slider::Ptr m_value = Slider::create(0, 100); + + Panel::Ptr m_last = Panel::create({60, 30}); + Panel::Ptr m_current = Panel::create({60, 30}); + + bool m_colorRead = false; + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#endif //TGUI_COLOR_PICKER_HPP diff --git a/src/TGUI/CMakeLists.txt b/src/TGUI/CMakeLists.txt index f767d651e..f6df81481 100644 --- a/src/TGUI/CMakeLists.txt +++ b/src/TGUI/CMakeLists.txt @@ -33,6 +33,7 @@ set(TGUI_SRC Renderers/ButtonRenderer.cpp Renderers/ChatBoxRenderer.cpp Renderers/ChildWindowRenderer.cpp + Renderers/ColorPickerRenderer.cpp Renderers/ComboBoxRenderer.cpp Renderers/EditBoxRenderer.cpp Renderers/GroupRenderer.cpp @@ -64,6 +65,7 @@ set(TGUI_SRC Widgets/CheckBox.cpp Widgets/ChildWindow.cpp Widgets/ClickableWidget.cpp + Widgets/ColorPicker.cpp Widgets/ComboBox.cpp Widgets/EditBox.cpp Widgets/Group.cpp diff --git a/src/TGUI/Renderers/ColorPickerRenderer.cpp b/src/TGUI/Renderers/ColorPickerRenderer.cpp new file mode 100644 index 000000000..3d43ee916 --- /dev/null +++ b/src/TGUI/Renderers/ColorPickerRenderer.cpp @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2020 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui +{ + TGUI_RENDERER_PROPERTY_RENDERER(ColorPickerRenderer, Button, "button") + + TGUI_RENDERER_PROPERTY_RENDERER(ColorPickerRenderer, Label, "label") + + TGUI_RENDERER_PROPERTY_RENDERER(ColorPickerRenderer, Slider, "slider") +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/TGUI/Signal.cpp b/src/TGUI/Signal.cpp index 067041c80..7b577acdb 100644 --- a/src/TGUI/Signal.cpp +++ b/src/TGUI/Signal.cpp @@ -82,6 +82,8 @@ namespace tgui constexpr const char* const ChildWindow::Minimized; constexpr const char* const ChildWindow::Maximized; constexpr const char* const ChildWindow::EscapeKeyPressed; + constexpr const char* const ColorPicker::ColorChange; + constexpr const char* const ColorPicker::OkPressed; constexpr const char* const ComboBox::ItemSelected; constexpr const char* const EditBox::TextChanged; constexpr const char* const EditBox::ReturnKeyPressed; @@ -218,6 +220,7 @@ namespace tgui TGUI_SIGNAL_VALUE_CONNECT_DEFINITION(Float, float) TGUI_SIGNAL_VALUE_CONNECT_DEFINITION(String, const sf::String&) TGUI_SIGNAL_VALUE_CONNECT_DEFINITION(Vector2f, Vector2f) + TGUI_SIGNAL_VALUE_CONNECT_DEFINITION(Color, Color) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -279,6 +282,16 @@ namespace tgui return Signal::validateTypes(unboundParameters); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + unsigned int SignalColor::validateTypes(std::initializer_list unboundParameters) const + { + if ((unboundParameters.size() == 1) && (checkParamType(unboundParameters.begin()) || checkParamType(unboundParameters.begin()))) + return 1; + else + return Signal::validateTypes(unboundParameters); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// unsigned int SignalRange::connect(const DelegateRange& handler) diff --git a/src/TGUI/Widgets/ColorPicker.cpp b/src/TGUI/Widgets/ColorPicker.cpp new file mode 100644 index 000000000..54842e29b --- /dev/null +++ b/src/TGUI/Widgets/ColorPicker.cpp @@ -0,0 +1,722 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2020 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui +{ + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + sf::Color hsv2rgb(sf::Vector3f c /**hsv*/) + { + /** + * vec3 hsv2rgb(vec3 c) { + * vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + * vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + * return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + * } + **/ + auto fract = [](auto &&x) { return x - std::floor(x); }; + auto mix = [](auto &&x, auto &&y, auto &&a) { return x * (1.0f - a) + y * a; }; + auto clamp = [](auto &&x, auto &&minVal, auto &&maxVal) { + return std::min(std::max(x, minVal), maxVal); + }; + + c.x = clamp(c.x, 0.f, 1.f); + c.y = clamp(c.y, 0.f, 1.f); + c.z = clamp(c.z, 0.f, 1.f); + + ///xyzw + ///rgba + ///vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float K[] = {1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0}; + + ///vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + float p[] = {std::abs(fract(c.x + K[0]) * 6.0f - K[3]), + std::abs(fract(c.x + K[1]) * 6.0f - K[3]), + std::abs(fract(c.x + K[2]) * 6.0f - K[3])}; + + ///return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); + float C[] = {c.z * mix(K[0], clamp(p[0] - K[0], 0.f, 1.f), c.y), + c.z * mix(K[0], clamp(p[1] - K[0], 0.f, 1.f), c.y), + c.z * mix(K[0], clamp(p[2] - K[0], 0.f, 1.f), c.y)}; + + return {static_cast(clamp(static_cast(255 * C[0]), 0, 255)), + static_cast(clamp(static_cast(255 * C[1]), 0, 255)), + static_cast(clamp(static_cast(255 * C[2]), 0, 255))}; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + sf::Color calculateColor(sf::Vector2f position, float V, int A) + { + /** + * vec2 position = ( gl_FragCoord.xy / resolution.xy ); + * vec2 p2 = position - vec2(0.5, 0.5); + + * float S = length(p2*2.0); + * if(S > 1. && S < 1.01){ + * discard; + * } + + * float V = 1.; + * float H = atan(-p2.y, -p2.x); + + * H /= 2.*Pi; + * H += 0.5; + * gl_FragColor.rgb = hsv2rgb(vec3(H, S, V)); + * gl_FragColor.a = 1.0; + */ + + auto length = [](sf::Vector2f x) { + return std::sqrt(x.x * x.x + x.y * x.y); + }; + + float S = length(position); + + float H = atan2(position.y, -position.x); + + constexpr float Pi = 3.14159265359f; + + H /= 2.f * Pi; + H += 0.5f; + + auto c = hsv2rgb({H, S, V}); + c.a = A; + return c; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + float logInvCurve(float x) + { + /** + * 0.1 - normal curve + * e-1 - e curve (e^x-1)/(e-1) + * + - bigger curve + */ + const double a = std::exp(1.0) - 1.0; + return (std::exp(std::log(a + 1.0) * static_cast(x)) - 1.0) / a; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker::ColorPicker() + { + m_type = "ColorPicker"; + + m_renderer = aurora::makeCopied(); + setRenderer(Theme::getDefault()->getRendererNoThrow(m_type)); + + setTitleButtons(ChildWindow::TitleButton::None); + Container::setTextSize(getGlobalTextSize()); + + m_HSV = std::make_shared(); + m_HSV->loadFromMemory("#version 110\n" + "\n" + "uniform float V;\n" + "uniform vec2 resolution;\n" + "\n" + "const float Pi = 3.14159265359;\n" + "\n" + "vec3 hsv2rgb(vec3 c) {\n" + " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n" + " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n" + " return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n" + "}\n" + "\n" + "void main( void ) {\n" + " vec2 position = ( gl_FragCoord.xy / resolution.xy );\n" + " vec2 p2 = position - vec2(0.5, 0.5);//<-0.5,0.5>\n" + " \n" + " float S = length(p2*2.0);\n" + " if(S > 1.0){\n" + " discard;\n" + " }\n" + " \n" + " float H = atan(-p2.y, -p2.x);\n" + " \n" + " H /= 2.*Pi;\n" + " H += 0.5;\n" + " gl_FragColor.rgb = hsv2rgb(vec3(H, S, V));\n" + " gl_FragColor.a = 1.0;\n" + "}", sf::Shader::Fragment); + + Container::add(Label::create("R"), "#TGUI_INTERNAL$ColorPickerLR#"); + Container::add(m_red, "#TGUI_INTERNAL$ColorPickerRed#"); + auto redBox = EditBox::create(); + redBox->setSize(50, 20); + redBox->setInputValidator(EditBox::Validator::Int); + Container::add(redBox, "#TGUI_INTERNAL$ColorPickerRedBox#"); + + Container::add(Label::create("G"), "#TGUI_INTERNAL$ColorPickerLG#"); + Container::add(m_green, "#TGUI_INTERNAL$ColorPickerGreen#"); + auto greenBox = EditBox::create(); + greenBox->setSize(50, 20); + greenBox->setInputValidator(EditBox::Validator::Int); + Container::add(greenBox, "#TGUI_INTERNAL$ColorPickerGreenBox#"); + + Container::add(Label::create("B"), "#TGUI_INTERNAL$ColorPickerLB#"); + Container::add(m_blue, "#TGUI_INTERNAL$ColorPickerBlue#"); + auto blueBox = EditBox::create(); + blueBox->setSize(50, 20); + blueBox->setInputValidator(EditBox::Validator::Int); + Container::add(blueBox, "#TGUI_INTERNAL$ColorPickerBlueBox#"); + + Container::add(Label::create("A"), "#TGUI_INTERNAL$ColorPickerLA#"); + Container::add(m_alpha, "#TGUI_INTERNAL$ColorPickerAlpha#"); + auto alphaBox = EditBox::create(); + alphaBox->setSize(50, 20); + alphaBox->setInputValidator(EditBox::Validator::Int); + Container::add(alphaBox, "#TGUI_INTERNAL$ColorPickerAlphaBox#"); + + Container::add(m_canvas, "#TGUI_INTERNAL$ColorPickerCanvas#"); + Container::add(m_value, "#TGUI_INTERNAL$ColorPickerValue#"); + m_value->setValue(m_value->getMaximum()); + m_value->setVerticalScroll(true); + + Container::add(Label::create("Last:"), "#TGUI_INTERNAL$ColorPickerLabelLast#"); + Container::add(m_last, "#TGUI_INTERNAL$ColorPickerLast#"); + Container::add(Label::create("Current:"), "#TGUI_INTERNAL$ColorPickerLabelCurrent#"); + Container::add(m_current, "#TGUI_INTERNAL$ColorPickerCurrent#"); + + m_current->getRenderer()->setBackgroundColor(Color::Black); + m_last->getRenderer()->setBackgroundColor(Color::Black); + + Container::add(Button::create("Reset"), "#TGUI_INTERNAL$ColorPickerBack#"); + Container::add(Button::create("OK"), "#TGUI_INTERNAL$ColorPickerOK#"); + Container::add(Button::create("Cancel"), "#TGUI_INTERNAL$ColorPickerCancel#"); + + ChildWindow::setSize({535, 220}); + + rearrange(); + identifyButtonsAndConnect(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker::ColorPicker(const ColorPicker &other) : + ChildWindow{other}, + onColorChange{other.onColorChange}, + onOkPressed{other.onOkPressed}, + m_HSV{other.m_HSV} + { + identifyButtonsAndConnect(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker::ColorPicker(ColorPicker &&other) : + ChildWindow{std::move(other)}, + onColorChange{std::move(other.onColorChange)}, + onOkPressed{std::move(other.onOkPressed)}, + m_HSV{std::move(other.m_HSV)} + { + identifyButtonsAndConnect(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker &ColorPicker::operator=(const ColorPicker &other) + { + if (this != &other) + { + ColorPicker temp(other); + ChildWindow::operator=(temp); + + std::swap(onColorChange, temp.onColorChange); + std::swap(onOkPressed, temp.onOkPressed); + std::swap(m_HSV, temp.m_HSV); + + identifyButtonsAndConnect(); + } + + return *this; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker &ColorPicker::operator=(ColorPicker &&other) + { + if (this != &other) + { + onColorChange = std::move(other.onColorChange); + onOkPressed = std::move(other.onOkPressed); + m_canvas = std::move(other.m_canvas); + m_red = std::move(other.m_red); + m_green = std::move(other.m_green); + m_blue = std::move(other.m_blue); + m_alpha = std::move(other.m_alpha); + m_value = std::move(other.m_value); + m_last = std::move(other.m_last); + m_current = std::move(other.m_current); + m_HSV = std::move(other.m_HSV); + + ChildWindow::operator=(std::move(other)); + + identifyButtonsAndConnect(); + } + + return *this; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker::Ptr ColorPicker::create(sf::String title, Color color) + { + auto colorPicker = std::make_shared(); + colorPicker->setTitle(title); + colorPicker->setColor(color); + + return colorPicker; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPicker::Ptr ColorPicker::copy(ColorPicker::ConstPtr colorPicker) + { + if (colorPicker) + return std::static_pointer_cast(colorPicker->clone()); + else + return nullptr; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPickerRenderer *ColorPicker::getSharedRenderer() + { + return aurora::downcast(Widget::getSharedRenderer()); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + const ColorPickerRenderer *ColorPicker::getSharedRenderer() const + { + return aurora::downcast(Widget::getSharedRenderer()); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ColorPickerRenderer *ColorPicker::getRenderer() + { + return aurora::downcast(Widget::getRenderer()); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + const ColorPickerRenderer *ColorPicker::getRenderer() const + { + return aurora::downcast(Widget::getRenderer()); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ColorPicker::setColor(const Color &color) + { + auto colorLast = m_current->getRenderer()->getBackgroundColor(); + m_last->getRenderer()->setBackgroundColor(color); + m_current->getRenderer()->setBackgroundColor(color); + + onColorChange.setEnabled(false); + m_red->setValue(color.getRed()); + m_green->setValue(color.getGreen()); + m_blue->setValue(color.getBlue()); + m_alpha->setValue(color.getAlpha()); + onColorChange.setEnabled(true); + + if (colorLast != color) + onColorChange.emit(this, color); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Color ColorPicker::getColor() const + { + return m_current->getRenderer()->getBackgroundColor(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ColorPicker::leftMousePressed(Vector2f pos) + { + ChildWindow::leftMousePressed(pos); + + pos -= getPosition() + getChildWidgetsOffset(); + + if (m_canvas->mouseOnWidget(pos)) + { + m_colorRead = true; + + auto length = [](sf::Vector2f x) { + return std::sqrt(x.x * x.x + x.y * x.y); + }; + + sf::Vector2f position = {(pos.x - m_canvas->getPosition().x) / m_canvas->getSize().x, + (pos.y - m_canvas->getPosition().y) / m_canvas->getSize().y}; + + position -= {0.5f, 0.5f}; + position *= 2.0f; + + if (length(position) > 1.f) + { + m_colorRead = false; + return; + } + + float V = m_value->getValue() / m_value->getMaximum(); + V = logInvCurve(V); + + auto c = calculateColor(position, V, m_alpha->getValue()); + + m_current->getRenderer()->setBackgroundColor(c); + onColorChange.setEnabled(false); + m_red->setValue(c.r); + m_green->setValue(c.g); + m_blue->setValue(c.b); + m_alpha->setValue(c.a); + onColorChange.setEnabled(true); + + onColorChange.emit(this, c); + } + + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ColorPicker::leftMouseButtonNoLongerDown() + { + ChildWindow::leftMouseButtonNoLongerDown(); + + if (m_colorRead) + { + m_colorRead = false; + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ColorPicker::mouseMoved(Vector2f pos) + { + ChildWindow::mouseMoved(pos); + + pos -= getPosition() + getChildWidgetsOffset(); + + if (m_colorRead) + { + + sf::Vector2f position = {(pos.x - m_canvas->getPosition().x) / m_canvas->getSize().x, + (pos.y - m_canvas->getPosition().y) / m_canvas->getSize().y}; + + position -= {0.5f, 0.5f}; + position *= 2.0f; + + float V = m_value->getValue() / m_value->getMaximum(); + V = logInvCurve(V); + + auto c = calculateColor(position, V, m_alpha->getValue()); + + m_current->getRenderer()->setBackgroundColor(c); + onColorChange.setEnabled(false); + m_red->setValue(c.r); + m_green->setValue(c.g); + m_blue->setValue(c.b); + m_alpha->setValue(c.a); + onColorChange.setEnabled(true); + + onColorChange.emit(this, c); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ColorPicker::rearrange() + { + m_canvas->setPosition(10, 10); + m_value->setPosition("#TGUI_INTERNAL$ColorPickerCanvas#.right + 10", 10); + + get