]> Pileus Git - ~andy/gtk/blob - gtk/gtkcolorchooserwidget.c
Mark strings for translation
[~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 "gtkcoloreditor.h"
26 #include "gtkcolorswatch.h"
27 #include "gtkbox.h"
28 #include "gtkgrid.h"
29 #include "gtkhsv.h"
30 #include "gtklabel.h"
31 #include "gtkorientable.h"
32 #include "gtkprivate.h"
33 #include "gtkintl.h"
34 #include "gtksizegroup.h"
35 #include "gtkalignment.h"
36
37 struct _GtkColorChooserWidgetPrivate
38 {
39   GtkWidget *palette;
40   GtkWidget *editor;
41
42   GtkWidget *colors;
43   GtkWidget *grays;
44   GtkWidget *custom;
45
46   GtkWidget *button;
47   GtkColorSwatch *current;
48   gboolean show_alpha;
49
50   GtkSizeGroup *size_group;
51
52   GSettings *settings;
53 };
54
55 enum
56 {
57   PROP_ZERO,
58   PROP_COLOR,
59   PROP_SHOW_ALPHA,
60   PROP_SHOW_EDITOR
61 };
62
63 static void gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface);
64
65 G_DEFINE_TYPE_WITH_CODE (GtkColorChooserWidget, gtk_color_chooser_widget, GTK_TYPE_BOX,
66                          G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
67                                                 gtk_color_chooser_widget_iface_init))
68
69 static void
70 select_swatch (GtkColorChooserWidget *cc,
71                GtkColorSwatch        *swatch)
72 {
73   GdkRGBA color;
74
75   if (cc->priv->current == swatch)
76     return;
77   if (cc->priv->current != NULL)
78     gtk_color_swatch_set_selected (cc->priv->current, FALSE);
79   gtk_color_swatch_set_selected (swatch, TRUE);
80   cc->priv->current = swatch;
81   gtk_color_swatch_get_color (swatch, &color);
82   g_settings_set (cc->priv->settings, "selected-color", "(bdddd)",
83                   TRUE, color.red, color.green, color.blue, color.alpha);
84
85   g_object_notify (G_OBJECT (cc), "color");
86 }
87
88 static void save_custom_colors (GtkColorChooserWidget *cc);
89
90 static void
91 button_activate (GtkColorSwatch        *swatch,
92                  GtkColorChooserWidget *cc)
93 {
94   GdkRGBA color;
95
96   color.red = 0.75;
97   color.green = 0.25;
98   color.blue = 0.25;
99   color.alpha = 1.0;
100
101   gtk_color_chooser_set_color (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
102
103   gtk_widget_hide (cc->priv->palette);
104   gtk_widget_show (cc->priv->editor);
105 }
106
107 static void
108 swatch_activate (GtkColorSwatch        *swatch,
109                  GtkColorChooserWidget *cc)
110 {
111   GdkRGBA color;
112
113   gtk_color_swatch_get_color (swatch, &color);
114   _gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
115 }
116
117 static void
118 swatch_customize (GtkColorSwatch        *swatch,
119                   GtkColorChooserWidget *cc)
120 {
121   GdkRGBA color;
122
123   gtk_color_swatch_get_color (swatch, &color);
124   gtk_color_chooser_set_color (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
125
126   gtk_widget_hide (cc->priv->palette);
127   gtk_widget_show (cc->priv->editor);
128 }
129
130 static void
131 swatch_selected (GtkColorSwatch        *swatch,
132                  GParamSpec            *pspec,
133                  GtkColorChooserWidget *cc)
134 {
135   select_swatch (cc, swatch);
136 }
137
138 static void
139 connect_swatch_signals (GtkWidget *p, gpointer data)
140 {
141   g_signal_connect (p, "activate", G_CALLBACK (swatch_activate), data);
142   g_signal_connect (p, "customize", G_CALLBACK (swatch_customize), data);
143   g_signal_connect (p, "notify::selected", G_CALLBACK (swatch_selected), data);
144 }
145
146 static void
147 connect_button_signals (GtkWidget *p, gpointer data)
148 {
149   g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
150 }
151
152 static void
153 connect_custom_signals (GtkWidget *p, gpointer data)
154 {
155   connect_swatch_signals (p, data);
156   g_signal_connect_swapped (p, "notify::color",
157                             G_CALLBACK (save_custom_colors), data);
158 }
159
160 static void
161 save_custom_colors (GtkColorChooserWidget *cc)
162 {
163   GVariantBuilder builder;
164   GVariant *variant;
165   GdkRGBA color;
166   GtkWidget *child;
167   gint i;
168
169   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dddd)"));
170
171   i = 1;
172   while ((child = gtk_grid_get_child_at (GTK_GRID (cc->priv->custom), i, 0)) != NULL)
173     {
174       i++;
175       if (gtk_color_swatch_get_color (GTK_COLOR_SWATCH (child), &color))
176         {
177           g_variant_builder_add (&builder, "(dddd)",
178                                  color.red, color.green, color.blue, color.alpha);
179        }
180     }
181
182   variant = g_variant_builder_end (&builder);
183   g_settings_set_value (cc->priv->settings, "custom-colors", variant);
184 }
185
186 static void
187 gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
188 {
189   GtkWidget *grid;
190   GtkWidget *p;
191   GtkWidget *alignment;
192   GtkWidget *button;
193   GtkWidget *label;
194   gint i, j;
195   gint left;
196   GdkRGBA color;
197   GVariant *variant;
198   GVariantIter iter;
199   gboolean selected;
200   const gchar *default_palette[9][3] = {
201     { "#ef2929", "#cc0000", "#a40000" }, /* Scarlet Red */
202     { "#fcaf3e", "#f57900", "#ce5c00" }, /* Orange */
203     { "#fce94f", "#edd400", "#c4a000" }, /* Butter */
204     { "#8ae234", "#73d216", "#4e9a06" }, /* Chameleon */
205     { "#729fcf", "#3465a4", "#204a87" }, /* Sky Blue */
206     { "#ad7fa8", "#75507b", "#5c3566" }, /* Plum */
207     { "#e9b96e", "#c17d11", "#8f5902" }, /* Chocolate */
208     { "#888a85", "#555753", "#2e3436" }, /* Aluminum 1 */
209     { "#eeeeec", "#d3d7cf", "#babdb6" }  /* Aluminum 2 */
210   };
211   const gchar *default_grayscale[9] = {
212     "#000000",
213     "#2e3436",
214     "#555753",
215     "#888a85",
216     "#babdb6",
217     "#d3d7cf",
218     "#eeeeec",
219     "#f3f3f3",
220     "#ffffff"
221   };
222
223   cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc, GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetPrivate);
224
225   gtk_orientable_set_orientation (GTK_ORIENTABLE (cc), GTK_ORIENTATION_VERTICAL);
226   cc->priv->palette = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
227   gtk_container_add (GTK_CONTAINER (cc), cc->priv->palette);
228
229   cc->priv->colors = grid = gtk_grid_new ();
230   gtk_widget_set_margin_bottom (grid, 12);
231   gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
232   gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
233   gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);
234
235   for (i = 0; i < 9; i++)
236     {
237       for (j = 0; j < 3; j++)
238         {
239           gdk_rgba_parse (&color, default_palette[i][j]);
240
241           p = gtk_color_swatch_new ();
242           connect_swatch_signals (p, cc);
243
244           if (j == 0)
245             gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 10, 10, 1, 1);
246           else if (j == 2)
247             gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 1, 10, 10);
248           else
249             gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 1, 1, 1);
250
251           gtk_color_swatch_set_color (GTK_COLOR_SWATCH (p), &color);
252           gtk_grid_attach (GTK_GRID (grid), p, i, j, 1, 1);
253         }
254     }
255
256   cc->priv->grays = grid = gtk_grid_new ();
257   g_object_set (grid, "margin-bottom", 18, NULL);
258   gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
259   gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);
260
261   left = (gtk_widget_get_direction (GTK_WIDGET (cc)) == GTK_TEXT_DIR_LTR) ? 0 : 8;
262
263   for (i = 0; i < 9; i++)
264     {
265        gdk_rgba_parse (&color, default_grayscale[i]);
266        color.alpha = 1.0;
267
268        p = gtk_color_swatch_new ();
269        connect_swatch_signals (p, cc);
270        if (i == left)
271          gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 10, 1, 1, 10);
272        else if (i == (8 - left))
273          gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 10, 10, 1);
274        else
275          gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 1, 1, 1);
276
277        gtk_color_swatch_set_color (GTK_COLOR_SWATCH (p), &color);
278        gtk_grid_attach (GTK_GRID (grid), p, i, 0, 1, 1);
279     }
280
281   /* translators: label for the custom section in the color chooser */
282   label = gtk_label_new (_("Custom"));
283   gtk_widget_set_halign (label, GTK_ALIGN_START);
284   gtk_container_add (GTK_CONTAINER (cc->priv->palette), label);
285
286   cc->priv->custom = grid = gtk_grid_new ();
287   g_object_set (grid, "margin-top", 12, NULL);
288   gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
289   gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);
290
291   cc->priv->button = button = gtk_color_swatch_new ();
292   gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (button), 10, 10, 10, 10);
293   connect_button_signals (button, cc);
294   gtk_color_swatch_set_icon (GTK_COLOR_SWATCH (button), "list-add-symbolic");
295   gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);
296
297   cc->priv->settings = g_settings_new_with_path ("org.gtk.Settings.ColorChooser",
298                                                  "/org/gtk/settings/color-chooser/");
299   variant = g_settings_get_value (cc->priv->settings, "custom-colors");
300   g_variant_iter_init (&iter, variant);
301   i = 0;
302   while (g_variant_iter_loop (&iter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha))
303     {
304       i++;
305       p = gtk_color_swatch_new ();
306       gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 1, 1, 1);
307       gtk_color_swatch_set_color (GTK_COLOR_SWATCH (p), &color);
308       gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
309       connect_custom_signals (p, cc);
310       gtk_grid_attach (GTK_GRID (grid), p, i, 0, 1, 1);
311
312       if (i == 8)
313         break;
314     }
315   g_variant_unref (variant);
316
317   if (i > 0)
318     {
319       if (gtk_widget_get_direction (GTK_WIDGET (cc)) == GTK_TEXT_DIR_LTR)
320         {
321           gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 10, 10, 1);
322           gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (button), 10, 1, 1, 10);
323         }
324       else
325         {
326           gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (button), 1, 10, 10, 1);
327           gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 10, 1, 1, 10);
328         }
329     }
330
331   cc->priv->editor = gtk_color_editor_new ();
332   alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
333   gtk_container_add (GTK_CONTAINER (cc), alignment);
334   gtk_container_add (GTK_CONTAINER (alignment), cc->priv->editor);
335
336   g_settings_get (cc->priv->settings, "selected-color", "(bdddd)",
337                   &selected,
338                   &color.red, &color.green, &color.blue, &color.alpha);
339   if (selected)
340     gtk_color_chooser_set_color (GTK_COLOR_CHOOSER (cc), &color);
341
342   gtk_widget_show_all (GTK_WIDGET (cc));
343   gtk_widget_hide (GTK_WIDGET (cc->priv->editor));
344   gtk_widget_hide (GTK_WIDGET (cc));
345
346   gtk_widget_set_no_show_all (cc->priv->palette, TRUE);
347   gtk_widget_set_no_show_all (cc->priv->editor, TRUE);
348
349   cc->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
350   gtk_size_group_add_widget (cc->priv->size_group, cc->priv->palette);
351   gtk_size_group_add_widget (cc->priv->size_group, alignment);
352 }
353
354 static void
355 gtk_color_chooser_widget_get_property (GObject    *object,
356                                        guint       prop_id,
357                                        GValue     *value,
358                                        GParamSpec *pspec)
359 {
360   GtkColorChooserWidget *cw = GTK_COLOR_CHOOSER_WIDGET (object);
361   GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
362
363   switch (prop_id)
364     {
365     case PROP_COLOR:
366       {
367         GdkRGBA color;
368
369         gtk_color_chooser_get_color (cc, &color);
370         g_value_set_boxed (value, &color);
371       }
372       break;
373     case PROP_SHOW_ALPHA:
374       g_value_set_boolean (value, cw->priv->show_alpha);
375       break;
376     case PROP_SHOW_EDITOR:
377       g_value_set_boolean (value, gtk_widget_get_visible (cw->priv->editor));
378       break;
379     default:
380       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
381       break;
382     }
383 }
384
385 static void
386 gtk_color_chooser_widget_set_show_alpha (GtkColorChooserWidget *cc,
387                                          gboolean               show_alpha)
388 {
389   GtkWidget *grids[3];
390   gint i;
391   GList *children, *l;
392   GtkWidget *swatch;
393
394   cc->priv->show_alpha = show_alpha;
395   gtk_color_chooser_set_show_alpha (GTK_COLOR_CHOOSER (cc->priv->editor), show_alpha);
396
397   grids[0] = cc->priv->colors;
398   grids[1] = cc->priv->grays;
399   grids[2] = cc->priv->custom;
400
401   for (i = 0; i < 3; i++)
402     {
403       children = gtk_container_get_children (GTK_CONTAINER (grids[i]));
404       for (l = children; l; l = l->next)
405         {
406           swatch = l->data;
407           gtk_color_swatch_set_show_alpha (GTK_COLOR_SWATCH (swatch), show_alpha);
408         }
409       g_list_free (children);
410     }
411
412   gtk_widget_queue_draw (GTK_WIDGET (cc));
413 }
414
415 static void
416 gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
417                                           gboolean               show_editor)
418 {
419   gtk_widget_set_visible (cc->priv->editor, show_editor);
420   gtk_widget_set_visible (cc->priv->palette, !show_editor);
421 }
422
423 static void
424 gtk_color_chooser_widget_set_property (GObject      *object,
425                                        guint         prop_id,
426                                        const GValue *value,
427                                        GParamSpec   *pspec)
428 {
429   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
430
431   switch (prop_id)
432     {
433     case PROP_COLOR:
434       gtk_color_chooser_set_color (GTK_COLOR_CHOOSER (cc),
435                                    g_value_get_boxed (value));
436       break;
437     case PROP_SHOW_ALPHA:
438       gtk_color_chooser_widget_set_show_alpha (cc,
439                                                g_value_get_boolean (value));
440       break;
441     case PROP_SHOW_EDITOR:
442       gtk_color_chooser_widget_set_show_editor (cc,
443                                                 g_value_get_boolean (value));
444       break;
445     default:
446       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
447       break;
448     }
449 }
450
451 static void
452 gtk_color_chooser_widget_finalize (GObject *object)
453 {
454   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
455
456   g_object_unref (cc->priv->size_group);
457   g_object_unref (cc->priv->settings);
458
459   G_OBJECT_CLASS (gtk_color_chooser_widget_parent_class)->finalize (object);
460 }
461
462 static void
463 gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
464 {
465   GObjectClass *object_class = G_OBJECT_CLASS (class);
466
467   object_class->get_property = gtk_color_chooser_widget_get_property;
468   object_class->set_property = gtk_color_chooser_widget_set_property;
469   object_class->finalize = gtk_color_chooser_widget_finalize;
470
471   g_object_class_override_property (object_class, PROP_COLOR, "color");
472   g_object_class_override_property (object_class, PROP_SHOW_ALPHA, "show-alpha");
473
474   g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
475       g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
476                             FALSE, GTK_PARAM_READWRITE));
477
478   g_type_class_add_private (object_class, sizeof (GtkColorChooserWidgetPrivate));
479 }
480
481 static void
482 gtk_color_chooser_widget_get_color (GtkColorChooser *chooser,
483                                     GdkRGBA         *color)
484 {
485   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
486
487   if (gtk_widget_get_visible (cc->priv->editor))
488     gtk_color_chooser_get_color (GTK_COLOR_CHOOSER (cc->priv->editor), color);
489   else if (cc->priv->current)
490     gtk_color_swatch_get_color (cc->priv->current, color);
491   else
492     {
493       color->red = 1.0;
494       color->green = 1.0;
495       color->blue = 1.0;
496       color->alpha = 1.0;
497     }
498
499   if (!cc->priv->show_alpha)
500     color->alpha = 1.0;
501 }
502
503 static void
504 add_custom_color (GtkColorChooserWidget *cc,
505                   const GdkRGBA         *color)
506 {
507   GtkWidget *last;
508   GtkWidget *p;
509
510   last = gtk_grid_get_child_at (GTK_GRID (cc->priv->custom), 8, 0);
511   if (last)
512     {
513       gtk_container_remove (GTK_CONTAINER (cc->priv->custom), last);
514       last = gtk_grid_get_child_at (GTK_GRID (cc->priv->custom), 7, 0);
515       gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (last), 1, 10, 10, 1);
516     }
517
518   gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (cc->priv->button), 10, 1, 1, 10);
519
520   p = gtk_color_swatch_new ();
521   gtk_color_swatch_set_color (GTK_COLOR_SWATCH (p), color);
522   gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
523   connect_custom_signals (p, cc);
524
525   if (gtk_grid_get_child_at (GTK_GRID (cc->priv->custom), 1, 0) != NULL)
526     gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 1, 1, 1);
527   else
528     gtk_color_swatch_set_corner_radii (GTK_COLOR_SWATCH (p), 1, 10, 10, 1);
529
530   gtk_grid_insert_next_to (GTK_GRID (cc->priv->custom), cc->priv->button, GTK_POS_RIGHT);
531   gtk_grid_attach (GTK_GRID (cc->priv->custom), p, 1, 0, 1, 1);
532   gtk_widget_show (p);
533
534   select_swatch (cc, GTK_COLOR_SWATCH (p));
535   save_custom_colors (cc);
536 }
537
538 static void
539 gtk_color_chooser_widget_set_color (GtkColorChooser *chooser,
540                                     const GdkRGBA   *color)
541 {
542   GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
543   GList *children, *l;
544   GtkColorSwatch *swatch;
545   GdkRGBA c;
546   GtkWidget *grids[3];
547   gint i;
548
549   grids[0] = cc->priv->colors;
550   grids[1] = cc->priv->grays;
551   grids[2] = cc->priv->custom;
552
553   for (i = 0; i < 3; i++)
554     {
555       children = gtk_container_get_children (GTK_CONTAINER (grids[i]));
556       for (l = children; l; l = l->next)
557         {
558           swatch = l->data;
559           gtk_color_swatch_get_color (swatch, &c);
560           if (!cc->priv->show_alpha)
561             c.alpha = color->alpha;
562           if (gdk_rgba_equal (color, &c))
563             {
564               select_swatch (cc, swatch);
565               g_list_free (children);
566               return;
567             }
568         }
569       g_list_free (children);
570     }
571
572   add_custom_color (cc, color);
573 }
574
575 static void
576 gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface)
577 {
578   iface->get_color = gtk_color_chooser_widget_get_color;
579   iface->set_color = gtk_color_chooser_widget_set_color;
580 }
581
582 GtkWidget *
583 gtk_color_chooser_widget_new (void)
584 {
585   return g_object_new (GTK_TYPE_COLOR_CHOOSER_WIDGET, NULL);
586 }