1 /* e-color-combo.c
2 *
3 * Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program 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 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include "evolution-config.h"
21
22 #include "e-color-combo.h"
23 #include "e-color-chooser-widget.h"
24
25 #include <glib/gi18n-lib.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <cairo/cairo.h>
28
29 #define E_COLOR_COMBO_GET_PRIVATE(obj) \
30 (G_TYPE_INSTANCE_GET_PRIVATE \
31 ((obj), E_TYPE_COLOR_COMBO, EColorComboPrivate))
32
33 struct _EColorComboPrivate {
34 GtkWidget *color_frame; /* not referenced */
35 GtkWidget *arrow; /* not referenced */
36
37 GtkWidget *popover;
38 GtkWidget *default_button; /* not referenced */
39 GtkWidget *chooser_widget; /* not referenced */
40
41 guint popup_shown : 1;
42 guint popup_in_progress : 1;
43
44 guint default_transparent: 1;
45 GdkRGBA *current_color;
46 GdkRGBA *default_color;
47
48 GList *palette;
49 };
50
51 enum {
52 PROP_0,
53 PROP_CURRENT_COLOR,
54 PROP_DEFAULT_COLOR,
55 PROP_DEFAULT_LABEL,
56 PROP_DEFAULT_TRANSPARENT,
57 PROP_PALETTE,
58 PROP_POPUP_SHOWN
59 };
60
61 enum {
62 ACTIVATED,
63 POPUP,
64 POPDOWN,
65 LAST_SIGNAL
66 };
67
68 static guint signals[LAST_SIGNAL];
69 static GdkRGBA black = { 0, 0, 0, 1 };
70
71 G_DEFINE_TYPE (
72 EColorCombo,
73 e_color_combo,
74 GTK_TYPE_BUTTON);
75
76 static void
color_combo_popup(EColorCombo * combo)77 color_combo_popup (EColorCombo *combo)
78 {
79 if (!gtk_widget_get_realized (GTK_WIDGET (combo)))
80 return;
81
82 if (combo->priv->popup_shown)
83 return;
84
85 /* Always make sure the editor-mode is OFF */
86 g_object_set (
87 G_OBJECT (combo->priv->chooser_widget),
88 "show-editor", FALSE, NULL);
89
90 /* Show the pop-up. */
91 gtk_widget_show_all (combo->priv->popover);
92 gtk_widget_grab_focus (combo->priv->chooser_widget);
93 }
94
95 static void
color_combo_popdown(EColorCombo * combo)96 color_combo_popdown (EColorCombo *combo)
97 {
98 if (!gtk_widget_get_realized (GTK_WIDGET (combo)))
99 return;
100
101 if (!combo->priv->popup_shown)
102 return;
103
104 gtk_widget_hide (combo->priv->popover);
105 }
106
107 static gboolean
color_combo_window_button_press_event_cb(EColorCombo * combo,GdkEvent * event,gpointer user_data)108 color_combo_window_button_press_event_cb (EColorCombo *combo,
109 GdkEvent *event,
110 gpointer user_data)
111 {
112 GtkWidget *event_widget;
113
114 event_widget = gtk_get_event_widget ((GdkEvent *) event);
115
116 if (event_widget == combo->priv->popover)
117 return TRUE;
118
119 if (combo->priv->popup_shown)
120 return FALSE;
121
122 combo->priv->popup_in_progress = TRUE;
123 color_combo_popup (combo);
124
125 return TRUE;
126 }
127
128 static gboolean
color_combo_window_button_release_event_cb(EColorCombo * combo,GdkEvent * event,gpointer user_data)129 color_combo_window_button_release_event_cb (EColorCombo *combo,
130 GdkEvent *event,
131 gpointer user_data)
132 {
133 gboolean popup_in_progress;
134
135 popup_in_progress = combo->priv->popup_in_progress;
136 combo->priv->popup_in_progress = FALSE;
137
138 if (popup_in_progress)
139 return FALSE;
140
141 if (combo->priv->popup_shown)
142 goto popdown;
143
144 return FALSE;
145
146 popdown:
147 color_combo_popdown (combo);
148
149 return TRUE;
150 }
151
152 static void
color_combo_child_show_cb(EColorCombo * combo)153 color_combo_child_show_cb (EColorCombo *combo)
154 {
155 combo->priv->popup_shown = TRUE;
156 g_object_notify (G_OBJECT (combo), "popup-shown");
157 }
158
159 static void
color_combo_child_hide_cb(EColorCombo * combo)160 color_combo_child_hide_cb (EColorCombo *combo)
161 {
162 combo->priv->popup_shown = FALSE;
163 g_object_notify (G_OBJECT (combo), "popup-shown");
164 }
165
166 static void
color_combo_get_preferred_width(GtkWidget * widget,gint * min_width,gint * natural_width)167 color_combo_get_preferred_width (GtkWidget *widget,
168 gint *min_width,
169 gint *natural_width)
170 {
171 GtkWidgetClass *widget_class;
172
173 widget_class = GTK_WIDGET_CLASS (e_color_combo_parent_class);
174 widget_class->get_preferred_width (widget, min_width, natural_width);
175
176 /* Make sure the box with color sample is always visible */
177 if (min_width)
178 *min_width += 20;
179
180 if (natural_width)
181 *natural_width += 20;
182 }
183
184 static gboolean
color_combo_button_press_event_cb(GtkWidget * widget,GdkEventButton * event)185 color_combo_button_press_event_cb (GtkWidget *widget,
186 GdkEventButton *event)
187 {
188 EColorCombo *combo = E_COLOR_COMBO (widget);
189 GdkWindow *window;
190 gint x, y, width, height;
191
192 window = gtk_widget_get_window (combo->priv->color_frame);
193 gdk_window_get_position (window, &x, &y);
194 /* Width - only width of the frame with color box */
195 width = gtk_widget_get_allocated_width (combo->priv->color_frame);
196
197 /* Height - height of the entire button (widget) */
198 height = gtk_widget_get_allocated_height (widget);
199
200 /* Check whether user clicked on the color frame - in such case
201 * apply the color immediatelly without displaying the popup widget */
202 if ((event->x_root >= x) && (event->x_root <= x + width) &&
203 (event->y_root >= y) && (event->y_root <= y + height)) {
204 GdkRGBA color;
205
206 e_color_combo_get_current_color (combo, &color);
207 g_signal_emit (combo, signals[ACTIVATED], 0, &color);
208
209 return TRUE;
210 }
211
212 /* Otherwise display the popup widget */
213 if (combo->priv->popup_shown) {
214 color_combo_popdown (combo);
215 } else {
216 combo->priv->popup_in_progress = TRUE;
217 color_combo_popup (combo);
218 }
219
220 return FALSE;
221 }
222
223 static void
color_combo_swatch_color_changed(EColorCombo * combo,GdkRGBA * color,gpointer user_data)224 color_combo_swatch_color_changed (EColorCombo *combo,
225 GdkRGBA *color,
226 gpointer user_data)
227 {
228 g_signal_emit (combo, signals[ACTIVATED], 0, color);
229
230 e_color_combo_set_current_color (combo, color);
231
232 color_combo_popdown (combo);
233 }
234
235 static void
draw_transparent_graphic(cairo_t * cr,gint width,gint height)236 draw_transparent_graphic (cairo_t *cr,
237 gint width,
238 gint height)
239 {
240 gint ii, step, x_offset, y_offset;
241
242 step = height / 2;
243 x_offset = width % step;
244 y_offset = height % step;
245
246 for (ii = 0; ii < width; ii += step) {
247 if (ii % 2)
248 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
249 else
250 cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
251
252 if (ii + step >= width)
253 cairo_rectangle (cr, ii, 0, step + x_offset, step);
254 else
255 cairo_rectangle (cr, ii, 0, step, step);
256
257 cairo_fill (cr);
258
259 if (ii % 2)
260 cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
261 else
262 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
263
264 if (ii + step >= width)
265 cairo_rectangle (cr, ii, step, step + x_offset, step + y_offset);
266 else
267 cairo_rectangle (cr, ii, step, step, step + y_offset);
268
269 cairo_fill (cr);
270 }
271 }
272
273 static void
color_combo_draw_frame_cb(GtkWidget * widget,cairo_t * cr,gpointer user_data)274 color_combo_draw_frame_cb (GtkWidget *widget,
275 cairo_t *cr,
276 gpointer user_data)
277 {
278 EColorCombo *combo = user_data;
279 GdkRGBA rgba;
280 GtkAllocation allocation;
281 gint height, width;
282
283 e_color_combo_get_current_color (combo, &rgba);
284
285 gtk_widget_get_allocation (widget, &allocation);
286 width = allocation.width;
287 height = allocation.height;
288
289 if (rgba.alpha == 0) {
290 draw_transparent_graphic (cr, width, height);
291 } else {
292 cairo_set_source_rgba (cr, rgba.red, rgba.green, rgba.blue, rgba.alpha);
293 cairo_rectangle (cr, 0, 0, width, height);
294 cairo_fill (cr);
295 }
296 }
297
298 static void
color_combo_set_default_color_cb(EColorCombo * combo,gpointer user_data)299 color_combo_set_default_color_cb (EColorCombo *combo,
300 gpointer user_data)
301 {
302 GdkRGBA color;
303
304 e_color_combo_get_default_color (combo, &color);
305 e_color_combo_set_current_color (combo, &color);
306
307 g_signal_emit (combo, signals[ACTIVATED], 0, &color);
308 }
309
310 static void
color_combo_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)311 color_combo_set_property (GObject *object,
312 guint property_id,
313 const GValue *value,
314 GParamSpec *pspec)
315 {
316 switch (property_id) {
317 case PROP_CURRENT_COLOR:
318 e_color_combo_set_current_color (
319 E_COLOR_COMBO (object),
320 g_value_get_boxed (value));
321 return;
322
323 case PROP_DEFAULT_COLOR:
324 e_color_combo_set_default_color (
325 E_COLOR_COMBO (object),
326 g_value_get_boxed (value));
327 return;
328
329 case PROP_DEFAULT_LABEL:
330 e_color_combo_set_default_label (
331 E_COLOR_COMBO (object),
332 g_value_get_string (value));
333 return;
334
335 case PROP_DEFAULT_TRANSPARENT:
336 e_color_combo_set_default_transparent (
337 E_COLOR_COMBO (object),
338 g_value_get_boolean (value));
339 return;
340
341 case PROP_PALETTE:
342 e_color_combo_set_palette (
343 E_COLOR_COMBO (object),
344 g_value_get_object (value));
345 return;
346
347 case PROP_POPUP_SHOWN:
348 if (g_value_get_boolean (value))
349 e_color_combo_popup (
350 E_COLOR_COMBO (object));
351 else
352 e_color_combo_popdown (
353 E_COLOR_COMBO (object));
354 return;
355 }
356
357 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
358 }
359
360 static void
color_combo_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)361 color_combo_get_property (GObject *object,
362 guint property_id,
363 GValue *value,
364 GParamSpec *pspec)
365 {
366 EColorComboPrivate *priv;
367 GdkRGBA color;
368
369 priv = E_COLOR_COMBO_GET_PRIVATE (object);
370
371 switch (property_id) {
372 case PROP_CURRENT_COLOR:
373 e_color_combo_get_current_color (
374 E_COLOR_COMBO (object), &color);
375 g_value_set_boxed (value, &color);
376 return;
377
378 case PROP_DEFAULT_COLOR:
379 e_color_combo_get_default_color (
380 E_COLOR_COMBO (object), &color);
381 g_value_set_boxed (value, &color);
382 return;
383
384 case PROP_DEFAULT_LABEL:
385 g_value_set_string (
386 value, e_color_combo_get_default_label (
387 E_COLOR_COMBO (object)));
388 return;
389
390 case PROP_DEFAULT_TRANSPARENT:
391 g_value_set_boolean (
392 value,
393 e_color_combo_get_default_transparent (
394 E_COLOR_COMBO (object)));
395 return;
396
397 case PROP_PALETTE:
398 g_value_set_object (
399 value, e_color_combo_get_palette (
400 E_COLOR_COMBO (object)));
401 return;
402
403 case PROP_POPUP_SHOWN:
404 g_value_set_boolean (value, priv->popup_shown);
405 return;
406 }
407
408 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
409 }
410
411 static void
color_combo_dispose(GObject * object)412 color_combo_dispose (GObject *object)
413 {
414 EColorComboPrivate *priv;
415
416 priv = E_COLOR_COMBO_GET_PRIVATE (object);
417 g_clear_pointer (&priv->popover, gtk_widget_destroy);
418 g_clear_pointer (&priv->current_color, gdk_rgba_free);
419 g_clear_pointer (&priv->default_color, gdk_rgba_free);
420
421 g_list_free_full (priv->palette, (GDestroyNotify) gdk_rgba_free);
422 priv->palette = NULL;
423
424 /* Chain up to parent's dispose() method. */
425 G_OBJECT_CLASS (e_color_combo_parent_class)->dispose (object);
426 }
427
428 static void
e_color_combo_class_init(EColorComboClass * class)429 e_color_combo_class_init (EColorComboClass *class)
430 {
431 GObjectClass *object_class;
432 GtkWidgetClass *widget_class;
433
434 g_type_class_add_private (class, sizeof (EColorComboPrivate));
435
436 object_class = G_OBJECT_CLASS (class);
437 object_class->set_property = color_combo_set_property;
438 object_class->get_property = color_combo_get_property;
439 object_class->dispose = color_combo_dispose;
440
441 widget_class = GTK_WIDGET_CLASS (class);
442 widget_class->get_preferred_width = color_combo_get_preferred_width;
443 widget_class->button_press_event = color_combo_button_press_event_cb;
444
445 class->popup = color_combo_popup;
446 class->popdown = color_combo_popdown;
447
448 g_object_class_install_property (
449 object_class,
450 PROP_CURRENT_COLOR,
451 g_param_spec_boxed (
452 "current-color",
453 "Current color",
454 "The currently selected color",
455 GDK_TYPE_RGBA,
456 G_PARAM_READWRITE));
457
458 g_object_class_install_property (
459 object_class,
460 PROP_DEFAULT_COLOR,
461 g_param_spec_boxed (
462 "default-color",
463 "Default color",
464 "The color associated with the default button",
465 GDK_TYPE_RGBA,
466 G_PARAM_CONSTRUCT |
467 G_PARAM_READWRITE));
468
469 g_object_class_install_property (
470 object_class,
471 PROP_DEFAULT_LABEL,
472 g_param_spec_string (
473 "default-label",
474 "Default label",
475 "The label for the default button",
476 _("Default"),
477 G_PARAM_CONSTRUCT |
478 G_PARAM_READWRITE));
479
480 g_object_class_install_property (
481 object_class,
482 PROP_DEFAULT_TRANSPARENT,
483 g_param_spec_boolean (
484 "default-transparent",
485 "Default is transparent",
486 "Whether the default color is transparent",
487 FALSE,
488 G_PARAM_CONSTRUCT |
489 G_PARAM_READWRITE));
490
491 g_object_class_install_property (
492 object_class,
493 PROP_PALETTE,
494 g_param_spec_pointer (
495 "palette",
496 "Color palette",
497 "Custom color palette",
498 G_PARAM_READWRITE));
499
500 g_object_class_install_property (
501 object_class,
502 PROP_POPUP_SHOWN,
503 g_param_spec_boolean (
504 "popup-shown",
505 "Popup shown",
506 "Whether the combo's dropdown is shown",
507 FALSE,
508 G_PARAM_READWRITE));
509
510 signals[ACTIVATED] = g_signal_new (
511 "activated",
512 G_OBJECT_CLASS_TYPE (class),
513 G_SIGNAL_RUN_LAST,
514 G_STRUCT_OFFSET (EColorComboClass, activated),
515 NULL, NULL,
516 g_cclosure_marshal_VOID__VOID,
517 G_TYPE_NONE, 0);
518
519 signals[POPUP] = g_signal_new (
520 "popup",
521 G_OBJECT_CLASS_TYPE (class),
522 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
523 G_STRUCT_OFFSET (EColorComboClass, popup),
524 NULL, NULL,
525 g_cclosure_marshal_VOID__VOID,
526 G_TYPE_NONE, 0);
527
528 signals[POPDOWN] = g_signal_new (
529 "popdown",
530 G_OBJECT_CLASS_TYPE (class),
531 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
532 G_STRUCT_OFFSET (EColorComboClass, popdown),
533 NULL, NULL,
534 g_cclosure_marshal_VOID__VOID,
535 G_TYPE_NONE, 0);
536
537 gtk_binding_entry_add_signal (
538 gtk_binding_set_by_class (class),
539 GDK_KEY_Down, GDK_MOD1_MASK, "popup", 0);
540 gtk_binding_entry_add_signal (
541 gtk_binding_set_by_class (class),
542 GDK_KEY_KP_Down, GDK_MOD1_MASK, "popup", 0);
543
544 gtk_binding_entry_add_signal (
545 gtk_binding_set_by_class (class),
546 GDK_KEY_Up, GDK_MOD1_MASK, "popdown", 0);
547 gtk_binding_entry_add_signal (
548 gtk_binding_set_by_class (class),
549 GDK_KEY_KP_Up, GDK_MOD1_MASK, "popdown", 0);
550 gtk_binding_entry_add_signal (
551 gtk_binding_set_by_class (class),
552 GDK_KEY_Escape, 0, "popdown", 0);
553 }
554
555 static void
e_color_combo_init(EColorCombo * combo)556 e_color_combo_init (EColorCombo *combo)
557 {
558 struct {
559 const gchar *color;
560 const gchar *tooltip;
561 GdkRGBA rgba;
562 } default_colors[] = {
563
564 { "#000000", N_("black"), { 0, } },
565 { "#993300", N_("light brown"), { 0, } },
566 { "#333300", N_("brown gold"), { 0, } },
567 { "#003300", N_("dark green #2"), { 0, } },
568 { "#003366", N_("navy"), { 0, } },
569 { "#000080", N_("dark blue"), { 0, } },
570 { "#333399", N_("purple #2"), { 0, } },
571 { "#333333", N_("very dark gray"), { 0, } },
572
573 { "#800000", N_("dark red"), { 0, } },
574 { "#FF6600", N_("red-orange"), { 0, } },
575 { "#808000", N_("gold"), { 0, } },
576 { "#008000", N_("dark green"), { 0, } },
577 { "#008080", N_("dull blue"), { 0, } },
578 { "#0000FF", N_("blue"), { 0, } },
579 { "#666699", N_("dull purple"), { 0, } },
580 { "#808080", N_("dark grey"), { 0, } },
581
582 { "#FF0000", N_("red"), { 0, } },
583 { "#FF9900", N_("orange"), { 0, } },
584 { "#99CC00", N_("lime"), { 0, } },
585 { "#339966", N_("dull green"), { 0, } },
586 { "#33CCCC", N_("dull blue #2"), { 0, } },
587 { "#3366FF", N_("sky blue #2"), { 0, } },
588 { "#800080", N_("purple"), { 0, } },
589 { "#969696", N_("gray"), { 0, } },
590
591 { "#FF00FF", N_("magenta"), { 0, } },
592 { "#FFCC00", N_("bright orange"), { 0, } },
593 { "#FFFF00", N_("yellow"), { 0, } },
594 { "#00FF00", N_("green"), { 0, } },
595 { "#00FFFF", N_("cyan"), { 0, } },
596 { "#00CCFF", N_("bright blue"), { 0, } },
597 { "#993366", N_("red purple"), { 0, } },
598 { "#C0C0C0", N_("light grey"), { 0, } },
599
600 { "#FF99CC", N_("pink"), { 0, } },
601 { "#FFCC99", N_("light orange"), { 0, } },
602 { "#FFFF99", N_("light yellow"), { 0, } },
603 { "#CCFFCC", N_("light green"), { 0, } },
604 { "#CCFFFF", N_("light cyan"), { 0, } },
605 { "#99CCFF", N_("light blue"), { 0, } },
606 { "#CC99FF", N_("light purple"), { 0, } },
607 { "#FFFFFF", N_("white"), { 0, } }
608 };
609 GtkWidget *container;
610 GtkWidget *widget;
611 GList *palette;
612 gint ii;
613
614 combo->priv = E_COLOR_COMBO_GET_PRIVATE (combo);
615
616 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
617 gtk_container_add (GTK_CONTAINER (combo), widget);
618
619 container = widget;
620
621 /* Build the combo button. */
622 widget = gtk_frame_new (NULL);
623 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
624 g_signal_connect (
625 widget, "draw",
626 G_CALLBACK (color_combo_draw_frame_cb), combo);
627 combo->priv->color_frame = widget; /* do not reference */
628
629 widget = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
630 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
631
632 widget = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
633 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
634 combo->priv->arrow = widget; /* do not reference */
635
636 gtk_widget_show_all (container);
637
638 /* Build the drop-down menu */
639 widget = gtk_popover_new (GTK_WIDGET (combo));
640 gtk_popover_set_position (GTK_POPOVER (widget), GTK_POS_BOTTOM);
641 gtk_popover_set_modal (GTK_POPOVER (widget), TRUE);
642 combo->priv->popover = g_object_ref_sink (widget);
643
644 g_signal_connect_swapped (
645 widget, "show",
646 G_CALLBACK (color_combo_child_show_cb), combo);
647 g_signal_connect_swapped (
648 widget, "hide",
649 G_CALLBACK (color_combo_child_hide_cb), combo);
650 g_signal_connect_swapped (
651 widget, "button-press-event",
652 G_CALLBACK (color_combo_window_button_press_event_cb), combo);
653 g_signal_connect_swapped (
654 widget, "button-release-event",
655 G_CALLBACK (color_combo_window_button_release_event_cb), combo);
656
657 container = widget;
658
659 widget = gtk_grid_new ();
660 gtk_grid_set_row_spacing (GTK_GRID (widget), 5);
661 gtk_container_add (GTK_CONTAINER (container), widget);
662
663 container = widget;
664
665 widget = gtk_button_new ();
666 gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
667 combo->priv->default_button = widget; /* do not reference */
668
669 g_signal_connect_swapped (
670 widget, "clicked",
671 G_CALLBACK (color_combo_set_default_color_cb), combo);
672 g_signal_connect_swapped (
673 widget, "clicked",
674 G_CALLBACK (color_combo_popdown), combo);
675
676 widget = e_color_chooser_widget_new ();
677 g_object_set_data (G_OBJECT (widget), "window", combo->priv->popover);
678 gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1);
679 combo->priv->chooser_widget = widget; /* do not reference */
680
681 g_signal_connect_swapped (
682 widget, "color-activated",
683 G_CALLBACK (color_combo_swatch_color_changed), combo);
684 g_signal_connect_swapped (
685 widget, "editor-activated",
686 G_CALLBACK (color_combo_popdown), combo);
687
688 palette = NULL;
689 for (ii = G_N_ELEMENTS (default_colors) - 1; ii >= 0 ; ii--) {
690 gdk_rgba_parse (&(default_colors[ii].rgba), default_colors[ii].color);
691
692 palette = g_list_prepend (palette, &(default_colors[ii].rgba));
693 }
694 e_color_combo_set_palette (combo, palette);
695 g_list_free (palette);
696
697 combo->priv->current_color = gdk_rgba_copy (&black);
698 combo->priv->default_color = gdk_rgba_copy (&black);
699 }
700
701 GtkWidget *
e_color_combo_new(void)702 e_color_combo_new (void)
703 {
704 return g_object_new (E_TYPE_COLOR_COMBO, NULL);
705 }
706
707 GtkWidget *
e_color_combo_new_defaults(GdkRGBA * default_color,const gchar * default_label)708 e_color_combo_new_defaults (GdkRGBA *default_color,
709 const gchar *default_label)
710 {
711 g_return_val_if_fail (default_color != NULL, NULL);
712 g_return_val_if_fail (default_label != NULL, NULL);
713
714 return g_object_new (
715 E_TYPE_COLOR_COMBO,
716 "default-color", default_color,
717 "default-label", default_label,
718 NULL);
719 }
720
721 void
e_color_combo_popup(EColorCombo * combo)722 e_color_combo_popup (EColorCombo *combo)
723 {
724 g_return_if_fail (E_IS_COLOR_COMBO (combo));
725
726 g_signal_emit (combo, signals[POPUP], 0);
727 }
728
729 void
e_color_combo_popdown(EColorCombo * combo)730 e_color_combo_popdown (EColorCombo *combo)
731 {
732 g_return_if_fail (E_IS_COLOR_COMBO (combo));
733
734 g_signal_emit (combo, signals[POPDOWN], 0);
735 }
736
737 void
e_color_combo_get_current_color(EColorCombo * combo,GdkRGBA * color)738 e_color_combo_get_current_color (EColorCombo *combo,
739 GdkRGBA *color)
740 {
741 g_return_if_fail (E_IS_COLOR_COMBO (combo));
742 g_return_if_fail (color != NULL);
743
744 color->red = combo->priv->current_color->red;
745 color->green = combo->priv->current_color->green;
746 color->blue = combo->priv->current_color->blue;
747 color->alpha = combo->priv->current_color->alpha;
748 }
749
750 void
e_color_combo_set_current_color(EColorCombo * combo,const GdkRGBA * color)751 e_color_combo_set_current_color (EColorCombo *combo,
752 const GdkRGBA *color)
753 {
754 g_return_if_fail (E_IS_COLOR_COMBO (combo));
755
756 if (color == NULL)
757 color = &black;
758
759 if (combo->priv->current_color) {
760
761 if (gdk_rgba_equal (color, combo->priv->current_color)) {
762 return;
763 }
764
765 gdk_rgba_free (combo->priv->current_color);
766 }
767
768 combo->priv->current_color = gdk_rgba_copy (color);
769
770 gtk_color_chooser_set_rgba (
771 GTK_COLOR_CHOOSER (combo->priv->chooser_widget), color);
772 gtk_widget_queue_draw (combo->priv->color_frame);
773
774 g_object_notify (G_OBJECT (combo), "current-color");
775 }
776
777 void
e_color_combo_get_default_color(EColorCombo * combo,GdkRGBA * color)778 e_color_combo_get_default_color (EColorCombo *combo,
779 GdkRGBA *color)
780 {
781 g_return_if_fail (E_IS_COLOR_COMBO (combo));
782 g_return_if_fail (color != NULL);
783
784 color->red = combo->priv->default_color->red;
785 color->green = combo->priv->default_color->green;
786 color->blue = combo->priv->default_color->blue;
787 color->alpha = combo->priv->default_color->alpha;
788 }
789
790 void
e_color_combo_set_default_color(EColorCombo * combo,const GdkRGBA * color)791 e_color_combo_set_default_color (EColorCombo *combo,
792 const GdkRGBA *color)
793 {
794 g_return_if_fail (E_IS_COLOR_COMBO (combo));
795
796 if (color == NULL)
797 color = &black;
798
799 if (combo->priv->default_color) {
800 if (gdk_rgba_equal (color, combo->priv->default_color))
801 return;
802
803 gdk_rgba_free (combo->priv->default_color);
804 }
805 combo->priv->default_color = gdk_rgba_copy (color);
806
807 gtk_color_chooser_set_rgba (
808 GTK_COLOR_CHOOSER (combo->priv->chooser_widget), color);
809
810 g_object_notify (G_OBJECT (combo), "default-color");
811 }
812
813 const gchar *
e_color_combo_get_default_label(EColorCombo * combo)814 e_color_combo_get_default_label (EColorCombo *combo)
815 {
816 g_return_val_if_fail (E_IS_COLOR_COMBO (combo), NULL);
817
818 return gtk_button_get_label (GTK_BUTTON (combo->priv->default_button));
819 }
820
821 void
e_color_combo_set_default_label(EColorCombo * combo,const gchar * text)822 e_color_combo_set_default_label (EColorCombo *combo,
823 const gchar *text)
824 {
825 g_return_if_fail (E_IS_COLOR_COMBO (combo));
826
827 gtk_button_set_label (GTK_BUTTON (combo->priv->default_button), text);
828
829 g_object_notify (G_OBJECT (combo), "default-label");
830 }
831
832 gboolean
e_color_combo_get_default_transparent(EColorCombo * combo)833 e_color_combo_get_default_transparent (EColorCombo *combo)
834 {
835 g_return_val_if_fail (E_IS_COLOR_COMBO (combo), FALSE);
836
837 return combo->priv->default_transparent;
838 }
839
840 void
e_color_combo_set_default_transparent(EColorCombo * combo,gboolean transparent)841 e_color_combo_set_default_transparent (EColorCombo *combo,
842 gboolean transparent)
843 {
844 g_return_if_fail (E_IS_COLOR_COMBO (combo));
845
846 combo->priv->default_transparent = transparent;
847 if (transparent)
848 combo->priv->default_color->alpha = 0;
849
850 g_object_notify (G_OBJECT (combo), "default-transparent");
851 }
852
853 GList *
e_color_combo_get_palette(EColorCombo * combo)854 e_color_combo_get_palette (EColorCombo *combo)
855 {
856 g_return_val_if_fail (E_IS_COLOR_COMBO (combo), NULL);
857
858 return g_list_copy (combo->priv->palette);
859 }
860
861 void
e_color_combo_set_palette(EColorCombo * combo,GList * palette)862 e_color_combo_set_palette (EColorCombo *combo,
863 GList *palette)
864 {
865 gint ii, count, colors_per_line;
866 GList *iter;
867 GdkRGBA *colors;
868
869 g_return_if_fail (E_IS_COLOR_COMBO (combo));
870
871 count = g_list_length (palette);
872 colors_per_line = (count % 10 == 0) ? 10 : 9;
873
874 colors = g_malloc_n (count, sizeof (GdkRGBA));
875 g_list_free_full (combo->priv->palette, (GDestroyNotify) gdk_rgba_free);
876 ii = 0;
877 combo->priv->palette = NULL;
878 for (iter = palette; iter; iter = g_list_next (iter)) {
879 combo->priv->palette = g_list_prepend (
880 combo->priv->palette, gdk_rgba_copy (iter->data));
881
882 colors[ii] = *((GdkRGBA *) iter->data);
883 ii++;
884 }
885 combo->priv->palette = g_list_reverse (combo->priv->palette);
886
887 gtk_color_chooser_add_palette (
888 GTK_COLOR_CHOOSER (combo->priv->chooser_widget),
889 GTK_ORIENTATION_HORIZONTAL, 0, 0, NULL);
890 gtk_color_chooser_add_palette (
891 GTK_COLOR_CHOOSER (combo->priv->chooser_widget),
892 GTK_ORIENTATION_HORIZONTAL, colors_per_line, count, colors);
893 g_free (colors);
894 }
895