1 /* menus_n_tools.c - menus and toolbar constructors / destructors
2  * One application = a menu / tool bar + a list of documents
3  *
4  * Copyright (C) 2001 Patrice St-Gelais
5  *         patrstg@users.sourceforge.net
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include <stdlib.h>
23 #include <gtk/gtk.h>
24 #include "utils.h"
25 #include "x_alloc.h"
26 #include "menus_n_tools.h"
27 // #define _(x) pr(x)
28 
pr(gchar * x)29 gchar *pr(gchar *x) {
30 	printf(x);
31 	return (gchar *) gettext(x);
32 }
33 
submenu_new(gint ndx,gchar * label,GtkWidget * bar)34 submenu_struct *submenu_new (gint ndx, gchar *label, GtkWidget *bar) {
35 
36 	// Creates and shows a submenu (to be inserted in a menu bar)
37 	// ndx is the index in ((command_item_struct *)tools) of the first item in the submenu
38 	submenu_struct *subm_buf;
39 // printf("SUBMENU_NEW: Adding label: %s\n",label);
40 	if (NULL == (subm_buf = (submenu_struct *) x_malloc(sizeof(submenu_struct), "submenu_struct")))
41 		my_msg("Allocation: submenu_struct ???\n",ABORT);
42 	subm_buf->itemndx = (GList *)NULL;
43 	subm_buf->itemndx = g_list_append(subm_buf->itemndx, (gpointer) ndx);
44 	subm_buf->sm_item = gtk_menu_item_new_with_label(label);
45 	gtk_menu_bar_append (GTK_MENU_BAR (bar), subm_buf->sm_item);
46 	gtk_widget_show(subm_buf->sm_item);
47 	subm_buf->sm_menu = gtk_menu_new();
48 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (subm_buf->sm_item), subm_buf->sm_menu);
49 // printf("Added label: %s\n",label);
50 	return subm_buf;
51 }
52 
menu_new(gint nbitems,command_item_struct * items,GtkAccelGroup * accel_grp,gpointer callback_data)53 menu_struct *menu_new(gint nbitems, command_item_struct *items,
54 			GtkAccelGroup *accel_grp,
55 			gpointer callback_data) {
56 
57 //	Initializes a menu bar and submenus from a command_item_struct table
58 //	Initializes substructures in menu
59 
60 	gint i=0;
61 	gchar *cur_group = "*";
62 	menu_struct *menu;
63 	GtkWidget *item_buf;
64 // printf("MENU_NEW\n");
65 
66 	if (NULL == (menu = (menu_struct *)x_malloc(sizeof(menu_struct), "menu_struct")))
67 		my_msg("Allocation: menu ???\n",ABORT);
68 
69 	menu->nbtools = nbitems;
70 	menu->tools = items;
71 	menu->submenus = (GList *) NULL;
72 	menu->bar = gtk_menu_bar_new();
73 	gtk_widget_show(menu->bar);
74 
75 	for (i=0; i<nbitems; i++) {
76 
77 // printf ("Current group: %d - %s / %s, label: %s, tooltip: %s, \n",
78 //	i, cur_group, (items+i)->group, (items+i)->label, (items+i)->tooltip);
79 
80 		if ( strcmp(cur_group,(items+i)->group)) {
81 			// Add an item (submenu) to the menu bar when the label changes
82 			cur_group = (items+i)->group;
83 			menu->submenus =
84 				g_list_append(menu->submenus,
85 					(gpointer) submenu_new(i, _(cur_group), menu->bar) );
86 
87 // printf("Longueur liste:  %d; noeud courant: %d \n",g_list_length(menu->submenus), menu->submenus);
88 		}
89 
90 		// Add submenu item to the current submenu
91 		if ( ! (items+i)->label) {
92 		// Add a separator
93 			item_buf = gtk_menu_item_new();
94 		}
95 		else {
96 			if ((items+i)->iftoggle) {
97 				item_buf = gtk_check_menu_item_new_with_label(_((items+i)->label));
98 			}
99 			else {
100 				item_buf = gtk_menu_item_new_with_label(_((items+i)->label));
101 			}
102 			gtk_signal_connect (GTK_OBJECT (item_buf), "activate",
103 				GTK_SIGNAL_FUNC((items+i)->command_callb),callback_data);
104 		}
105 		gtk_menu_append (GTK_MENU ( ((submenu_struct*) g_list_last(menu->submenus)->data)->sm_menu),
106 			item_buf);
107 		// Keep the indexes for future use (?)
108 		((submenu_struct *) g_list_last(menu->submenus)->data)->itemndx =
109 			g_list_append( ((submenu_struct *) g_list_last(menu->submenus)->data)->itemndx  , (gpointer) i);
110 		(items+i)->menu_item = item_buf;  // For future use (ex. freeing the widget)
111 		if ((items+i)->accel)
112 			gtk_widget_add_accelerator (item_buf, "activate", accel_grp,
113 				(items+i)->accel, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
114 
115 		gtk_widget_show (item_buf);
116 
117 	}
118 	return menu;
119 }
120 
set_toolbar_button_from_label(GtkWidget * tb,gchar * label,gboolean value)121 void set_toolbar_button_from_label (GtkWidget *tb, gchar *label, gboolean value) {
122 	GtkToolbarChild *child;
123 	GList *node, *list;
124 	gchar *lbl;
125 	for (node = (GList *)GTK_TOOLBAR(tb)->children; node; node = node->next) {
126 		child = (GtkToolbarChild *) node->data;
127 		for (list = gtk_container_children(GTK_CONTAINER(GTK_BIN(child->widget)->child));
128 			 list ; list = list->next) {
129   			if (GTK_IS_LABEL(GTK_OBJECT(list->data)))
130 				gtk_label_get(GTK_LABEL(list->data), &lbl);
131 		}
132 // printf("LABEL: %s; LBL: %s\n",_(label),lbl);
133 		if (!strcmp(_(label),lbl)) {
134 //			gtk_widget_activate(GTK_WIDGET(child->widget));
135 // printf("Setting %s to %d\n",lbl,value);
136 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( child->widget), value);
137 			return;
138 		}
139 	}
140 }
141 
set_toolbar_button_from_order(GtkWidget * tb,gint order,gboolean value)142 void set_toolbar_button_from_order (GtkWidget *tb, gint order, gboolean value) {
143 //	"order" starts at 0
144 	GtkToolbarChild *child;
145 	child = (GtkToolbarChild *) g_list_nth_data(GTK_TOOLBAR(tb)->children,order);
146 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( child->widget), value);
147 }
148 
standard_toolbar_new(gint nbitems,command_item_struct * items,GtkTooltips * tooltips,GtkWidget * window,gpointer callback_data,GtkOrientation tborient,GtkToolbarStyle tbstyle,gboolean ifradio)149 GtkWidget *standard_toolbar_new (gint nbitems, command_item_struct *items,
150 	GtkTooltips *tooltips, GtkWidget *window, gpointer callback_data,
151 	GtkOrientation tborient, GtkToolbarStyle tbstyle, gboolean ifradio) {
152 	// 2004-01-16 Variation on toolbar_new
153 	// More generic
154 	// Returns a simple GtkWidget - no specialized struct here
155 
156 	gint i, index_toggled = 0;
157 	gchar *cur_group;
158 	GtkWidget *lastitem=NULL, *toolbar;
159 
160 	cur_group = items->group;
161 	toolbar = gtk_toolbar_new ();
162 	gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar),tborient);
163 	gtk_toolbar_set_style(GTK_TOOLBAR(toolbar),tbstyle);
164 	gtk_widget_show (toolbar);
165 
166 // printf("TOOLBAR_NEW avant boucle;  nbitems: %d\n",nbitems);
167 	for (i=0; i<nbitems; i++) {
168 
169 // printf ("Current group: %s ;", cur_group);
170 
171 		if ( strcmp(cur_group,(items+i)->group)) {
172 			// Add double space when menu item in menu bar changes
173 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
174 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
175 			cur_group = (items+i)->group;
176 		}
177 // printf("i: %d\n",i);
178 		// Add submenu item to the current submenu
179 		if ( ! (items+i)->label) {
180 		// Add space as separator
181 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar));
182 		}
183 		else {
184 			if (ifradio) {
185 // printf("IFRADIO\nlabel: %s\ntooltip: %s\nwindow: %d\ncommand_callb: %d\ncallb_data: %d\nicon: %d\n",
186 // (items+i)->label, (items+i)->tooltip,window, (items+i)->command_callb, callback_data, (items+i)->icon);
187 				(items+i)->toolbar_item = gtk_toolbar_append_element (
188 					GTK_TOOLBAR(toolbar),
189 					GTK_TOOLBAR_CHILD_RADIOBUTTON,
190 					lastitem,
191 					_((items+i)->label),
192 					_((items+i)->tooltip),
193 					NULL,
194 					create_widget_from_xpm(window,(items+i)->icon),
195 					GTK_SIGNAL_FUNC((items+i)->command_callb),
196 					callback_data);
197 // printf("IFRADIO fin\n");
198 				lastitem = (items+i)->toolbar_item;
199 				if ((items+i)->iftoggle )
200 					index_toggled = i;
201 			} // if (ifradio)
202 			else {
203 				(items+i)->toolbar_item = gtk_toolbar_append_element (
204 					GTK_TOOLBAR(toolbar),
205 					(items+i)->iftoggle?GTK_TOOLBAR_CHILD_TOGGLEBUTTON :
206 						GTK_TOOLBAR_CHILD_BUTTON,
207 					NULL,
208 					_((items+i)->label),
209 					_((items+i)->tooltip),
210 					NULL,
211 					create_widget_from_xpm(window,(items+i)->icon),
212 					GTK_SIGNAL_FUNC((items+i)->command_callb),
213 					callback_data);
214 			} // else (ifradio)
215 		} // else (! (items+i)->label)
216 	} // for
217 //	Seg fault with some toolbars, probably because
218 //	of a callback trying to process a NULL pointer
219 //	if (ifradio)
220 //		set_toolbar_button_from_order(toolbar->toolbarwdg, index_toggled, TRUE);
221 
222 	return toolbar ;
223 }
224 
toolbar_new(gint nbitems,command_item_struct * items,GtkTooltips * tooltips,GtkWidget * window,gpointer callback_data,GtkOrientation tborient,GtkToolbarStyle tbstyle,gboolean ifradio)225 toolbar_struct *toolbar_new( gint nbitems, command_item_struct *items,
226 	GtkTooltips *tooltips, GtkWidget *window, gpointer callback_data,
227 	GtkOrientation tborient, GtkToolbarStyle tbstyle, gboolean ifradio)  {
228 
229 	gint i, index_toggled = 0;
230 	gchar *cur_group;
231 	GtkWidget *lastitem=NULL;
232 
233 	toolbar_struct *toolbar;
234 	if (NULL == (toolbar = (toolbar_struct *) x_malloc(sizeof(toolbar_struct), "toolbar_struct")))
235 		my_msg("Allocation: toolbar ???\n",ABORT);
236 
237 	cur_group = items->group;
238 	toolbar->tborient = tborient;
239 	toolbar->tbstyle = tbstyle;
240 	toolbar->ifradio = ifradio;
241 	toolbar->toolbarwdg = gtk_toolbar_new ();
242 	gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar->toolbarwdg),tborient);
243 	gtk_toolbar_set_style(GTK_TOOLBAR(toolbar->toolbarwdg),tbstyle);
244 	gtk_widget_show (toolbar->toolbarwdg);
245 
246 // printf("TOOLBAR_NEW avant boucle;  nbitems: %d\n",nbitems);
247 	for (i=0; i<nbitems; i++) {
248 
249 // printf ("Current group: %s ;", cur_group);
250 
251 		if ( strcmp(cur_group,(items+i)->group)) {
252 			// Add double space when menu item in menu bar changes
253 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar->toolbarwdg));
254 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar->toolbarwdg));
255 			cur_group = (items+i)->group;
256 		}
257 // printf("i: %d\n",i);
258 		// Add submenu item to the current submenu
259 		if ( ! (items+i)->label) {
260 		// Add space as separator
261 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar->toolbarwdg));
262 		}
263 		else {
264 			if (ifradio) {
265 // printf("IFRADIO\nlabel: %s\ntooltip: %s\nwindow: %d\ncommand_callb: %d\ncallb_data: %d\nicon: %d\n",
266 // (items+i)->label, (items+i)->tooltip,window, (items+i)->command_callb, callback_data, (items+i)->icon);
267 				(items+i)->toolbar_item = gtk_toolbar_append_element (
268 					GTK_TOOLBAR(toolbar->toolbarwdg),
269 					GTK_TOOLBAR_CHILD_RADIOBUTTON,
270 					lastitem,
271 					_((items+i)->label),
272 					_((items+i)->tooltip),
273 					NULL,
274 					create_widget_from_xpm(window,(items+i)->icon),
275 					GTK_SIGNAL_FUNC((items+i)->command_callb),
276 					callback_data);
277 // printf("IFRADIO fin\n");
278 				lastitem = (items+i)->toolbar_item;
279 				if ((items+i)->iftoggle )
280 					index_toggled = i;
281 			}
282 			else
283 				(items+i)->toolbar_item = gtk_toolbar_append_element (
284 					GTK_TOOLBAR(toolbar->toolbarwdg),
285 					(items+i)->iftoggle?GTK_TOOLBAR_CHILD_TOGGLEBUTTON :
286 						GTK_TOOLBAR_CHILD_BUTTON,
287 					NULL,
288 					_((items+i)->label),
289 					_((items+i)->tooltip),
290 					NULL,
291 					create_widget_from_xpm(window,(items+i)->icon),
292 					GTK_SIGNAL_FUNC((items+i)->command_callb),
293 					callback_data);
294 		}
295 	}
296 //	Seg fault with some toolbars, probably because
297 //	of a callback trying to process a NULL pointer
298 //	if (ifradio)
299 //		set_toolbar_button_from_order(toolbar->toolbarwdg, index_toggled, TRUE);
300 
301 	return toolbar ;
302 }
303 
multi_toolbar_new(gint nbitems,command_item_struct * items,GtkTooltips * tooltips,GtkWidget * window,gpointer callback_data,GtkOrientation tborient,GtkToolbarStyle tbstyle,gboolean ifradio)304 toolbar_struct *multi_toolbar_new( gint nbitems, command_item_struct *items,
305 	GtkTooltips *tooltips, GtkWidget *window, gpointer callback_data,
306 	GtkOrientation tborient, GtkToolbarStyle tbstyle, gboolean ifradio)  {
307 
308 //	Builds a toolbar OR a box of toolbars,
309 //	depending on the separators in command_item
310 //	(we create a new line / column each time we encounter a separator)
311 	gint i, nbbars=0;
312 	gchar *cur_group;
313 	GtkWidget *lastitem=NULL, *tb=NULL, *box=NULL;
314 
315 	toolbar_struct *toolbar;
316 	if (NULL == (toolbar = (toolbar_struct *) x_malloc(sizeof(toolbar_struct), "toolbar_struct")))
317 		my_msg("Allocation: toolbar ???\n",ABORT);
318 
319 	cur_group = items->group;
320 	toolbar->tborient = tborient;
321 	toolbar->tbstyle = tbstyle;
322 	toolbar->ifradio = ifradio;
323 	tb = gtk_toolbar_new ();
324 	gtk_toolbar_set_orientation(GTK_TOOLBAR(tb),tborient);
325 	gtk_toolbar_set_style(GTK_TOOLBAR(tb),tbstyle);
326 	gtk_widget_show(tb);
327 	box = tb;
328 
329 // printf("TOOLBAR_NEW avant boucle;  nbitems: %d\n",nbitems);
330 	for (i=0; i<nbitems; i++) {
331 
332 // printf ("Current group: %s ;", cur_group);
333 
334 		if ( strcmp(cur_group,(items+i)->group)) {
335 			// Add double space when menu item in menu bar changes
336 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar->toolbarwdg));
337 			gtk_toolbar_append_space (GTK_TOOLBAR(toolbar->toolbarwdg));
338 			cur_group = (items+i)->group;
339 		}
340 // printf("i: %d\n",i);
341 		// Add submenu item to the current submenu
342 		if ( ! (items+i)->label) {
343 			// Add space as separator
344 			// ... 2002.04.14 - Create a new line / column!
345 			// gtk_toolbar_append_space (GTK_TOOLBAR(toolbar->toolbarwdg));
346 			if (!nbbars) {
347 				if (tborient == GTK_ORIENTATION_HORIZONTAL)
348 					box = gtk_vbox_new(FALSE,0);
349 				else
350 					box = gtk_hbox_new(FALSE,0);
351 				gtk_widget_show(GTK_WIDGET(box));
352 			}
353 			nbbars++;
354 			gtk_box_pack_start(GTK_BOX(box),tb,FALSE,FALSE,0);
355 			tb = gtk_toolbar_new ();
356 			gtk_toolbar_set_orientation(GTK_TOOLBAR(tb),tborient);
357 			gtk_toolbar_set_style(GTK_TOOLBAR(tb),tbstyle);
358 			gtk_widget_show(tb);
359 		}
360 		else {
361 			if (ifradio) {
362 // printf("IFRADIO\nlabel: %s\ntooltip: %s\nwindow: %d\ncommand_callb: %d\ncallb_data: %d\nicon: %d\n",
363 // (items+i)->label, (items+i)->tooltip,window, (items+i)->command_callb, callback_data, (items+i)->icon);
364 				(items+i)->toolbar_item = gtk_toolbar_append_element (
365 					GTK_TOOLBAR(tb),
366 					GTK_TOOLBAR_CHILD_RADIOBUTTON,
367 					lastitem,
368 					_((items+i)->label),
369 					_((items+i)->tooltip),
370 					NULL,
371 					create_widget_from_xpm(window,(items+i)->icon),
372 					GTK_SIGNAL_FUNC((items+i)->command_callb),
373 					callback_data);
374 // printf("IFRADIO fin\n");
375 				lastitem = (items+i)->toolbar_item;
376 			}
377 			else
378 				(items+i)->toolbar_item = gtk_toolbar_append_element (
379 					GTK_TOOLBAR(tb),
380 					(items+i)->iftoggle?GTK_TOOLBAR_CHILD_TOGGLEBUTTON :
381 						GTK_TOOLBAR_CHILD_BUTTON,
382 					NULL,
383 					_((items+i)->label),
384 					_((items+i)->tooltip),
385 					NULL,
386 					create_widget_from_xpm(window,(items+i)->icon),
387 					GTK_SIGNAL_FUNC((items+i)->command_callb),
388 					callback_data);
389 		}
390 	}
391 	if (!nbbars)
392 		toolbar->toolbarwdg = tb;
393 	else {
394 		gtk_box_pack_start(GTK_BOX(box),tb,FALSE,FALSE,0);
395 		toolbar->toolbarwdg = box;
396 	}
397 	return toolbar ;
398 }
399 
400 
menu_free(menu_struct * menu)401 void menu_free(menu_struct *menu) {
402 
403 	gint i;
404 	GList *node;
405 	// We free the menuitem widgets in the commands table (probably not necessary...)
406 	for (i=0; i<menu->nbtools; i++) {
407 		if ((menu->tools+i)->menu_item)
408 			gtk_widget_destroy((menu->tools+i)->menu_item);
409 	}
410 
411 	// We free the menu bar struct
412 
413 	for (node = g_list_nth (menu->submenus,1); node; node = node->next) {
414 		g_list_free(((submenu_struct*)node->data)->itemndx);
415 		gtk_widget_destroy( ((submenu_struct*)node->data)->sm_item);
416 		gtk_widget_destroy( ((submenu_struct*)node->data)->sm_menu);
417 	}
418 	g_list_free(menu->submenus);
419 
420 	// We free the whole structure
421 	x_free(menu);
422 }
423 
toolbar_free(toolbar_struct * toolbar)424 void toolbar_free(toolbar_struct *toolbar) {
425 	gint i;
426 	// We free the menuitem widgets in the commands table
427 	for (i=0; i<toolbar->nbtools; i++) {
428 		if ((toolbar->tools+i)->toolbar_item)
429 			gtk_widget_destroy((toolbar->tools+i)->toolbar_item);
430 	}
431 
432 	// Freeing the whole structure
433 	gtk_widget_destroy(toolbar->toolbarwdg);
434 	x_free(toolbar);
435 }
436 
437 
438