Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
color-preview.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Author:
4 * Lauris Kaplinski <lauris@kaplinski.com>
5 * Ralf Stephan <ralf@ark.in-berlin.de>
6 * Michael Kowalski
7 *
8 * Copyright (C) 2001-2005 Authors
9 * Copyright (C) 2001 Ximian, Inc.
10 *
11 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
12 */
13
15
16#include <cairo.h>
17#include <cairomm/context.h>
18#include <cairomm/matrix.h>
19#include <cairomm/pattern.h>
20#include <gdkmm/rgba.h>
21#include <gtkmm/enums.h>
22#include <gtkmm/window.h>
23#include <sigc++/functors/mem_fun.h>
24#include <gtkmm/drawingarea.h>
25#include "display/cairo-utils.h"
26#include "colors/color.h"
27#include "colors/spaces/enum.h"
28#include <2geom/rect.h>
29#include "ui/util.h"
30
31namespace Inkscape::UI::Widget {
32
33ColorPreview::ColorPreview(std::uint32_t const rgba)
34 : _rgba{rgba}
35{
36 set_name("ColorPreview");
37 set_draw_func(sigc::mem_fun(*this, &ColorPreview::draw_func));
39}
40
41void ColorPreview::setRgba32(std::uint32_t const rgba) {
42 if (_rgba == rgba && !_pattern) return;
43
44 _rgba = rgba;
45 _pattern = {};
46 queue_draw();
47}
48
49void ColorPreview::setPattern(Cairo::RefPtr<Cairo::Pattern> pattern) {
50 if (_pattern == pattern) return;
51
52 _pattern = pattern;
53 _rgba = 0;
54 queue_draw();
55}
56
57Geom::Rect round_rect(const Cairo::RefPtr<Cairo::Context>& ctx, Geom::Rect rect, double radius) {
58 auto x = rect.left();
59 auto y = rect.top();
60 auto width = rect.width();
61 auto height = rect.height();
62 ctx->arc(x + width - radius, y + radius, radius, -M_PI_2, 0);
63 ctx->arc(x + width - radius, y + height - radius, radius, 0, M_PI_2);
64 ctx->arc(x + radius, y + height - radius, radius, M_PI_2, M_PI);
65 ctx->arc(x + radius, y + radius, radius, M_PI, 3 * M_PI_2);
66 ctx->close_path();
67 return rect.shrunkBy(1);
68}
69
70Cairo::RefPtr<Cairo::Pattern> create_checkerboard_pattern(double tx, double ty) {
71 auto pattern = Cairo::RefPtr<Cairo::Pattern>(new Cairo::Pattern(ink_cairo_pattern_create_checkerboard(), true));
72 pattern->set_matrix(Cairo::translation_matrix(tx, ty));
73 return pattern;
74}
75
76void ColorPreview::draw_func(Cairo::RefPtr<Cairo::Context> const &cr,
77 int const widget_width, int const widget_height)
78{
79 double width = widget_width;
80 double height = widget_height;
81 auto x = 0.0;
82 auto y = 0.0;
83 double radius = _style == Simple ? 0.0 : 2.0;
84 double degrees = M_PI / 180.0;
85 auto rect = Geom::Rect(x, y, x + width, y + height);
86
87 std::uint32_t outline_color = 0x00000000;
88 std::uint32_t border_color = 0xffffff00;
89
90 auto style = get_style_context();
91 Gdk::RGBA bgnd;
92 bool found = style->lookup_color("theme_bg_color", bgnd);
93 // use theme background color as a proxy for dark theme; this method is fast, which is important here
94 auto dark_theme = found && get_luminance(bgnd) <= 0.5;
95 auto state = get_state_flags();
96 auto disabled = (state & Gtk::StateFlags::INSENSITIVE) == Gtk::StateFlags::INSENSITIVE;
97 auto backdrop = (state & Gtk::StateFlags::BACKDROP) == Gtk::StateFlags::BACKDROP;
98 if (dark_theme) {
99 std::swap(outline_color, border_color);
100 }
101
102 if (_style == Outlined) {
103 // outside outline
104 rect = round_rect(cr, rect, radius--);
105 // opacity of outside outline is reduced
106 int alpha = disabled || backdrop ? 0x2f : 0x5f;
107 ink_cairo_set_source_color(cr->cobj(), Colors::Color(outline_color | alpha));
108 cr->fill();
109
110 // inside border
111 rect = round_rect(cr, rect, radius--);
112 ink_cairo_set_source_color(cr->cobj(), Colors::Color(border_color, false));
113 cr->fill();
114 }
115
116 if (_pattern) {
117 // draw pattern-based preview
118 round_rect(cr, rect, radius);
119
120 // checkers first
121 auto checkers = create_checkerboard_pattern(-x, -y);
122 cr->set_source(checkers);
123 cr->fill_preserve();
124
125 cr->set_source(_pattern);
126 cr->fill();
127 }
128 else {
129 // color itself
130 auto color = Colors::Color(_rgba);
131 auto opacity = color.stealOpacity();
132 // if preview is disabled, render colors with reduced saturation and intensity
133 if (disabled) {
134 color = make_disabled_color(color, dark_theme);
135 }
136
137 width = rect.width() / 2;
138 height = rect.height();
139 x = rect.min().x();
140 y = rect.min().y();
141
142 // solid on the right
143 cairo_new_sub_path(cr->cobj());
144 cairo_line_to(cr->cobj(), x + width, y);
145 cairo_line_to(cr->cobj(), x + width, y + height);
146 cairo_arc(cr->cobj(), x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
147 cairo_arc(cr->cobj(), x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
148 cairo_close_path(cr->cobj());
149 ink_cairo_set_source_color(cr->cobj(), color);
150 cr->fill();
151
152 // semi-transparent on the left
153 x += width;
154 cairo_new_sub_path(cr->cobj());
155 cairo_arc(cr->cobj(), x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
156 cairo_arc(cr->cobj(), x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
157 cairo_line_to(cr->cobj(), x, y + height);
158 cairo_line_to(cr->cobj(), x, y);
159 cairo_close_path(cr->cobj());
160 if (opacity < 1.0) {
161 auto checkers = create_checkerboard_pattern(-x, -y);
162 cr->set_source(checkers);
163 cr->fill_preserve();
164 }
165 color.setOpacity(opacity);
166 ink_cairo_set_source_color(cr->cobj(), color);
167 cr->fill();
168 }
169
170 if (_indicator != None) {
171 constexpr double side = 7.5;
172 constexpr double line = 1.5; // 1.5 pixles b/c it's a diagonal line, so 1px is too thin
173 const auto right = rect.right();
174 const auto bottom = rect.bottom();
175 if (_indicator == Swatch) {
176 // draw swatch color indicator - a black corner
177 cr->move_to(right, bottom - side);
178 cr->line_to(right, bottom - side + line);
179 cr->line_to(right - side + line, bottom);
180 cr->line_to(right - side, bottom);
181 cr->set_source_rgb(1, 1, 1); // white separator
182 cr->fill();
183 cr->move_to(right, bottom - side + line);
184 cr->line_to(right, bottom);
185 cr->line_to(right - side + line, bottom);
186 cr->set_source_rgb(0, 0, 0); // black
187 cr->fill();
188 }
189 else if (_indicator == SpotColor) {
190 // draw spot color indicator - a black dot
191 cr->move_to(right, bottom);
192 cr->line_to(right, bottom - side);
193 cr->line_to(right - side, bottom);
194 cr->set_source_rgb(1, 1, 1); // white background
195 cr->fill();
196 constexpr double r = 2;
197 cr->arc(right - r, bottom - r, r, 0, 2*M_PI);
198 cr->set_source_rgb(0, 0, 0);
199 cr->fill();
200 }
201 else {
202 assert(false);
203 }
204 }
205}
206
208 _style = style;
209 if (style == Simple) {
210 add_css_class("simple");
211 }
212 else {
213 remove_css_class("simple");
214 }
215 queue_draw();
216}
217
219 if (_indicator != indicator) {
220 _indicator = indicator;
221 queue_draw();
222 }
223}
224
225} // namespace Inkscape::UI::Widget
226
227/*
228 Local Variables:
229 mode:c++
230 c-file-style:"stroustrup"
231 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
232 indent-tabs-mode:nil
233 fill-column:99
234 End:
235*/
236// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
cairo_pattern_t * ink_cairo_pattern_create_checkerboard(guint32 rgba, bool use_alpha)
static constexpr uint16_t get_luminance(uint32_t r, uint32_t g, uint32_t b)
void ink_cairo_set_source_color(Cairo::RefPtr< Cairo::Context > &ctx, Colors::Color const &color, bool to_srgb)
Set the source color of the Cairo context.
Cairo integration helpers.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
Axis aligned, non-empty rectangle.
Definition rect.h:92
Rect shrunkBy(Coord amount) const
Return a new rectangle which results from shrinking this one by the same amount along both axes.
Definition rect.cpp:144
Cairo::RefPtr< Cairo::Pattern > _pattern
void draw_func(Cairo::RefPtr< Cairo::Context > const &cr, int width, int height)
void setIndicator(Indicator indicator)
void setRgba32(std::uint32_t rgba)
void setPattern(Cairo::RefPtr< Cairo::Pattern > pattern)
Color make_disabled_color(Color const &orig, bool dark)
Make a disabled color, a desaturated version of the given color.
Definition utils.cpp:169
Custom widgets.
Definition desktop.h:126
Geom::Rect round_rect(const Cairo::RefPtr< Cairo::Context > &ctx, Geom::Rect rect, double radius)
static constexpr int height
Cairo::RefPtr< Cairo::Pattern > create_checkerboard_pattern(double tx, double ty)
void cairo_line_to(cairo_t *cr, Geom::Point p1)
Axis-aligned rectangle.
double width