]> git.sur5r.net Git - glabels/blob - src/mygal/color-palette.c
Imported Upstream version 2.2.8
[glabels] / src / mygal / color-palette.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * color-palette.c - A color selector palette
4  * Copyright 2000, 2001, Ximian, Inc.
5  *
6  * Authors:
7  * This code was extracted from widget-color-combo.c
8  *   written by Miguel de Icaza (miguel@kernel.org) and
9  *   Dom Lachowicz (dominicl@seas.upenn.edu). The extracted
10  *   code was re-packaged into a separate object by
11  *   Michael Levy (mlevy@genoscope.cns.fr)
12  *   And later revised and polished by
13  *   Almer S. Tigelaar (almer@gnome.org)
14  *
15  * Modified for gLabels by:
16  *   Jim Evins <evins@snaught.com>
17  *
18  * This library is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public
20  * License, version 2, as published by the Free Software Foundation.
21  *
22  * This library is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
30  * 02111-1307, USA.
31  */
32
33 #include <config.h>
34 #include <gnome.h>
35 #include <gtk/gtklabel.h>
36 #include <gtk/gtksignal.h>
37 #include <gtk/gtktable.h>
38 #include <libgnomecanvas/gnome-canvas.h>
39 #include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
40 #include <gdk/gdkcolor.h>
41 #include "e-util.h"
42 #include "color-group.h"
43 #include "color-palette.h"
44 #include "e-colors.h"
45
46 #define COLOR_PREVIEW_WIDTH 15
47 #define COLOR_PREVIEW_HEIGHT 15
48
49 enum {
50         COLOR_CHANGED,
51         LAST_SIGNAL
52 };
53
54 struct _ColorNamePair {
55         char *color;    /* rgb color or otherwise - eg. "#FFFFFF" */
56         char *name;     /* english name - eg. "white" */
57 };
58
59 static guint color_palette_signals [LAST_SIGNAL] = { 0, };
60
61 #define PARENT_TYPE GTK_TYPE_VBOX
62 static GObjectClass *color_palette_parent_class;
63
64 #define make_color(P,COL) (((COL) != NULL) ? (COL) : ((P) ? ((P)->default_color) : NULL))
65
66 static void
67 color_palette_destroy (GtkObject *object)
68 {
69         ColorPalette *P = COLOR_PALETTE (object);
70         GtkObjectClass *klass = (GtkObjectClass *)color_palette_parent_class;
71
72         if (P->tool_tip) {
73                 g_object_unref (P->tool_tip);
74                 P->tool_tip = NULL;
75         }
76
77         if (P->current_color) {
78                 gdk_color_free (P->current_color);
79                 P->current_color = NULL;
80         }
81         
82         color_palette_set_group (P, NULL);
83
84         memset (P->items, 0, P->total * sizeof (GnomeCanvasItem *));
85
86         if (klass->destroy)
87                 klass->destroy (object);
88 }
89
90 static void
91 color_palette_finalize (GObject *object)
92 {
93         ColorPalette *P = COLOR_PALETTE (object);
94
95         g_free (P->items);
96
97         (*color_palette_parent_class->finalize) (object);
98 }
99
100 static void
101 color_palette_class_init (GObjectClass *object_class)
102 {
103         object_class->finalize = color_palette_finalize;
104         ((GtkObjectClass *)object_class)->destroy = color_palette_destroy;
105
106         color_palette_parent_class = g_type_class_peek_parent (object_class);
107
108         color_palette_signals [COLOR_CHANGED] =
109                 g_signal_new ("color_changed",
110                               G_OBJECT_CLASS_TYPE (object_class),
111                               G_SIGNAL_RUN_LAST,
112                               G_STRUCT_OFFSET (ColorPaletteClass, color_changed),
113                               NULL, NULL,
114                               e_marshal_NONE__POINTER_BOOLEAN_BOOLEAN_BOOLEAN,
115                               G_TYPE_NONE, 4, G_TYPE_POINTER,
116                               G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
117 }
118
119 E_MAKE_TYPE (color_palette,
120              "ColorPalette",
121              ColorPalette,
122              color_palette_class_init,
123              NULL,
124              PARENT_TYPE)
125
126 static void
127 emit_color_changed (ColorPalette *P, GdkColor *color,
128                     gboolean custom, gboolean by_user, gboolean is_default)
129 {
130         GdkColor *new = make_color (P, color);
131
132         if (new != NULL)
133                 new = gdk_color_copy (new);
134         if (P->current_color)
135                 gdk_color_free (P->current_color);
136         P->current_color = new;
137         P->current_is_default = is_default;
138
139         /* Only add custom colors to the group */
140         if (custom && color)
141                 color_group_add_color (P->color_group, color);
142         
143         g_signal_emit (P, color_palette_signals [COLOR_CHANGED], 0,
144                        color, custom, by_user, is_default);
145 }
146
147
148 /*
149  * Add the new custom color as the first custom color in the custom color rows
150  * and shift all of the others 'one step down'
151  *
152  * Also take care of setting up the GtkColorButton 'display'
153  */
154 static void
155 color_palette_change_custom_color (ColorPalette *P, GdkColor const * const new)
156 {
157         int index;
158         GnomeCanvasItem *item;
159         GnomeCanvasItem *next_item;
160
161         g_return_if_fail (P != NULL);
162         g_return_if_fail (new != NULL);
163         g_return_if_fail (P->picker);
164
165         /* make sure there is room */
166         if (P->custom_color_pos == -1)
167                 return;
168
169         for (index = P->custom_color_pos; index < P->total - 1; index++) {
170                 GdkColor *color;
171                 GdkColor *outline;
172                 item = P->items[index];
173                 next_item = P->items[index + 1];
174
175                 g_object_get (G_OBJECT (next_item),
176                         "fill_color_gdk",       &color,
177                         "outline_color_gdk",    &outline,
178                         NULL);
179                 gnome_canvas_item_set (item,
180                         "fill_color_gdk",       color,
181                         "outline_color_gdk",    outline,
182                         NULL);
183                 gdk_color_free (color);
184                 gdk_color_free (outline);
185         }
186         item = P->items[index];
187         gnome_canvas_item_set (item,
188                                "fill_color_gdk", new,
189                                "outline_color_gdk", new,
190                                NULL);
191         gtk_color_button_set_color (P->picker, new);
192 }
193
194 /*
195  * The custom color box was clicked. Find out its value and emit it
196  * And add it to the custom color row
197  */
198 static void
199 cust_color_set (GtkWidget  *color_picker, ColorPalette *P)
200 {
201         GdkColor c_color;
202
203         gtk_color_button_get_color (GTK_COLOR_BUTTON (color_picker), &c_color);
204
205         e_color_alloc_gdk (NULL, &c_color);
206         emit_color_changed (P, &c_color, TRUE, TRUE, FALSE);
207 }
208
209 static void
210 cb_default_clicked (GtkWidget *button, ColorPalette *P)
211 {
212         emit_color_changed (P, P->default_color, FALSE, TRUE, TRUE);
213 }
214
215 /*
216  * Something in our table was clicked. Find out what and emit it
217  */
218 static void
219 color_clicked (GtkWidget *button, ColorPalette *P)
220 {
221         int              index;
222         GnomeCanvasItem *item;
223         GdkColor        *gdk_color;
224
225         index = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (button)));
226         item  = P->items[index];
227
228         g_object_get (item,
229                       "fill_color_gdk", &gdk_color,
230                       NULL);
231
232         emit_color_changed (P, gdk_color, FALSE, TRUE, FALSE);
233
234         gdk_color_free (gdk_color);
235 }
236
237 /*
238  * The color group sent the 'custom_color_add' signal
239  */
240 static void
241 cb_group_custom_color_add (GtkObject *cg, GdkColor *color, ColorPalette *P)
242 {
243         GdkColor *new;
244         
245         new = make_color (P, color);
246         color_palette_change_custom_color (P, new);
247 }
248
249 /*
250  * Find out if a color is in the default palette (not in the custom colors!)
251  *
252  * Utility function
253  */
254 static gboolean
255 color_in_palette (ColorNamePair *set, GdkColor *color)
256 {
257         int i;
258
259         g_return_val_if_fail (set != NULL, FALSE);
260        
261         if (color == NULL)
262                 return TRUE;
263                 
264         /* Iterator over all the colors and try to find
265          * if we can find @color
266          */
267         for (i = 0; set[i].color != NULL; i++) {
268                 GdkColor current;
269                 
270                 gdk_color_parse (set[i].color, &current);
271                 
272                 if (gdk_color_equal (color, &current))
273                         return TRUE;
274         }
275
276         return FALSE;
277 }
278
279 /*
280  * Create the individual color buttons
281  *
282  * Utility function
283  */
284 static GnomeCanvasItem *
285 color_palette_button_new(ColorPalette *P, GtkTable* table,
286                          GtkTooltips *tool_tip, ColorNamePair* color_name,
287                          gint col, gint row, int data)
288 {
289         GtkWidget *button;
290         GtkWidget *canvas;
291         GnomeCanvasItem *item;
292
293         button = gtk_button_new ();
294         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
295
296         canvas = gnome_canvas_new ();
297
298         gtk_widget_set_usize (canvas, COLOR_PREVIEW_WIDTH, COLOR_PREVIEW_HEIGHT);
299         gtk_container_add (GTK_CONTAINER (button), canvas);
300
301         item  = gnome_canvas_item_new (GNOME_CANVAS_GROUP (gnome_canvas_root
302                                                            (GNOME_CANVAS (canvas))),
303                                        gnome_canvas_rect_get_type (),
304                                        "x1", 0.0,
305                                        "y1", 0.0,
306                                        "x2", (double) COLOR_PREVIEW_WIDTH,
307                                        "y2", (double) COLOR_PREVIEW_HEIGHT,
308                                        "fill_color", color_name->color,
309                                        NULL);
310
311         gtk_tooltips_set_tip (tool_tip, button, _(color_name->name),
312                               "Private+Unused");
313
314         gtk_table_attach (table, button,
315                           col, col+1, row, row+1, GTK_FILL, GTK_FILL, 1, 1);
316
317         g_signal_connect (button, "clicked",
318                           G_CALLBACK (color_clicked), P);
319         gtk_object_set_user_data (GTK_OBJECT (button),
320                                   GINT_TO_POINTER (data));
321         return item;
322 }
323
324 static void
325 cb_custom_colors (GdkColor const * const color, gpointer data)
326 {
327         ColorPalette *P = data;
328         
329         if (color)
330                 color_palette_change_custom_color (P, color);
331 }
332
333 /*
334  * gets history information from the group
335  */
336 static void
337 custom_color_history_setup(ColorPalette *P)
338 {
339         g_return_if_fail (P != NULL);
340         g_return_if_fail (P->color_group != NULL);
341
342         /* Sync our own palette with all the custom colors in the group */
343         color_group_get_custom_colors (P->color_group, (CbCustomColors) cb_custom_colors, P);
344 }
345
346 /*
347  * Creates the color table
348  */
349 static GtkWidget *
350 color_palette_setup (ColorPalette *P,
351                      char const * const no_color_label,
352                      int ncols, int nrows,
353                      ColorNamePair *color_names)
354 {
355         GtkWidget *default_button;
356         GtkWidget *cust_label;
357         GtkWidget *table;
358         GtkTooltips *tool_tip;
359         int total, row, col;
360
361         table = gtk_table_new (ncols, nrows, FALSE);
362
363         if (no_color_label != NULL) {
364                 default_button = gtk_button_new_with_label (no_color_label);
365
366                 gtk_table_attach (GTK_TABLE (table), default_button,
367                                   0, ncols, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
368                 g_signal_connect (default_button, "clicked",
369                                   G_CALLBACK (cb_default_clicked), P);
370         }
371
372         P->tool_tip = tool_tip = gtk_tooltips_new ();
373         g_object_ref (P->tool_tip);
374         gtk_object_sink (GTK_OBJECT (P->tool_tip));
375
376         P->custom_color_pos = -1;
377         total = 0;
378
379         for (row = 0; row < nrows; row++) {
380                 for (col = 0; col < ncols; col++) {
381                         int pos;
382
383                         pos = row * ncols + col;
384                         /*
385                          * If we are done with all of the colors in color_names
386                          */
387                         if (color_names [pos].color == NULL) {
388                                 /* This is the default custom color */
389                                 ColorNamePair color_name  = {"#000", N_("custom")};
390                                 row++;
391                                 if (col == 0 || row < nrows) {
392                                         /* Add a full row for custom colors */
393                                         for (col = 0; col < ncols; col++) {
394                                                 /* Have we set custom pos yet ? */
395                                                 if (P->custom_color_pos == -1) {
396                                                         P->custom_color_pos = total;
397                                                 }
398                                                 P->items[total] =
399                                                         color_palette_button_new(
400                                                                 P,
401                                                                 GTK_TABLE (table),
402                                                                 GTK_TOOLTIPS (tool_tip),
403                                                                 &(color_name),
404                                                                 col,
405                                                                 row + 1,
406                                                                 total);
407                                                 total++;
408                                         }
409                                 }
410                                 /* Break out of two for-loops.  */
411                                 row = nrows;
412                                 break;
413                         }
414
415                         P->items[total] =
416                                 color_palette_button_new (
417                                         P,
418                                         GTK_TABLE (table),
419                                         GTK_TOOLTIPS (tool_tip),
420                                         &(color_names [pos]),
421                                         col,
422                                         row + 1,
423                                         total);
424                         total++;
425                 }
426         }
427         P->total = total;
428
429
430         /* "Custom" color - we'll pop up a GtkColorButton */
431         cust_label = gtk_label_new (_("Custom Color:"));
432         gtk_table_attach (GTK_TABLE (table), cust_label, 0, ncols - 3 ,
433                           row + 1, row + 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
434         /*
435           Keep a pointer to the picker so that we can update it's color
436           to keep it in synch with that of other members of the group
437         */
438         P->picker = GTK_COLOR_BUTTON (gtk_color_button_new ());
439         gtk_color_button_set_title (P->picker, _("Choose Custom Color"));
440         gtk_table_attach (GTK_TABLE (table), GTK_WIDGET (P->picker), ncols - 3, ncols,
441                           row + 1, row + 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
442         g_signal_connect (P->picker, "color-set",
443                           G_CALLBACK (cust_color_set), P);
444         return table;
445 }
446
447 void
448 color_palette_set_color_to_default (ColorPalette *P)
449 {
450         g_return_if_fail (P != NULL);
451         g_return_if_fail (IS_COLOR_GROUP (P->color_group));
452
453         emit_color_changed (P, P->default_color, FALSE, TRUE, TRUE);
454 }
455
456 void
457 color_palette_set_current_color (ColorPalette *P, GdkColor *color)
458 {
459         g_return_if_fail (P != NULL);
460         g_return_if_fail (IS_COLOR_GROUP (P->color_group));
461
462         if (color)
463                 emit_color_changed
464                         (P, color, color_in_palette (P->default_set, color),
465                          FALSE, FALSE);
466         else
467                 color_palette_set_color_to_default (P);
468 }
469
470 GdkColor *
471 color_palette_get_current_color (ColorPalette *P, gboolean *is_default)
472 {
473         g_return_val_if_fail (P != NULL, NULL);
474         g_return_val_if_fail (IS_COLOR_GROUP (P->color_group), NULL);
475
476         if (is_default != NULL)
477                 *is_default = P->current_is_default;
478
479         return P->current_color ? gdk_color_copy (P->current_color) : NULL;
480 }
481
482 GtkWidget *
483 color_palette_get_color_picker (ColorPalette *P)
484 {
485         g_return_val_if_fail (IS_COLOR_PALETTE (P), NULL);
486
487         return GTK_WIDGET (P->picker);
488 }
489
490
491 /*
492  * Where the actual construction goes on
493  */
494 static void
495 color_palette_construct (ColorPalette *P,
496                          char const * const no_color_label,
497                          int ncols, int nrows)
498 {
499         GtkWidget * table;
500         g_return_if_fail (P != NULL);
501         g_return_if_fail (IS_COLOR_PALETTE (P));
502
503         P->items = g_malloc (sizeof (GnomeCanvasItem *) * ncols * nrows);
504
505         /*
506          * Our table selector
507          */
508         table = color_palette_setup (P, no_color_label, ncols,
509                                      nrows, P->default_set);
510         gtk_container_add (GTK_CONTAINER(P), table);
511 }
512
513 /*
514  * More verbose constructor. Allows for specifying the rows, columns, and
515  * Colors this palette will contain
516  *
517  * Note that if after placing all of the color_names there remains an entire
518  * row available then a row of custum colors (initialized to black) is added
519  *
520  */
521 static GtkWidget*
522 color_palette_new_with_vals (char const * const no_color_label,
523                              int ncols, int nrows, ColorNamePair *color_names,
524                              GdkColor *default_color,
525                              ColorGroup *cg)
526 {
527         ColorPalette *P;
528
529         g_return_val_if_fail (color_names != NULL, NULL);
530
531         P = g_object_new (COLOR_PALETTE_TYPE, NULL);
532
533         P->default_set   = color_names;
534         P->default_color = default_color;
535         P->current_color = default_color ? gdk_color_copy (default_color) : NULL;
536         P->current_is_default = TRUE;
537         color_palette_set_group (P, cg);
538
539         color_palette_construct (P, no_color_label, ncols, nrows);
540         custom_color_history_setup(P);
541
542         return GTK_WIDGET (P);
543 }
544
545 /**
546  * color_palette_set_group : absorbs the reference to the group
547  */
548 void
549 color_palette_set_group (ColorPalette *P, ColorGroup *cg)
550 {
551         if (P->color_group == cg)
552                 return;
553
554         if (P->color_group) {
555                 g_signal_handlers_disconnect_by_func (
556                         G_OBJECT (P->color_group),
557                         G_CALLBACK (cb_group_custom_color_add),
558                         P);
559                 g_object_unref (G_OBJECT (P->color_group));
560                 P->color_group = NULL;
561         }
562         if (cg != NULL) {
563                 P->color_group = COLOR_GROUP (cg);
564                 g_signal_connect (G_OBJECT (cg), "custom_color_add",
565                         G_CALLBACK (cb_group_custom_color_add),
566                         P);
567
568         }
569 }
570
571 static ColorNamePair default_color_set [] = {
572         {"#000000", N_("black")},
573         {"#993300", N_("light brown")},
574         {"#333300", N_("brown gold")},
575         {"#003300", N_("dark green #2")},
576         {"#003366", N_("navy")},
577         {"#000080", N_("dark blue")},
578         {"#333399", N_("purple #2")},
579         {"#333333", N_("very dark gray")},
580
581
582         {"#800000", N_("dark red")},
583         {"#FF6600", N_("red-orange")},
584         {"#808000", N_("gold")},
585         {"#008000", N_("dark green")},
586         {"#008080", N_("dull blue")},
587         {"#0000FF", N_("blue")},
588         {"#666699", N_("dull purple")},
589         {"#808080", N_("dark grey")},
590
591
592         {"#FF0000", N_("red")},
593         {"#FF9900", N_("orange")},
594         {"#99CC00", N_("lime")},
595         {"#339966", N_("dull green")},
596         {"#33CCCC",N_("dull blue #2")},
597         {"#3366FF", N_("sky blue #2")},
598         {"#800080", N_("purple")},
599         {"#969696", N_("gray")},
600
601
602         {"#FF00FF", N_("magenta")},
603         {"#FFCC00", N_("bright orange")},
604         {"#FFFF00", N_("yellow")},
605         {"#00FF00", N_("green")},
606         {"#00FFFF", N_("cyan")},
607         {"#00CCFF", N_("bright blue")},
608         {"#993366", N_("red purple")},
609         {"#C0C0C0", N_("light grey")},
610
611
612         {"#FF99CC", N_("pink")},
613         {"#FFCC99", N_("light orange")},
614         {"#FFFF99", N_("light yellow")},
615         {"#CCFFCC", N_("light green")},
616         {"#CCFFFF", N_("light cyan")},
617         {"#99CCFF", N_("light blue")},
618         {"#CC99FF", N_("light purple")},
619         {"#FFFFFF", N_("white")},
620
621         /* Disable these for now, they are mostly repeats */
622         {NULL, NULL},
623
624         {"#9999FF", N_("purplish blue")},
625         {"#993366", N_("red purple")},
626         {"#FFFFCC", N_("light yellow")},
627         {"#CCFFFF", N_("light blue")},
628         {"#660066", N_("dark purple")},
629         {"#FF8080", N_("pink")},
630         {"#0066CC", N_("sky blue")},
631         {"#CCCCFF", N_("light purple")},
632
633         {"#000080", N_("dark blue")},
634         {"#FF00FF", N_("magenta")},
635         {"#FFFF00", N_("yellow")},
636         {"#00FFFF", N_("cyan")},
637         {"#800080", N_("purple")},
638         {"#800000", N_("dark red")},
639         {"#008080", N_("dull blue")},
640         {"#0000FF", N_("blue")},
641
642         {NULL, NULL}
643 };
644
645
646
647 /*
648  * Default constructor. Pass an optional label for
649  * the no/auto color button.
650  *
651  */
652 GtkWidget*
653 color_palette_new (const char *no_color_label,
654                    GdkColor *default_color, ColorGroup *color_group)
655 {
656         /* specify 6 rows to allow for a row of custom colors */
657         return color_palette_new_with_vals (no_color_label,
658                                             8, 6,
659                                             default_color_set, default_color,
660                                             color_group);
661 }