1 /* Copyright (C) 2007-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "cvundoes.h"
31 #include "fontforgeui.h"
32 #include "usermenu.h"
33 #include "ustring.h"
34
35 typedef struct menu_info {
36 menu_info_func func;
37 menu_info_check check_enabled;
38 menu_info_data data;
39 } MenuInfo;
40
41 static MenuInfo *cv_menu_data = NULL;
42 static MenuInfo *fv_menu_data = NULL;
43 static int cv_menu_cnt = 0;
44 static int cv_menu_max = 0;
45 static int fv_menu_cnt = 0;
46 static int fv_menu_max = 0;
47
48 GMenuItem2 *cv_menu;
49 GMenuItem2 *fv_menu;
50
51 static void
tl2listcheck(struct gmenuitem * mi,void * owner,struct menu_info * menu_data,int menu_cnt)52 tl2listcheck(struct gmenuitem *mi,
53 void *owner,
54 struct menu_info *menu_data,
55 int menu_cnt)
56 {
57 int result;
58
59 if (menu_data==NULL)
60 return;
61
62 for (mi = mi->sub; mi->ti.text != NULL || mi->ti.line; ++mi) {
63 if (mi->mid == -1) /* Submenu */
64 continue;
65 if (mi->mid < 0 || mi->mid >= menu_cnt) {
66 fprintf(stderr, "Bad Menu ID in python menu %d\n", mi->mid);
67 mi->ti.disabled = true;
68 continue;
69 }
70 if (menu_data[mi->mid].check_enabled == NULL) {
71 mi->ti.disabled = false;
72 continue;
73 }
74 result = (*menu_data[mi->mid].check_enabled)(menu_data[mi->mid].data, owner);
75 mi->ti.disabled = (result == 0);
76 }
77 }
78
79 void
cv_tl2listcheck(GWindow gw,struct gmenuitem * mi,GEvent * e)80 cv_tl2listcheck(GWindow gw, struct gmenuitem *mi, GEvent *e)
81 {
82 CharView *cv = (CharView *) GDrawGetUserData(gw);
83
84 if (cv_menu_data != NULL) {
85 sc_active_in_ui = cv->b.sc;
86 layer_active_in_ui = CVLayer((CharViewBase *) cv);
87 tl2listcheck(mi, cv->b.sc, cv_menu_data, cv_menu_cnt);
88 sc_active_in_ui = NULL;
89 layer_active_in_ui = ly_fore;
90 }
91 }
92
93 void
fv_tl2listcheck(GWindow gw,struct gmenuitem * mi,GEvent * e)94 fv_tl2listcheck(GWindow gw, struct gmenuitem *mi, GEvent *e)
95 {
96 FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
97
98 if (fv_menu_data != NULL) {
99 fv_active_in_ui = fv;
100 layer_active_in_ui = fv->active_layer;
101 tl2listcheck(mi, fv, fv_menu_data, fv_menu_cnt);
102 fv_active_in_ui = NULL;
103 }
104 }
105
106 static void
menuactivate(struct gmenuitem * mi,void * owner,MenuInfo * menu_data,int menu_cnt)107 menuactivate(struct gmenuitem *mi,
108 void *owner,
109 MenuInfo *menu_data,
110 int menu_cnt)
111 {
112 if (mi->mid == -1) /* Submenu */
113 return;
114 if (mi->mid < 0 || mi->mid >= menu_cnt) {
115 fprintf(stderr, "Bad Menu ID in python menu %d\n", mi->mid);
116 return;
117 }
118 if (menu_data[mi->mid].func == NULL) {
119 return;
120 }
121 (*menu_data[mi->mid].func)(menu_data[mi->mid].data, owner);
122 }
123
124 static void
cv_menuactivate(GWindow gw,struct gmenuitem * mi,GEvent * e)125 cv_menuactivate(GWindow gw, struct gmenuitem *mi, GEvent *e)
126 {
127 CharView *cv = (CharView *) GDrawGetUserData(gw);
128
129 if (cv_menu_data != NULL) {
130 sc_active_in_ui = cv->b.sc;
131 layer_active_in_ui = CVLayer((CharViewBase *) cv);
132 menuactivate(mi, cv->b.sc, cv_menu_data, cv_menu_cnt);
133 sc_active_in_ui = NULL;
134 layer_active_in_ui = ly_fore;
135 }
136 }
137
138 static void
fv_menuactivate(GWindow gw,struct gmenuitem * mi,GEvent * e)139 fv_menuactivate(GWindow gw, struct gmenuitem *mi, GEvent *e)
140 {
141 FontViewBase *fv = (FontViewBase *) GDrawGetUserData(gw);
142
143 if (fv_menu_data!=NULL) {
144 fv_active_in_ui = fv;
145 layer_active_in_ui = fv->active_layer;
146 menuactivate(mi, fv, fv_menu_data, fv_menu_cnt);
147 fv_active_in_ui = NULL;
148 }
149 }
150
151 static int
MenuDataAdd(menu_info_func func,menu_info_check check,menu_info_data data,int is_cv)152 MenuDataAdd(menu_info_func func, menu_info_check check, menu_info_data data, int is_cv)
153 {
154 int index;
155
156 if (is_cv) {
157 if (cv_menu_cnt >= cv_menu_max)
158 cv_menu_data = realloc(cv_menu_data,(cv_menu_max+=10)*sizeof(struct menu_info));
159 cv_menu_data[cv_menu_cnt].func = func;
160 cv_menu_data[cv_menu_cnt].check_enabled = check;
161 cv_menu_data[cv_menu_cnt].data = data;
162 index = cv_menu_cnt;
163 cv_menu_cnt++;
164 } else {
165 if (fv_menu_cnt >= fv_menu_max)
166 fv_menu_data = realloc(fv_menu_data,(fv_menu_max+=10)*sizeof(struct menu_info));
167 fv_menu_data[fv_menu_cnt].func = func;
168 fv_menu_data[fv_menu_cnt].check_enabled = check;
169 fv_menu_data[fv_menu_cnt].data = data;
170 index = fv_menu_cnt;
171 fv_menu_cnt++;
172 }
173 return index;
174 }
175
176 static void
InsertSubMenus(menu_info_func func,menu_info_check check,menu_info_data data,char * shortcut_str,char ** submenu_names,GMenuItem2 ** mn,int is_cv)177 InsertSubMenus(menu_info_func func,
178 menu_info_check check,
179 menu_info_data data,
180 char *shortcut_str,
181 char **submenu_names,
182 GMenuItem2 **mn,
183 int is_cv)
184 {
185 int i;
186 int j;
187 GMenuItem2 *mmn;
188
189 for (i = 0; submenu_names[i] != NULL; ++i) {
190 unichar_t *submenuu = utf82u_copy(submenu_names[i]);
191
192 j = 0;
193 if (*mn != NULL) {
194 for (j = 0; (*mn)[j].ti.text != NULL || (*mn)[j].ti.line; ++j) {
195 if ((*mn)[j].ti.text == NULL)
196 continue;
197 if (u_strcmp((*mn)[j].ti.text, submenuu) == 0)
198 break;
199 }
200 }
201
202 if (*mn == NULL || (*mn)[j].ti.text == NULL) {
203 *mn = realloc(*mn,(j+2)*sizeof(GMenuItem2));
204 memset(*mn+j,0,2*sizeof(GMenuItem2));
205 }
206 mmn = *mn;
207 if (mmn[j].ti.text == NULL) {
208 mmn[j].ti.text = submenuu;
209 mmn[j].ti.fg = mmn[j].ti.bg = COLOR_DEFAULT;
210 if (submenu_names[i + 1] != NULL) {
211 mmn[j].mid = -1;
212 mmn[j].moveto = is_cv ? cv_tl2listcheck : fv_tl2listcheck;
213 mn = &mmn[j].sub;
214 } else {
215 mmn[j].shortcut = copy(shortcut_str);
216 mmn[j].invoke = is_cv ? cv_menuactivate : fv_menuactivate;
217 mmn[j].mid = MenuDataAdd(func, check, data, is_cv);
218 }
219 } else {
220 if (submenu_names[i + 1] != NULL)
221 mn = &mmn[j].sub;
222 else {
223 mmn[j].shortcut = copy(shortcut_str);
224 mmn[j].invoke = is_cv ? cv_menuactivate : fv_menuactivate;
225 mmn[j].mid = MenuDataAdd(func, check, data, is_cv);
226 fprintf(stderr, "Redefining menu item %s\n", submenu_names[i]);
227 free(submenuu);
228 }
229 }
230 }
231 }
232
233 void
RegisterMenuItem(menu_info_func func,menu_info_check check,menu_info_data data,int flags,char * shortcut_str,char ** submenu_names)234 RegisterMenuItem(menu_info_func func,
235 menu_info_check check,
236 menu_info_data data,
237 int flags,
238 char *shortcut_str,
239 char **submenu_names)
240 {
241 if (!no_windowing_ui) {
242 if (flags & menu_fv)
243 InsertSubMenus(func, check, data, shortcut_str,
244 submenu_names, &fv_menu, false);
245 if (flags & menu_cv)
246 InsertSubMenus(func, check, data, shortcut_str,
247 submenu_names, &cv_menu, true);
248 }
249 }
250