1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * color-palette.c - A color selector palette
4 * Copyright 2000, 2001, Ximian, Inc.
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)
15 * Modified for gLabels by:
16 * Jim Evins <evins@snaught.com>
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.
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.
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
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>
42 #include "color-group.h"
43 #include "color-palette.h"
46 #define COLOR_PREVIEW_WIDTH 15
47 #define COLOR_PREVIEW_HEIGHT 15
54 struct _ColorNamePair {
55 char *color; /* rgb color or otherwise - eg. "#FFFFFF" */
56 char *name; /* english name - eg. "white" */
59 static guint color_palette_signals [LAST_SIGNAL] = { 0, };
61 #define PARENT_TYPE GTK_TYPE_VBOX
62 static GObjectClass *color_palette_parent_class;
64 #define make_color(P,COL) (((COL) != NULL) ? (COL) : ((P) ? ((P)->default_color) : NULL))
67 color_palette_destroy (GtkObject *object)
69 ColorPalette *P = COLOR_PALETTE (object);
70 GtkObjectClass *klass = (GtkObjectClass *)color_palette_parent_class;
73 g_object_unref (P->tool_tip);
77 if (P->current_color) {
78 gdk_color_free (P->current_color);
79 P->current_color = NULL;
82 color_palette_set_group (P, NULL);
84 memset (P->items, 0, P->total * sizeof (GnomeCanvasItem *));
87 klass->destroy (object);
91 color_palette_finalize (GObject *object)
93 ColorPalette *P = COLOR_PALETTE (object);
97 (*color_palette_parent_class->finalize) (object);
101 color_palette_class_init (GObjectClass *object_class)
103 object_class->finalize = color_palette_finalize;
104 ((GtkObjectClass *)object_class)->destroy = color_palette_destroy;
106 color_palette_parent_class = g_type_class_peek_parent (object_class);
108 color_palette_signals [COLOR_CHANGED] =
109 g_signal_new ("color_changed",
110 G_OBJECT_CLASS_TYPE (object_class),
112 G_STRUCT_OFFSET (ColorPaletteClass, color_changed),
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);
119 E_MAKE_TYPE (color_palette,
122 color_palette_class_init,
127 emit_color_changed (ColorPalette *P, GdkColor *color,
128 gboolean custom, gboolean by_user, gboolean is_default)
130 GdkColor *new = make_color (P, color);
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;
139 /* Only add custom colors to the group */
141 color_group_add_color (P->color_group, color);
143 g_signal_emit (P, color_palette_signals [COLOR_CHANGED], 0,
144 color, custom, by_user, is_default);
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'
152 * Also take care of setting up the GtkColorButton 'display'
155 color_palette_change_custom_color (ColorPalette *P, GdkColor const * const new)
158 GnomeCanvasItem *item;
159 GnomeCanvasItem *next_item;
161 g_return_if_fail (P != NULL);
162 g_return_if_fail (new != NULL);
163 g_return_if_fail (P->picker);
165 /* make sure there is room */
166 if (P->custom_color_pos == -1)
169 for (index = P->custom_color_pos; index < P->total - 1; index++) {
172 item = P->items[index];
173 next_item = P->items[index + 1];
175 g_object_get (G_OBJECT (next_item),
176 "fill_color_gdk", &color,
177 "outline_color_gdk", &outline,
179 gnome_canvas_item_set (item,
180 "fill_color_gdk", color,
181 "outline_color_gdk", outline,
183 gdk_color_free (color);
184 gdk_color_free (outline);
186 item = P->items[index];
187 gnome_canvas_item_set (item,
188 "fill_color_gdk", new,
189 "outline_color_gdk", new,
191 gtk_color_button_set_color (P->picker, new);
195 * The custom color box was clicked. Find out its value and emit it
196 * And add it to the custom color row
199 cust_color_set (GtkWidget *color_picker, ColorPalette *P)
203 gtk_color_button_get_color (GTK_COLOR_BUTTON (color_picker), &c_color);
205 e_color_alloc_gdk (NULL, &c_color);
206 emit_color_changed (P, &c_color, TRUE, TRUE, FALSE);
210 cb_default_clicked (GtkWidget *button, ColorPalette *P)
212 emit_color_changed (P, P->default_color, FALSE, TRUE, TRUE);
216 * Something in our table was clicked. Find out what and emit it
219 color_clicked (GtkWidget *button, ColorPalette *P)
222 GnomeCanvasItem *item;
225 index = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (button)));
226 item = P->items[index];
229 "fill_color_gdk", &gdk_color,
232 emit_color_changed (P, gdk_color, FALSE, TRUE, FALSE);
234 gdk_color_free (gdk_color);
238 * The color group sent the 'custom_color_add' signal
241 cb_group_custom_color_add (GtkObject *cg, GdkColor *color, ColorPalette *P)
245 new = make_color (P, color);
246 color_palette_change_custom_color (P, new);
250 * Find out if a color is in the default palette (not in the custom colors!)
255 color_in_palette (ColorNamePair *set, GdkColor *color)
259 g_return_val_if_fail (set != NULL, FALSE);
264 /* Iterator over all the colors and try to find
265 * if we can find @color
267 for (i = 0; set[i].color != NULL; i++) {
270 gdk_color_parse (set[i].color, ¤t);
272 if (gdk_color_equal (color, ¤t))
280 * Create the individual color buttons
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)
291 GnomeCanvasItem *item;
293 button = gtk_button_new ();
294 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
296 canvas = gnome_canvas_new ();
298 gtk_widget_set_usize (canvas, COLOR_PREVIEW_WIDTH, COLOR_PREVIEW_HEIGHT);
299 gtk_container_add (GTK_CONTAINER (button), canvas);
301 item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (gnome_canvas_root
302 (GNOME_CANVAS (canvas))),
303 gnome_canvas_rect_get_type (),
306 "x2", (double) COLOR_PREVIEW_WIDTH,
307 "y2", (double) COLOR_PREVIEW_HEIGHT,
308 "fill_color", color_name->color,
311 gtk_tooltips_set_tip (tool_tip, button, _(color_name->name),
314 gtk_table_attach (table, button,
315 col, col+1, row, row+1, GTK_FILL, GTK_FILL, 1, 1);
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));
325 cb_custom_colors (GdkColor const * const color, gpointer data)
327 ColorPalette *P = data;
330 color_palette_change_custom_color (P, color);
334 * gets history information from the group
337 custom_color_history_setup(ColorPalette *P)
339 g_return_if_fail (P != NULL);
340 g_return_if_fail (P->color_group != NULL);
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);
347 * Creates the color table
350 color_palette_setup (ColorPalette *P,
351 char const * const no_color_label,
352 int ncols, int nrows,
353 ColorNamePair *color_names)
355 GtkWidget *default_button;
356 GtkWidget *cust_label;
358 GtkTooltips *tool_tip;
361 table = gtk_table_new (ncols, nrows, FALSE);
363 if (no_color_label != NULL) {
364 default_button = gtk_button_new_with_label (no_color_label);
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);
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));
376 P->custom_color_pos = -1;
379 for (row = 0; row < nrows; row++) {
380 for (col = 0; col < ncols; col++) {
383 pos = row * ncols + col;
385 * If we are done with all of the colors in color_names
387 if (color_names [pos].color == NULL) {
388 /* This is the default custom color */
389 ColorNamePair color_name = {"#000", N_("custom")};
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;
399 color_palette_button_new(
402 GTK_TOOLTIPS (tool_tip),
410 /* Break out of two for-loops. */
416 color_palette_button_new (
419 GTK_TOOLTIPS (tool_tip),
420 &(color_names [pos]),
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);
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
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);
448 color_palette_set_color_to_default (ColorPalette *P)
450 g_return_if_fail (P != NULL);
451 g_return_if_fail (IS_COLOR_GROUP (P->color_group));
453 emit_color_changed (P, P->default_color, FALSE, TRUE, TRUE);
457 color_palette_set_current_color (ColorPalette *P, GdkColor *color)
459 g_return_if_fail (P != NULL);
460 g_return_if_fail (IS_COLOR_GROUP (P->color_group));
464 (P, color, color_in_palette (P->default_set, color),
467 color_palette_set_color_to_default (P);
471 color_palette_get_current_color (ColorPalette *P, gboolean *is_default)
473 g_return_val_if_fail (P != NULL, NULL);
474 g_return_val_if_fail (IS_COLOR_GROUP (P->color_group), NULL);
476 if (is_default != NULL)
477 *is_default = P->current_is_default;
479 return P->current_color ? gdk_color_copy (P->current_color) : NULL;
483 color_palette_get_color_picker (ColorPalette *P)
485 g_return_val_if_fail (IS_COLOR_PALETTE (P), NULL);
487 return GTK_WIDGET (P->picker);
492 * Where the actual construction goes on
495 color_palette_construct (ColorPalette *P,
496 char const * const no_color_label,
497 int ncols, int nrows)
500 g_return_if_fail (P != NULL);
501 g_return_if_fail (IS_COLOR_PALETTE (P));
503 P->items = g_malloc (sizeof (GnomeCanvasItem *) * ncols * nrows);
508 table = color_palette_setup (P, no_color_label, ncols,
509 nrows, P->default_set);
510 gtk_container_add (GTK_CONTAINER(P), table);
514 * More verbose constructor. Allows for specifying the rows, columns, and
515 * Colors this palette will contain
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
522 color_palette_new_with_vals (char const * const no_color_label,
523 int ncols, int nrows, ColorNamePair *color_names,
524 GdkColor *default_color,
529 g_return_val_if_fail (color_names != NULL, NULL);
531 P = g_object_new (COLOR_PALETTE_TYPE, NULL);
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);
539 color_palette_construct (P, no_color_label, ncols, nrows);
540 custom_color_history_setup(P);
542 return GTK_WIDGET (P);
546 * color_palette_set_group : absorbs the reference to the group
549 color_palette_set_group (ColorPalette *P, ColorGroup *cg)
551 if (P->color_group == cg)
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),
559 g_object_unref (G_OBJECT (P->color_group));
560 P->color_group = 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),
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")},
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")},
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")},
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")},
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")},
621 /* Disable these for now, they are mostly repeats */
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")},
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")},
648 * Default constructor. Pass an optional label for
649 * the no/auto color button.
653 color_palette_new (const char *no_color_label,
654 GdkColor *default_color, ColorGroup *color_group)
656 /* specify 6 rows to allow for a row of custom colors */
657 return color_palette_new_with_vals (no_color_label,
659 default_color_set, default_color,