1 /* Copyright (C) 2000-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 "basics.h"
31 #include "fontforgeui.h"
32 #include "gfile.h"
33 #include "scripting.h"
34 #include "splinefont.h"
35 #include "ustring.h"
36 
WindowSelect(GWindow base,struct gmenuitem * mi,GEvent * e)37 static void WindowSelect(GWindow base,struct gmenuitem *mi,GEvent *e) {
38     GDrawRaise(mi->ti.userdata);
39 }
40 
AddMI(GMenuItem * mi,GWindow gw,int changed,int top)41 static void AddMI(GMenuItem *mi,GWindow gw,int changed, int top) {
42     mi->ti.userdata = gw;
43     mi->ti.bg = GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(gw));
44     mi->invoke = WindowSelect;
45     mi->ti.text = GDrawGetWindowTitle(gw);
46     if(mi->ti.text == NULL)
47 	mi->ti.text = utf82u_copy("(null)");
48     if ( u_strlen( mi->ti.text ) > 35 )
49 	mi->ti.text[35] = '\0';
50 }
51 
52 /* Builds up a menu containing the titles of all the major windows */
WindowMenuBuild(GWindow basew,struct gmenuitem * mi,GEvent * e)53 void WindowMenuBuild(GWindow basew,struct gmenuitem *mi,GEvent *e) {
54     int i, cnt, precnt;
55     FontViewBase *fv;
56     CharViewBase *cv;
57     MetricsView *mv;
58     BitmapView *bv;
59     GMenuItem *sub;
60     BDFFont *bdf;
61 
62     precnt = 6;
63     cnt = precnt;
64 
65     for ( fv = (FontViewBase *) fv_list; fv!=NULL; fv = fv->next ) {
66 	++cnt;		/* for the font */
67 	for ( i=0; i<fv->sf->glyphcnt; ++i ) if ( fv->sf->glyphs[i]!=NULL ) {
68 	    for ( cv = fv->sf->glyphs[i]->views; cv!=NULL; cv=cv->next )
69 		++cnt;		/* for each char view in the font */
70 	}
71 	for ( bdf= fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
72 	    for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL ) {
73 		for ( bv = bdf->glyphs[i]->views; bv!=NULL; bv=bv->next )
74 		    ++cnt;
75 	    }
76 	}
77 	for ( mv=fv->sf->metrics; mv!=NULL; mv=mv->next )
78 	    ++cnt;
79     }
80     if ( cnt==0 ) {
81 	/* This can't happen */
82 return;
83     }
84     sub = calloc(cnt+1,sizeof(GMenuItem));
85     memcpy(sub,mi->sub,precnt*sizeof(struct gmenuitem));
86     for ( i=0; i<precnt; ++i )
87 	mi->sub[i].ti.text = NULL;
88     GMenuItemArrayFree(mi->sub);
89     mi->sub = sub;
90 
91     for ( i=0; sub[i].ti.text!=NULL || sub[i].ti.line; ++i ) {
92 	if ( sub[i].ti.text_is_1byte && sub[i].ti.text_in_resource) {
93 	    sub[i].ti.text = utf82u_mncopy((char *) sub[i].ti.text,&sub[i].ti.mnemonic);
94 	    sub[i].ti.text_is_1byte = sub[i].ti.text_in_resource = false;
95 	} else if ( sub[i].ti.text_is_1byte ) {
96 	    sub[i].ti.text = utf82u_copy((char *) sub[i].ti.text);
97 	    sub[i].ti.text_is_1byte = false;
98 	} else if ( sub[i].ti.text_in_resource ) {
99 	    sub[i].ti.text = u_copy(GStringGetResource((intpt) sub[i].ti.text,NULL));
100 	    sub[i].ti.text_in_resource = false;
101 	} else
102 	    sub[i].ti.text = u_copy(sub[i].ti.text);
103     }
104     cnt = precnt;
105     for ( fv = (FontViewBase *) fv_list; fv!=NULL; fv = fv->next ) {
106 	if( !((FontView *) fv)->gw ) {
107 	    continue;
108 	}
109 
110 	AddMI(&sub[cnt++],((FontView *) fv)->gw,fv->sf->changed,true);
111 	for ( i=0; i<fv->sf->glyphcnt; ++i ) if ( fv->sf->glyphs[i]!=NULL ) {
112 	    for ( cv = fv->sf->glyphs[i]->views; cv!=NULL; cv=cv->next )
113 		AddMI(&sub[cnt++],((CharView *) cv)->gw,cv->sc->changed,false);
114 	}
115 	for ( bdf= fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
116 	    for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL ) {
117 		for ( bv = bdf->glyphs[i]->views; bv!=NULL; bv=bv->next )
118 		    AddMI(&sub[cnt++],bv->gw,bv->bc->changed,false);
119 	    }
120 	}
121 	for ( mv=fv->sf->metrics; mv!=NULL; mv=mv->next )
122 	    AddMI(&sub[cnt++],mv->gw,false,false);
123     }
124 }
125 
RecentSelect(GWindow base,struct gmenuitem * mi,GEvent * e)126 static void RecentSelect(GWindow base,struct gmenuitem *mi,GEvent *e) {
127     ViewPostScriptFont((char *) (mi->ti.userdata),0);
128 }
129 
130 /* Builds up a menu containing the titles of all the unused recent files */
MenuRecentBuild(GWindow base,struct gmenuitem * mi,GEvent * e)131 void MenuRecentBuild(GWindow base,struct gmenuitem *mi,GEvent *e) {
132     int i, cnt, cnt1;
133     FontViewBase *fv;
134     GMenuItem *sub;
135 
136     if ( mi->sub!=NULL ) {
137 	GMenuItemArrayFree(mi->sub);
138 	mi->sub = NULL;
139     }
140 
141     cnt = 0;
142     for ( i=0; i<RECENT_MAX && RecentFiles[i]!=NULL; ++i ) {
143 	for ( fv=(FontViewBase *) fv_list; fv!=NULL; fv=fv->next )
144 	    if ( fv->sf->filename!=NULL && strcmp(fv->sf->filename,RecentFiles[i])==0 )
145 	break;
146 	if ( fv==NULL )
147 	    ++cnt;
148     }
149     if ( cnt==0 ) {
150 	/* This can't happen */
151 return;
152     }
153     sub = calloc(cnt+1,sizeof(GMenuItem));
154     cnt1 = 0;
155     for ( i=0; i<RECENT_MAX && RecentFiles[i]!=NULL; ++i ) {
156 	for ( fv=(FontViewBase *) fv_list; fv!=NULL; fv=fv->next )
157 	    if ( fv->sf->filename!=NULL && strcmp(fv->sf->filename,RecentFiles[i])==0 )
158 	break;
159 	if ( fv==NULL ) {
160 	    GMenuItem *mi = &sub[cnt1++];
161 	    mi->ti.userdata = RecentFiles[i];
162 	    mi->ti.bg = mi->ti.fg = COLOR_DEFAULT;
163 	    mi->invoke = RecentSelect;
164 	    mi->ti.text = def2u_copy(GFileNameTail(RecentFiles[i]));
165 	}
166     }
167     if ( cnt!=cnt1 )
168 	IError( "Bad counts in MenuRecentBuild");
169     mi->sub = sub;
170 }
171 
RecentFilesAny(void)172 int RecentFilesAny(void) {
173     int i;
174     FontViewBase *fvl;
175 
176     for ( i=0; i<RECENT_MAX && RecentFiles[i]!=NULL; ++i ) {
177 	for ( fvl=(FontViewBase *) fv_list; fvl!=NULL; fvl=fvl->next )
178 	    if ( fvl->sf->filename!=NULL && strcmp(fvl->sf->filename,RecentFiles[i])==0 )
179 	break;
180 	if ( fvl==NULL )
181 return( true );
182     }
183 return( false );
184 }
185 
186 #if !defined(_NO_FFSCRIPT) || !defined(_NO_PYTHON)
ScriptSelect(GWindow base,struct gmenuitem * mi,GEvent * e)187 static void ScriptSelect(GWindow base,struct gmenuitem *mi,GEvent *e) {
188     int index = (intpt) (mi->ti.userdata);
189     FontView *fv = (FontView *) GDrawGetUserData(base);
190 
191     /* the menu is not always up to date. If user changed prefs and then used */
192     /*  Alt|Ctl|Digit s/he would not get a new menu built and the old one might*/
193     /*  refer to something out of bounds. Hence the check */
194     if ( index<0 || script_filenames[index]==NULL )
195 return;
196     ExecuteScriptFile((FontViewBase *) fv,NULL,script_filenames[index]);
197 }
198 
199 /* Builds up a menu containing any user defined scripts */
MenuScriptsBuild(GWindow base,struct gmenuitem * mi,GEvent * e)200 void MenuScriptsBuild(GWindow base,struct gmenuitem *mi,GEvent *e) {
201     int i;
202     GMenuItem *sub;
203 
204     if ( mi->sub!=NULL ) {
205 	GMenuItemArrayFree(mi->sub);
206 	mi->sub = NULL;
207     }
208 
209     for ( i=0; i<SCRIPT_MENU_MAX && script_menu_names[i]!=NULL; ++i );
210     if ( i==0 ) {
211 	/* This can't happen */
212 return;
213     }
214     sub = calloc(i+1,sizeof(GMenuItem));
215     for ( i=0; i<SCRIPT_MENU_MAX && script_menu_names[i]!=NULL; ++i ) {
216 	GMenuItem *mi = &sub[i];
217 	mi->ti.userdata = (void *) (intpt) i;
218 	mi->ti.bg = mi->ti.fg = COLOR_DEFAULT;
219 	mi->invoke = ScriptSelect;
220 	mi->shortcut = i==9?'0':'1'+i;
221 	mi->short_mask = ksm_control|ksm_meta;
222 	mi->ti.text = u_copy(script_menu_names[i]);
223     }
224     mi->sub = sub;
225 }
226 #endif
227 
228 /* Builds up a menu containing all the anchor classes */
_aplistbuild(struct gmenuitem * top,SplineFont * sf,void (* func)(GWindow,struct gmenuitem *,GEvent *))229 void _aplistbuild(struct gmenuitem *top,SplineFont *sf,
230 	void (*func)(GWindow,struct gmenuitem *,GEvent *)) {
231     int cnt;
232     GMenuItem *mi, *sub;
233     AnchorClass *ac;
234 
235     if ( top->sub!=NULL ) {
236 	GMenuItemArrayFree(top->sub);
237 	top->sub = NULL;
238     }
239 
240     cnt = 0;
241     for ( ac = sf->anchor; ac!=NULL; ac=ac->next ) ++cnt;
242     if ( cnt==0 )
243 	cnt = 1;
244     else
245 	cnt += 2;
246     sub = calloc(cnt+1,sizeof(GMenuItem));
247     mi = &sub[0];
248     mi->ti.userdata = (void *) (-1);
249     mi->ti.bg = mi->ti.fg = COLOR_DEFAULT;
250     mi->invoke = func;
251     mi->ti.text = utf82u_copy(_("All"));
252     if ( cnt==1 )
253 	mi->ti.disabled = true;
254     else {
255 	++mi;
256 	mi->ti.bg = mi->ti.fg = COLOR_DEFAULT;
257 	mi->ti.line = true;
258 	++mi;
259     }
260     for ( ac=sf->anchor; ac!=NULL; ac = ac->next, ++mi ) {
261 	mi->ti.userdata = (void *) ac;
262 	mi->ti.bg = mi->ti.fg = COLOR_DEFAULT;
263 	mi->invoke = func;
264 	mi->ti.text = utf82u_copy(ac->name);
265     }
266     top->sub = sub;
267 }
268 
mbFreeGetText(GMenuItem * mb)269 void mbFreeGetText(GMenuItem *mb) {
270     /* free gettext substitutions on this menu and all sub menus */
271     int i;
272 
273     if ( mb==NULL )
274 return;
275     for ( i=0; mb[i].ti.text!=NULL || mb[i].ti.line || mb[i].ti.image!=NULL; ++i ) {
276         if (mb[i].ti.text_untranslated != NULL) { free(mb[i].ti.text_untranslated); mb[i].ti.text_untranslated = NULL; }
277 	if ( mb[i].ti.text!=NULL ) {
278 	    if ( mb[i].sub!=NULL )
279 		mbFreeGetText(mb[i].sub);
280 	}
281     }
282 }
283 
mbDoGetText(GMenuItem * mb)284 void mbDoGetText(GMenuItem *mb) {
285     /* perform gettext substitutions on this menu and all sub menus */
286     int i;
287 
288     if ( mb==NULL )
289 return;
290     for ( i=0; mb[i].ti.text!=NULL || mb[i].ti.line || mb[i].ti.image!=NULL; ++i ) {
291 	if( mb[i].shortcut ) {
292 	    unichar_t tmp[2];
293 	    tmp[0] = mb[i].shortcut;
294 	    tmp[1] = (unichar_t)(0);
295 	    mb[i].ti.text_untranslated = cu_copy(tmp);
296 	} else
297 	    mb[i].ti.text_untranslated = copy((char*)mb[i].ti.text);
298 	if ( mb[i].ti.text!=NULL ) {
299 	    mb[i].ti.text = (unichar_t *) S_((char *) mb[i].ti.text);
300 	    if ( mb[i].sub!=NULL )
301 		mbDoGetText(mb[i].sub);
302 	}
303     }
304 }
305 
mb2FreeGetText(GMenuItem2 * mb)306 void mb2FreeGetText(GMenuItem2 *mb) {
307     /* free gettext substitutions on this menu and all sub menus */
308     int i;
309 
310     if ( mb==NULL )
311 return;
312     for ( i=0; mb[i].ti.text!=NULL || mb[i].ti.line || mb[i].ti.image!=NULL; ++i ) {
313 	if (mb[i].ti.text_untranslated != NULL) { free(mb[i].ti.text_untranslated); mb[i].ti.text_untranslated = NULL; }
314 	if ( mb[i].ti.text!=NULL ) {
315 	    if ( mb[i].sub!=NULL )
316 		mb2FreeGetText(mb[i].sub);
317 	}
318     }
319 }
320 
mb2DoGetText(GMenuItem2 * mb)321 void mb2DoGetText(GMenuItem2 *mb) {
322     /* perform gettext substitutions on this menu and all sub menus */
323     int i;
324 
325     if ( mb==NULL )
326 return;
327     for ( i=0; mb[i].ti.text!=NULL || mb[i].ti.line || mb[i].ti.image!=NULL; ++i ) {
328 	if( mb[i].shortcut )
329 	    mb[i].ti.text_untranslated = copy(mb[i].shortcut);
330 	else
331 	    mb[i].ti.text_untranslated = copy((char*)mb[i].ti.text);
332 	if ( mb[i].ti.text!=NULL ) {
333 	    mb[i].ti.text = (unichar_t *) S_((char *) mb[i].ti.text);
334 	    if ( mb[i].sub!=NULL )
335 		mb2DoGetText(mb[i].sub);
336 	}
337     }
338 }
339