1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2012 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * - move out custom sliders
27 #include "gtkcolorchooserprivate.h"
28 #include "gtkcoloreditor.h"
29 #include "gtkcolorplane.h"
30 #include "gtkcolorswatch.h"
33 #include "gtkaspectframe.h"
34 #include "gtkdrawingarea.h"
37 #include "gtkadjustment.h"
42 struct _GtkColorEditorPrivate
53 cairo_surface_t *h_surface;
54 cairo_surface_t *a_surface;
58 guint text_changed : 1;
69 static void gtk_color_editor_iface_init (GtkColorChooserInterface *iface);
71 G_DEFINE_TYPE_WITH_CODE (GtkColorEditor, gtk_color_editor, GTK_TYPE_BOX,
72 G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
73 gtk_color_editor_iface_init))
76 scale_round (gdouble value, gdouble scale)
78 value = floor (value * scale + 0.5);
79 value = MAX (value, 0);
80 value = MIN (value, scale);
85 update_entry (GtkColorEditor *editor)
89 text = g_strdup_printf ("#%02X%02X%02X",
90 scale_round (editor->priv->color.red, 255),
91 scale_round (editor->priv->color.green, 255),
92 scale_round (editor->priv->color.blue, 255));
93 gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), text);
94 editor->priv->text_changed = FALSE;
99 entry_apply (GtkWidget *entry,
100 GtkColorEditor *editor)
105 if (!editor->priv->text_changed)
108 text = gtk_editable_get_chars (GTK_EDITABLE (editor->priv->entry), 0, -1);
109 if (gdk_rgba_parse (&color, text))
111 color.alpha = editor->priv->color.alpha;
112 gtk_color_chooser_set_color (GTK_COLOR_CHOOSER (editor), &color);
115 editor->priv->text_changed = FALSE;
121 entry_focus_out (GtkWidget *entry,
122 GdkEventFocus *event,
123 GtkColorEditor *editor)
125 entry_apply (entry, editor);
130 entry_text_changed (GtkWidget *entry,
132 GtkColorEditor *editor)
134 editor->priv->text_changed = TRUE;
138 h_changed (GtkAdjustment *adj,
139 GtkColorEditor *editor)
141 editor->priv->h = gtk_adjustment_get_value (adj);
142 gtk_hsv_to_rgb (editor->priv->h, editor->priv->s, editor->priv->v,
143 &editor->priv->color.red,
144 &editor->priv->color.green,
145 &editor->priv->color.blue);
146 gtk_color_plane_set_h (GTK_COLOR_PLANE (editor->priv->sv_plane), editor->priv->h);
147 update_entry (editor);
148 gtk_color_swatch_set_color (GTK_COLOR_SWATCH (editor->priv->swatch), &editor->priv->color);
149 gtk_widget_queue_draw (editor->priv->a_slider);
150 if (editor->priv->a_surface)
152 cairo_surface_destroy (editor->priv->a_surface);
153 editor->priv->a_surface = NULL;
155 g_object_notify (G_OBJECT (editor), "color");
159 sv_changed (GtkColorPlane *plane,
160 GtkColorEditor *editor)
162 editor->priv->s = gtk_color_plane_get_s (plane);
163 editor->priv->v = gtk_color_plane_get_v (plane);
164 gtk_hsv_to_rgb (editor->priv->h, editor->priv->s, editor->priv->v,
165 &editor->priv->color.red,
166 &editor->priv->color.green,
167 &editor->priv->color.blue);
168 update_entry (editor);
169 gtk_color_swatch_set_color (GTK_COLOR_SWATCH (editor->priv->swatch), &editor->priv->color);
170 gtk_widget_queue_draw (editor->priv->a_slider);
171 if (editor->priv->a_surface)
173 cairo_surface_destroy (editor->priv->a_surface);
174 editor->priv->a_surface = NULL;
176 g_object_notify (G_OBJECT (editor), "color");
180 a_changed (GtkAdjustment *adj,
181 GtkColorEditor *editor)
183 editor->priv->color.alpha = gtk_adjustment_get_value (adj);
184 gtk_color_swatch_set_color (GTK_COLOR_SWATCH (editor->priv->swatch), &editor->priv->color);
185 g_object_notify (G_OBJECT (editor), "color");
188 static cairo_pattern_t *
189 get_checkered_pattern (void)
191 /* need to respect pixman's stride being a multiple of 4 */
192 static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
193 0x00, 0xFF, 0x00, 0x00 };
194 static cairo_surface_t *checkered = NULL;
195 cairo_pattern_t *pattern;
197 if (checkered == NULL)
198 checkered = cairo_image_surface_create_for_data (data,
202 pattern = cairo_pattern_create_for_surface (checkered);
203 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
204 cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
209 static cairo_surface_t *
210 create_h_surface (GtkWidget *widget)
213 cairo_surface_t *surface;
214 gint width, height, stride;
215 cairo_surface_t *tmp;
216 guint red, green, blue;
223 if (!gtk_widget_get_realized (widget))
226 width = gtk_widget_get_allocated_width (widget);
227 height = gtk_widget_get_allocated_height (widget);
229 surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
233 if (width == 1 || height == 1)
236 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
238 data = g_malloc (height * stride);
240 f = 1.0 / (height - 1);
241 for (y = 0; y < height; y++)
243 h = CLAMP (y * f, 0.0, 1.0);
244 p = data + y * (stride / 4);
245 for (x = 0; x < width; x++)
247 gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b);
248 red = CLAMP (r * 255, 0, 255);
249 green = CLAMP (g * 255, 0, 255);
250 blue = CLAMP (b * 255, 0, 255);
251 p[x] = (red << 16) | (green << 8) | blue;
255 tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
256 width, height, stride);
257 cr = cairo_create (surface);
259 cairo_set_source_surface (cr, tmp, 0, 0);
263 cairo_surface_destroy (tmp);
270 h_draw (GtkWidget *widget,
272 GtkColorEditor *editor)
274 cairo_surface_t *surface;
277 width = gtk_widget_get_allocated_width (widget);
278 height = gtk_widget_get_allocated_height (widget);
280 if (!editor->priv->h_surface)
281 editor->priv->h_surface = create_h_surface (widget);
282 surface = editor->priv->h_surface;
286 cairo_rectangle (cr, 1, 1, width - 2, height - 2);
288 cairo_set_source_surface (cr, surface, 0, 0);
296 static cairo_surface_t *
297 create_a_surface (GtkWidget *widget,
301 cairo_surface_t *surface;
302 cairo_pattern_t *pattern;
303 cairo_matrix_t matrix;
306 if (!gtk_widget_get_realized (widget))
309 width = gtk_widget_get_allocated_width (widget);
310 height = gtk_widget_get_allocated_height (widget);
312 surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
316 if (width == 1 || height == 1)
319 cr = cairo_create (surface);
321 cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
323 cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
325 pattern = get_checkered_pattern ();
326 cairo_matrix_init_scale (&matrix, 0.125, 0.125);
327 cairo_pattern_set_matrix (pattern, &matrix);
328 cairo_mask (cr, pattern);
329 cairo_pattern_destroy (pattern);
331 pattern = cairo_pattern_create_linear (0, 0, width, 0);
332 cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0);
333 cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1);
334 cairo_set_source (cr, pattern);
336 cairo_pattern_destroy (pattern);
344 a_draw (GtkWidget *widget,
346 GtkColorEditor *editor)
348 cairo_surface_t *surface;
351 width = gtk_widget_get_allocated_width (widget);
352 height = gtk_widget_get_allocated_height (widget);
354 if (!editor->priv->a_surface)
355 editor->priv->a_surface = create_a_surface (widget, &editor->priv->color);
356 surface = editor->priv->a_surface;
360 cairo_rectangle (cr, 1, 1, width - 2, height - 2);
362 cairo_set_source_surface (cr, surface, 0, 0);
371 gtk_color_editor_init (GtkColorEditor *editor)
376 editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor,
377 GTK_TYPE_COLOR_EDITOR,
378 GtkColorEditorPrivate);
379 editor->priv->show_alpha = TRUE;
381 gtk_widget_push_composite_child ();
383 editor->priv->grid = grid = gtk_grid_new ();
384 gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
385 gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
387 editor->priv->swatch = gtk_color_swatch_new ();
388 gtk_widget_set_sensitive (editor->priv->swatch, FALSE);
389 gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (editor->priv->swatch), 2, 2, 2, 2);
391 editor->priv->entry = gtk_entry_new ();
392 g_signal_connect (editor->priv->entry, "activate",
393 G_CALLBACK (entry_apply), editor);
394 g_signal_connect (editor->priv->entry, "notify::text",
395 G_CALLBACK (entry_text_changed), editor);
396 g_signal_connect (editor->priv->entry, "focus-out-event",
397 G_CALLBACK (entry_focus_out), editor);
399 adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
400 g_signal_connect (adj, "value-changed", G_CALLBACK (h_changed), editor);
401 editor->priv->h_slider = gtk_scale_new (GTK_ORIENTATION_VERTICAL, adj);
402 editor->priv->h_adj = adj;
403 g_signal_connect (editor->priv->h_slider, "draw", G_CALLBACK (h_draw), editor);
405 gtk_scale_set_draw_value (GTK_SCALE (editor->priv->h_slider), FALSE);
406 editor->priv->sv_plane = gtk_color_plane_new ();
407 gtk_widget_set_size_request (editor->priv->sv_plane, 300, 300);
408 gtk_widget_set_hexpand (editor->priv->sv_plane, TRUE);
409 gtk_widget_set_vexpand (editor->priv->sv_plane, TRUE);
411 g_signal_connect (editor->priv->sv_plane, "changed", G_CALLBACK (sv_changed), editor);
413 adj = gtk_adjustment_new (1, 0, 1, 0.01, 0.1, 0);
414 editor->priv->a_slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adj);
415 g_signal_connect (adj, "value-changed", G_CALLBACK (a_changed), editor);
416 gtk_scale_set_draw_value (GTK_SCALE (editor->priv->a_slider), FALSE);
417 editor->priv->a_adj = adj;
418 g_signal_connect (editor->priv->a_slider, "draw", G_CALLBACK (a_draw), editor);
420 gtk_grid_attach (GTK_GRID (grid), editor->priv->swatch, 1, 0, 1, 1);
421 gtk_grid_attach (GTK_GRID (grid), editor->priv->entry, 2, 0, 1, 1);
422 gtk_grid_attach (GTK_GRID (grid), editor->priv->h_slider, 0, 1, 1, 1);
423 gtk_grid_attach (GTK_GRID (grid), editor->priv->sv_plane, 1, 1, 2, 1);
424 gtk_grid_attach (GTK_GRID (grid), editor->priv->a_slider, 1, 2, 2, 1);
425 gtk_widget_show_all (grid);
427 gtk_container_add (GTK_CONTAINER (editor), grid);
428 gtk_widget_pop_composite_child ();
432 gtk_color_editor_get_property (GObject *object,
437 GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
438 GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
445 gtk_color_chooser_get_color (cc, &color);
446 g_value_set_boxed (value, &color);
449 case PROP_SHOW_ALPHA:
450 g_value_set_boolean (value, gtk_widget_get_visible (ce->priv->a_slider));
453 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
459 gtk_color_editor_set_show_alpha (GtkColorEditor *editor,
462 if (editor->priv->show_alpha != show_alpha)
464 editor->priv->show_alpha = show_alpha;
466 gtk_widget_set_visible (editor->priv->a_slider, show_alpha);
468 gtk_color_swatch_set_show_alpha (GTK_COLOR_SWATCH (editor->priv->swatch), show_alpha);
473 gtk_color_editor_set_property (GObject *object,
478 GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
479 GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
484 gtk_color_chooser_set_color (cc, g_value_get_boxed (value));
486 case PROP_SHOW_ALPHA:
487 gtk_color_editor_set_show_alpha (ce, g_value_get_boolean (value));
490 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
496 gtk_color_editor_finalize (GObject *object)
498 GtkColorEditor *editor = GTK_COLOR_EDITOR (object);
500 if (editor->priv->h_surface)
501 cairo_surface_destroy (editor->priv->h_surface);
502 if (editor->priv->a_surface)
503 cairo_surface_destroy (editor->priv->a_surface);
505 G_OBJECT_CLASS (gtk_color_editor_parent_class)->finalize (object);
509 gtk_color_editor_class_init (GtkColorEditorClass *class)
511 GObjectClass *object_class = G_OBJECT_CLASS (class);
513 object_class->finalize = gtk_color_editor_finalize;
514 object_class->get_property = gtk_color_editor_get_property;
515 object_class->set_property = gtk_color_editor_set_property;
517 g_object_class_override_property (object_class, PROP_COLOR, "color");
518 g_object_class_override_property (object_class, PROP_SHOW_ALPHA, "show-alpha");
520 g_type_class_add_private (class, sizeof (GtkColorEditorPrivate));
524 gtk_color_editor_get_color (GtkColorChooser *chooser,
527 GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
529 color->red = editor->priv->color.red;
530 color->green = editor->priv->color.green;
531 color->blue = editor->priv->color.blue;
532 color->alpha = editor->priv->color.alpha;
536 gtk_color_editor_set_color (GtkColorChooser *chooser,
537 const GdkRGBA *color)
539 GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
542 editor->priv->color.red = color->red;
543 editor->priv->color.green = color->green;
544 editor->priv->color.blue = color->blue;
545 editor->priv->color.alpha = color->alpha;
546 gtk_rgb_to_hsv (color->red, color->green, color->blue, &h, &s, &v);
550 gtk_color_plane_set_h (GTK_COLOR_PLANE (editor->priv->sv_plane), h);
551 gtk_color_plane_set_s (GTK_COLOR_PLANE (editor->priv->sv_plane), s);
552 gtk_color_plane_set_v (GTK_COLOR_PLANE (editor->priv->sv_plane), v);
553 gtk_color_swatch_set_color (GTK_COLOR_SWATCH (editor->priv->swatch), color);
555 gtk_adjustment_set_value (editor->priv->h_adj, h);
556 gtk_adjustment_set_value (editor->priv->a_adj, color->alpha);
557 update_entry (editor);
559 if (editor->priv->a_surface)
561 cairo_surface_destroy (editor->priv->a_surface);
562 editor->priv->a_surface = NULL;
564 gtk_widget_queue_draw (GTK_WIDGET (editor));
566 g_object_notify (G_OBJECT (editor), "color");
570 gtk_color_editor_iface_init (GtkColorChooserInterface *iface)
572 iface->get_color = gtk_color_editor_get_color;
573 iface->set_color = gtk_color_editor_set_color;
577 gtk_color_editor_new (void)
579 return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_EDITOR, NULL);