]> Pileus Git - ~andy/gtk/blob - gtk/gtkcolorchooserwidget.c
Mark color names as translatable
[~andy/gtk] / gtk / gtkcolorchooserwidget.c
1 /* GTK - The GIMP Toolkit
2  *
3  * Copyright (C) 2012 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include "gtkcolorchooserprivate.h"
24 #include "gtkcolorchooserwidget.h"
25 #include "gtkcoloreditorprivate.h"
26 #include "gtkcolorswatchprivate.h"
27 #include "gtkbox.h"
28 #include "gtkgrid.h"
29 #include "gtklabel.h"
30 #include "gtkorientable.h"
31 #include "gtkprivate.h"
32 #include "gtkintl.h"
33 #include "gtksizegroup.h"
34
35 #include <math.h>
36
37 /**
38  * SECTION:gtkcolorchooserwidget
39  * @Short_description: A widget for choosing colors
40  * @Title: GtkColorChooserWidget
41  * @See_also: #GtkColorChooserDialog
42  *
43  * The #GtkColorChooserWidget widget lets the user select a
44  * color. By default, the chooser presents a prefined palette
45  * of colors, plus a small number of settable custom colors.
46  * It is also possible to select a different color with the
47  * single-color editor. To enter the single-color editing mode,
48  * use the context menu of any color of the palette, or use the
49  * '+' button to add a new custom color.
50  *
51  * The chooser automatically remembers the last selection, as well
52  * as custom colors.
53  *
54  * To change the initially selected color, use gtk_color_chooser_set_rgba().
55  * To get the selected font use gtk_color_chooser_get_rgba().
56  *
57  * The #GtkColorChooserWidget is used in the #GtkColorChooserDialog
58  * to provide a dialog for selecting colors.
59  *
60  * Since: 3.4
61  */
62
63 struct _GtkColorChooserWidgetPrivate
64 {
65   GtkWidget *palette;
66   GtkWidget *editor;
67   GtkSizeGroup *size_group;
68
69   GtkWidget *custom_label;
70   GtkWidget *custom;
71
72   GtkWidget *button;
73   GtkColorSwatch *current;
74
75   gboolean use_alpha;
76   gboolean has_default_palette;
77
78   GSettings *settings;
79 };
80
81 enum
82 {
83   PROP_ZERO,
84   PROP_RGBA,
85   PROP_USE_ALPHA,
86   PROP_SHOW_EDITOR
87 };
88
89 static void gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface);
90
91 G_DEFINE_TYPE_WITH_CODE (GtkColorChooserWidget, gtk_color_chooser_widget, GTK_TYPE_BOX,
92                          G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
93                                                 gtk_color_chooser_widget_iface_init))
94
95 static void
96 select_swatch (GtkColorChooserWidget *cc,
97                GtkColorSwatch        *swatch)
98 {
99   GdkRGBA color;
100
101   if (cc->priv->current == swatch)
102     return;
103
104   if (cc->priv->current != NULL)
105     gtk_widget_unset_state_flags (GTK_WIDGET (cc->priv->current), GTK_STATE_FLAG_SELECTED);
106   gtk_widget_set_state_flags (GTK_WIDGET (swatch), GTK_STATE_FLAG_SELECTED, FALSE);
107   cc->priv->current = swatch;
108
109   gtk_color_swatch_get_rgba (swatch, &color);
110   g_settings_set (cc->priv->settings, "selected-color", "(bdddd)",
111                   TRUE, color.red, color.green, color.blue, color.alpha);
112
113   g_object_notify (G_OBJECT (cc), "rgba");
114 }
115
116 static void
117 swatch_activate (GtkColorSwatch        *swatch,
118                  GtkColorChooserWidget *cc)
119 {
120   GdkRGBA color;
121
122   gtk_color_swatch_get_rgba (swatch, &color);
123   _gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
124 }
125
126 static void
127 swatch_customize (GtkColorSwatch        *swatch,
128                   GtkColorChooserWidget *cc)
129 {
130   GdkRGBA color;
131
132   gtk_color_swatch_get_rgba (swatch, &color);
133   gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
134
135   gtk_widget_hide (cc->priv->palette);
136   gtk_widget_show (cc->priv->editor);
137   g_object_notify (G_OBJECT (cc), "show-editor");
138 }
139
140 static void
141 swatch_selected (GtkColorSwatch        *swatch,
142                  GtkStateFlags          previous,
143                  GtkColorChooserWidget *cc)
144 {
145   GtkStateFlags flags;
146
147   flags = gtk_widget_get_state_flags (GTK_WIDGET (swatch));
148   if ((flags & GTK_STATE_FLAG_SELECTED) != (previous & GTK_STATE_FLAG_SELECTED) &&
149       (flags & GTK_STATE_FLAG_SELECTED) != 0)
150     select_swatch (cc, swatch);
151 }
152
153 static void
154 connect_swatch_signals (GtkWidget *p,
155                         gpointer   data)
156 {
157   g_signal_connect (p, "activate", G_CALLBACK (swatch_activate), data);
158   g_signal_connect (p, "customize", G_CALLBACK (swatch_customize), data);
159   g_signal_connect (p, "state-flags-changed", G_CALLBACK (swatch_selected), data);
160 }
161
162 static void
163 button_activate (GtkColorSwatch        *swatch,
164                  GtkColorChooserWidget *cc)
165 {
166   /* somewhat random, makes the hairline nicely visible */
167   GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
168
169   gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
170
171   gtk_widget_hide (cc->priv->palette);
172   gtk_widget_show (cc->priv->editor);
173   g_object_notify (G_OBJECT (cc), "show-editor");
174 }
175
176 static void
177 connect_button_signals (GtkWidget *p,
178                         gpointer   data)
179 {
180   g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
181 }
182
183 static void
184 save_custom_colors (GtkColorChooserWidget *cc)
185 {
186   GVariantBuilder builder;
187   GVariant *variant;
188   GdkRGBA color;
189   GList *children, *l;
190   GtkWidget *child;
191
192   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dddd)"));
193
194   children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
195   for (l = g_list_nth (children, 1); l != NULL; l = l->next)
196     {
197       child = l->data;
198       if (gtk_color_swatch_get_rgba (GTK_COLOR_SWATCH (child), &color))
199         g_variant_builder_add (&builder, "(dddd)",
200                                color.red, color.green, color.blue, color.alpha);
201     }
202
203   variant = g_variant_builder_end (&builder);
204   g_settings_set_value (cc->priv->settings, "custom-colors", variant);
205
206   g_list_free (children);
207 }
208
209 static void
210 connect_custom_signals (GtkWidget *p,
211                         gpointer   data)
212 {
213   connect_swatch_signals (p, data);
214   g_signal_connect_swapped (p, "notify::rgba",
215                             G_CALLBACK (save_custom_colors), data);
216 }
217
218 static void
219 gtk_color_chooser_widget_set_use_alpha (GtkColorChooserWidget *cc,
220                                         gboolean               use_alpha)
221 {
222   GList *children, *l;
223   GList *palettes, *p;
224   GtkWidget *swatch;
225   GtkWidget *grid;
226
227   cc->priv->use_alpha = use_alpha;
228   gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cc->priv->editor), use_alpha);
229
230   palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
231   for (p = palettes; p; p = p->next)
232     {
233       grid = p->data;
234
235       if (!GTK_IS_CONTAINER (grid))
236         continue;
237
238       children = gtk_container_get_children (GTK_CONTAINER (grid));
239       for (l = children; l; l = l->next)
240         {
241           swatch = l->data;
242           gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (swatch), use_alpha);
243         }
244       g_list_free (children);
245     }
246   g_list_free (palettes);
247
248   gtk_widget_queue_draw (GTK_WIDGET (cc));
249 }
250
251 static void
252 gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
253                                           gboolean               show_editor)
254 {
255   if (show_editor)
256     {
257       GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
258
259       if (cc->priv->current)
260         gtk_color_swatch_get_rgba (cc->priv->current, &color);
261       gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
262     }
263
264   gtk_widget_set_visible (cc->priv->editor, show_editor);
265   gtk_widget_set_visible (cc->priv->palette, !show_editor);
266 }
267
268 /* UI construction {{{1 */
269
270 static void
271 add_palette (GtkColorChooserWidget  *cc,
272              gboolean                horizontal,
273              gint                    colors_per_line,
274              gint                    n_colors,
275              GdkRGBA                *colors,
276              const gchar           **names)
277 {
278   GtkWidget *grid;
279   GtkWidget *p;
280   AtkObject *atk_obj;
281   gint line, pos;
282   gint i;
283   gint left, right;
284
285   grid = gtk_grid_new ();
286   gtk_widget_set_margin_bottom (grid, 12);
287   gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
288   gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
289   gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);
290
291   left = 0;
292   right = colors_per_line - 1;
293   if (gtk_widget_get_direction (GTK_WIDGET (cc)) == GTK_TEXT_DIR_RTL)
294     {
295       i = left;
296       left = right;
297       right = i;
298     }
299
300   for (i = 0; i < n_colors; i++)
301     {
302       p = gtk_color_swatch_new ();
303       if (names)
304         {
305           atk_obj = gtk_widget_get_accessible (p);
306           atk_object_set_description (atk_obj, C_("Color name", names[i]));
307         }
308       gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &colors[i]);
309       connect_swatch_signals (p, cc);
310
311       line = i / colors_per_line;
312       pos = i % colors_per_line;
313
314       if (horizontal)
315         {
316             if (pos == left)
317               gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_LEFT);
318             else if (pos == right)
319               gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_RIGHT);
320
321             gtk_grid_attach (GTK_GRID (grid), p, pos, line, 1, 1);
322         }
323       else
324         {
325           if (pos == 0)
326             gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_TOP);
327           else if (pos == colors_per_line - 1)
328             gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_BOTTOM);
329
330           gtk_grid_attach (GTK_GRID (grid), p, line, pos, 1, 1);
331        }
332     }
333
334   gtk_widget_show_all (grid);
335 }
336
337 static void
338 remove_default_palette (GtkColorChooserWidget *cc)
339 {
340   GList *children, *l;
341   GtkWidget *widget;
342
343   if (!cc->priv->has_default_palette)
344     return;
345
346   children = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
347   for (l = children; l; l = l->next)
348     {
349       widget = l->data;
350       if (widget == cc->priv->custom_label || widget == cc->priv->custom)
351         continue;
352       gtk_container_remove (GTK_CONTAINER (cc->priv->palette), widget);
353     }
354   g_list_free (children);
355
356   cc->priv->has_default_palette = FALSE;
357 }
358
359 static void
360 add_default_palette (GtkColorChooserWidget *cc)
361 {
362   const gchar *default_colors[9][3] = {
363     { "#ef2929", "#cc0000", "#a40000" }, /* Scarlet Red */
364     { "#fcaf3e", "#f57900", "#ce5c00" }, /* Orange */
365     { "#fce94f", "#edd400", "#c4a000" }, /* Butter */
366     { "#8ae234", "#73d216", "#4e9a06" }, /* Chameleon */
367     { "#729fcf", "#3465a4", "#204a87" }, /* Sky Blue */
368     { "#ad7fa8", "#75507b", "#5c3566" }, /* Plum */
369     { "#e9b96e", "#c17d11", "#8f5902" }, /* Chocolate */
370     { "#888a85", "#555753", "#2e3436" }, /* Aluminum 1 */
371     { "#eeeeec", "#d3d7cf", "#babdb6" }  /* Aluminum 2 */
372   };
373   const gchar *color_names[] = {
374     NC_("Color name", "Light Scarlet Red"),
375     NC_("Color name", "Scarlet Red"),
376     NC_("Color name", "Dark Scarlet Red"),
377     NC_("Color name", "Light Orange"),
378     NC_("Color name", "Orange"),
379     NC_("Color name", "Dark Orange"),
380     NC_("Color name", "Light Butter"),
381     NC_("Color name", "Butter"),
382     NC_("Color name", "Dark Butter"),
383     NC_("Color name", "Light Chameleon"),
384     NC_("Color name", "Chameleon"),
385     NC_("Color name", "Dark Chameleon"),
386     NC_("Color name", "Light Sky Blue"),
387     NC_("Color name", "Sky Blue"),
388     NC_("Color name", "Dark Sky Blue"),
389     NC_("Color name", "Light Plum"),
390     NC_("Color name", "Plum"),
391     NC_("Color name", "Dark Plum"),
392     NC_("Color name", "Light Chocolate"),
393     NC_("Color name", "Chocolate"),
394     NC_("Color name", "Dark Chocolate"),
395     NC_("Color name", "Light Aluminum 1"),
396     NC_("Color name", "Aluminum 1"),
397     NC_("Color name", "Dark Aluminum 1"),
398     NC_("Color name", "Light Aluminum 2"),
399     NC_("Color name", "Aluminum 2"),
400     NC_("Color name", "Dark Aluminum 2")
401   };
402   const gchar *default_grays[9] = {
403     "#000000", /* black */
404     "#2e3436", /* very dark gray */
405     "#555753", /* darker gray */
406     "#888a85", /* dark gray */
407     "#babdb6", /* medium gray */
408     "#d3d7cf", /* light gray */
409     "#eeeeec", /* lighter gray */
410     "#f3f3f3", /* very light gray */
411     "#ffffff"  /* white */
412   };
413   const gchar *gray_names[] = {
414     NC_("Color name", "Black"),
415     NC_("Color name", "Very Dark Gray"),
416     NC_("Color name", "Darker Gray"),
417     NC_("Color name", "Dark Gray"),
418     NC_("Color name", "Medium Gray"),
419     NC_("Color name", "Light Gray"),
420     NC_("Color name", "Lighter Gray"),
421     NC_("Color name", "Very Light Gray"),
422     NC_("Color name", "White")
423   };
424   GdkRGBA colors[9*3];
425   gint i, j;
426
427   for (i = 0; i < 9; i++)
428     for (j = 0; j < 3; j++)
429       gdk_rgba_parse (&colors[i*3 + j], default_colors[i][j]);
430
431   add_palette (cc, FALSE, 3, 9*3, colors, color_names);
432
433   for (i = 0; i < 9; i++)
434     gdk_rgba_parse (&colors[i], default_grays[i]);
435
436   add_palette (cc, TRUE, 9, 9, colors, gray_names);
437
438   cc->priv->has_default_palette = TRUE;
439 }
440
441 static guint
442 scale_round (gdouble value, gdouble scale)
443 {
444   value = floor (value * scale + 0.5);
445   value = MAX (value, 0);
446   value = MIN (value, scale);
447   return (guint)value;
448 }
449
450 static void
451 gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
452 {
453   GtkWidget *box;
454   GtkWidget *p;
455   GtkWidget *button;
456   GtkWidget *label;
457   gint i;
458   GdkRGBA color;
459   GVariant *variant;
460   GVariantIter iter;
461   gboolean selected;
462   AtkObject *atk_obj;
463   gchar *text;
464
465   cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc, GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetPrivate);
466
467   cc->priv->use_alpha = TRUE;
468
469   gtk_orientable_set_orientation (GTK_ORIENTABLE (cc), GTK_ORIENTATION_VERTICAL);
470   cc->priv->palette = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
471   gtk_container_add (GTK_CONTAINER (cc), cc->priv->palette);
472
473   add_default_palette (cc);
474
475   cc->priv->custom = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
476   g_object_set (box, "margin-top", 12, NULL);
477   gtk_box_pack_end (GTK_BOX (cc->priv->palette), box, FALSE, TRUE, 0);
478
479   /* translators: label for the custom section in the color chooser */
480   cc->priv->custom_label = label = gtk_label_new (_("Custom"));
481   gtk_widget_set_halign (label, GTK_ALIGN_START);
482   gtk_box_pack_end (GTK_BOX (cc->priv->palette), label, FALSE, TRUE, 0);
483
484   cc->priv->button = button = gtk_color_swatch_new ();
485   atk_obj = gtk_widget_get_accessible (button);
486   atk_object_set_role (atk_obj, ATK_ROLE_PUSH_BUTTON);
487   atk_object_set_description (atk_obj, _("Create custom color"));
488   connect_button_signals (button, cc);
489   gtk_color_swatch_set_icon (GTK_COLOR_SWATCH (button), "list-add-symbolic");
490   gtk_container_add (GTK_CONTAINER (box), button);
491
492   cc->priv->settings = g_settings_new_with_path ("org.gtk.Settings.ColorChooser",
493                                                  "/org/gtk/settings/color-chooser/");
494   variant = g_settings_get_value (cc->priv->settings, "custom-colors");
495   g_variant_iter_init (&iter, variant);
496   i = 0;
497   p = NULL;
498   while (g_variant_iter_loop (&iter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha))
499     {
500       i++;
501       p = gtk_color_swatch_new ();
502       gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &color);
503       gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
504       atk_obj = gtk_widget_get_accessible (p);
505       text = g_strdup_printf (_("Custom color %d: Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"), i,
506                               scale_round (color.red, 100),
507                               scale_round (color.green, 100),
508                               scale_round (color.blue, 100),
509                               scale_round (color.alpha, 100));
510       atk_object_set_description (atk_obj, text);
511       g_free (text);
512       connect_custom_signals (p, cc);
513       gtk_container_add (GTK_CONTAINER (box), p);
514
515       if (i == 8)
516         break;
517     }
518   g_variant_unref (variant);
519
520   cc->priv->editor = gtk_color_editor_new ();
521   gtk_widget_set_halign (cc->priv->editor, GTK_ALIGN_CENTER);
522   gtk_widget_set_hexpand (cc->priv->editor, TRUE);
523
524   box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
525   gtk_container_add (GTK_CONTAINER (cc), box);
526   gtk_container_add (GTK_CONTAINER (box), cc->priv->editor);
527
528   g_settings_get (cc->priv->settings, "selected-color", "(bdddd)",
529                   &selected,
530                   &color.red, &color.green, &color.blue, &color.alpha);
531   if (selected)
532     gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc), &color);
533
534   gtk_widget_show_all (GTK_WIDGET (cc));
535   gtk_widget_hide (GTK_WIDGET (cc->priv->editor));
536   gtk_widget_hide (GTK_WIDGET (cc));
537
538   gtk_widget_set_no_show_all (cc->priv->palette, TRUE);
539   gtk_widget_set_no_show_all (cc->priv->editor, TRUE);
540
541   cc->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
542   gtk_size_group_add_widget (cc->priv->size_group, cc->priv->palette);
543   gtk_size_group_add_widget (cc->priv->size_group, box);
544 }
545
546 /* GObject implementation {{{1 */
547
548 static void
549 gtk_color_chooser_widget_get_property (GObject    *object,
550                                        guint       prop_id,
551                                        GValue     *value,
552                                        GParamSpec *pspec)
553 {
554   GtkColorChooserWidget *cw = GTK_COLOR_CHOOSER_WIDGET (object);
555   GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
556
557   switch (prop_id)
558     {
559     case PROP_RGBA:
560       {
561         GdkRGBA color;
562
563         gtk_color_chooser_get_rgba (cc, &color);
564         g_value_set_boxed (value, &color);
565       }
566       break;
567     case PROP_USE_ALPHA:
568       g_value_set_boolean (value, cw->priv->use_alpha);
569       break;
570     case PROP_SHOW_EDITOR:
571       g_value_set_boolean (value, gtk_widget_get_visible (cw->priv->editor));
572       break;
573     default:
574       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
575       break;
576     }
577 }
578
579 static void
580 gtk_color_chooser_widget_set_property (GObject      *object,
581                                        guint         prop_id,
582                                        const GValue *value,
583                                        GParamSpec   *pspec)
584 {
585   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
586
587   switch (prop_id)
588     {
589     case PROP_RGBA:
590       gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc),
591                                   g_value_get_boxed (value));
592       break;
593     case PROP_USE_ALPHA:
594       gtk_color_chooser_widget_set_use_alpha (cc,
595                                               g_value_get_boolean (value));
596       break;
597     case PROP_SHOW_EDITOR:
598       gtk_color_chooser_widget_set_show_editor (cc,
599                                                 g_value_get_boolean (value));
600       break;
601     default:
602       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
603       break;
604     }
605 }
606
607 static void
608 gtk_color_chooser_widget_finalize (GObject *object)
609 {
610   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
611
612   g_object_unref (cc->priv->size_group);
613   g_object_unref (cc->priv->settings);
614
615   G_OBJECT_CLASS (gtk_color_chooser_widget_parent_class)->finalize (object);
616 }
617
618 static void
619 gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
620 {
621   GObjectClass *object_class = G_OBJECT_CLASS (class);
622
623   object_class->get_property = gtk_color_chooser_widget_get_property;
624   object_class->set_property = gtk_color_chooser_widget_set_property;
625   object_class->finalize = gtk_color_chooser_widget_finalize;
626
627   g_object_class_override_property (object_class, PROP_RGBA, "rgba");
628   g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
629
630   /**
631    * GtkColorChooserWidget:show-editor:
632    *
633    * The ::show-editor property is %TRUE when the color chooser
634    * is showing the single-color editor. It can be set to switch
635    * the color chooser into single-color editing mode.
636    *
637    * Since: 3.4
638    */
639   g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
640       g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
641                             FALSE, GTK_PARAM_READWRITE));
642
643   g_type_class_add_private (object_class, sizeof (GtkColorChooserWidgetPrivate));
644 }
645
646 /* GtkColorChooser implementation {{{1 */
647
648 static void
649 gtk_color_chooser_widget_get_rgba (GtkColorChooser *chooser,
650                                    GdkRGBA         *color)
651 {
652   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
653
654   if (gtk_widget_get_visible (cc->priv->editor))
655     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), color);
656   else if (cc->priv->current)
657     gtk_color_swatch_get_rgba (cc->priv->current, color);
658   else
659     {
660       color->red = 1.0;
661       color->green = 1.0;
662       color->blue = 1.0;
663       color->alpha = 1.0;
664     }
665
666   if (!cc->priv->use_alpha)
667     color->alpha = 1.0;
668 }
669
670 static void
671 add_custom_color (GtkColorChooserWidget *cc,
672                   const GdkRGBA         *color)
673 {
674   GtkWidget *last;
675   GtkWidget *p;
676   GList *children;
677
678   children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
679   if (g_list_length (children) >= 8)
680     {
681       last = g_list_last (children)->data;
682       gtk_widget_destroy (last);
683     }
684
685   g_list_free (children);
686
687   p = gtk_color_swatch_new ();
688   gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), color);
689   gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
690   connect_custom_signals (p, cc);
691
692   gtk_container_add (GTK_CONTAINER (cc->priv->custom), p);
693   gtk_box_reorder_child (GTK_BOX (cc->priv->custom), p, 1);
694   gtk_widget_show (p);
695
696   select_swatch (cc, GTK_COLOR_SWATCH (p));
697   save_custom_colors (cc);
698 }
699
700 static void
701 gtk_color_chooser_widget_set_rgba (GtkColorChooser *chooser,
702                                    const GdkRGBA   *color)
703 {
704   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
705   GList *children, *l;
706   GList *palettes, *p;
707   GtkColorSwatch *swatch;
708   GtkWidget *w;
709   GdkRGBA c;
710
711   palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
712   for (p = palettes; p; p = p->next)
713     {
714       w = p->data;
715       if (!GTK_IS_GRID (w) && !GTK_IS_BOX (w))
716         continue;
717
718       children = gtk_container_get_children (GTK_CONTAINER (w));
719       for (l = children; l; l = l->next)
720         {
721           swatch = l->data;
722           gtk_color_swatch_get_rgba (swatch, &c);
723           if (!cc->priv->use_alpha)
724             c.alpha = color->alpha;
725           if (gdk_rgba_equal (color, &c))
726             {
727               select_swatch (cc, swatch);
728               g_list_free (children);
729               return;
730             }
731         }
732       g_list_free (children);
733     }
734   g_list_free (palettes);
735
736   add_custom_color (cc, color);
737 }
738
739 static void
740 gtk_color_chooser_widget_add_palette (GtkColorChooser *chooser,
741                                       gboolean         horizontal,
742                                       gint             colors_per_line,
743                                       gint             n_colors,
744                                       GdkRGBA         *colors)
745 {
746   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
747
748   remove_default_palette (cc);
749   add_palette (cc, horizontal, colors_per_line, n_colors, colors, NULL);
750 }
751
752 static void
753 gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface)
754 {
755   iface->get_rgba = gtk_color_chooser_widget_get_rgba;
756   iface->set_rgba = gtk_color_chooser_widget_set_rgba;
757   iface->add_palette = gtk_color_chooser_widget_add_palette;
758 }
759
760 /* Public API {{{1 */
761
762 /**
763  * gtk_color_chooser_widget_new:
764  *
765  * Creates a new #GtkColorChooserWidget.
766  *
767  * Returns: a new #GtkColorChooserWidget
768  *
769  * Since: 3.4
770  */
771 GtkWidget *
772 gtk_color_chooser_widget_new (void)
773 {
774   return g_object_new (GTK_TYPE_COLOR_CHOOSER_WIDGET, NULL);
775 }
776
777 /* vim:set foldmethod=marker: */