Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
ink-color-wheel.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * @file
4 * HSLuv color wheel widget, based on the web implementation at
5 * https://www.hsluv.org
6*//*
7 * Authors:
8 * Tavmjong Bah
9 * Massinissa Derriche <massinissa.derriche@gmail.com>
10 * Daniel Boles <dboles.src+inkscape@gmail.com>
11 *
12 * Copyright (C) 2018, 2021, 2023 Authors
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#ifndef INK_COLORWHEEL_H
18#define INK_COLORWHEEL_H
19
20#include <array>
21#include <memory>
22#include <utility>
23#include <vector>
24#include <2geom/point.h>
25#include <2geom/line.h>
26#include <sigc++/signal.h>
27#include <gtk/gtk.h> // GtkEventControllerKey
28#include <gtkmm/aspectframe.h>
29#include <gtkmm/gesture.h> // Gtk::EventSequenceState
30
31#include "color-wheel.h"
32#include "colors/color.h"
33#include "ui/widget/widget-vfuncs-class-init.h" // for focus
34
35namespace Gtk {
36class Builder;
37class DrawingArea;
38class EventControllerMotion;
39class GestureClick;
40} // namespace Gtk
41
42namespace Inkscape::Colors {
43class Color;
44} // namespace Inkscape::Colors
45
46namespace Inkscape::UI::Widget {
47
48class Bin;
49
50struct ColorPoint final
51{
52 ColorPoint();
53 ColorPoint(double x, double y, Colors::Color color);
54 ColorPoint(double x, double y, guint color);
55
56 std::pair<double const &, double const &> get_xy() const { return {x, y}; }
57
58 // eurgh!
59 double x;
60 double y;
62};
63
67// AspectFrame because we are circular & enforcing 1:1 eases drawing without overallocating buffers
68class ColorWheelBase : public Gtk::AspectFrame, public ColorWheel
69{
70public:
71 ColorWheelBase(Colors::Space::Type type, std::vector<double> initial_color);
72 ColorWheelBase(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder, Colors::Space::Type type, std::vector<double> initial_color);
73
78 virtual bool setColor(Colors::Color const &color,
79 bool overrideHue = true, bool emit = true) = 0;
80 virtual Colors::Color getColor() const { return _values; }
81
82 bool isAdjusting() const { return _adjusting; }
83
85 sigc::connection connect_color_changed(sigc::slot<void ()>);
86
87 // debug facility - performance testing only
88 void redraw(const Cairo::RefPtr<Cairo::Context>& ctx) override { on_drawing_area_draw(ctx, 1024, 1024); }
89protected:
91 bool _adjusting = false;
92
94 void color_changed();
96
97 [[nodiscard]] Gtk::Allocation get_drawing_area_allocation() const;
98 [[nodiscard]] bool drawing_area_has_focus() const;
99 void focus_drawing_area();
100
101private:
102 void set_color(const Colors::Color& color) override { setColor(color, false, false); }
103 // Colors::Color get_color() const override { return getColor(); }
104 sigc::connection connect_color_changed(sigc::slot<void(const Colors::Color&)> callback) override {
105 return _signal_color_changed.connect([this, callback](){ callback(getColor()); });
106 }
107 Gtk::Widget& get_widget() override { return *this; }
108
109 void construct();
110 sigc::signal<void ()> _signal_color_changed;
111
113 Gtk::DrawingArea *_drawing_area;
114 virtual void on_drawing_area_size(int width, int height, int baseline) {}
115 virtual void on_drawing_area_draw(Cairo::RefPtr<Cairo::Context> const &cr, int, int) = 0;
116
118 virtual Gtk::EventSequenceState on_click_pressed (Gtk::GestureClick const& controller,
119 int n_press, double x, double y) = 0;
120 virtual Gtk::EventSequenceState on_click_released(int n_press, double x, double y) = 0;
121
122 virtual void on_motion(Gtk::EventControllerMotion const &motion, double x, double y) = 0;
123 void _on_motion(Gtk::EventControllerMotion const &motion, double x, double y);
124
125 virtual bool on_key_pressed(unsigned keyval, unsigned keycode, Gdk::ModifierType state)
126 {
127 return false;
128 }
129
130 void on_key_released(unsigned keyval, unsigned keycode, Gdk::ModifierType state);
131};
132
137 : public WidgetVfuncsClassInit // As Gtkmm4 doesn't wrap focus_vfunc
138 , public ColorWheelBase
139{
140public:
142 ColorWheelHSL(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
143 bool setColor(Colors::Color const &color,
144 bool overrideHue = true, bool emit = true) override;
145
146private:
147 void on_drawing_area_size(int width, int height, int baseline) override;
148 void on_drawing_area_draw(Cairo::RefPtr<Cairo::Context> const &cr, int, int) override;
149 std::optional<bool> focus(Gtk::DirectionType direction) override;
150
151 bool _set_from_xy(double x, double y);
152 bool set_from_xy_delta(double dx, double dy);
153 bool _is_in_ring(double x, double y);
154 bool _is_in_triangle(double x, double y);
155 void _update_ring_color(double x, double y);
156
157 enum class DragMode {
158 NONE,
159 HUE,
161 };
162
163 static constexpr double _ring_width = 0.2;
165 bool _focus_on_ring = true;
166
167 Gtk::EventSequenceState on_click_pressed (Gtk::GestureClick const& controller,
168 int n_press, double x, double y) final;
169 Gtk::EventSequenceState on_click_released(int n_press, double x, double y) final;
170 void on_motion(Gtk::EventControllerMotion const &motion, double x, double y) final;
171 bool on_key_pressed(unsigned keyval, unsigned keycode, Gdk::ModifierType state) final;
172
173 // caches to speed up drawing
174 using TriangleCorners = std::array<ColorPoint, 3>;
175 using MinMax = std::array<double , 2>;
176 std::optional<Geom::IntPoint> _cache_size;
177 std::optional<MinMax > _radii;
178 std::optional<TriangleCorners > _triangle_corners;
179 std::optional<Geom::Point > _marker_point;
180 std::vector <guint32 > _buffer_ring, _buffer_triangle;
181 Cairo::RefPtr<Cairo::ImageSurface> _source_ring, _source_triangle;
182 [[nodiscard]] MinMax const &get_radii ();
183 [[nodiscard]] TriangleCorners const &get_triangle_corners();
184 [[nodiscard]] Geom::Point const &get_marker_point ();
185 void update_ring_source ();
187};
188
193 std::vector<Geom::Point> vertices;
196};
197
198
203{
204public:
206 ColorWheelHSLuv(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
207
209 bool setColor(Colors::Color const &color,
210 bool overrideHue = true, bool emit = true) override;
211
212 void updateGeometry();
213
214private:
215 void on_drawing_area_draw(Cairo::RefPtr<Cairo::Context> const &cr, int, int) final;
216
217 bool _set_from_xy(double const x, double const y);
218 void _setFromPoint(Geom::Point const &pt) { _set_from_xy(pt[Geom::X], pt[Geom::Y]); }
219 void _updatePolygon();
220 bool _vertex() const;
221
222 Gtk::EventSequenceState on_click_pressed (Gtk::GestureClick const& controller,
223 int n_press, double x, double y) final;
224 Gtk::EventSequenceState on_click_released(int n_press, double x, double y) final;
225 void on_motion(Gtk::EventControllerMotion const &motion, double x, double y) final;
226 bool on_key_pressed(unsigned keyval, unsigned keycode, Gdk::ModifierType state) final;
227
228 double _scale = 1.0;
229 std::unique_ptr<PickerGeometry> _picker_geometry;
230 std::vector<guint32> _buffer_polygon;
231 Cairo::RefPtr<::Cairo::ImageSurface> _surface_polygon;
234};
235
236} // namespace Inkscape::UI::Widget
237
238#endif // INK_COLORWHEEL_HSLUV_H
239
240/*
241 Local Variables:
242 mode:c++
243 c-file-style:"stroustrup"
244 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
245 indent-tabs-mode:nil
246 fill-column:99
247 End:
248*/
249// vim:filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8: textwidth=99:
Cartesian point / 2D vector and related operations.
uint32_t Color
Two-dimensional point with integer coordinates.
Definition int-point.h:57
Two-dimensional point that doubles as a vector.
Definition point.h:66
The Bin is a widget that can hold a single child.
Definition bin.h:31
virtual Gtk::EventSequenceState on_click_released(int n_press, double x, double y)=0
void color_changed()
Call when color has changed! Emits signal_color_changed & calls _drawing_area->queue_draw()
Gtk::Widget & get_widget() override
sigc::signal< void()> _signal_color_changed
virtual Gtk::EventSequenceState on_click_pressed(Gtk::GestureClick const &controller, int n_press, double x, double y)=0
All event controllers are connected to the DrawingArea.
sigc::connection connect_color_changed(sigc::slot< void()>)
Connect a slot to be called after the color has changed.
virtual void on_drawing_area_draw(Cairo::RefPtr< Cairo::Context > const &cr, int, int)=0
virtual void on_drawing_area_size(int width, int height, int baseline)
void redraw(const Cairo::RefPtr< Cairo::Context > &ctx) override
virtual Colors::Color getColor() const
virtual bool on_key_pressed(unsigned keyval, unsigned keycode, Gdk::ModifierType state)
virtual void on_motion(Gtk::EventControllerMotion const &motion, double x, double y)=0
void _on_motion(Gtk::EventControllerMotion const &motion, double x, double y)
Gtk::Allocation get_drawing_area_allocation() const
virtual bool setColor(Colors::Color const &color, bool overrideHue=true, bool emit=true)=0
Set the RGB of the wheel.
void on_key_released(unsigned keyval, unsigned keycode, Gdk::ModifierType state)
sigc::connection connect_color_changed(sigc::slot< void(const Colors::Color &)> callback) override
void set_color(const Colors::Color &color) override
void _update_ring_color(double x, double y)
std::array< ColorPoint, 3 > TriangleCorners
std::optional< TriangleCorners > _triangle_corners
bool setColor(Colors::Color const &color, bool overrideHue=true, bool emit=true) override
Set the RGB of the wheel.
bool set_from_xy_delta(double dx, double dy)
void on_drawing_area_size(int width, int height, int baseline) override
bool _set_from_xy(double x, double y)
Gtk::EventSequenceState on_click_released(int n_press, double x, double y) final
std::vector< guint32 > _buffer_triangle
std::optional< Geom::Point > _marker_point
static constexpr double _ring_width
Cairo::RefPtr< Cairo::ImageSurface > _source_ring
bool on_key_pressed(unsigned keyval, unsigned keycode, Gdk::ModifierType state) final
std::optional< Geom::IntPoint > _cache_size
TriangleCorners const & get_triangle_corners()
void on_motion(Gtk::EventControllerMotion const &motion, double x, double y) final
void on_drawing_area_draw(Cairo::RefPtr< Cairo::Context > const &cr, int, int) override
bool _is_in_triangle(double x, double y)
std::optional< bool > focus(Gtk::DirectionType direction) override
Called before gtk_widget_focus(): return true if moving in direction keeps focus w/in self,...
Gtk::EventSequenceState on_click_pressed(Gtk::GestureClick const &controller, int n_press, double x, double y) final
All event controllers are connected to the DrawingArea.
Cairo::RefPtr< Cairo::ImageSurface > _source_triangle
void on_motion(Gtk::EventControllerMotion const &motion, double x, double y) final
bool on_key_pressed(unsigned keyval, unsigned keycode, Gdk::ModifierType state) final
Gtk::EventSequenceState on_click_pressed(Gtk::GestureClick const &controller, int n_press, double x, double y) final
All event controllers are connected to the DrawingArea.
void on_drawing_area_draw(Cairo::RefPtr< Cairo::Context > const &cr, int, int) final
bool _set_from_xy(double const x, double const y)
Gtk::EventSequenceState on_click_released(int n_press, double x, double y) final
bool setColor(Colors::Color const &color, bool overrideHue=true, bool emit=true) override
See base doc & N.B. that overrideHue is unused by this class.
void updateGeometry()
Update the PickerGeometry structure owned by the instance.
Cairo::RefPtr<::Cairo::ImageSurface > _surface_polygon
std::unique_ptr< PickerGeometry > _picker_geometry
void _setFromPoint(Geom::Point const &pt)
bool _vertex() const
Detect whether we're at the top or bottom vertex of the color space.
A class you can inherit to access GTK4ʼs Widget.css_changed & .focus vfuncs, missing in gtkmm4.
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Infinite straight line.
Definition desktop.h:50
A set of useful color modifying functions which do not fit as generic methods on the color class itse...
Definition profile.cpp:24
Custom widgets.
Definition desktop.h:126
static constexpr int height
static Geom::Point direction(Geom::Point const &first, Geom::Point const &second)
Computes an unit vector of the direction from first to second control point.
Definition node.cpp:164
std::pair< double const &, double const & > get_xy() const
Used to represent the in RGB gamut colors polygon of the HSLuv color wheel.
double outer_circle_radius
Smallest circle with center at origin such that polygon fits inside.
std::vector< Geom::Point > vertices
Vertices, in counter-clockwise order.
double inner_circle_radius
Largest circle with center at origin such that it fits inside polygon.
double width
Glib::RefPtr< Gtk::Builder > builder
A class that can be inherited to access GTK4ʼs Widget.css_changed & .focus vfuncs,...