1 /* gstyle-color-plane.c
2 *
3 * based on : gtk-color-plane
4 * GTK - The GIMP Toolkit
5 * Copyright 2012 Red Hat, Inc.
6 *
7 * Copyright 2016 sebastien lafargue <slafargue@gnome.org>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * SPDX-License-Identifier: GPL-3.0-or-later
23 */
24
25 #define G_LOG_DOMAIN "gstyle-color-plane"
26
27 #include <math.h>
28 #include <cairo/cairo.h>
29 #include <glib/gi18n.h>
30
31 #include "gstyle-cielab.h"
32 #include "gstyle-color-convert.h"
33 #include "gstyle-css-provider.h"
34 #include "gstyle-utils.h"
35
36 #include "gstyle-color-plane.h"
37
38 typedef struct _ComputeData
39 {
40 gint width;
41 gint height;
42 gint stride;
43 guint32 *buffer;
44
45 gdouble x_factor;
46 gdouble y_factor;
47 gdouble lab_x_factor;
48 gdouble lab_y_factor;
49 gdouble lab_l_factor;
50 } ComputeData;
51
52 typedef enum _ColorSpaceId
53 {
54 COLOR_SPACE_RGB,
55 COLOR_SPACE_CIELAB,
56 COLOR_SPACE_HSV,
57 COLOR_SPACE_NONE
58 } ColorSpaceId;
59
60 typedef struct _Component
61 {
62 GtkAdjustment *adj;
63 gulong handler;
64 gdouble val;
65 gdouble factor;
66 ColorSpaceId color_space;
67 } Component;
68
69 typedef struct
70 {
71 cairo_surface_t *surface;
72
73 GstyleCssProvider *default_provider;
74
75 GtkGesture *drag_gesture;
76 GtkGesture *long_press_gesture;
77
78 GtkBorder cached_margin;
79 GtkBorder cached_border;
80 GdkRectangle cached_margin_box;
81 GdkRectangle cached_border_box;
82
83 GstyleColorPlaneMode mode;
84 GstyleXYZ xyz;
85 gdouble cursor_x;
86 gdouble cursor_y;
87
88 ComputeData data;
89 GstyleColorFilterFunc filter;
90 gpointer filter_user_data;
91
92 Component comp [N_GSTYLE_COLOR_COMPONENT];
93 GstyleColorComponent ref_comp;
94 GstyleColorUnit preferred_unit;
95 gdouble hue_backup;
96
97 guint hue_backup_set : 1;
98 } GstyleColorPlanePrivate;
99
100 G_DEFINE_TYPE_WITH_PRIVATE (GstyleColorPlane, gstyle_color_plane, GTK_TYPE_DRAWING_AREA)
101
102 enum {
103 PROP_0,
104 PROP_MODE,
105 PROP_RGBA,
106 PROP_XYZ,
107 N_PROPS
108 };
109
110 static GParamSpec *properties [N_PROPS];
111
112 /* We return %TRUE if there's no changes in border and margin, %FALSE otherwise.*/
113 static gboolean
update_css_boxes(GstyleColorPlane * self)114 update_css_boxes (GstyleColorPlane *self)
115 {
116 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
117 GtkWidget *widget = GTK_WIDGET (self);
118 GtkStyleContext *style_context;
119 GtkStateFlags state;
120 GdkRectangle margin_box;
121 GdkRectangle border_box;
122 GtkBorder margin;
123 GtkBorder border;
124 gboolean res;
125
126 g_assert (GSTYLE_IS_COLOR_PLANE (self));
127
128 style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
129 state = gtk_style_context_get_state (style_context);
130
131 gtk_style_context_get_margin (style_context, state, &margin);
132 gtk_style_context_get_border (style_context, state, &border);
133 gtk_widget_get_allocation (widget, &margin_box);
134 margin_box.x = margin_box.y = 0;
135
136 gstyle_utils_get_rect_resized_box (margin_box, &margin_box, &margin);
137 gstyle_utils_get_rect_resized_box (margin_box, &border_box, &border);
138
139 res = (gstyle_utils_cmp_border (margin, priv->cached_margin) ||
140 gstyle_utils_cmp_border (border, priv->cached_border));
141
142 priv->cached_margin_box = margin_box;
143 priv->cached_border_box = border_box;
144 priv->cached_margin = margin;
145 priv->cached_border = border;
146
147 return res;
148 }
149
150 static void
get_xyz_from_cursor(GstyleColorPlane * self,GstyleXYZ * xyz)151 get_xyz_from_cursor (GstyleColorPlane *self,
152 GstyleXYZ *xyz)
153 {
154 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
155 gdouble hsv_h, hsv_s, hsv_v;
156 GstyleCielab lab;
157 GdkRGBA rgba = {0};
158
159 g_assert (GSTYLE_IS_COLOR_PLANE (self));
160 g_assert (xyz != NULL);
161
162 switch (priv->mode)
163 {
164 case GSTYLE_COLOR_PLANE_MODE_HUE:
165 hsv_h = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].factor,
166 hsv_s = priv->cursor_x * priv->data.x_factor;
167 hsv_v = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
168 gstyle_color_convert_hsv_to_xyz (hsv_h, hsv_s, hsv_v, xyz);
169 break;
170
171 case GSTYLE_COLOR_PLANE_MODE_SATURATION:
172 hsv_s = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].factor,
173 hsv_h = priv->cursor_x * priv->data.x_factor;
174 hsv_v = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
175 gstyle_color_convert_hsv_to_xyz (hsv_h, hsv_s, hsv_v, xyz);
176 break;
177
178 case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
179 hsv_v = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].factor,
180 hsv_h = priv->cursor_x * priv->data.x_factor;
181 hsv_s = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
182 gstyle_color_convert_hsv_to_xyz (hsv_h, hsv_s, hsv_v, xyz);
183 break;
184
185 case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
186 lab.l = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].factor,
187 lab.a = priv->cursor_x * priv->data.lab_x_factor - 128.0;
188 lab.b = (priv->data.height - priv->cursor_y - 1) * priv->data.lab_y_factor - 128.0;
189 gstyle_color_convert_cielab_to_xyz (&lab, xyz);
190 break;
191
192 case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
193 lab.a = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].factor,
194 lab.b = priv->cursor_x * priv->data.lab_x_factor - 128.0;
195 lab.l = (priv->data.height - priv->cursor_y - 1) * priv->data.lab_l_factor;
196 gstyle_color_convert_cielab_to_xyz (&lab, xyz);
197 break;
198
199 case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
200 lab.b = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].factor,
201 lab.a = priv->cursor_x * priv->data.lab_x_factor - 128.0;
202 lab.l = (priv->data.height - priv->cursor_y - 1) * priv->data.lab_l_factor;
203 gstyle_color_convert_cielab_to_xyz (&lab, xyz);
204 break;
205
206 case GSTYLE_COLOR_PLANE_MODE_RED:
207 rgba.red = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].factor,
208 rgba.blue = priv->cursor_x * priv->data.x_factor;
209 rgba.green = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
210 gstyle_color_convert_rgb_to_xyz (&rgba, xyz);
211 break;
212
213 case GSTYLE_COLOR_PLANE_MODE_GREEN:
214 rgba.green = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor,
215 rgba.blue = priv->cursor_x * priv->data.x_factor;
216 rgba.red = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
217 gstyle_color_convert_rgb_to_xyz (&rgba, xyz);
218 break;
219
220 case GSTYLE_COLOR_PLANE_MODE_BLUE:
221 rgba.blue = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor,
222 rgba.red = priv->cursor_x * priv->data.x_factor;
223 rgba.green = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
224 gstyle_color_convert_rgb_to_xyz (&rgba, xyz);
225 break;
226
227 case GSTYLE_COLOR_PLANE_MODE_NONE:
228 default:
229 g_assert_not_reached ();
230 }
231 }
232
233 static void
set_cursor_from_xyz(GstyleColorPlane * self,GstyleXYZ * xyz)234 set_cursor_from_xyz (GstyleColorPlane *self,
235 GstyleXYZ *xyz)
236 {
237 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
238 gdouble hsv_h, hsv_s, hsv_v;
239 GstyleCielab lab;
240 GdkRGBA rgba = {0};
241 gdouble x = 0.0, y = 0.0;
242
243 g_assert (GSTYLE_IS_COLOR_PLANE (self));
244 g_assert (xyz != NULL);
245
246 switch (priv->mode)
247 {
248 case GSTYLE_COLOR_PLANE_MODE_HUE:
249 gstyle_color_convert_xyz_to_hsv (xyz, &hsv_h, &hsv_s, &hsv_v);
250 x = hsv_s / priv->data.x_factor;
251 y = (1.0 - hsv_v) / priv->data.y_factor;
252 break;
253
254 case GSTYLE_COLOR_PLANE_MODE_SATURATION:
255 gstyle_color_convert_xyz_to_hsv (xyz, &hsv_h, &hsv_s, &hsv_v);
256 x = hsv_h / priv->data.x_factor;
257 y = (1.0 - hsv_v) / priv->data.y_factor;
258 break;
259
260 case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
261 gstyle_color_convert_xyz_to_hsv (xyz, &hsv_h, &hsv_s, &hsv_v);
262 x = hsv_h / priv->data.x_factor;
263 y = (1.0 - hsv_s) / priv->data.y_factor;
264 break;
265
266 case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
267 gstyle_color_convert_xyz_to_cielab (xyz, &lab);
268 x = (lab.a + 128.0) / priv->data.lab_x_factor;
269 y = (128.0 - lab.b) / priv->data.lab_y_factor;
270 break;
271
272 case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
273 gstyle_color_convert_xyz_to_cielab (xyz, &lab);
274 x = (lab.b + 128.0) / priv->data.lab_x_factor;
275 y = (100.0 - lab.l) / priv->data.lab_l_factor;
276 break;
277
278 case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
279 gstyle_color_convert_xyz_to_cielab (xyz, &lab);
280 x = (lab.a + 128.0) / priv->data.lab_x_factor;
281 y = (100.0 - lab.l) / priv->data.lab_y_factor;
282 break;
283
284 case GSTYLE_COLOR_PLANE_MODE_RED:
285 gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
286 x = rgba.blue / priv->data.x_factor;
287 y = (1.0 - rgba.green) / priv->data.y_factor;
288 break;
289
290 case GSTYLE_COLOR_PLANE_MODE_GREEN:
291 gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
292 x = rgba.blue / priv->data.x_factor;
293 y = (1.0 - rgba.red) / priv->data.y_factor;
294 break;
295
296 case GSTYLE_COLOR_PLANE_MODE_BLUE:
297 gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
298 x = rgba.red / priv->data.x_factor;
299 y = (1.0 - rgba.green) / priv->data.y_factor;
300 break;
301
302 case GSTYLE_COLOR_PLANE_MODE_NONE:
303 default:
304 g_assert_not_reached ();
305 }
306
307 priv->cursor_x = CLAMP (x, 0.0, (gdouble)priv->data.width - 1.0);
308 priv->cursor_y = CLAMP (y, 0.0, (gdouble)priv->data.height - 1.0);
309 }
310
311 static void
configure_component(GstyleColorPlane * self,GstyleColorComponent comp,gdouble upper,gdouble factor)312 configure_component (GstyleColorPlane *self,
313 GstyleColorComponent comp,
314 gdouble upper,
315 gdouble factor)
316 {
317 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
318 gdouble new_value;
319
320 g_assert (GSTYLE_IS_COLOR_PLANE (self));
321 g_assert (GTK_IS_ADJUSTMENT (priv->comp [comp].adj));
322
323 new_value = priv->comp [comp].val / priv->comp [comp].factor * factor;
324 priv->comp [comp].factor = factor;
325
326 g_object_freeze_notify (G_OBJECT (priv->comp [comp].adj));
327 gtk_adjustment_set_upper (priv->comp [comp].adj, upper);
328 gtk_adjustment_set_value (priv->comp [comp].adj, new_value);
329 g_object_thaw_notify (G_OBJECT (priv->comp [comp].adj));
330 }
331
332 static void
setup_component(GstyleColorPlane * self,GstyleColorComponent comp,gdouble origin,gdouble lower,gdouble upper,gdouble step_increment,gdouble page_increment,gdouble factor,ColorSpaceId color_space)333 setup_component (GstyleColorPlane *self,
334 GstyleColorComponent comp,
335 gdouble origin,
336 gdouble lower,
337 gdouble upper,
338 gdouble step_increment,
339 gdouble page_increment,
340 gdouble factor,
341 ColorSpaceId color_space)
342 {
343 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
344
345 g_assert (GSTYLE_IS_COLOR_PLANE (self));
346
347 priv->comp [comp].adj = g_object_ref (gtk_adjustment_new (origin, lower, upper, step_increment, page_increment, 0));
348 priv->comp [comp].factor = factor;
349 priv->comp [comp].color_space = color_space;
350 }
351
352 /**
353 * gstyle_color_plane_set_preferred_unit:
354 * @self: a #GstyleColorPlane
355 * @preferred_unit: a #GstyleColorUnit enum value
356 *
357 * Set percent or value as the preferred unit for rgb adjustment range.
358 * [0, 100] for percent unit or [0, 255] for value.
359 *
360 */
361 void
gstyle_color_plane_set_preferred_unit(GstyleColorPlane * self,GstyleColorUnit preferred_unit)362 gstyle_color_plane_set_preferred_unit (GstyleColorPlane *self,
363 GstyleColorUnit preferred_unit)
364 {
365 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
366 gdouble max_range = 0.0;
367
368 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
369
370 if (priv->preferred_unit != preferred_unit)
371 {
372 priv->preferred_unit = preferred_unit;
373 if (preferred_unit == GSTYLE_COLOR_UNIT_PERCENT)
374 max_range = 100.0;
375 else if (preferred_unit == GSTYLE_COLOR_UNIT_VALUE)
376 max_range = 255.0;
377 else
378 g_assert_not_reached ();
379
380 configure_component (self, GSTYLE_COLOR_COMPONENT_RGB_RED, max_range, max_range);
381 configure_component (self, GSTYLE_COLOR_COMPONENT_RGB_GREEN, max_range, max_range);
382 configure_component (self, GSTYLE_COLOR_COMPONENT_RGB_BLUE, max_range, max_range);
383 }
384 }
385
386 /**
387 * gstyle_color_plane_get_filter_func: (skip):
388 * @self: a #GstyleColorPlane
389 *
390 * Get a pointer to the current filter function or %NULL
391 * if no filter is actually set.
392 *
393 * Returns: (nullable): A GstyleColorFilterFunc function pointer.
394 *
395 */
396 GstyleColorFilterFunc
gstyle_color_plane_get_filter_func(GstyleColorPlane * self)397 gstyle_color_plane_get_filter_func (GstyleColorPlane *self)
398 {
399 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
400
401 g_return_val_if_fail (GSTYLE_IS_COLOR_PLANE (self), NULL);
402
403 return priv->filter;
404 }
405
406 /**
407 * gstyle_color_plane_set_filter_func:
408 * @self: a #GstyleColorPlane
409 * @filter_cb: (scope notified) (nullable): A GstyleColorFilterFunc filter function or
410 * %NULL to unset the current filter. In this case, user_data is ignored
411 * @user_data: (closure) (nullable): user data to pass when calling the filter function
412 *
413 * Set a filter to be used to change the drawing of the color plane.
414 *
415 */
416 void
gstyle_color_plane_set_filter_func(GstyleColorPlane * self,GstyleColorFilterFunc filter_cb,gpointer user_data)417 gstyle_color_plane_set_filter_func (GstyleColorPlane *self,
418 GstyleColorFilterFunc filter_cb,
419 gpointer user_data)
420 {
421 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
422
423 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
424
425 priv->filter = filter_cb;
426 priv->filter_user_data = (filter_cb == NULL) ? NULL : user_data;
427
428 gtk_widget_queue_draw (GTK_WIDGET (self));
429 }
430
431 static void
compute_plane_hue_mode(GstyleColorPlane * self,ComputeData data)432 compute_plane_hue_mode (GstyleColorPlane *self,
433 ComputeData data)
434 {
435 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
436 gdouble hue, saturation, value;
437 GdkRGBA rgba = {0};
438 guint32 *p;
439
440 g_assert (GSTYLE_IS_COLOR_PLANE (self));
441
442 hue = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].factor;
443 for (gint y = 0; y < data.height; ++y)
444 {
445 value = CLAMP ((data.height - y) * data.y_factor, 0.0, 1.0);
446 p = data.buffer + y * (data.stride / 4);
447 for (gint x = 0; x < data.width; ++x)
448 {
449 saturation = x * data.x_factor;
450 gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
451 if (priv->filter != NULL)
452 priv->filter (&rgba, &rgba, priv->filter_user_data);
453
454 p[x] = pack_rgba24 (&rgba);
455 }
456 }
457 }
458
459 static void
compute_plane_saturation_mode(GstyleColorPlane * self,ComputeData data)460 compute_plane_saturation_mode (GstyleColorPlane *self,
461 ComputeData data)
462 {
463 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
464 gdouble hue, saturation, value;
465 GdkRGBA rgba = {0};
466 guint32 *p;
467
468 g_assert (GSTYLE_IS_COLOR_PLANE (self));
469
470 saturation = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].factor;
471 for (gint y = 0; y < data.height; ++y)
472 {
473 value = CLAMP ((data.height - y) * data.y_factor, 0.0, 1.0);
474 p = data.buffer + y * (data.stride / 4);
475 for (gint x = 0; x < data.width; ++x)
476 {
477 hue = x * data.x_factor;
478 gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
479 if (priv->filter != NULL)
480 priv->filter (&rgba, &rgba, priv->filter_user_data);
481
482 p[x] = pack_rgba24 (&rgba);
483 }
484 }
485 }
486
487 static void
compute_plane_brightness_mode(GstyleColorPlane * self,ComputeData data)488 compute_plane_brightness_mode (GstyleColorPlane *self,
489 ComputeData data)
490 {
491 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
492 gdouble hue, saturation, value;
493 GdkRGBA rgba = {0};
494 guint32 *p;
495
496 g_assert (GSTYLE_IS_COLOR_PLANE (self));
497
498 value = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].factor;
499 for (gint y = 0; y < data.height - 1; ++y)
500 {
501 saturation = CLAMP ((data.height - y) * data.y_factor, 0.0, 1.0);
502 p = data.buffer + y * (data.stride / 4);
503 for (gint x = 0; x < data.width; ++x)
504 {
505 hue = x * data.x_factor;
506 gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
507 if (priv->filter != NULL)
508 priv->filter (&rgba, &rgba, priv->filter_user_data);
509
510 p[x] = pack_rgba24 (&rgba);
511 }
512 }
513 }
514
515 static void
compute_plane_cielab_l_mode(GstyleColorPlane * self,ComputeData data)516 compute_plane_cielab_l_mode (GstyleColorPlane *self,
517 ComputeData data)
518 {
519 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
520 GstyleCielab lab;
521 GdkRGBA rgba = {0};
522 guint32 *p;
523
524 g_assert (GSTYLE_IS_COLOR_PLANE (self));
525
526 lab.l = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].factor;
527 for (gint y = 0; y < data.height; ++y)
528 {
529 lab.b = (data.height - y) * data.lab_y_factor - 128.0;
530 p = data.buffer + y * (data.stride / 4);
531 for (gint x = 0; x < data.width; ++x)
532 {
533 lab.a = x * data.lab_x_factor - 128.0;
534 gstyle_color_convert_cielab_to_rgb (&lab, &rgba);
535 if (priv->filter != NULL)
536 priv->filter (&rgba, &rgba, priv->filter_user_data);
537
538 p[x] = pack_rgba24 (&rgba);
539 }
540 }
541 }
542
543 static void
compute_plane_cielab_a_mode(GstyleColorPlane * self,ComputeData data)544 compute_plane_cielab_a_mode (GstyleColorPlane *self,
545 ComputeData data)
546 {
547 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
548 GstyleCielab lab;
549 GdkRGBA rgba = {0};
550 guint32 *p;
551
552 g_assert (GSTYLE_IS_COLOR_PLANE (self));
553
554 lab.a = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].factor;
555 for (gint y = 0; y < data.height; ++y)
556 {
557 lab.l = (data.height - y) * data.lab_l_factor;
558 p = data.buffer + y * (data.stride / 4);
559 for (gint x = 0; x < data.width; ++x)
560 {
561 lab.b = x * data.lab_x_factor - 128.0;
562 gstyle_color_convert_cielab_to_rgb (&lab, &rgba);
563 if (priv->filter != NULL)
564 priv->filter (&rgba, &rgba, priv->filter_user_data);
565
566 p[x] = pack_rgba24 (&rgba);
567 }
568 }
569 }
570
571 static void
compute_plane_cielab_b_mode(GstyleColorPlane * self,ComputeData data)572 compute_plane_cielab_b_mode (GstyleColorPlane *self,
573 ComputeData data)
574 {
575 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
576 GstyleCielab lab;
577 GdkRGBA rgba = {0};
578 guint32 *p;
579
580 g_assert (GSTYLE_IS_COLOR_PLANE (self));
581
582 lab.b = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].factor;
583 for (gint y = 0; y < data.height; ++y)
584 {
585 lab.l = (data.height - y) * data.lab_l_factor;
586 p = data.buffer + y * (data.stride / 4);
587 for (gint x = 0; x < data.width; ++x)
588 {
589 lab.a = x * data.lab_x_factor - 128.0;
590 gstyle_color_convert_cielab_to_rgb (&lab, &rgba);
591 if (priv->filter != NULL)
592 priv->filter (&rgba, &rgba, priv->filter_user_data);
593
594 p[x] = pack_rgba24 (&rgba);
595 }
596 }
597 }
598
599 static void
compute_plane_red_mode(GstyleColorPlane * self,ComputeData data)600 compute_plane_red_mode (GstyleColorPlane *self,
601 ComputeData data)
602 {
603 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
604 GdkRGBA rgba = {0};
605 guint32 *p;
606
607 g_assert (GSTYLE_IS_COLOR_PLANE (self));
608
609 rgba.red = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].factor;
610 for (gint y = 0; y < data.height; ++y)
611 {
612 rgba.green = (data.height - y) * data.y_factor;
613 p = data.buffer + y * (data.stride / 4);
614 for (gint x = 0; x < data.width; ++x)
615 {
616 rgba.blue = x * data.x_factor;
617 if (priv->filter != NULL)
618 priv->filter (&rgba, &rgba, priv->filter_user_data);
619
620 p[x] = pack_rgba24 (&rgba);
621 }
622 }
623 }
624
625 static void
compute_plane_green_mode(GstyleColorPlane * self,ComputeData data)626 compute_plane_green_mode (GstyleColorPlane *self,
627 ComputeData data)
628 {
629 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
630 GdkRGBA rgba = {0};
631 guint32 *p;
632
633 g_assert (GSTYLE_IS_COLOR_PLANE (self));
634
635 rgba.green = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor;
636 for (gint y = 0; y < data.height; ++y)
637 {
638 rgba.red = (data.height - y) * data.y_factor;
639 p = data.buffer + y * (data.stride / 4);
640 for (gint x = 0; x < data.width; ++x)
641 {
642 rgba.blue = x * data.x_factor;
643 if (priv->filter != NULL)
644 priv->filter (&rgba, &rgba, priv->filter_user_data);
645
646 p[x] = pack_rgba24 (&rgba);
647 }
648 }
649 }
650
651 static void
compute_plane_blue_mode(GstyleColorPlane * self,ComputeData data)652 compute_plane_blue_mode (GstyleColorPlane *self,
653 ComputeData data)
654 {
655 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
656 GdkRGBA rgba = {0};
657 guint32 *p;
658
659 g_assert (GSTYLE_IS_COLOR_PLANE (self));
660
661 rgba.blue = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor;
662 for (gint y = 0; y < data.height; ++y)
663 {
664 rgba.green = (data.height - y) * data.y_factor;
665 p = data.buffer + y * (data.stride / 4);
666 for (gint x = 0; x < data.width; ++x)
667 {
668 rgba.red = x * data.x_factor;
669 if (priv->filter != NULL)
670 priv->filter (&rgba, &rgba, priv->filter_user_data);
671
672 p[x] = pack_rgba24 (&rgba);
673 }
674 }
675 }
676
677 static gboolean
create_surface(GstyleColorPlane * self)678 create_surface (GstyleColorPlane *self)
679 {
680 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
681 GtkWidget *widget = (GtkWidget *)self;
682 cairo_surface_t *surface;
683 cairo_surface_t *tmp;
684 cairo_t *cr;
685 gint adjusted_height;
686 gint adjusted_width;
687
688 g_assert (GSTYLE_IS_COLOR_PLANE (self));
689
690 if (!gtk_widget_get_realized (widget))
691 return FALSE;
692
693 /* TODO: keep only one of priv->data.width or priv->cached_border_box.width */
694
695 priv->data.width = priv->cached_border_box.width;
696 priv->data.height = priv->cached_border_box.height;
697 adjusted_height = priv->data.height - 1;
698 adjusted_width = priv->data.width - 1;
699
700 priv->data.y_factor = 1.0 / adjusted_height;
701 priv->data.x_factor = 1.0 / adjusted_width;
702 priv->data.lab_y_factor = 255.0 / adjusted_height;
703 priv->data.lab_x_factor = 255.0 / adjusted_width;
704 priv->data.lab_l_factor = 100.0 / adjusted_height;
705
706 surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
707 CAIRO_CONTENT_COLOR,
708 priv->data.width, priv->data.height);
709
710 if (priv->surface)
711 cairo_surface_destroy (priv->surface);
712
713 priv->surface = surface;
714
715 if (priv->data.width <= 1 || priv->data.height <= 1)
716 return FALSE;
717
718 priv->data.stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, priv->data.width);
719 priv->data.buffer = g_malloc (priv->data.height * priv->data.stride);
720
721 switch (priv->mode)
722 {
723 case GSTYLE_COLOR_PLANE_MODE_HUE:
724 compute_plane_hue_mode (self, priv->data);
725 break;
726
727 case GSTYLE_COLOR_PLANE_MODE_SATURATION:
728 compute_plane_saturation_mode (self, priv->data);
729 break;
730
731 case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
732 compute_plane_brightness_mode (self, priv->data);
733 break;
734
735 case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
736 compute_plane_cielab_l_mode (self, priv->data);
737 break;
738
739 case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
740 compute_plane_cielab_a_mode (self, priv->data);
741 break;
742
743 case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
744 compute_plane_cielab_b_mode (self, priv->data);
745 break;
746
747 case GSTYLE_COLOR_PLANE_MODE_RED:
748 compute_plane_red_mode (self, priv->data);
749 break;
750
751 case GSTYLE_COLOR_PLANE_MODE_GREEN:
752 compute_plane_green_mode (self, priv->data);
753 break;
754
755 case GSTYLE_COLOR_PLANE_MODE_BLUE:
756 compute_plane_blue_mode (self, priv->data);
757 break;
758
759 case GSTYLE_COLOR_PLANE_MODE_NONE:
760 default:
761 g_assert_not_reached ();
762 }
763
764 tmp = cairo_image_surface_create_for_data ((guchar *)priv->data.buffer, CAIRO_FORMAT_RGB24,
765 priv->data.width, priv->data.height, priv->data.stride);
766 cr = cairo_create (surface);
767 cairo_set_source_surface (cr, tmp, 0, 0);
768 cairo_paint (cr);
769
770 cairo_destroy (cr);
771 cairo_surface_destroy (tmp);
772 g_free (priv->data.buffer);
773
774 return TRUE;
775 }
776
777 static gboolean
gstyle_color_plane_draw(GtkWidget * widget,cairo_t * cr)778 gstyle_color_plane_draw (GtkWidget *widget,
779 cairo_t *cr)
780 {
781 GstyleColorPlane *self = (GstyleColorPlane *)widget;
782 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
783 gint left_spacing;
784 gint top_spacing;
785 gint x, y;
786
787 g_assert (GSTYLE_IS_COLOR_PLANE (self));
788 g_assert (cr != NULL);
789
790 if (!gtk_widget_get_visible (widget))
791 return GDK_EVENT_PROPAGATE;
792
793 if (update_css_boxes (self) || priv->surface == NULL)
794 create_surface (self);
795
796 left_spacing = priv->cached_margin.left + priv->cached_border.left;
797 top_spacing = priv->cached_margin.top + priv->cached_border.top;
798 x = round (priv->cursor_x) + left_spacing;
799 y = round (priv->cursor_y) + top_spacing;
800
801 cairo_set_source_surface (cr, priv->surface, priv->cached_border_box.x, priv->cached_border_box.y);
802 cairo_paint (cr);
803
804 gtk_render_frame (gtk_widget_get_style_context (widget), cr,
805 priv->cached_margin_box.x, priv->cached_margin_box.y,
806 priv->cached_margin_box.width, priv->cached_margin_box.height);
807
808 cairo_move_to (cr, left_spacing, y + 0.5);
809 cairo_line_to (cr, left_spacing + priv->cached_border_box.width, y + 0.5);
810
811 cairo_move_to (cr, x + 0.5, top_spacing);
812 cairo_line_to (cr, x + 0.5, top_spacing + priv->cached_border_box.height);
813
814 if (gtk_widget_has_visible_focus (widget))
815 {
816 cairo_set_line_width (cr, 3.0);
817 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
818 cairo_stroke_preserve (cr);
819
820 cairo_set_line_width (cr, 1.0);
821 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
822 cairo_stroke (cr);
823 }
824 else
825 {
826 cairo_set_line_width (cr, 1.0);
827 cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8);
828 cairo_stroke (cr);
829 }
830
831 return FALSE;
832 }
833
834 static inline gboolean
compare_xyz(GstyleXYZ xyz1,GstyleXYZ xyz2)835 compare_xyz (GstyleXYZ xyz1,
836 GstyleXYZ xyz2)
837 {
838 return (xyz1.x == xyz2.x &&
839 xyz1.y == xyz2.y &&
840 xyz1.z == xyz2.z &&
841 xyz1.alpha == xyz2.alpha);
842 }
843
844 /* Adjustments are updated from the stored xyz */
845 static void
update_adjustments(GstyleColorPlane * self,GstyleXYZ * xyz,GstyleColorComponent changed_comp)846 update_adjustments (GstyleColorPlane *self,
847 GstyleXYZ *xyz,
848 GstyleColorComponent changed_comp)
849 {
850 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
851 gdouble hue, saturation, value;
852 gdouble current_hue;
853 GstyleCielab lab;
854 ColorSpaceId color_space;
855 GdkRGBA rgba = {0};
856
857 g_assert (GSTYLE_IS_COLOR_PLANE (self));
858 g_assert (xyz != NULL);
859
860 if (!compare_xyz (priv->xyz, *xyz))
861 {
862 color_space = (changed_comp == GSTYLE_COLOR_COMPONENT_NONE) ? COLOR_SPACE_NONE : priv->comp [changed_comp].color_space;
863 if (color_space != COLOR_SPACE_RGB)
864 {
865 gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
866 priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val = rgba.red * priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].factor;
867 priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val = rgba.green * priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor;
868 priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val = rgba.blue * priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor;
869 }
870
871 if (color_space != COLOR_SPACE_CIELAB)
872 {
873 gstyle_color_convert_xyz_to_cielab (xyz, &lab);
874 priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val = lab.l * priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].factor;
875 priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val = lab.a * priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].factor;
876 priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val = lab.b * priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].factor;
877 }
878
879 if (color_space != COLOR_SPACE_HSV)
880 {
881 current_hue = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val;
882 gstyle_color_convert_xyz_to_hsv (xyz, &hue, &saturation, &value);
883 if (saturation > 1e-6)
884 {
885 if (priv->hue_backup_set)
886 {
887 priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val = priv->hue_backup;
888 priv->hue_backup_set = FALSE;
889 }
890 else
891 priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val = hue * priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].factor;
892 }
893 else if (!priv->hue_backup_set)
894 {
895 priv->hue_backup = current_hue;
896 priv->hue_backup_set = TRUE;
897 priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val = hue;
898 }
899
900 priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val = saturation * priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].factor;
901 priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val = value * priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].factor;
902 }
903
904 for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
905 if (priv->comp [i].color_space != color_space)
906 {
907 g_signal_handler_block (priv->comp [i].adj, priv->comp [i].handler);
908 gtk_adjustment_set_value (priv->comp [i].adj, priv->comp [i].val);
909 g_signal_handler_unblock (priv->comp [i].adj, priv->comp [i].handler);
910 }
911 }
912 }
913
914 static void
update_surface_and_cursor(GstyleColorPlane * self,gboolean update_surface)915 update_surface_and_cursor (GstyleColorPlane *self,
916 gboolean update_surface)
917 {
918 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
919
920 g_assert (GSTYLE_IS_COLOR_PLANE (self));
921
922 if (update_surface)
923 create_surface (self);
924
925 set_cursor_from_xyz (self, &priv->xyz);
926
927 if (gtk_widget_get_realized (GTK_WIDGET (self)))
928 gtk_widget_queue_draw (GTK_WIDGET (self));
929 }
930
931 static void
update_cursor(GstyleColorPlane * self,gdouble x,gdouble y)932 update_cursor (GstyleColorPlane *self,
933 gdouble x,
934 gdouble y)
935 {
936 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
937 gint left_spacing;
938 gint top_spacing;
939 GstyleXYZ xyz = {0};
940
941 g_assert (GSTYLE_IS_COLOR_PLANE (self));
942
943 left_spacing = priv->cached_margin.left + priv->cached_border.left;
944 top_spacing = priv->cached_margin.top + priv->cached_border.top;
945 x = CLAMP (x - left_spacing, 0.0, priv->data.width - 1.0);
946 y = CLAMP (y - top_spacing, 0.0, priv->data.height - 1.0);
947
948 if (priv->cursor_x != x || priv->cursor_y != y)
949 {
950 priv->cursor_x = x;
951 priv->cursor_y = y;
952
953 get_xyz_from_cursor (self, &xyz);
954 update_adjustments (self, &xyz, GSTYLE_COLOR_COMPONENT_NONE);
955 priv->xyz = xyz;
956
957 gtk_widget_queue_draw (GTK_WIDGET (self));
958 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RGBA]);
959 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_XYZ]);
960 }
961 }
962
963 static void
move_cursor(GstyleColorPlane * self,gdouble step_x,gdouble step_y)964 move_cursor (GstyleColorPlane *self,
965 gdouble step_x,
966 gdouble step_y)
967 {
968 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
969
970 g_assert (GSTYLE_IS_COLOR_PLANE (self));
971
972 if (!gtk_widget_get_realized (GTK_WIDGET (self)))
973 return;
974
975 update_cursor (self, priv->cursor_x + step_x, priv->cursor_y - step_y);
976 /* TODO: ring when reaching the border */
977 }
978
979 static GstyleColorComponent
get_adj_id(GstyleColorPlane * self,GtkAdjustment * adj)980 get_adj_id (GstyleColorPlane *self,
981 GtkAdjustment *adj)
982 {
983 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
984
985 g_assert (GSTYLE_IS_COLOR_PLANE (self));
986 g_assert (GTK_IS_ADJUSTMENT (adj));
987
988 for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
989 if (adj == priv->comp [i].adj)
990 return i;
991
992 g_return_val_if_reached (0);
993 }
994
995 static void
adjustments_changed(GstyleColorPlane * self,GtkAdjustment * adj)996 adjustments_changed (GstyleColorPlane *self,
997 GtkAdjustment *adj)
998 {
999 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1000 gdouble hue, saturation, value;
1001 GdkRGBA rgba;
1002 GstyleXYZ xyz;
1003 GstyleCielab lab;
1004 GstyleColorComponent changed_comp;
1005 gdouble old_ref_val;
1006
1007 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1008 g_assert (GTK_IS_ADJUSTMENT (adj));
1009
1010 old_ref_val = priv->comp [priv->ref_comp].val;
1011 changed_comp = get_adj_id (self, adj);
1012 priv->comp [changed_comp].val = gtk_adjustment_get_value (priv->comp [changed_comp].adj);
1013
1014 if (changed_comp == GSTYLE_COLOR_COMPONENT_HSV_H ||
1015 changed_comp == GSTYLE_COLOR_COMPONENT_HSV_S ||
1016 changed_comp == GSTYLE_COLOR_COMPONENT_HSV_V)
1017 {
1018 hue = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].factor;
1019 saturation = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].factor;
1020 value = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].factor;
1021
1022 gstyle_color_convert_hsv_to_xyz (hue, saturation, value, &xyz);
1023 }
1024 else if (changed_comp == GSTYLE_COLOR_COMPONENT_LAB_L ||
1025 changed_comp == GSTYLE_COLOR_COMPONENT_LAB_A ||
1026 changed_comp == GSTYLE_COLOR_COMPONENT_LAB_B)
1027 {
1028 lab.l = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].factor;
1029 lab.a = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].factor;
1030 lab.b = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].factor;
1031
1032 gstyle_color_convert_cielab_to_xyz (&lab, &xyz);
1033 }
1034 else
1035 {
1036 rgba.red = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].factor;
1037 rgba.green = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor;
1038 rgba.blue = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val / priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor;
1039 gstyle_color_convert_rgb_to_xyz (&rgba, &xyz);
1040 }
1041
1042 xyz.alpha = 1;
1043 update_adjustments (self, &xyz, changed_comp);
1044 priv->xyz = xyz;
1045 update_surface_and_cursor (self, old_ref_val != priv->comp [priv->ref_comp].val);
1046
1047 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RGBA]);
1048 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_XYZ]);
1049 }
1050
1051 /**
1052 * gstyle_color_plane_new:
1053 *
1054 * Returns: a new #GstyleColorPlane
1055 */
1056 GstyleColorPlane *
gstyle_color_plane_new(void)1057 gstyle_color_plane_new (void)
1058 {
1059 return g_object_new (GSTYLE_TYPE_COLOR_PLANE, NULL);
1060 }
1061
1062 static void
gstyle_color_plane_size_allocate(GtkWidget * widget,GtkAllocation * allocation)1063 gstyle_color_plane_size_allocate (GtkWidget *widget,
1064 GtkAllocation *allocation)
1065 {
1066 GstyleColorPlane *self = GSTYLE_COLOR_PLANE (widget);
1067 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1068
1069 GTK_WIDGET_CLASS (gstyle_color_plane_parent_class)->size_allocate (widget, allocation);
1070
1071 update_css_boxes (self);
1072
1073 if (create_surface (GSTYLE_COLOR_PLANE (widget)))
1074 set_cursor_from_xyz (self, &priv->xyz);
1075 }
1076
1077 static gboolean
gstyle_color_plane_key_press(GtkWidget * widget,GdkEventKey * event)1078 gstyle_color_plane_key_press (GtkWidget *widget,
1079 GdkEventKey *event)
1080 {
1081 GstyleColorPlane *self = GSTYLE_COLOR_PLANE (widget);
1082 gdouble step;
1083
1084 g_assert (event != NULL);
1085
1086 if ((event->state & GDK_MOD1_MASK) != 0)
1087 step = 0.1;
1088 else
1089 step = 0.01;
1090
1091 if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
1092 move_cursor (self, 0, step);
1093 else if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
1094 move_cursor (self, 0, -step);
1095 else if (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left)
1096 move_cursor (self, -step, 0);
1097 else if (event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right)
1098 move_cursor (self, step, 0);
1099 else
1100 return GTK_WIDGET_CLASS (gstyle_color_plane_parent_class)->key_press_event (widget, event);
1101
1102 return TRUE;
1103 }
1104
1105 /**
1106 * gstyle_color_plane_get_xyz:
1107 * @self: a #GstyleColorPlane
1108 * @xyz: (out): a #GstyleXYZ adress
1109 *
1110 * Fill @xyz with value at cursor position.
1111 * The alpha component is always equal to 1.
1112 *
1113 */
1114 void
gstyle_color_plane_get_xyz(GstyleColorPlane * self,GstyleXYZ * xyz)1115 gstyle_color_plane_get_xyz (GstyleColorPlane *self,
1116 GstyleXYZ *xyz)
1117 {
1118 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1119
1120 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
1121 g_return_if_fail (xyz != NULL);
1122
1123 *xyz = priv->xyz;
1124 }
1125
1126 /**
1127 * gstyle_color_plane_get_rgba:
1128 * @self: a #GstyleColorPlane
1129 * @rgba: (out): a #GdkRGBA adress
1130 *
1131 * Fill @rgba with value at cursor position.
1132 * The alpha component is always equal to 1.
1133 *
1134 */
1135 void
gstyle_color_plane_get_rgba(GstyleColorPlane * self,GdkRGBA * rgba)1136 gstyle_color_plane_get_rgba (GstyleColorPlane *self,
1137 GdkRGBA *rgba)
1138 {
1139 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1140
1141 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
1142 g_return_if_fail (rgba != NULL);
1143
1144 gstyle_color_convert_xyz_to_rgb (&priv->xyz, rgba);
1145 }
1146
1147 /**
1148 * gstyle_color_plane_get_filtered_rgba:
1149 * @self: a #GstyleColorPlane
1150 * @rgba: (out): a #GdkRGBA adress
1151 *
1152 * Fill @rgba with filtered value at cursor position.
1153 *
1154 */
1155 void
gstyle_color_plane_get_filtered_rgba(GstyleColorPlane * self,GdkRGBA * rgba)1156 gstyle_color_plane_get_filtered_rgba (GstyleColorPlane *self,
1157 GdkRGBA *rgba)
1158 {
1159 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1160
1161 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
1162 g_return_if_fail (rgba != NULL);
1163
1164 gstyle_color_convert_xyz_to_rgb (&priv->xyz, rgba);
1165 priv->filter (rgba, rgba, priv->filter_user_data);
1166 }
1167
1168 /**
1169 * gstyle_color_plane_get_component_adjustment:
1170 * @self: a #GstyleColorPlane
1171 * @comp: a #GstyleColorComponent enum value
1172 *
1173 * Return the color component adjustment designated by
1174 * the #GstyleColorComponent value.
1175 *
1176 * Returns: (transfer none): #GtkAdjustment.
1177 *
1178 */
1179 GtkAdjustment *
gstyle_color_plane_get_component_adjustment(GstyleColorPlane * self,GstyleColorComponent comp)1180 gstyle_color_plane_get_component_adjustment (GstyleColorPlane *self,
1181 GstyleColorComponent comp)
1182 {
1183 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1184
1185 g_return_val_if_fail (GSTYLE_IS_COLOR_PLANE (self), NULL);
1186 g_return_val_if_fail (comp != GSTYLE_COLOR_COMPONENT_NONE, NULL);
1187
1188 return priv->comp [comp].adj;
1189 }
1190
1191 /**
1192 * gstyle_color_plane_set_rgba:
1193 * @self: a #GstyleColorPlane
1194 * @rgba: a #GdkRGBA
1195 *
1196 * Set cursor position from @rgba value.
1197 *
1198 */
1199 void
gstyle_color_plane_set_rgba(GstyleColorPlane * self,const GdkRGBA * rgba)1200 gstyle_color_plane_set_rgba (GstyleColorPlane *self,
1201 const GdkRGBA *rgba)
1202 {
1203 GstyleColorPlanePrivate *priv;
1204 GstyleXYZ xyz = {0};
1205
1206 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
1207 g_return_if_fail (rgba != NULL);
1208
1209 priv = gstyle_color_plane_get_instance_private (self);
1210
1211 gstyle_color_convert_rgb_to_xyz ((GdkRGBA *)rgba, &xyz);
1212 if (compare_xyz (xyz, priv->xyz))
1213 return;
1214
1215 update_adjustments (self, &xyz, GSTYLE_COLOR_COMPONENT_NONE);
1216 priv->xyz = xyz;
1217 update_surface_and_cursor (self, TRUE);
1218
1219 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
1220 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
1221 }
1222
1223 /**
1224 * gstyle_color_plane_set_xyz:
1225 * @self: a #GstyleColorPlane.
1226 * @xyz: a #GstyleXYZ struct.
1227 *
1228 * Set cursor position from @rgba value.
1229 *
1230 */
1231 void
gstyle_color_plane_set_xyz(GstyleColorPlane * self,const GstyleXYZ * xyz)1232 gstyle_color_plane_set_xyz (GstyleColorPlane *self,
1233 const GstyleXYZ *xyz)
1234 {
1235 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1236
1237 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
1238 g_return_if_fail (xyz != NULL);
1239
1240 if (compare_xyz (*xyz, priv->xyz))
1241 return;
1242
1243 update_adjustments (self, (GstyleXYZ *)xyz, GSTYLE_COLOR_COMPONENT_NONE);
1244 priv->xyz = *xyz;
1245 update_surface_and_cursor (self, TRUE);
1246
1247 /* TODO: add xyz props */
1248 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
1249 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
1250 }
1251
1252 /**
1253 * gstyle_color_plane_set_mode:
1254 * @self: a #GstyleColorPlane.
1255 * @mode: a #GstylewColorPlaneMode.
1256 *
1257 * Set the displayed mode to use.
1258 *
1259 */
1260 void
gstyle_color_plane_set_mode(GstyleColorPlane * self,GstyleColorPlaneMode mode)1261 gstyle_color_plane_set_mode (GstyleColorPlane *self,
1262 GstyleColorPlaneMode mode)
1263 {
1264 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1265 gdouble hsv_h, hsv_s, hsv_v;
1266 gdouble ref_val = 0.0;
1267 GstyleCielab lab;
1268 GdkRGBA rgba = {0};
1269
1270 g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
1271
1272 if (priv->mode != mode)
1273 {
1274 priv->mode = mode;
1275
1276 switch (priv->mode)
1277 {
1278 case GSTYLE_COLOR_PLANE_MODE_HUE:
1279 gstyle_color_convert_xyz_to_hsv (&priv->xyz, &hsv_h, &hsv_s, &hsv_v);
1280 priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_H;
1281 ref_val = hsv_h;
1282 break;
1283
1284 case GSTYLE_COLOR_PLANE_MODE_SATURATION:
1285 gstyle_color_convert_xyz_to_hsv (&priv->xyz, &hsv_h, &hsv_s, &hsv_v);
1286 priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_S;
1287 ref_val = hsv_s;
1288 break;
1289
1290 case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
1291 gstyle_color_convert_xyz_to_hsv (&priv->xyz, &hsv_h, &hsv_s, &hsv_v);
1292 priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_V;
1293 ref_val = hsv_v;
1294 break;
1295
1296 case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
1297 gstyle_color_convert_xyz_to_cielab (&priv->xyz, &lab);
1298 priv->ref_comp = GSTYLE_COLOR_COMPONENT_LAB_L;
1299 ref_val = lab.l;
1300 break;
1301
1302 case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
1303 gstyle_color_convert_xyz_to_cielab (&priv->xyz, &lab);
1304 priv->ref_comp = GSTYLE_COLOR_COMPONENT_LAB_A;
1305 ref_val = lab.a;
1306 break;
1307
1308 case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
1309 gstyle_color_convert_xyz_to_cielab (&priv->xyz, &lab);
1310 priv->ref_comp = GSTYLE_COLOR_COMPONENT_LAB_B;
1311 ref_val = lab.b;
1312 break;
1313
1314 case GSTYLE_COLOR_PLANE_MODE_RED:
1315 gstyle_color_convert_xyz_to_rgb (&priv->xyz, &rgba);
1316 priv->ref_comp = GSTYLE_COLOR_COMPONENT_RGB_RED;
1317 ref_val = rgba.red;
1318 break;
1319
1320 case GSTYLE_COLOR_PLANE_MODE_GREEN:
1321 gstyle_color_convert_xyz_to_rgb (&priv->xyz, &rgba);
1322 priv->ref_comp = GSTYLE_COLOR_COMPONENT_RGB_GREEN;
1323 ref_val = rgba.green;
1324 break;
1325
1326 case GSTYLE_COLOR_PLANE_MODE_BLUE:
1327 gstyle_color_convert_xyz_to_rgb (&priv->xyz, &rgba);
1328 priv->ref_comp = GSTYLE_COLOR_COMPONENT_RGB_BLUE;
1329 ref_val = rgba.blue;
1330 break;
1331
1332 case GSTYLE_COLOR_PLANE_MODE_NONE:
1333 default:
1334 g_assert_not_reached ();
1335 }
1336
1337 g_signal_handler_block (priv->comp [priv->ref_comp].adj, priv->comp [priv->ref_comp].handler);
1338
1339 priv->comp [priv->ref_comp].val = ref_val * priv->comp [priv->ref_comp].factor;
1340 gtk_adjustment_set_value (priv->comp [priv->ref_comp].adj, priv->comp [priv->ref_comp].val);
1341
1342 g_signal_handler_unblock (priv->comp [priv->ref_comp].adj, priv->comp [priv->ref_comp].handler);
1343
1344 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MODE]);
1345 update_surface_and_cursor (self, TRUE);
1346 }
1347 }
1348
1349 static void
gstyle_color_plane_destroy(GtkWidget * widget)1350 gstyle_color_plane_destroy (GtkWidget *widget)
1351 {
1352 GstyleColorPlane *self = (GstyleColorPlane *)widget;
1353 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1354
1355 gstyle_clear_pointer (&priv->surface, cairo_surface_destroy);
1356
1357 GTK_WIDGET_CLASS (gstyle_color_plane_parent_class)->destroy (widget);
1358 }
1359
1360 static void
gstyle_color_plane_finalize(GObject * object)1361 gstyle_color_plane_finalize (GObject *object)
1362 {
1363 GstyleColorPlane *self = (GstyleColorPlane *)object;
1364 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1365
1366 g_clear_object (&priv->drag_gesture);
1367 g_clear_object (&priv->long_press_gesture);
1368 g_clear_object (&priv->default_provider);
1369
1370 for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
1371 g_clear_object (&priv->comp [i].adj);
1372
1373 G_OBJECT_CLASS (gstyle_color_plane_parent_class)->finalize (object);
1374 }
1375
1376 static void
gstyle_color_plane_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1377 gstyle_color_plane_get_property (GObject *object,
1378 guint prop_id,
1379 GValue *value,
1380 GParamSpec *pspec)
1381 {
1382 GstyleColorPlane *self = GSTYLE_COLOR_PLANE (object);
1383 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1384 GdkRGBA rgba = {0};
1385 GstyleXYZ xyz;
1386
1387 switch (prop_id)
1388 {
1389 case PROP_MODE:
1390 g_value_set_enum (value, priv->mode);
1391 break;
1392
1393 case PROP_RGBA:
1394 gstyle_color_plane_get_rgba (self, &rgba);
1395 g_value_set_boxed (value, &rgba);
1396 break;
1397
1398 case PROP_XYZ:
1399 gstyle_color_plane_get_xyz (self, &xyz);
1400 g_value_set_boxed (value, &xyz);
1401 break;
1402
1403 default:
1404 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1405 }
1406 }
1407
1408 static void
gstyle_color_plane_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1409 gstyle_color_plane_set_property (GObject *object,
1410 guint prop_id,
1411 const GValue *value,
1412 GParamSpec *pspec)
1413 {
1414 GstyleColorPlane *self = GSTYLE_COLOR_PLANE (object);
1415 GdkRGBA *rgba_p;
1416 GstyleXYZ *xyz_p;
1417 GstyleXYZ xyz = {0};
1418 GdkRGBA rgba = {0.5, 0.3, 0.3, 0.0};
1419
1420 switch (prop_id)
1421 {
1422 case PROP_MODE:
1423 gstyle_color_plane_set_mode (self, g_value_get_enum (value));
1424 break;
1425
1426 case PROP_RGBA:
1427 rgba_p = (GdkRGBA *)g_value_get_boxed (value);
1428 if (rgba_p == NULL)
1429 rgba_p = &rgba;
1430
1431 gstyle_color_plane_set_rgba (self, rgba_p);
1432 break;
1433
1434 case PROP_XYZ:
1435 xyz_p = (GstyleXYZ *)g_value_get_boxed (value);
1436 if (xyz_p == NULL)
1437 {
1438 gstyle_color_convert_rgb_to_xyz (&rgba, &xyz);
1439 gstyle_color_plane_set_xyz (self, &xyz);
1440 }
1441 else
1442 gstyle_color_plane_set_xyz (self, xyz_p);
1443 break;
1444
1445 default:
1446 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1447 }
1448 }
1449
1450 static void
gstyle_color_plane_class_init(GstyleColorPlaneClass * klass)1451 gstyle_color_plane_class_init (GstyleColorPlaneClass *klass)
1452 {
1453 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1454 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1455
1456 object_class->finalize = gstyle_color_plane_finalize;
1457 object_class->get_property = gstyle_color_plane_get_property;
1458 object_class->set_property = gstyle_color_plane_set_property;
1459
1460 widget_class->draw = gstyle_color_plane_draw;
1461 widget_class->size_allocate = gstyle_color_plane_size_allocate;
1462 widget_class->key_press_event = gstyle_color_plane_key_press;
1463 widget_class->destroy = gstyle_color_plane_destroy;
1464
1465 properties [PROP_MODE] =
1466 g_param_spec_enum ("mode",
1467 "Mode",
1468 "The mode displayed",
1469 GSTYLE_TYPE_COLOR_PLANE_MODE,
1470 GSTYLE_COLOR_PLANE_MODE_HUE,
1471 (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1472
1473 properties [PROP_RGBA] =
1474 g_param_spec_boxed ("rgba",
1475 "rgba",
1476 "Color pointed by the cursor",
1477 GDK_TYPE_RGBA,
1478 (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1479
1480 properties [PROP_XYZ] =
1481 g_param_spec_boxed ("xyz",
1482 "xyz",
1483 "Color pointed by the cursor",
1484 GSTYLE_TYPE_XYZ,
1485 (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1486
1487 /* TODO: add *_adjustment properties */
1488
1489 g_object_class_install_properties (object_class, N_PROPS, properties);
1490
1491 gtk_widget_class_set_css_name (widget_class, "gstylecolorplane");
1492 }
1493
1494 static void
set_cross_cursor(GtkWidget * widget,gboolean enabled)1495 set_cross_cursor (GtkWidget *widget,
1496 gboolean enabled)
1497 {
1498 GstyleColorPlane *self = (GstyleColorPlane *)widget;
1499 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1500 GdkCursor *cursor = NULL;
1501 GdkWindow *window;
1502 GdkDevice *device;
1503
1504 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1505
1506 window = gtk_widget_get_window (widget);
1507 device = gtk_gesture_get_device (priv->drag_gesture);
1508
1509 if (!window || !device)
1510 return;
1511
1512 if (enabled)
1513 cursor = gdk_cursor_new_from_name (gtk_widget_get_display (GTK_WIDGET (widget)), "crosshair");
1514
1515 gdk_window_set_device_cursor (window, device, cursor);
1516
1517 if (cursor)
1518 g_object_unref (cursor);
1519 }
1520
1521 static void
hold_action(GtkGestureLongPress * gesture,gdouble x,gdouble y,GstyleColorPlane * self)1522 hold_action (GtkGestureLongPress *gesture,
1523 gdouble x,
1524 gdouble y,
1525 GstyleColorPlane *self)
1526 {
1527 gboolean handled;
1528
1529 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1530
1531 g_signal_emit_by_name (self, "popup-menu", &handled);
1532 }
1533
1534 static void
drag_gesture_begin(GtkGestureDrag * gesture,gdouble start_x,gdouble start_y,GstyleColorPlane * self)1535 drag_gesture_begin (GtkGestureDrag *gesture,
1536 gdouble start_x,
1537 gdouble start_y,
1538 GstyleColorPlane *self)
1539 {
1540 /* GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self); */
1541 guint button;
1542
1543 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1544
1545 button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
1546 if (button == GDK_BUTTON_SECONDARY)
1547 {
1548 gboolean handled;
1549 g_signal_emit_by_name (self, "popup-menu", &handled);
1550 }
1551
1552 if (button != GDK_BUTTON_PRIMARY)
1553 {
1554 gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
1555 return;
1556 }
1557
1558 set_cross_cursor (GTK_WIDGET (self), TRUE);
1559 update_cursor (self, start_x, start_y);
1560
1561 gtk_widget_grab_focus (GTK_WIDGET (self));
1562 gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
1563 }
1564
1565 static void
drag_gesture_update(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,GstyleColorPlane * self)1566 drag_gesture_update (GtkGestureDrag *gesture,
1567 gdouble offset_x,
1568 gdouble offset_y,
1569 GstyleColorPlane *self)
1570 {
1571 /* GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self); */
1572 gdouble start_x, start_y;
1573
1574 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1575
1576 gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture),
1577 &start_x, &start_y);
1578
1579 update_cursor (self, start_x + offset_x, start_y + offset_y);
1580 }
1581
1582 static void
drag_gesture_end(GtkGestureDrag * gesture,gdouble offset_x,gdouble offset_y,GstyleColorPlane * self)1583 drag_gesture_end (GtkGestureDrag *gesture,
1584 gdouble offset_x,
1585 gdouble offset_y,
1586 GstyleColorPlane *self)
1587 {
1588 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1589
1590 set_cross_cursor (GTK_WIDGET (self), FALSE);
1591 }
1592
1593 static void
gstyle_color_plane_init(GstyleColorPlane * self)1594 gstyle_color_plane_init (GstyleColorPlane *self)
1595 {
1596 GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
1597 GtkStyleContext *context;
1598 AtkObject *atk_obj;
1599
1600 g_assert (GSTYLE_IS_COLOR_PLANE (self));
1601
1602 gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
1603 gtk_widget_set_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK |
1604 GDK_TOUCH_MASK |
1605 GDK_BUTTON_PRESS_MASK |
1606 GDK_BUTTON_RELEASE_MASK |
1607 GDK_POINTER_MOTION_MASK);
1608
1609 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (self));
1610 if (GTK_IS_ACCESSIBLE (atk_obj))
1611 {
1612 atk_object_set_name (atk_obj, _("Color Plane"));
1613 atk_object_set_role (atk_obj, ATK_ROLE_COLOR_CHOOSER);
1614 }
1615
1616 setup_component (self, GSTYLE_COLOR_COMPONENT_HSV_H, 0.0, 0.0, 360.0, 1.0, 1.0, 360.0, COLOR_SPACE_HSV);
1617 setup_component (self, GSTYLE_COLOR_COMPONENT_HSV_S, 0.0, 0.0, 100.0, 1.0, 1.0, 100.0, COLOR_SPACE_HSV);
1618 setup_component (self, GSTYLE_COLOR_COMPONENT_HSV_V, 0.0, 0.0, 100.0, 1.0, 1.0, 100.0, COLOR_SPACE_HSV);
1619
1620 setup_component (self, GSTYLE_COLOR_COMPONENT_LAB_L, 0.0, 0.0, 100.0, 1.0, 1.0, 1.0, COLOR_SPACE_CIELAB);
1621 setup_component (self, GSTYLE_COLOR_COMPONENT_LAB_A, 0.0, -128.0, 128.0, 1.0, 1.0, 1.0, COLOR_SPACE_CIELAB);
1622 setup_component (self, GSTYLE_COLOR_COMPONENT_LAB_B, 0.0, -128.0, 128.0, 1.0, 1.0, 1.0, COLOR_SPACE_CIELAB);
1623
1624 setup_component (self, GSTYLE_COLOR_COMPONENT_RGB_RED, 0.0, 0.0, 255.0, 1.0, 1.0, 255.0, COLOR_SPACE_RGB);
1625 setup_component (self, GSTYLE_COLOR_COMPONENT_RGB_GREEN, 0.0, 0.0, 255.0, 1.0, 1.0, 255.0, COLOR_SPACE_RGB);
1626 setup_component (self, GSTYLE_COLOR_COMPONENT_RGB_BLUE, 0.0, 0.0, 255.0, 1.0, 1.0, 255.0, COLOR_SPACE_RGB);
1627
1628 priv->preferred_unit = GSTYLE_COLOR_UNIT_VALUE;
1629
1630 for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
1631 priv->comp [i].handler = g_signal_connect_swapped (priv->comp [i].adj,
1632 "value-changed",
1633 G_CALLBACK (adjustments_changed), self);
1634
1635 priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (self));
1636 g_signal_connect (priv->drag_gesture, "drag-begin", G_CALLBACK (drag_gesture_begin), self);
1637 g_signal_connect (priv->drag_gesture, "drag-update", G_CALLBACK (drag_gesture_update), self);
1638 g_signal_connect (priv->drag_gesture, "drag-end", G_CALLBACK (drag_gesture_end), self);
1639
1640 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
1641
1642 priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (self));
1643 g_signal_connect (priv->long_press_gesture, "pressed", G_CALLBACK (hold_action), self);
1644
1645 gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->long_press_gesture), TRUE);
1646
1647 priv->mode = GSTYLE_COLOR_PLANE_MODE_HUE;
1648 priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_H;
1649 priv->xyz.alpha = 1;
1650
1651 context = gtk_widget_get_style_context (GTK_WIDGET (self));
1652 priv->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
1653 }
1654
1655 GType
gstyle_color_plane_mode_get_type(void)1656 gstyle_color_plane_mode_get_type (void)
1657 {
1658 static GType type_id;
1659 static const GEnumValue values[] = {
1660 { GSTYLE_COLOR_PLANE_MODE_HUE, "GSTYLE_COLOR_PLANE_MODE_HUE", "hue" },
1661 { GSTYLE_COLOR_PLANE_MODE_SATURATION, "GSTYLE_COLOR_PLANE_MODE_SATURATION", "saturation" },
1662 { GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS, "GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS", "brightness" },
1663 { GSTYLE_COLOR_PLANE_MODE_CIELAB_L, "GSTYLE_COLOR_PLANE_MODE_CIELAB_L", "cielab-l" },
1664 { GSTYLE_COLOR_PLANE_MODE_CIELAB_A, "GSTYLE_COLOR_PLANE_MODE_CIELAB_A", "cielab-a" },
1665 { GSTYLE_COLOR_PLANE_MODE_CIELAB_B, "GSTYLE_COLOR_PLANE_MODE_CIELAB_B", "cielab-b" },
1666 { GSTYLE_COLOR_PLANE_MODE_RED, "GSTYLE_COLOR_PLANE_MODE_RED", "red" },
1667 { GSTYLE_COLOR_PLANE_MODE_GREEN, "GSTYLE_COLOR_PLANE_MODE_GREEN", "green" },
1668 { GSTYLE_COLOR_PLANE_MODE_BLUE, "GSTYLE_COLOR_PLANE_MODE_BLUE", "blue" },
1669 { 0 }
1670 };
1671
1672 if (g_once_init_enter (&type_id))
1673 {
1674 GType _type_id;
1675
1676 _type_id = g_enum_register_static ("GstyleColorPlaneMode", values);
1677 g_once_init_leave (&type_id, _type_id);
1678 }
1679
1680 return type_id;
1681 }
1682