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