titemfactory.c - vaccinewars - be a doctor and try to vaccinate the world
HTML git clone git://src.adamsgaard.dk/vaccinewars
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
titemfactory.c (8647B)
---
1 /************************************************************************
2 * itemfactory.c GtkItemFactory and friends for Unix/Win32 *
3 * Copyright (C) 1998-2021 Ben Webb *
4 * Email: benwebb@users.sf.net *
5 * WWW: https://dopewars.sourceforge.io/ *
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License *
9 * as published by the Free Software Foundation; either version 2 *
10 * of the License, or (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, *
20 * MA 02111-1307, USA. *
21 ************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "gtkport.h"
28
29 /* No need to reimplement functions if we have GTK+2 */
30 #if GTK_MAJOR_VERSION == 2
31 GtkItemFactory *dp_gtk_item_factory_new(const gchar *path,
32 GtkAccelGroup *accel_group)
33 {
34 return gtk_item_factory_new(GTK_TYPE_MENU_BAR, path, accel_group);
35 }
36 #endif
37
38 #if defined(CYGWIN) || GTK_MAJOR_VERSION > 2
39
40 #ifdef CYGWIN
41
42 #define OurAccel ACCEL
43
44 #else
45 typedef struct _OurAccel OurAccel;
46 struct _OurAccel {
47 guint key;
48 GdkModifierType mods;
49 GtkAccelFlags flags;
50 };
51 #endif
52
53 typedef struct _DPGtkItemFactoryChild DPGtkItemFactoryChild;
54
55 struct _DPGtkItemFactoryChild {
56 gchar *path;
57 GtkWidget *widget;
58 };
59
60 DPGtkItemFactory *dp_gtk_item_factory_new(const gchar *path,
61 GtkAccelGroup *accel_group)
62 {
63 DPGtkItemFactory *new_fac;
64
65 new_fac = g_new0(DPGtkItemFactory, 1);
66 new_fac->path = g_strdup(path);
67 new_fac->accel_group = accel_group;
68 new_fac->top_widget = gtk_menu_bar_new();
69 new_fac->translate_func = NULL;
70 return new_fac;
71 }
72
73 static gint PathCmp(const gchar *path1, const gchar *path2)
74 {
75 gint Match = 1;
76
77 if (!path1 || !path2)
78 return 0;
79
80 while (*path1 && *path2 && Match) {
81 while (*path1 == '_')
82 path1++;
83 while (*path2 == '_')
84 path2++;
85 if (*path1 == *path2) {
86 path1++;
87 path2++;
88 } else
89 Match = 0;
90 }
91 if (*path1 || *path2)
92 Match = 0;
93 return Match;
94 }
95
96 static gchar *TransPath(DPGtkItemFactory *ifactory, gchar *path)
97 {
98 gchar *transpath = NULL;
99
100 if (ifactory->translate_func) {
101 transpath =
102 (*ifactory->translate_func) (path, ifactory->translate_data);
103 }
104
105 return transpath ? transpath : path;
106 }
107
108 static void gtk_item_factory_parse_path(DPGtkItemFactory *ifactory,
109 gchar *path,
110 DPGtkItemFactoryChild **parent,
111 GString *menu_title)
112 {
113 GSList *list;
114 DPGtkItemFactoryChild *child;
115 gchar *root, *pt, *transpath;
116
117 transpath = TransPath(ifactory, path);
118 pt = strrchr(transpath, '/');
119 if (pt)
120 g_string_assign(menu_title, pt + 1);
121
122 pt = strrchr(path, '/');
123 if (!pt)
124 return;
125 root = g_strdup(path);
126 root[pt - path] = '\0';
127
128 for (list = ifactory->children; list; list = g_slist_next(list)) {
129 child = (DPGtkItemFactoryChild *)list->data;
130 if (PathCmp(child->path, root) == 1) {
131 *parent = child;
132 break;
133 }
134 }
135 g_free(root);
136 }
137
138 static gboolean gtk_item_factory_parse_accel(DPGtkItemFactory *ifactory,
139 gchar *accelerator,
140 GString *menu_title,
141 OurAccel *accel)
142 {
143 gchar *apt;
144
145 if (!accelerator)
146 return FALSE;
147
148 apt = accelerator;
149 #ifdef CYGWIN
150 accel->fVirt = 0;
151 accel->key = 0;
152 accel->cmd = 0;
153 g_string_append(menu_title, "\t");
154 #else
155 accel->key = 0;
156 accel->mods = 0;
157 accel->flags = GTK_ACCEL_VISIBLE;
158 #endif
159
160 if (strncmp(apt, "<control>", 9) == 0) {
161 #ifdef CYGWIN
162 accel->fVirt |= FCONTROL;
163 g_string_append(menu_title, "Ctrl+");
164 #else
165 accel->mods |= GDK_CONTROL_MASK;
166 #endif
167 apt += 9;
168 }
169
170 if (strlen(apt) == 1) {
171 accel->key = *apt;
172 #ifdef CYGWIN
173 g_string_append_c(menu_title, *apt);
174 accel->fVirt |= FVIRTKEY;
175 #endif
176 } else if (strcmp(apt, "F1") == 0) {
177 #ifdef CYGWIN
178 g_string_append(menu_title, apt);
179 accel->fVirt |= FVIRTKEY;
180 accel->key = VK_F1;
181 #else
182 accel->key = GDK_KEY_F1;
183 #endif
184 }
185 return (accel->key != 0);
186 }
187
188 void dp_gtk_item_factory_create_item(DPGtkItemFactory *ifactory,
189 DPGtkItemFactoryEntry *entry,
190 gpointer callback_data,
191 guint callback_type)
192 {
193 DPGtkItemFactoryChild *new_child, *parent = NULL;
194 GString *menu_title;
195 GtkWidget *menu_item, *menu;
196 OurAccel accel;
197 gboolean haveaccel;
198
199 new_child = g_new0(DPGtkItemFactoryChild, 1);
200
201 new_child->path = g_strdup(entry->path);
202
203 menu_title = g_string_new("");
204
205 gtk_item_factory_parse_path(ifactory, new_child->path, &parent,
206 menu_title);
207 haveaccel =
208 gtk_item_factory_parse_accel(ifactory, entry->accelerator,
209 menu_title, &accel);
210
211 if (entry->item_type && strcmp(entry->item_type, "<CheckItem>") == 0) {
212 menu_item = gtk_check_menu_item_new_with_mnemonic(menu_title->str);
213 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), TRUE);
214 } else {
215 menu_item = gtk_menu_item_new_with_mnemonic(menu_title->str);
216 }
217 new_child->widget = menu_item;
218 if (entry->callback) {
219 g_signal_connect(G_OBJECT(menu_item), "activate",
220 entry->callback, callback_data);
221 }
222
223 if (parent) {
224 menu = GTK_WIDGET(gtk_menu_item_get_submenu(GTK_MENU_ITEM(parent->widget)));
225 if (!menu) {
226 menu = gtk_menu_new();
227 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent->widget), menu);
228 }
229 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
230 } else {
231 gtk_menu_shell_append(GTK_MENU_SHELL(ifactory->top_widget), menu_item);
232 }
233
234 if (haveaccel && ifactory->accel_group) {
235 #ifdef CYGWIN
236 GTK_MENU_ITEM(menu_item)->accelind =
237 gtk_accel_group_add(ifactory->accel_group, &accel);
238 #else
239 gtk_widget_add_accelerator(menu_item, "activate", ifactory->accel_group,
240 accel.key, accel.mods, accel.flags);
241 #endif
242 }
243
244 g_string_free(menu_title, TRUE);
245
246 ifactory->children = g_slist_append(ifactory->children, new_child);
247 }
248
249 void dp_gtk_item_factory_create_items(DPGtkItemFactory *ifactory,
250 guint n_entries,
251 DPGtkItemFactoryEntry *entries,
252 gpointer callback_data)
253 {
254 gint i;
255
256 for (i = 0; i < n_entries; i++) {
257 dp_gtk_item_factory_create_item(ifactory, &entries[i], callback_data, 0);
258 }
259 }
260
261 GtkWidget *dp_gtk_item_factory_get_widget(DPGtkItemFactory *ifactory,
262 const gchar *path)
263 {
264 gint root_len;
265 GSList *list;
266 DPGtkItemFactoryChild *child;
267
268 root_len = strlen(ifactory->path);
269 if (!path || strlen(path) < root_len)
270 return NULL;
271
272 if (strncmp(ifactory->path, path, root_len) != 0)
273 return NULL;
274 if (strlen(path) == root_len)
275 return ifactory->top_widget;
276
277 for (list = ifactory->children; list; list = g_slist_next(list)) {
278 child = (DPGtkItemFactoryChild *)list->data;
279 if (PathCmp(child->path, &path[root_len]) == 1)
280 return child->widget;
281 }
282 return NULL;
283 }
284
285 void dp_gtk_item_factory_set_translate_func(DPGtkItemFactory *ifactory,
286 DPGtkTranslateFunc func,
287 gpointer data,
288 GDestroyNotify notify)
289 {
290 ifactory->translate_func = func;
291 ifactory->translate_data = data;
292 }
293
294 #endif /* defined(CYGWIN) || GTK_MAJOR_VERSION > 2 */