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