2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2001-2018 Hiroyuki Yamamoto & The Claws Mail Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 /* (alfons) - based on a contribution by Satoshi Nagayasu; revised for colorful
20 * menu and more Sylpheed integration. The idea to put the code in a separate
21 * file is just that it make it easier to allow "user changeable" label colors.
28 #include <glib/gi18n.h>
30 #include <gdk/gdkkeysyms.h>
32 #include "colorlabel.h"
35 #include "prefs_common.h"
37 static gchar *labels[COLORLABELS] = {
55 #define CL(x) ((gdouble)x / 65535)
56 static GdkRGBA default_colors[COLORLABELS] = {
57 { CL(65535), CL(39168), CL(0), 1.0 },
58 { CL(65535), CL(0), CL(0), 1.0 },
59 { CL(65535), CL(26112), CL(65535), 1.0 },
60 { CL(0), CL(52224), CL(65535), 1.0 },
61 { CL(0), CL(0), CL(65535), 1.0 },
62 { CL(0), CL(39168), CL(0), 1.0 },
63 { CL(26112), CL(13056), CL(13056), 1.0 },
64 { CL(43520), CL(43520), CL(43520), 1.0 },
65 { CL(49152), CL(29184), CL(21504), 1.0 },
66 { CL(49152), CL(0), CL(0), 1.0 },
67 { CL(52224), CL(4096), CL(29696), 1.0 },
68 { CL(20480), CL(37888), CL(52480), 1.0 },
69 { CL(65535), CL(54528), CL(0), 1.0 },
70 { CL(0), CL(55296), CL(0), 1.0 },
71 { CL(49152), CL(24576), CL(49152), 1.0 }
75 typedef enum LabelColorChangeFlags_ {
78 LCCF_ALL = LCCF_COLOR | LCCF_LABEL
79 } LabelColorChangeFlags;
81 /* XXX: if you add colors, make sure you also check the procmsg.h.
82 * color indices are stored as 3 bits; that explains the max. of 7 colors */
85 LabelColorChangeFlags changed;
86 /* color here is initialized from default_colors[] at startup */
89 /* XXX: note that the label member is supposed to be dynamically
90 * allocated and freed */
93 } label_colors[NUM_MENUS][COLORLABELS] = {
95 { LCCF_ALL, { 0 }, NULL, NULL },
96 { LCCF_ALL, { 0 }, NULL, NULL },
97 { LCCF_ALL, { 0 }, NULL, NULL },
98 { LCCF_ALL, { 0 }, NULL, NULL },
99 { LCCF_ALL, { 0 }, NULL, NULL },
100 { LCCF_ALL, { 0 }, NULL, NULL },
101 { LCCF_ALL, { 0 }, NULL, NULL },
102 { LCCF_ALL, { 0 }, NULL, NULL },
103 { LCCF_ALL, { 0 }, NULL, NULL },
104 { LCCF_ALL, { 0 }, NULL, NULL },
105 { LCCF_ALL, { 0 }, NULL, NULL },
106 { LCCF_ALL, { 0 }, NULL, NULL },
107 { LCCF_ALL, { 0 }, NULL, NULL },
108 { LCCF_ALL, { 0 }, NULL, NULL },
109 { LCCF_ALL, { 0 }, NULL, NULL }},
111 { LCCF_ALL, { 0 }, NULL, NULL },
112 { LCCF_ALL, { 0 }, NULL, NULL },
113 { LCCF_ALL, { 0 }, NULL, NULL },
114 { LCCF_ALL, { 0 }, NULL, NULL },
115 { LCCF_ALL, { 0 }, NULL, NULL },
116 { LCCF_ALL, { 0 }, NULL, NULL },
117 { LCCF_ALL, { 0 }, NULL, NULL },
118 { LCCF_ALL, { 0 }, NULL, NULL },
119 { LCCF_ALL, { 0 }, NULL, NULL },
120 { LCCF_ALL, { 0 }, NULL, NULL },
121 { LCCF_ALL, { 0 }, NULL, NULL },
122 { LCCF_ALL, { 0 }, NULL, NULL },
123 { LCCF_ALL, { 0 }, NULL, NULL },
124 { LCCF_ALL, { 0 }, NULL, NULL },
125 { LCCF_ALL, { 0 }, NULL, NULL }}
128 #define LABEL_COLOR_WIDTH 28
129 #define LABEL_COLOR_HEIGHT 16
131 #define LABEL_COLORS_ELEMS (sizeof label_colors[0] / sizeof label_colors[0][0])
133 #define G_RETURN_VAL_IF_INVALID_COLOR(color, val) \
134 do if ((color) < 0 || (color) >= LABEL_COLORS_ELEMS) { \
138 static void colorlabel_recreate (gint);
139 static void colorlabel_recreate_label (gint);
141 void colorlabel_update_colortable_from_prefs(void)
145 for (i = 0; i < NUM_MENUS; i++) {
146 for (c = 0; c < COLORLABELS; c++) {
147 label_colors[i][c].color = prefs_common.custom_colorlabel[c].color;
148 g_free(label_colors[i][c].label);
149 label_colors[i][c].label =
150 g_strdup(prefs_common.custom_colorlabel[c].label);
156 gint colorlabel_get_color_count(void)
158 return LABEL_COLORS_ELEMS;
161 GdkRGBA colorlabel_get_color(gint color_index)
163 GdkRGBA invalid = { 0 };
165 G_RETURN_VAL_IF_INVALID_COLOR(color_index, invalid);
167 return label_colors[0][color_index].color;
170 GdkRGBA colorlabel_get_default_color(gint color_index)
172 GdkRGBA invalid = { 0 };
174 G_RETURN_VAL_IF_INVALID_COLOR(color_index, invalid);
176 return default_colors[color_index];
179 gchar *colorlabel_get_color_default_text(gint color_index)
181 G_RETURN_VAL_IF_INVALID_COLOR(color_index, NULL);
183 return labels[color_index];
186 static gboolean colorlabel_drawing_area_expose_event_cb
187 (GtkWidget *widget, cairo_t *cr, gpointer data)
189 GdkRGBA *color = (GdkRGBA *)data;
190 GtkAllocation allocation;
192 gtk_widget_get_allocation(widget, &allocation);
194 cairo_set_source_rgb(cr, 0., 0., 0.);
195 cairo_rectangle(cr, 0, 0,
196 allocation.width - 1,
197 allocation.height - 1);
200 gdk_cairo_set_source_rgba(cr, color);
201 cairo_rectangle(cr, 1, 1,
202 allocation.width - 2,
203 allocation.height - 2);
209 static GtkWidget *colorlabel_create_color_widget(GdkRGBA *color)
213 widget = gtk_drawing_area_new();
214 gtk_widget_set_size_request(widget, LABEL_COLOR_WIDTH - 2,
215 LABEL_COLOR_HEIGHT - 4);
217 g_signal_connect(G_OBJECT(widget), "draw",
218 G_CALLBACK(colorlabel_drawing_area_expose_event_cb),
224 static GdkPixbuf *colorlabel_create_colormenu_pixbuf(GdkRGBA *color)
229 cm_return_val_if_fail(color != NULL, NULL);
231 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
232 LABEL_COLOR_WIDTH - 2, LABEL_COLOR_HEIGHT - 4);
234 /* "pixel" needs to be set to 0xrrggbb00 */
235 pixel += (guint32)(color->red * 255) << 24;
236 pixel += (guint32)(color->green * 255) << 16;
237 pixel += (guint32)(color->blue * 255) << 8;
238 gdk_pixbuf_fill(pixbuf, pixel);
243 /* XXX: colorlabel_recreate_XXX are there to make sure everything
244 * is initialized ok, without having to call a global _xxx_init_
246 static void colorlabel_recreate_color(gint color)
251 for (i = 0; i < NUM_MENUS; i++) {
252 if (!(label_colors[i][color].changed & LCCF_COLOR))
255 widget = colorlabel_create_color_widget(&label_colors[i][color].color);
256 cm_return_if_fail(widget);
258 if (label_colors[i][color].widget)
259 gtk_widget_destroy(label_colors[i][color].widget);
261 label_colors[i][color].widget = widget;
262 label_colors[i][color].changed &= ~LCCF_COLOR;
266 static void colorlabel_recreate_label(gint color)
270 for (i = 0; i < NUM_MENUS; i++) {
271 if (!(label_colors[i][color].changed & LCCF_LABEL))
274 if (label_colors[i][color].label == NULL)
275 label_colors[i][color].label = g_strdup(gettext(labels[color]));
277 label_colors[i][color].changed &= ~LCCF_LABEL;
281 /* XXX: call this function everytime when you're doing important
282 * stuff with the label_colors[] array */
283 static void colorlabel_recreate(gint color)
285 colorlabel_recreate_label(color);
286 colorlabel_recreate_color(color);
289 static void colorlabel_recreate_all(void)
293 for ( n = 0; n < LABEL_COLORS_ELEMS; n++)
294 colorlabel_recreate(n);
297 /* colorlabel_create_check_color_menu_item() - creates a color
298 * menu item with a check box */
299 GtkWidget *colorlabel_create_check_color_menu_item(gint color_index, gboolean force, gint menu_index)
307 G_RETURN_VAL_IF_INVALID_COLOR(color_index, NULL);
309 item = gtk_check_menu_item_new();
312 label_colors[menu_index][color_index].changed |= LCCF_COLOR;
313 label_colors[menu_index][color_index].changed |= LCCF_LABEL;
315 colorlabel_recreate(color_index);
317 /* XXX: gnome-core::panel::menu.c is a great example of
318 * how to create pixmap menus */
319 label = gtk_label_new(label_colors[menu_index][color_index].label);
321 gtk_widget_show(label);
322 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
323 gtk_widget_show(hbox);
324 gtk_container_add(GTK_CONTAINER(item), hbox);
326 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
327 gtk_widget_show(vbox);
328 gtk_container_set_border_width(GTK_CONTAINER(vbox), 1);
330 gtk_container_add(GTK_CONTAINER(vbox),
331 label_colors[menu_index][color_index].widget);
332 gtk_widget_show(label_colors[menu_index][color_index].widget);
334 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
335 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
336 if (color_index < 9) {
337 accel = gtk_accelerator_get_label(GDK_KEY_1+color_index, GDK_CONTROL_MASK);
338 label = gtk_label_new(accel);
339 gtk_widget_show(label);
340 gtk_label_set_xalign(GTK_LABEL(label), 1.0);
342 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 4);
343 g_object_set_data(G_OBJECT(item), "accel_label", label);
345 label = gtk_label_new("");
346 gtk_widget_show(label);
347 gtk_label_set_xalign(GTK_LABEL(label), 1.0);
348 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 4);
349 g_object_set_data(G_OBJECT(item), "accel_label", label);
354 /* colorlabel_create_color_menu() - creates a color menu without
355 * checkitems, probably for use in combo items */
356 GtkWidget *colorlabel_create_color_menu(void)
363 colorlabel_recreate_all();
365 /* create the menu items. each item has its color code attached */
366 menu = gtk_menu_new();
367 g_object_set_data(G_OBJECT(menu), "label_color_menu", menu);
369 item = gtk_menu_item_new_with_label(_("None"));
370 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
371 g_object_set_data(G_OBJECT(item), "color", GUINT_TO_POINTER(0));
372 gtk_widget_show(item);
374 item = gtk_separator_menu_item_new();
375 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
376 gtk_widget_show(item);
378 /* and the color items */
379 for (i = 0; i < LABEL_COLORS_ELEMS; i++) {
384 item = gtk_menu_item_new();
385 g_object_set_data(G_OBJECT(item), "color",
386 GUINT_TO_POINTER(i + 1));
388 label = gtk_label_new(label_colors[0][i].label);
390 gtk_widget_show(label);
391 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
392 gtk_widget_show(hbox);
393 gtk_container_add(GTK_CONTAINER(item), hbox);
395 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
396 gtk_widget_show(vbox);
397 gtk_container_set_border_width(GTK_CONTAINER(vbox), 1);
399 widget = colorlabel_create_color_widget(&label_colors[0][i].color);
400 gtk_widget_show(widget);
401 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
403 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
404 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
406 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
407 gtk_widget_show(item);
410 gtk_widget_show(menu);
415 guint colorlabel_get_color_menu_active_item(GtkWidget *menu)
420 menuitem = gtk_menu_get_active(GTK_MENU(menu));
421 color = GPOINTER_TO_UINT
422 (g_object_get_data(G_OBJECT(menuitem), "color"));
426 static gboolean colormenu_separator_func(GtkTreeModel *model,
427 GtkTreeIter *iter, gpointer data)
431 gtk_tree_model_get(model, iter, COLORMENU_COL_TEXT, &txt, -1);
439 GtkWidget *colorlabel_create_combobox_colormenu()
443 GtkCellRenderer *renderer;
445 store = gtk_list_store_new(3,
449 combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
451 gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(combobox),
452 (GtkTreeViewRowSeparatorFunc)colormenu_separator_func,
455 renderer = gtk_cell_renderer_pixbuf_new();
456 gtk_cell_renderer_set_padding(renderer, 2, 0);
457 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox),
459 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox),
461 "pixbuf", COLORMENU_COL_PIXBUF,
464 renderer = gtk_cell_renderer_text_new();
465 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox),
467 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox),
469 "text", COLORMENU_COL_TEXT,
472 colorlabel_refill_combobox_colormenu(GTK_COMBO_BOX(combobox));
477 void colorlabel_refill_combobox_colormenu(GtkComboBox *combobox)
483 cm_return_if_fail(combobox != NULL);
485 store = GTK_LIST_STORE(gtk_combo_box_get_model(combobox));
487 cm_return_if_fail(store != NULL);
489 gtk_list_store_clear(store);
492 gtk_list_store_append(store, &iter);
493 gtk_list_store_set(store, &iter,
494 COLORMENU_COL_PIXBUF, NULL,
495 COLORMENU_COL_TEXT, _("None"),
496 COLORMENU_COL_ID, -1,
499 gtk_list_store_append(store, &iter);
500 gtk_list_store_set(store, &iter,
501 COLORMENU_COL_PIXBUF, NULL,
502 COLORMENU_COL_TEXT, NULL,
503 COLORMENU_COL_ID, -1,
506 /* Menu items for individual colors */
507 for (i = 0; i < LABEL_COLORS_ELEMS; i++) {
508 gtk_list_store_append(store, &iter);
509 gtk_list_store_set(store, &iter,
510 COLORMENU_COL_PIXBUF, colorlabel_create_colormenu_pixbuf(&label_colors[0][i].color),
511 COLORMENU_COL_TEXT, label_colors[0][i].label,
517 gint colorlabel_get_combobox_colormenu_active(GtkComboBox *combobox)
523 cm_return_val_if_fail(combobox != NULL, 0);
525 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combobox), &iter))
528 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox));
529 gtk_tree_model_get(model, &iter,
530 COLORMENU_COL_ID, &value,
536 void colorlabel_set_combobox_colormenu_active(GtkComboBox *combobox,
543 cm_return_if_fail(combobox != NULL);
545 model = gtk_combo_box_get_model(combobox);
546 cm_return_if_fail(model != NULL);
548 if (!gtk_tree_model_get_iter_first(model, &iter))
552 gtk_tree_model_get(model, &iter,
553 COLORMENU_COL_ID, &id,
558 } while (gtk_tree_model_iter_next(model, &iter));
560 gtk_combo_box_set_active_iter(combobox, &iter);