1 /*
2 * gui_misc.c: misc gui routines
3 * Copyright (C) 2002-2004 Saulius Menkevicius
4 *
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 2 of the License, or
8 * (at your option) any later version.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Id: gui_misc.c,v 1.17 2004/12/29 15:58:24 bobas Exp $
20 */
21
22 #include <string.h>
23
24 #include <glib.h>
25 #include <gtk/gtk.h>
26 #include <gdk-pixbuf/gdk-pixbuf.h>
27
28 #include "main.h"
29 #include "net.h"
30 #include "gui.h"
31 #include "gui_misc.h"
32
33 #include "../pixmaps/stockpixbufs.h"
34
35 static struct stock_pixbuf_map {
36 const gchar * stock_id;
37 const guint8 * pixbuf, * pixbuf1;
38 const guint8 * button_pixbuf, * button_pixbuf1;
39 }
40 stock_pixbuf_maps[] = {
41 { GUI_STOCK_CHANNEL,
42 pixbuf_icon_channel, NULL,
43 NULL, NULL },
44 { GUI_STOCK_CHANNEL_INACTIVE,
45 pixbuf_icon_channel_inactive, NULL,
46 NULL, NULL },
47
48 { GUI_STOCK_STATUS,
49 pixbuf_icon_status, NULL,
50 NULL, NULL },
51 { GUI_STOCK_STATUS_INACTIVE,
52 pixbuf_icon_status_inactive, NULL,
53 NULL, NULL },
54
55 { GUI_STOCK_USER_DEAD,
56 pixbuf_icon_user_dead, NULL,
57 NULL, NULL },
58 { GUI_STOCK_USER_INVISIBLE,
59 pixbuf_icon_user_invisible, NULL,
60 NULL, NULL },
61
62 { GUI_STOCK_USER_NORMAL,
63 pixbuf_icon_user_normal, NULL,
64 NULL, NULL },
65 { GUI_STOCK_USER_NORMAL_AWAY,
66 pixbuf_icon_user_normal, pixbuf_icon_user_tag_away,
67 NULL, NULL },
68 { GUI_STOCK_USER_NORMAL_DND,
69 pixbuf_icon_user_normal, pixbuf_icon_user_tag_dnd,
70 NULL, NULL },
71 { GUI_STOCK_USER_NORMAL_OFFLINE,
72 pixbuf_icon_user_normal, pixbuf_icon_user_tag_offline,
73 NULL, NULL },
74
75 { GUI_STOCK_USER_INACTIVE,
76 pixbuf_icon_user_inactive, NULL,
77 NULL, NULL },
78 { GUI_STOCK_USER_INACTIVE_AWAY,
79 pixbuf_icon_user_inactive, pixbuf_icon_user_tag_away,
80 NULL, NULL },
81 { GUI_STOCK_USER_INACTIVE_DND,
82 pixbuf_icon_user_inactive, pixbuf_icon_user_tag_dnd,
83 NULL, NULL },
84 { GUI_STOCK_USER_INACTIVE_OFFLINE,
85 pixbuf_icon_user_inactive, pixbuf_icon_user_tag_offline,
86 NULL, NULL },
87
88 { GUI_STOCK_SEND_MESSAGE,
89 pixbuf_icon_send, NULL,
90 pixbuf_icon_send_button, NULL },
91 { GUI_STOCK_REPLY_MESSAGE,
92 pixbuf_icon_reply, NULL,
93 pixbuf_icon_reply_button, NULL },
94 { GUI_STOCK_QUOTE_MESSAGE,
95 pixbuf_icon_quote, NULL,
96 pixbuf_icon_quote_button, NULL },
97 { NULL, }
98 };
99
100 static GtkStockItem
101 stock_items[] = {
102 { GUI_STOCK_SEND_MESSAGE, N_("_Send"), 0, 0, GETTEXT_PACKAGE },
103 { GUI_STOCK_REPLY_MESSAGE,N_("_Reply"), 0, 0, GETTEXT_PACKAGE },
104 { GUI_STOCK_QUOTE_MESSAGE,N_("_Quote"), 0, 0, GETTEXT_PACKAGE },
105 { NULL, }
106 };
107
108 static GtkIconFactory * icon_factory = 0;
109
110 /** private routines
111 */
112
113 /** make_menu_item:
114 * Makes GtkMenuItem containing specified label
115 * and (optionally) a PIX.
116 * Special case when name=="---": separator is produced.
117 */
118 static GtkWidget *
make_menu_item(const char * name,const gchar * stock_id,gboolean sensitive)119 make_menu_item(
120 const char * name,
121 const gchar * stock_id,
122 gboolean sensitive)
123 {
124 GtkWidget * hbox_w, * image_w, * label_w, * item_w;
125
126 g_assert(name);
127
128 /* make menu item */
129 item_w = gtk_menu_item_new();
130
131 if(!strcmp(name, "---")) {
132 /* this is separator */
133 label_w = gtk_hseparator_new();
134 gtk_container_add(GTK_CONTAINER(item_w), label_w);
135 } else {
136 /* usual item */
137 label_w = gtk_label_new_with_mnemonic(name);
138
139 if(stock_id) {
140 /* image_w + label_w */
141 hbox_w = gtk_hbox_new(FALSE, 4);
142
143 image_w = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU);
144
145 gtk_box_pack_start(GTK_BOX(hbox_w), image_w, FALSE, FALSE, 0);
146 gtk_box_pack_start(GTK_BOX(hbox_w), label_w, FALSE, FALSE, 0);
147
148 gtk_container_add(GTK_CONTAINER(item_w), hbox_w);
149 } else {
150 gtk_container_add(GTK_CONTAINER(item_w), label_w);
151 }
152 }
153
154 /* make it insensitive, if needed */
155 if(!sensitive) {
156 gtk_widget_set_sensitive(item_w, FALSE);
157 }
158
159 return item_w;
160 }
161
162 /** E X P O R T E D R O U T I N E S
163 ******************************************/
164
165 /** gui_misc_init:
166 * initializes the module
167 */
gui_misc_init()168 void gui_misc_init()
169 {
170 GtkIconSource * source;
171 GtkIconSet * set;
172 struct stock_pixbuf_map * map;
173 gint num_items;
174
175 /* setup icon factory and all the icons it contains
176 */
177 if(icon_factory==0) {
178 /* setup icon factory and all the icons it contains */
179 icon_factory = gtk_icon_factory_new();
180 gtk_icon_factory_add_default(icon_factory);
181
182 /* register icons */
183 for(map = stock_pixbuf_maps; map->stock_id; map ++) {
184 GdkPixbuf * pixbuf, * composite;
185
186 g_assert(map->pixbuf);
187
188 set = gtk_icon_set_new();
189
190 /* create icon source for a small 16x16 icon */
191 source = gtk_icon_source_new();
192 gtk_icon_source_set_size(source, GTK_ICON_SIZE_MENU);
193
194 pixbuf = gdk_pixbuf_new_from_inline(-1, map->pixbuf, TRUE, NULL);
195 if(map->pixbuf1) {
196 composite = gdk_pixbuf_new_from_inline(
197 -1, map->pixbuf1, FALSE, NULL);
198
199 /* add composite pixbuf */
200 gdk_pixbuf_composite(
201 composite, pixbuf, 0, 0,
202 gdk_pixbuf_get_width(pixbuf),
203 gdk_pixbuf_get_height(pixbuf),
204 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
205
206 /* release the composite pixbuf */
207 g_object_unref(G_OBJECT(composite));
208 }
209 gtk_icon_source_set_pixbuf(source, pixbuf);
210
211 gtk_icon_set_add_source(set, source);
212 gtk_icon_source_free(source); /* this will g_object_unref `pixbuf, too */
213
214 /* create icon source for a "button" 24x24 icon (if any) */
215 if(map->button_pixbuf) {
216 source = gtk_icon_source_new();
217 gtk_icon_source_set_size(source, GTK_ICON_SIZE_BUTTON);
218
219 pixbuf = gdk_pixbuf_new_from_inline(
220 -1, map->button_pixbuf, TRUE, NULL);
221 if(map->button_pixbuf1) {
222 composite = gdk_pixbuf_new_from_inline(
223 -1, map->button_pixbuf1, FALSE, NULL);
224
225 gdk_pixbuf_composite(
226 composite, pixbuf, 0, 0,
227 gdk_pixbuf_get_width(pixbuf),
228 gdk_pixbuf_get_height(pixbuf),
229 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
230
231 g_object_unref(G_OBJECT(composite));
232 }
233 gtk_icon_source_set_pixbuf(source, pixbuf);
234
235 gtk_icon_set_add_source(set, source);
236 gtk_icon_source_free(source); /* this will free the pixbuf, too */
237 }
238
239 /* add icon set to icon_factory & release it */
240 gtk_icon_factory_add(icon_factory, map->stock_id, set);
241 gtk_icon_set_unref(set);
242 }
243 }
244
245 /* register stock items
246 */
247 for(num_items=0; stock_items[num_items].stock_id!=NULL; num_items++) ;
248 gtk_stock_add_static(stock_items, num_items);
249 }
250
251 /** gui_misc_destroy:
252 * cleanups data allocated in module
253 */
gui_misc_destroy()254 void gui_misc_destroy()
255 {
256 if(icon_factory) {
257 /* unreference and remove the icon factory */
258 gtk_icon_factory_remove_default(icon_factory);
259 g_object_unref(G_OBJECT(icon_factory));
260 }
261 }
262
263 /**
264 * gui_misc_set_icon_for:
265 * sets vqcc-gtk icon (list) for specified window
266 */
267 void
gui_misc_set_icon_for(GtkWindow * window)268 gui_misc_set_icon_for(GtkWindow * window)
269 {
270 GList * icon_list = NULL;
271
272 /* make icon list */
273 icon_list = g_list_prepend(
274 icon_list, gdk_pixbuf_new_from_inline(-1, pixbuf_logo_24, FALSE, NULL));
275 icon_list = g_list_prepend(
276 icon_list, gdk_pixbuf_new_from_inline(-1, pixbuf_logo_32, FALSE, NULL));
277 icon_list = g_list_prepend(
278 icon_list, gdk_pixbuf_new_from_inline(-1, pixbuf_logo_48, FALSE, NULL));
279
280 /* set window icons */
281 gtk_window_set_icon_list(window, icon_list);
282
283 /* unref icons & free the list */
284 while(icon_list) {
285 g_object_unref(G_OBJECT(icon_list->data));
286 icon_list = g_list_delete_link(icon_list, icon_list);
287 }
288 }
289
290 const gchar *
util_user_state_stock(enum user_mode_enum mode,gboolean active)291 util_user_state_stock(enum user_mode_enum mode, gboolean active)
292 {
293 const gchar * icon;
294
295 switch(mode) {
296 case UMODE_AWAY:
297 icon = active ? GUI_STOCK_USER_NORMAL_AWAY: GUI_STOCK_USER_INACTIVE_AWAY;
298 break;
299 case UMODE_DND:
300 icon = active ? GUI_STOCK_USER_NORMAL_DND: GUI_STOCK_USER_INACTIVE_DND;
301 break;
302 case UMODE_OFFLINE:
303 icon = active ? GUI_STOCK_USER_NORMAL_OFFLINE: GUI_STOCK_USER_INACTIVE_OFFLINE;
304 break;
305 case UMODE_INVISIBLE:
306 icon = GUI_STOCK_USER_INVISIBLE;
307 break;
308 case UMODE_DEAD:
309 icon = GUI_STOCK_USER_DEAD;
310 break;
311 default:
312 icon = active ? GUI_STOCK_USER_NORMAL: GUI_STOCK_USER_INACTIVE;
313 break;
314 }
315 return icon;
316 }
317
util_user_mode_tag_pixbuf(enum user_mode_enum user_mode)318 GdkPixbuf * util_user_mode_tag_pixbuf(enum user_mode_enum user_mode)
319 {
320 GdkPixbuf * pixbuf;
321
322 switch(user_mode) {
323 case UMODE_AWAY:
324 pixbuf = gdk_pixbuf_new_from_inline(-1, pixbuf_icon_user_tag_away, FALSE, NULL);
325 break;
326 case UMODE_DND:
327 pixbuf = gdk_pixbuf_new_from_inline(-1, pixbuf_icon_user_tag_dnd, FALSE, NULL);
328 break;
329 case UMODE_OFFLINE:
330 pixbuf = gdk_pixbuf_new_from_inline(-1, pixbuf_icon_user_tag_offline, FALSE, NULL);
331 break;
332 default:
333 pixbuf = NULL;
334 break;
335 }
336 return pixbuf;
337 }
338
339 static void
util_option_fwd_cb(GtkOptionMenu * opt_menu,gpointer callback)340 util_option_fwd_cb(GtkOptionMenu * opt_menu, gpointer callback)
341 {
342 ((util_option_changed_cb)callback)(
343 gtk_option_menu_get_history(GTK_OPTION_MENU(opt_menu)),
344 g_object_get_data(G_OBJECT(opt_menu), "changed_userdata")
345 );
346 }
347
348 GtkWidget *
util_net_type_option(util_option_changed_cb changed_cb,gpointer userdata)349 util_net_type_option(util_option_changed_cb changed_cb, gpointer userdata)
350 {
351 GtkWidget * menu, * opt_menu;
352 int i;
353
354 menu = gtk_menu_new();
355 for (i = 0; i < NET_TYPE_NUM; i++)
356 gtk_menu_shell_append(
357 GTK_MENU_SHELL(menu),
358 make_menu_item(net_name_of_type(i), NULL, TRUE));
359
360 opt_menu = gtk_option_menu_new();
361 g_object_set_data(G_OBJECT(opt_menu), "changed_userdata", userdata);
362 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt_menu), menu);
363 if(changed_cb)
364 g_signal_connect(G_OBJECT(opt_menu), "changed",
365 G_CALLBACK(util_option_fwd_cb), changed_cb);
366
367 return opt_menu;
368 }
369
370 GtkWidget *
util_user_mode_option(util_option_changed_cb changed_cb,gpointer userdata)371 util_user_mode_option(util_option_changed_cb changed_cb, gpointer userdata)
372 {
373 GtkWidget * menu, * opt_menu;
374 int mode;
375
376 menu = gtk_menu_new();
377 for (mode = UMODE_FIRST_VALID; mode < UMODE_NUM_VALID; mode++)
378 gtk_menu_shell_append(
379 GTK_MENU_SHELL(menu),
380 make_menu_item(user_mode_name(mode),
381 util_user_state_stock(mode, TRUE), TRUE) );
382
383 opt_menu = gtk_option_menu_new();
384 g_object_set_data(G_OBJECT(opt_menu), "changed_userdata", userdata);
385 gtk_option_menu_set_menu(GTK_OPTION_MENU(opt_menu), (gpointer)menu);
386 if(changed_cb)
387 g_signal_connect(G_OBJECT(opt_menu), "changed",
388 G_CALLBACK(util_option_fwd_cb), changed_cb);
389
390 return opt_menu;
391 }
392
393 GtkWidget *
util_image_menu_item(const gchar * icon_stock_id,const gchar * label_text,GCallback activate_cb,gpointer activate_user_data)394 util_image_menu_item(
395 const gchar * icon_stock_id,
396 const gchar * label_text,
397 GCallback activate_cb,
398 gpointer activate_user_data)
399 {
400 GtkWidget * item_w;
401
402 if(icon_stock_id) {
403 item_w = gtk_image_menu_item_new_with_label("");
404 gtk_image_menu_item_set_image(
405 GTK_IMAGE_MENU_ITEM(item_w),
406 gtk_image_new_from_stock(icon_stock_id, GTK_ICON_SIZE_MENU));
407 } else {
408 item_w = gtk_menu_item_new_with_label("");
409 }
410
411 gtk_label_set_markup_with_mnemonic(GTK_LABEL(GTK_BIN(item_w)->child), label_text);
412
413 /* hook up signal callback */
414 if(activate_cb)
415 g_signal_connect(G_OBJECT(item_w), "activate", activate_cb, activate_user_data);
416
417 return item_w;
418 }
419
420
421 /** misc_pix_button:
422 * makes button with pix & label
423 */
424 GtkWidget *
misc_pix_button(const char * label,const gchar * pix_stock_id,GCallback click_cb,gpointer click_cb_param)425 misc_pix_button(
426 const char * label,
427 const gchar * pix_stock_id,
428 GCallback click_cb,
429 gpointer click_cb_param)
430 {
431 GtkWidget * hbox_w, * btn_w, * w;
432
433 /* make button */
434 btn_w = gtk_button_new();
435 gtk_widget_show(btn_w);
436
437 /* make insides of button */
438 hbox_w = gtk_hbox_new(FALSE, 0);
439 gtk_widget_show(hbox_w);
440 gtk_container_add(GTK_CONTAINER(btn_w), hbox_w);
441
442 w = gtk_image_new_from_stock(pix_stock_id, GTK_ICON_SIZE_MENU);
443 gtk_widget_show(w);
444 gtk_box_pack_start(GTK_BOX(hbox_w), w, FALSE, FALSE, 2);
445
446 w = gtk_label_new_with_mnemonic(label);
447 gtk_widget_show(w);
448 gtk_box_pack_end(GTK_BOX(hbox_w), w, FALSE, FALSE, 2);
449
450 /* connect "click" signal */
451 if(click_cb) {
452 g_signal_connect(G_OBJECT(btn_w), "clicked",
453 click_cb, click_cb_param);
454 }
455
456 return btn_w;
457 }
458
459
460