fix bug 4773, 'remove obsolescent AC_C_CONST'
[claws.git] / src / gtk / colorlabel.c
blob661b97fc1b13997bf7133ca99f02554aae1f6ecd
1 /*
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.
24 #include "config.h"
25 #include "defs.h"
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkkeysyms.h>
32 #include "colorlabel.h"
33 #include "utils.h"
34 #include "gtkutils.h"
35 #include "prefs_common.h"
37 static gchar *labels[COLORLABELS] = {
38 N_("Orange"),
39 N_("Red") ,
40 N_("Pink"),
41 N_("Sky blue"),
42 N_("Blue"),
43 N_("Green"),
44 N_("Brown"),
45 N_("Grey"),
46 N_("Light brown"),
47 N_("Dark red"),
48 N_("Dark pink"),
49 N_("Steel blue"),
50 N_("Gold"),
51 N_("Bright green"),
52 N_("Magenta")
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_ {
76 LCCF_COLOR = 1 << 0,
77 LCCF_LABEL = 1 << 1,
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 */
83 static struct
85 LabelColorChangeFlags changed;
86 /* color here is initialized from default_colors[] at startup */
87 GdkRGBA color;
89 /* XXX: note that the label member is supposed to be dynamically
90 * allocated and freed */
91 gchar *label;
92 GtkWidget *widget;
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) { \
135 return val; \
136 } while(0)
138 static void colorlabel_recreate (gint);
139 static void colorlabel_recreate_label (gint);
141 void colorlabel_update_colortable_from_prefs(void)
143 gint i, c;
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);
198 cairo_stroke(cr);
200 gdk_cairo_set_source_rgba(cr, color);
201 cairo_rectangle(cr, 1, 1,
202 allocation.width - 2,
203 allocation.height - 2);
204 cairo_fill(cr);
206 return FALSE;
209 static GtkWidget *colorlabel_create_color_widget(GdkRGBA *color)
211 GtkWidget *widget;
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),
219 color);
221 return widget;
224 static GdkPixbuf *colorlabel_create_colormenu_pixbuf(GdkRGBA *color)
226 GdkPixbuf *pixbuf;
227 guint32 pixel = 0;
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);
240 return pixbuf;
243 /* XXX: colorlabel_recreate_XXX are there to make sure everything
244 * is initialized ok, without having to call a global _xxx_init_
245 * function */
246 static void colorlabel_recreate_color(gint color)
248 GtkWidget *widget;
249 int i;
251 for (i = 0; i < NUM_MENUS; i++) {
252 if (!(label_colors[i][color].changed & LCCF_COLOR))
253 continue;
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)
268 int i;
270 for (i = 0; i < NUM_MENUS; i++) {
271 if (!(label_colors[i][color].changed & LCCF_LABEL))
272 continue;
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)
291 gint n;
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)
301 GtkWidget *label;
302 GtkWidget *hbox;
303 GtkWidget *vbox;
304 GtkWidget *item;
305 gchar *accel;
307 G_RETURN_VAL_IF_INVALID_COLOR(color_index, NULL);
309 item = gtk_check_menu_item_new();
311 if (force) {
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);
341 g_free(accel);
342 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 4);
343 g_object_set_data(G_OBJECT(item), "accel_label", label);
344 } else {
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);
351 return item;
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)
358 GtkWidget *label;
359 GtkWidget *item;
360 GtkWidget *menu;
361 gint i;
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++) {
380 GtkWidget *hbox;
381 GtkWidget *vbox;
382 GtkWidget *widget;
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);
412 return menu;
415 guint colorlabel_get_color_menu_active_item(GtkWidget *menu)
417 GtkWidget *menuitem;
418 guint color;
420 menuitem = gtk_menu_get_active(GTK_MENU(menu));
421 color = GPOINTER_TO_UINT
422 (g_object_get_data(G_OBJECT(menuitem), "color"));
423 return color;
426 static gboolean colormenu_separator_func(GtkTreeModel *model,
427 GtkTreeIter *iter, gpointer data)
429 gchar *txt;
431 gtk_tree_model_get(model, iter, COLORMENU_COL_TEXT, &txt, -1);
433 if (txt == NULL)
434 return TRUE;
436 return FALSE;
439 GtkWidget *colorlabel_create_combobox_colormenu()
441 GtkWidget *combobox;
442 GtkListStore *store;
443 GtkCellRenderer *renderer;
445 store = gtk_list_store_new(3,
446 GDK_TYPE_PIXBUF,
447 G_TYPE_STRING,
448 G_TYPE_INT);
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,
453 NULL, NULL);
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),
458 renderer, FALSE);
459 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox),
460 renderer,
461 "pixbuf", COLORMENU_COL_PIXBUF,
462 NULL);
464 renderer = gtk_cell_renderer_text_new();
465 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox),
466 renderer, TRUE);
467 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox),
468 renderer,
469 "text", COLORMENU_COL_TEXT,
470 NULL);
472 colorlabel_refill_combobox_colormenu(GTK_COMBO_BOX(combobox));
474 return combobox;
477 void colorlabel_refill_combobox_colormenu(GtkComboBox *combobox)
479 GtkListStore *store;
480 GtkTreeIter iter;
481 gint i;
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);
491 /* "None" */
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,
497 -1);
498 /* Separator */
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,
504 -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,
512 COLORMENU_COL_ID, i,
513 -1);
517 gint colorlabel_get_combobox_colormenu_active(GtkComboBox *combobox)
519 gint value;
520 GtkTreeIter iter;
521 GtkTreeModel *model;
523 cm_return_val_if_fail(combobox != NULL, 0);
525 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combobox), &iter))
526 return 0;
528 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox));
529 gtk_tree_model_get(model, &iter,
530 COLORMENU_COL_ID, &value,
531 -1);
533 return value + 1;
536 void colorlabel_set_combobox_colormenu_active(GtkComboBox *combobox,
537 gint color)
539 GtkTreeModel *model;
540 GtkTreeIter iter;
541 gint id;
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))
549 return;
551 do {
552 gtk_tree_model_get(model, &iter,
553 COLORMENU_COL_ID, &id,
554 -1);
556 if (id == color - 1)
557 break;
558 } while (gtk_tree_model_iter_next(model, &iter));
560 gtk_combo_box_set_active_iter(combobox, &iter);