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