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
);