1 /* Copyright (C) 2003-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 "dumppfa.h"
31 #include "encoding.h"
32 #include "fontforgeui.h"
33 #include "fvfonts.h"
34 #include "gkeysym.h"
35 #include "macenc.h"
36 #include "mem.h"
37 #include "mm.h"
38 #include "parsettf.h"
39 #include "psread.h"
40 #include "sfd.h"
41 #include "splinefill.h"
42 #include "splineutil.h"
43 #include "splineutil2.h"
44 #include "tottfvar.h"
45 #include "ttf.h"
46 #include "ustring.h"
47 #include "utype.h"
48
49 #include <locale.h>
50 #include <math.h>
51
52 /* As far as I can tell, the CDV in AdobeSansMM is half gibberish */
53 /* This is disturbing */
54 /* But at least the CDV in Type1_supp.pdf for Myriad appears correct */
55 static char *standard_cdvs[5] = {
56 /* 0 axes? Impossible */
57 "{}",
58 /* 1 axis */
59 "{\n"
60 " 1 1 index sub 2 1 roll\n"
61 " 0 index 2 1 roll\n"
62 " pop\n"
63 "}",
64 /* 2 axes */
65 "{\n"
66 " 1 2 index sub 1 2 index sub mul 3 1 roll\n"
67 " 1 index 1 2 index sub mul 3 1 roll\n"
68 " 1 2 index sub 1 index mul 3 1 roll\n"
69 " 1 index 1 index mul 3 1 roll\n"
70 " pop pop\n"
71 "}",
72 /* 3 axes */
73 "{\n"
74 " 1 3 index sub 1 3 index sub mul 1 2 index sub mul 4 1 roll\n"
75 " 2 index 1 3 index sub mul 1 2 index sub mul 4 1 roll\n"
76 " 1 3 index sub 2 index mul 1 2 index sub mul 4 1 roll\n"
77 " 2 index 2 index mul 1 2 index sub mul 4 1 roll\n"
78 " 1 3 index sub 1 3 index sub mul 1 index mul 4 1 roll\n"
79 " 2 index 1 3 index sub mul 1 index mul 4 1 roll\n"
80 " 1 3 index sub 2 index mul 1 index mul 4 1 roll\n"
81 " 2 index 2 index mul 1 index mul 4 1 roll\n"
82 " pop pop pop\n"
83 "}",
84 /* 4 axes */
85 /* This requires too big a string. We must build it at runtime */
86 NULL
87 };
88 static char *cdv_4axis[3] = {
89 "{\n"
90 " 1 4 index sub 1 4 index sub mul 1 3 index sub mul 1 2 index sub mul 5 1 roll\n"
91 " 3 index 1 4 index sub mul 1 3 index sub mul 1 2 index sub mul 5 1 roll\n"
92 " 1 4 index sub 3 index mul 1 3 index sub mul 1 2 index sub mul 5 1 roll\n"
93 " 3 index 3 index mul 1 3 index sub mul 1 2 index sub mul 5 1 roll\n"
94 " 1 4 index sub 1 4 index sub mul 2 index mul 1 2 index sub mul 5 1 roll\n"
95 " 3 index 1 4 index sub mul 2 index mul 1 2 index sub mul 5 1 roll\n",
96 " 1 4 index sub 3 index mul 2 index mul 1 2 index sub mul 5 1 roll\n"
97 " 3 index 3 index mul 2 index mul 1 2 index sub mul 5 1 roll\n"
98 " 1 4 index sub 1 4 index sub mul 1 3 index sub mul 1 index mul 5 1 roll\n"
99 " 3 index 1 4 index sub mul 1 3 index sub mul 1 index mul 5 1 roll\n"
100 " 1 4 index sub 3 index mul 1 3 index sub mul 1 index mul 5 1 roll\n",
101 " 3 index 3 index mul 1 3 index sub mul 1 index mul 5 1 roll\n"
102 " 1 4 index sub 1 4 index sub mul 2 index mul 1 index mul 5 1 roll\n"
103 " 3 index 1 4 index sub mul 2 index mul 1 index mul 5 1 roll\n"
104 " 1 4 index sub 3 index mul 2 index mul 1 index mul 5 1 roll\n"
105 " 3 index 3 index mul 2 index mul 1 index mul 5 1 roll\n"
106 " pop pop pop pop\n"
107 "}"
108 };
109
110 static char *axistablab[] = { N_("Axis 1"), N_("Axis 2"), N_("Axis 3"), N_("Axis 4") };
111
ExecConvertDesignVector(real * designs,int dcnt,char * ndv,char * cdv,real * stack)112 static int ExecConvertDesignVector(real *designs, int dcnt, char *ndv, char *cdv,
113 real *stack) {
114 char *temp, dv[101];
115 int j, len, cnt;
116
117 /* PostScript parses things in "C" locale too */
118 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
119 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
120 len = 0;
121 for ( j=0; j<dcnt; ++j ) {
122 sprintf(dv+len, "%g ", (double) designs[j]);
123 len += strlen(dv+len);
124 }
125 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
126
127 temp = malloc(len+strlen(ndv)+strlen(cdv)+20);
128 strcpy(temp,dv);
129 /*strcpy(temp+len++," ");*/ /* dv always will end in a space */
130
131 while ( isspace(*ndv)) ++ndv;
132 if ( *ndv=='{' )
133 ++ndv;
134 strcpy(temp+len,ndv);
135 len += strlen(temp+len);
136 while ( len>0 && (temp[len-1]==' '||temp[len-1]=='\n') ) --len;
137 if ( len>0 && temp[len-1]=='}' ) --len;
138
139 while ( isspace(*cdv)) ++cdv;
140 if ( *cdv=='{' )
141 ++cdv;
142 strcpy(temp+len,cdv);
143 len += strlen(temp+len);
144 while ( len>0 && (temp[len-1]==' '||temp[len-1]=='\n') ) --len;
145 if ( len>0 && temp[len-1]=='}' ) --len;
146
147 cnt = EvaluatePS(temp,stack,MmMax);
148 free(temp);
149 return( cnt );
150 }
151
StandardPositions(MMSet * mm,int instance_count,int axis_count,int isapple)152 static int StandardPositions(MMSet *mm,int instance_count, int axis_count,int isapple) {
153 int i,j,factor,v;
154
155 if ( !isapple ) {
156 for ( i=0; i<instance_count; ++i ) {
157 for ( j=0; j<axis_count; ++j )
158 if ( mm->positions[i*mm->axis_count+j]!= ( (i&(1<<j)) ? 1 : 0 ))
159 return( false );
160 }
161 } else {
162 for ( i=0; i<instance_count; ++i ) {
163 factor = 1;
164 for ( j=0; j<axis_count; ++j ) {
165 v = (i/factor)%3 -1;
166 if ( mm->positions[i*mm->axis_count+j]!= v )
167 return( false );
168 factor *= 3;
169 }
170 }
171 }
172 return( true );
173 }
174
OrderedPositions(MMSet * mm,int instance_count,int isapple)175 static int OrderedPositions(MMSet *mm,int instance_count, int isapple) {
176 /* For a 1 axis system, check that the positions are ordered */
177 int i;
178
179 if ( mm->positions[0]!=isapple?-1:0 ) /* must start at 0 */
180 return( false );
181 if ( mm->positions[(instance_count-1)*4]!=1 ) /* and end at 1 */
182 return( false );
183 for ( i=1; i<mm->instance_count; ++i )
184 if ( mm->positions[i*mm->axis_count]<=mm->positions[(i-1)*mm->axis_count] )
185 return( false );
186
187 return( true );
188 }
189
MMDesignCoords(MMSet * mm)190 static unichar_t *MMDesignCoords(MMSet *mm) {
191 char buffer[80], *pt;
192 int i;
193 real axiscoords[4];
194
195 if ( mm->instance_count!=(1<<mm->axis_count) ||
196 !StandardPositions(mm,mm->instance_count,mm->axis_count,false))
197 return( uc_copy(""));
198 MMWeightsUnMap(mm->defweights,axiscoords,mm->axis_count);
199 pt = buffer;
200 for ( i=0; i<mm->axis_count; ++i ) {
201 sprintf( pt,"%g ", (double) MMAxisUnmap(mm,i,axiscoords[i]));
202 pt += strlen(pt);
203 }
204 pt[-1] = ' ';
205 return( uc_copy( buffer ));
206 }
207
DoDelta(int16 ** deltas,int pt,int is_y,real * blends,int instance_count)208 static real DoDelta(int16 **deltas,int pt,int is_y,real *blends,int instance_count) {
209 real diff = 0;
210 int j;
211
212 for ( j=0; j<instance_count; ++j ) {
213 if ( blends[j]!=0 && deltas[2*j+is_y]!=NULL )
214 diff += blends[j]*deltas[2*j+is_y][pt];
215 }
216 return( diff );
217 }
218
DistortChar(SplineFont * sf,MMSet * mm,int gid,real * blends)219 static void DistortChar(SplineFont *sf,MMSet *mm,int gid,real *blends) {
220 int i,j,ptcnt;
221 int16 **deltas;
222 SplineSet *ss;
223 SplinePoint *sp;
224 RefChar *ref;
225 SplineChar *sc = sf->glyphs[gid];
226 Spline *s, *first;
227
228 if ( sc==NULL )
229 return;
230 deltas = SCFindDeltas(mm,gid,&ptcnt);
231 if ( deltas==NULL )
232 return;
233 /* I never delta the left side bearing or top */
234 sc->width += DoDelta(deltas,ptcnt-3,0,blends,mm->instance_count);
235 sc->vwidth += DoDelta(deltas,ptcnt-1,1,blends,mm->instance_count);
236 if ( sc->layers[ly_fore].refs!=NULL ) {
237 for ( i=0,ref = sc->layers[ly_fore].refs; ref!=NULL; ref=ref->next, ++i ) {
238 ref->transform[4] += DoDelta(deltas,i,0,blends,mm->instance_count);
239 ref->transform[5] += DoDelta(deltas,i,1,blends,mm->instance_count);
240 }
241 } else {
242 for ( ss=sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) {
243 for ( sp=ss->first;; ) {
244 if ( sp->ttfindex!=0xffff ) {
245 sp->me.x += DoDelta(deltas,sp->ttfindex,0,blends,mm->instance_count);
246 sp->me.y += DoDelta(deltas,sp->ttfindex,1,blends,mm->instance_count);
247 }
248 if ( sp->nextcpindex!=0xffff ) {
249 sp->nextcp.x += DoDelta(deltas,sp->nextcpindex,0,blends,mm->instance_count);
250 sp->nextcp.y += DoDelta(deltas,sp->nextcpindex,1,blends,mm->instance_count);
251 } else
252 sp->nextcp = sp->me;
253 if ( sp->next!=NULL )
254 sp->next->to->prevcp = sp->nextcp;
255 if ( sp->next==NULL )
256 break;
257 sp = sp->next->to;
258 if ( sp==ss->first )
259 break;
260 }
261 for ( sp=ss->first;; ) {
262 if ( sp->ttfindex==0xffff ) {
263 sp->me.x = (sp->prevcp.x+sp->nextcp.x)/2;
264 sp->me.y = (sp->prevcp.y+sp->nextcp.y)/2;
265 }
266 if ( sp->next==NULL )
267 break;
268 sp = sp->next->to;
269 if ( sp==ss->first )
270 break;
271 }
272 first = NULL;
273 for ( s=ss->first->next; s!=NULL && s!=first; s=s->to->next ) {
274 SplineRefigure(s);
275 if ( first==NULL ) first = s;
276 }
277 }
278 }
279 for ( j=0; j<2*mm->instance_count; ++j )
280 free( deltas[j]);
281 free(deltas);
282 }
283
DistortCvt(struct ttf_table * cvt,MMSet * mm,real * blends)284 static void DistortCvt(struct ttf_table *cvt,MMSet *mm,real *blends) {
285 int i,j,ptcnt;
286 real diff;
287 int16 **deltas;
288
289 deltas = CvtFindDeltas(mm,&ptcnt);
290 if ( deltas==NULL )
291 return;
292 for ( i=0; i<ptcnt; ++i ) {
293 diff = 0;
294 for ( j=0; j<mm->instance_count; ++j ) {
295 if ( blends[j]!=0 && deltas[j]!=NULL )
296 diff += blends[j]*deltas[j][i];
297 }
298 memputshort(cvt->data,2*i,memushort(cvt->data,cvt->len,2*i)+rint(diff));
299 }
300 for ( j=0; j<mm->instance_count; ++j )
301 free( deltas[j]);
302 free(deltas);
303 }
304
MakeAppleBlend(FontView * fv,MMSet * mm,real * blends,real * normalized)305 static void MakeAppleBlend(FontView *fv,MMSet *mm,real *blends,real *normalized) {
306 SplineFont *base = mm->normal;
307 SplineFont *sf = _MMNewFont(mm,-2,base->familyname,normalized);
308 int i;
309 struct ttf_table *tab, *cvt=NULL, *last=NULL, *cur;
310 RefChar *ref;
311
312 sf->mm = NULL;
313 for ( i=0; i<base->glyphcnt && i<sf->glyphcnt; ++i ) if ( base->glyphs[i]!=NULL ) {
314 sf->glyphs[i] = SplineCharCopy(base->glyphs[i],base,NULL);
315 for ( ref=sf->glyphs[i]->layers[ly_fore].refs; ref!=NULL; ref=ref->next )
316 ref->sc = NULL;
317 sf->glyphs[i]->orig_pos = i;
318 DistortChar(sf,mm,i,blends);
319 }
320 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
321 ttfFixupRef(sf->glyphs,i);
322 for ( tab=base->ttf_tables; tab!=NULL; tab=tab->next ) {
323 cur = chunkalloc(sizeof(struct ttf_table));
324 cur->tag = tab->tag;
325 cur->len = tab->len;
326 cur->data = malloc(tab->len);
327 memcpy(cur->data,tab->data,tab->len);
328 if ( cur->tag==CHR('c','v','t',' '))
329 cvt = cur;
330 if ( last==NULL )
331 sf->ttf_tables = cur;
332 else
333 last->next = cur;
334 last = cur;
335 }
336 if ( cvt!=NULL )
337 DistortCvt(cvt,mm,blends);
338 /* I don't know how to blend kerns */
339 /* Apple's Skia has 5 kerning classes (one for the base font and one for */
340 /* some of the instances) and the classes have different glyph classes */
341 /* I can't make a kern class out of them. I suppose I could generate a bunch */
342 /* of kern pairs, but ug. */
343 /* Nor is it clear whether the kerning info is a delta or not */
344
345 sf->changed = true;
346 EncMapFree(sf->map);
347 sf->map = EncMapFromEncoding(sf,fv->b.map->enc);
348 FontViewCreate(sf,false);
349 }
350
351 struct mmcb {
352 int done;
353 GWindow gw;
354 MMSet *mm;
355 FontView *fv;
356 int tonew;
357 };
358
359 #define CID_Explicit 6001
360 #define CID_ByDesign 6002
361 #define CID_NewBlends 6003
362 #define CID_NewDesign 6004
363 #define CID_Knowns 6005
364
MMCB_KnownValues(MMSet * mm)365 static GTextInfo *MMCB_KnownValues(MMSet *mm) {
366 GTextInfo *ti = calloc(mm->named_instance_count+2,sizeof(GTextInfo));
367 int i;
368
369 ti[0].text = uc_copy(" --- ");
370 ti[0].bg = ti[0].fg = COLOR_DEFAULT;
371 for ( i=0; i<mm->named_instance_count; ++i ) {
372 ti[i+1].text = (unichar_t *) PickNameFromMacName(mm->named_instances[i].names);
373 ti[i+1].text_is_1byte = true;
374 ti[i+1].bg = ti[i+1].fg = COLOR_DEFAULT;
375 }
376 return( ti );
377 }
378
MMCB_PickedKnown(GGadget * g,GEvent * e)379 static int MMCB_PickedKnown(GGadget *g, GEvent *e) {
380 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
381 struct mmcb *mmcb = GDrawGetUserData(GGadgetGetWindow(g));
382 int which = GGadgetGetFirstListSelectedItem(g);
383 char buffer[24];
384 int i;
385 unichar_t *temp;
386
387 --which;
388 if ( which<0 )
389 return( true );
390 for ( i=0; i<mmcb->mm->axis_count; ++i ) {
391 sprintf( buffer, "%.4g", (double) mmcb->mm->named_instances[which].coords[i]);
392 temp = uc_copy(buffer);
393 GGadgetSetTitle(GWidgetGetControl(mmcb->gw,1000+i),temp);
394 free(temp);
395 }
396 }
397 return( true );
398 }
399
MMCB_Changed(GGadget * g,GEvent * e)400 static int MMCB_Changed(GGadget *g, GEvent *e) {
401 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
402 GWindow gw = GGadgetGetWindow(g);
403 int explicitblends = GGadgetIsChecked(GWidgetGetControl(gw,CID_Explicit));
404 GGadgetSetEnabled(GWidgetGetControl(gw,CID_NewBlends),explicitblends);
405 GGadgetSetEnabled(GWidgetGetControl(gw,CID_NewDesign),!explicitblends);
406 }
407 return( true );
408 }
409
GetWeights(GWindow gw,real blends[MmMax],MMSet * mm,int instance_count,int axis_count)410 static int GetWeights(GWindow gw, real blends[MmMax], MMSet *mm,
411 int instance_count, int axis_count) {
412 int explicitblends = GGadgetIsChecked(GWidgetGetControl(gw,CID_Explicit));
413 const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(gw,
414 explicitblends?CID_NewBlends:CID_NewDesign)), *upt;
415 unichar_t *uend;
416 int i;
417 real sum;
418
419 sum = 0;
420 for ( i=0, upt = ret; i<instance_count && *upt; ++i ) {
421 blends[i] = u_strtod(upt,&uend);
422 sum += blends[i];
423 if ( upt==uend )
424 break;
425 upt = uend;
426 while ( *upt==',' || *upt==' ' ) ++upt;
427 }
428 if ( (explicitblends && i!=instance_count ) ||
429 (!explicitblends && i!=axis_count ) ||
430 *upt!='\0' ) {
431 ff_post_error(_("Bad MM Weights"),_("Incorrect number of instances weights, or illegal numbers"));
432 return(false);
433 }
434 if ( explicitblends ) {
435 if ( sum<.99 || sum>1.01 ) {
436 ff_post_error(_("Bad MM Weights"),_("The weights for the default version of the font must sum to 1.0"));
437 return(false);
438 }
439 } else {
440 i = ExecConvertDesignVector(blends, i, mm->ndv, mm->cdv,
441 blends);
442 if ( i!=instance_count ) {
443 ff_post_error(_("Bad MM Weights"),_("The results produced by applying the NormalizeDesignVector and ConvertDesignVector functions were not the results expected. You may need to change these functions"));
444 return(false);
445 }
446 }
447 return( true );
448 }
449
MMCB_OKApple(GGadget * g,GEvent * e)450 static int MMCB_OKApple(GGadget *g, GEvent *e) {
451 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
452 struct mmcb *mmcb = GDrawGetUserData(GGadgetGetWindow(g));
453 real newcoords[4];
454 int i, j, k, err=false;
455 real blends[AppleMmMax];
456 MMSet *mm = mmcb->mm;
457
458 for ( i=0; i<mm->axis_count; ++i )
459 newcoords[i] = rint(GetReal8(mmcb->gw,1000+i,_(axistablab[i]),&err)*8096)/8096;
460 if ( err )
461 return( true );
462 /* Now normalize each */
463 for ( i=0; i<mm->axis_count; ++i ) {
464 for ( j=1; j<mm->axismaps[i].points; ++j ) {
465 if ( newcoords[i]<=mm->axismaps[i].designs[j] || j==mm->axismaps[i].points-1 ) {
466 if ( mm->axismaps[i].designs[j]==mm->axismaps[i].designs[j-1] )
467 newcoords[i] = mm->axismaps[i].blends[j];
468 else
469 newcoords[i] = mm->axismaps[i].blends[j-1] +
470 (newcoords[i]-mm->axismaps[i].designs[j-1])/
471 (mm->axismaps[i].designs[j]-mm->axismaps[i].designs[j-1]) *
472 (mm->axismaps[i].blends[j]-mm->axismaps[i].blends[j-1]);
473 newcoords[i] = rint(8096*newcoords[i])/8096; /* Apple's fixed numbers have a fair amount of rounding error */
474 break;
475 }
476 }
477 }
478 /* Now figure out the contribution of each design */
479 for ( k=0; k<mm->instance_count; ++k ) {
480 real factor = 1.0;
481 for ( i=0; i<mm->axis_count; ++i ) {
482 if ( (newcoords[i]<=0 && mm->positions[k*mm->axis_count+i]>0) ||
483 (newcoords[i]>=0 && mm->positions[k*mm->axis_count+i]<0)) {
484 factor = 0;
485 break;
486 }
487 if ( newcoords[i]==0 )
488 continue;
489 if ( newcoords[i]<0 )
490 factor *= -newcoords[i];
491 else
492 factor *= newcoords[i];
493 }
494 blends[k] = factor;
495 }
496 MakeAppleBlend(mmcb->fv,mm,blends,newcoords);
497 mmcb->done = true;
498 }
499 return( true );
500 }
501
MMCB_OK(GGadget * g,GEvent * e)502 static int MMCB_OK(GGadget *g, GEvent *e) {
503 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
504 struct mmcb *mmcb = GDrawGetUserData(GGadgetGetWindow(g));
505 real blends[MmMax];
506
507 if ( !GetWeights(mmcb->gw, blends, mmcb->mm, mmcb->mm->instance_count, mmcb->mm->axis_count))
508 return( true );
509 MMCreateBlendedFont(mmcb->mm,(FontViewBase *) mmcb->fv,blends,mmcb->tonew );
510 }
511 return( true );
512 }
513
MMCB_Cancel(GGadget * g,GEvent * e)514 static int MMCB_Cancel(GGadget *g, GEvent *e) {
515 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
516 struct mmcb *mmcb = GDrawGetUserData(GGadgetGetWindow(g));
517 mmcb->done = true;
518 }
519 return( true );
520 }
521
mmcb_e_h(GWindow gw,GEvent * event)522 static int mmcb_e_h(GWindow gw, GEvent *event) {
523 if ( event->type==et_close ) {
524 struct mmcb *mmcb = GDrawGetUserData(gw);
525 mmcb->done = true;
526 } else if ( event->type==et_char ) {
527 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
528 help("ui/menus/mmmenu.html", NULL);
529 return( true );
530 }
531 return( false );
532 }
533 return( true );
534 }
535
GCDFillupMacWeights(GGadgetCreateData * gcd,GTextInfo * label,int k,char * axisnames[4],char axisval[4][24],real * defcoords,int axis_count,MMSet * mm)536 static int GCDFillupMacWeights(GGadgetCreateData *gcd, GTextInfo *label, int k,
537 char *axisnames[4], char axisval[4][24],
538 real *defcoords,int axis_count,MMSet *mm) {
539 int i;
540 char *an;
541 char axisrange[80];
542
543 for ( i=0; i<axis_count; ++i ) {
544 sprintf( axisrange, " [%.4g %.4g %.4g]", (double) mm->axismaps[i].min,
545 (double) mm->axismaps[i].def, (double) mm->axismaps[i].max );
546 an = PickNameFromMacName(mm->axismaps[i].axisnames);
547 if ( an==NULL )
548 an = copy(mm->axes[i]);
549 axisnames[i] = malloc(strlen(axisrange)+3+strlen(an));
550 strcpy(axisnames[i],an);
551 strcat(axisnames[i],axisrange);
552 sprintf(axisval[i],"%.4g", (double) defcoords[i]);
553 free(an);
554 }
555 for ( ; i<4; ++i ) {
556 axisnames[i] = _(axistablab[i]);
557 axisval[i][0] = '\0';
558 }
559
560 for ( i=0; i<4; ++i ) {
561 label[k].text = (unichar_t *) axisnames[i];
562 label[k].text_is_1byte = true;
563 gcd[k].gd.label = &label[k];
564 gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = k==0 ? 4 : gcd[k-1].gd.pos.y+28;
565 gcd[k].gd.flags = i<axis_count ? (gg_visible | gg_enabled) : gg_visible;
566 gcd[k++].creator = GLabelCreate;
567
568 label[k].text = (unichar_t *) axisval[i];
569 label[k].text_is_1byte = true;
570 gcd[k].gd.label = &label[k];
571 gcd[k].gd.pos.x = 15; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+12;
572 gcd[k].gd.flags = gcd[k-1].gd.flags;
573 gcd[k].gd.cid = 1000+i;
574 gcd[k++].creator = GTextFieldCreate;
575 }
576 return( k );
577 }
578
MMChangeBlend(MMSet * mm,FontView * fv,int tonew)579 void MMChangeBlend(MMSet *mm,FontView *fv,int tonew) {
580 char buffer[MmMax*20], *pt;
581 unichar_t ubuf[MmMax*20];
582 int i, k, j, def_name;
583 struct mmcb mmcb;
584 GRect pos;
585 GWindow gw;
586 GWindowAttrs wattrs;
587 GGadgetCreateData gcd[14];
588 GTextInfo label[14];
589 unichar_t *utemp;
590 char axisval[4][24];
591 char *axisnames[4];
592 real defcoords[4];
593
594 if ( mm==NULL )
595 return;
596
597 memset(&mmcb,0,sizeof(mmcb));
598 mmcb.mm = mm;
599 mmcb.fv = fv;
600 mmcb.tonew = tonew;
601
602 memset(&wattrs,0,sizeof(wattrs));
603 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
604 wattrs.event_masks = ~(1<<et_charup);
605 wattrs.is_dlg = true;
606 wattrs.restrict_input_to_me = true;
607 wattrs.undercursor = 1;
608 wattrs.cursor = ct_pointer;
609 wattrs.utf8_window_title = tonew ? _("Blend to New Font"):_("MM Change Def Weights");
610 pos.x = pos.y = 0;
611
612 if ( !mm->apple ) {
613 pt = buffer;
614 for ( i=0; i<mm->instance_count; ++i ) {
615 sprintf( pt, "%g ", (double) mm->defweights[i]);
616 pt += strlen(pt);
617 }
618 if ( pt>buffer )
619 pt[-2] = '\0';
620 uc_strcpy(ubuf,buffer);
621
622 pos.width =GDrawPointsToPixels(NULL,GGadgetScale(270));
623 pos.height = GDrawPointsToPixels(NULL,200);
624 mmcb.gw = gw = GDrawCreateTopWindow(NULL,&pos,mmcb_e_h,&mmcb,&wattrs);
625
626 memset(&gcd,0,sizeof(gcd));
627 memset(&label,0,sizeof(label));
628
629 k=0;
630 /* GT: The following strings should be concatenated together, the result */
631 /* GT: translated, and then broken into lines by hand. I'm sure it would */
632 /* GT: be better to specify this all as one string, but my widgets won't support */
633 /* GT: that */
634 label[k].text = (unichar_t *) (tonew ? _("You may specify the new instance of this font") : _("You may change the default instance of this font"));
635 label[k].text_is_1byte = true;
636 gcd[k].gd.label = &label[k];
637 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = 10;
638 gcd[k].gd.flags = gg_visible | gg_enabled;
639 gcd[k++].creator = GLabelCreate;
640
641 label[k].text = (unichar_t *) _("either by explicitly entering the contribution");
642 label[k].text_is_1byte = true;
643 gcd[k].gd.label = &label[k];
644 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+13;
645 gcd[k].gd.flags = gg_visible | gg_enabled;
646 gcd[k++].creator = GLabelCreate;
647
648 label[k].text = (unichar_t *) _("of each master design, or by entering the design");
649 label[k].text_is_1byte = true;
650 gcd[k].gd.label = &label[k];
651 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+13;
652 gcd[k].gd.flags = gg_visible | gg_enabled;
653 gcd[k++].creator = GLabelCreate;
654
655 label[k].text = (unichar_t *) _("values for each axis");
656 label[k].text_is_1byte = true;
657 gcd[k].gd.label = &label[k];
658 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+13;
659 gcd[k].gd.flags = gg_visible | gg_enabled;
660 gcd[k++].creator = GLabelCreate;
661
662 label[k].text = (unichar_t *) _("Contribution of each master design");
663 label[k].text_is_1byte = true;
664 gcd[k].gd.label = &label[k];
665 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
666 gcd[k].gd.flags = gg_visible | gg_enabled | gg_cb_on;
667 gcd[k].gd.cid = CID_Explicit;
668 gcd[k].gd.handle_controlevent = MMCB_Changed;
669 gcd[k++].creator = GRadioCreate;
670
671 label[k].text = (unichar_t *) _("Design Axis Values");
672 label[k].text_is_1byte = true;
673 gcd[k].gd.label = &label[k];
674 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+45;
675 gcd[k].gd.flags = gg_visible | gg_enabled;
676 gcd[k].gd.cid = CID_ByDesign;
677 gcd[k].gd.handle_controlevent = MMCB_Changed;
678 gcd[k++].creator = GRadioCreate;
679
680 label[k].text = ubuf;
681 gcd[k].gd.label = &label[k];
682 gcd[k].gd.pos.x = 15; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y+18;
683 gcd[k].gd.pos.width = 240;
684 gcd[k].gd.flags = gg_visible | gg_enabled;
685 gcd[k].gd.cid = CID_NewBlends;
686 gcd[k++].creator = GTextFieldCreate;
687
688 label[k].text = utemp = MMDesignCoords(mm);
689 gcd[k].gd.label = &label[k];
690 gcd[k].gd.pos.x = 15; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y+18;
691 gcd[k].gd.pos.width = 240;
692 gcd[k].gd.flags = gg_visible;
693 gcd[k].gd.cid = CID_NewDesign;
694 gcd[k++].creator = GTextFieldCreate;
695
696 gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-35-3;
697 gcd[k].gd.pos.width = -1;
698 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
699 label[k].text = (unichar_t *) _("_OK");
700 label[k].text_is_1byte = true;
701 label[k].text_in_resource = true;
702 gcd[k].gd.label = &label[k];
703 gcd[k].gd.handle_controlevent = MMCB_OK;
704 gcd[k++].creator = GButtonCreate;
705
706 gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
707 gcd[k].gd.pos.width = -1;
708 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
709 label[k].text = (unichar_t *) _("_Cancel");
710 label[k].text_is_1byte = true;
711 label[k].text_in_resource = true;
712 gcd[k].gd.label = &label[k];
713 gcd[k].gd.handle_controlevent = MMCB_Cancel;
714 gcd[k++].creator = GButtonCreate;
715
716 gcd[k].gd.pos.x = 2; gcd[k].gd.pos.y = 2;
717 gcd[k].gd.pos.width = pos.width-4; gcd[k].gd.pos.height = pos.height-4;
718 gcd[k].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
719 gcd[k].creator = GGroupCreate;
720
721 GGadgetsCreate(gw,gcd);
722 free(utemp);
723 } else {
724 pos.width =GDrawPointsToPixels(NULL,GGadgetScale(270));
725 pos.height = GDrawPointsToPixels(NULL,200);
726 mmcb.gw = gw = GDrawCreateTopWindow(NULL,&pos,mmcb_e_h,&mmcb,&wattrs);
727
728 memset(&gcd,0,sizeof(gcd));
729 memset(&label,0,sizeof(label));
730
731 memset(defcoords,0,sizeof(defcoords));
732 for ( i=0; i<mm->axis_count; ++i )
733 defcoords[i] = mm->axismaps[i].def;
734 def_name = -1;
735 for ( i=0; i<mm->named_instance_count; ++i ) {
736 for ( j=0; j<mm->axis_count; ++j )
737 if ( !RealNear(mm->named_instances[i].coords[j],defcoords[j]))
738 break;
739 if ( j==mm->axis_count ) {
740 def_name = i;
741 break;
742 }
743 }
744
745 k=0;
746 k = GCDFillupMacWeights(gcd,label,k,axisnames,axisval,defcoords,
747 mm->axis_count,mm);
748
749 gcd[k].gd.pos.x = 130; gcd[k].gd.pos.y = gcd[k-4].gd.pos.y-12;
750 gcd[k].gd.flags = gg_visible | gg_enabled;
751 if ( mm->named_instance_count==0 )
752 gcd[k].gd.flags = 0;
753 gcd[k].gd.u.list = MMCB_KnownValues(mm);
754 if ( def_name!=-1 )
755 gcd[k].gd.u.list[def_name+1].selected = true;
756 gcd[k].gd.cid = CID_Knowns;
757 gcd[k].gd.handle_controlevent = MMCB_PickedKnown;
758 gcd[k++].creator = GListButtonCreate;
759
760 gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-35-3;
761 gcd[k].gd.pos.width = -1;
762 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
763 label[k].text = (unichar_t *) _("_OK");
764 label[k].text_is_1byte = true;
765 label[k].text_in_resource = true;
766 gcd[k].gd.label = &label[k];
767 gcd[k].gd.handle_controlevent = MMCB_OKApple;
768 gcd[k++].creator = GButtonCreate;
769
770 gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
771 gcd[k].gd.pos.width = -1;
772 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
773 label[k].text = (unichar_t *) _("_Cancel");
774 label[k].text_is_1byte = true;
775 label[k].text_in_resource = true;
776 gcd[k].gd.label = &label[k];
777 gcd[k].gd.handle_controlevent = MMCB_Cancel;
778 gcd[k++].creator = GButtonCreate;
779
780 gcd[k].gd.pos.x = 2; gcd[k].gd.pos.y = 2;
781 gcd[k].gd.pos.width = pos.width-4; gcd[k].gd.pos.height = pos.height-4;
782 gcd[k].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
783 gcd[k++].creator = GGroupCreate;
784
785 GGadgetsCreate(gw,gcd);
786 for ( i=0; i<mm->axis_count; ++i )
787 free(axisnames[i]);
788 GTextInfoListFree(gcd[k-4].gd.u.list);
789 GWidgetIndicateFocusGadget(gcd[1].ret);
790 }
791
792 GDrawSetVisible(gw,true);
793
794 while ( !mmcb.done )
795 GDrawProcessOneEvent(NULL);
796 GDrawDestroyWindow(gw);
797 }
798
799 GTextInfo axiscounts[] = {
800 { (unichar_t *) "1", NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
801 { (unichar_t *) "2", NULL, 0, 0, (void *) 2, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
802 { (unichar_t *) "3", NULL, 0, 0, (void *) 3, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
803 { (unichar_t *) "4", NULL, 0, 0, (void *) 4, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
804 GTEXTINFO_EMPTY
805 };
806
807 /* These names are fixed by Adobe & Apple and are not subject to translation */
808 GTextInfo axistypes[] = {
809 { (unichar_t *) "Weight", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
810 { (unichar_t *) "Width", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
811 { (unichar_t *) "OpticalSize", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
812 { (unichar_t *) "Slant", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
813 GTEXTINFO_EMPTY
814 };
815
816 GTextInfo mastercounts[] = {
817 { (unichar_t *) "1", NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
818 { (unichar_t *) "2", NULL, 0, 0, (void *) 2, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
819 { (unichar_t *) "3", NULL, 0, 0, (void *) 3, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
820 { (unichar_t *) "4", NULL, 0, 0, (void *) 4, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
821 { (unichar_t *) "5", NULL, 0, 0, (void *) 5, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
822 { (unichar_t *) "6", NULL, 0, 0, (void *) 6, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
823 { (unichar_t *) "7", NULL, 0, 0, (void *) 7, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
824 { (unichar_t *) "8", NULL, 0, 0, (void *) 8, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
825 { (unichar_t *) "9", NULL, 0, 0, (void *) 9, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
826 { (unichar_t *) "10", NULL, 0, 0, (void *) 10, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
827 { (unichar_t *) "11", NULL, 0, 0, (void *) 11, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
828 { (unichar_t *) "12", NULL, 0, 0, (void *) 12, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
829 { (unichar_t *) "13", NULL, 0, 0, (void *) 13, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
830 { (unichar_t *) "14", NULL, 0, 0, (void *) 14, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
831 { (unichar_t *) "15", NULL, 0, 0, (void *) 15, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
832 { (unichar_t *) "16", NULL, 0, 0, (void *) 16, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
833 { (unichar_t *) "17", NULL, 0, 0, (void *) 17, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
834 { (unichar_t *) "18", NULL, 0, 0, (void *) 18, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
835 { (unichar_t *) "19", NULL, 0, 0, (void *) 19, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
836 { (unichar_t *) "20", NULL, 0, 0, (void *) 20, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
837 { (unichar_t *) "21", NULL, 0, 0, (void *) 21, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
838 { (unichar_t *) "22", NULL, 0, 0, (void *) 22, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
839 { (unichar_t *) "23", NULL, 0, 0, (void *) 23, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
840 { (unichar_t *) "24", NULL, 0, 0, (void *) 24, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
841 { (unichar_t *) "25", NULL, 0, 0, (void *) 25, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
842 { (unichar_t *) "26", NULL, 0, 0, (void *) 26, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
843 { (unichar_t *) "27", NULL, 0, 0, (void *) 27, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
844 #if AppleMmMax!=26
845 #error "The mastercounts array needs to be expanded to match AppleMmMax"
846 /* Actually it should be one bigger than AppleMmMax */
847 #endif
848 GTEXTINFO_EMPTY
849 };
850
851 enum mmw_state { mmw_counts, mmw_axes, mmw_designs, mmw_named, mmw_funcs,
852 mmw_others };
853
854 typedef struct mmw {
855 GWindow gw;
856 enum mmw_state state;
857 GWindow subwins[mmw_others+1];
858 MMSet *mm, *old;
859 int isnew;
860 int done;
861 int old_axis_count, old_adobe;
862 int axis_count, instance_count; /* The data in mm are set to the max for each */
863 int last_instance_count, last_axis_count, lastw_instance_count;
864 struct axismap last_axismaps[4];
865 int canceldrop, subheightdiff;
866 int lcnt, lmax;
867 SplineFont **loaded;
868 } MMW;
869
870 #define MMW_Width 340
871 #define MMW_Height 300
872 #define ESD_Width 262
873 #define ESD_Height 316
874
875 #define CID_OK 1001
876 #define CID_Prev 1002
877 #define CID_Next 1003
878 #define CID_Cancel 1004
879 #define CID_Group 1005
880
881 #define CID_AxisCount 2001
882 #define CID_MasterCount 2002
883 #define CID_Adobe 2003
884 #define CID_Apple 2004
885
886 #define CID_WhichAxis 3000
887 #define CID_AxisType 3001 /* +[0,3]*100 */
888 #define CID_AxisBegin 3002 /* +[0,3]*100 */
889 #define CID_AxisDefault 3003 /* +[0,3]*100 */
890 #define CID_AxisDefaultLabel 3004 /* +[0,3]*100 */
891 #define CID_AxisEnd 3005 /* +[0,3]*100 */
892 #define CID_IntermediateDesign 3006 /* +[0,3]*100 */
893 #define CID_IntermediateNormalized 3007 /* +[0,3]*100 */
894
895 #define DesignScaleFactor 20
896
897 #define CID_WhichDesign 4000
898 #define CID_DesignFonts 4001 /* +[0,26]*DesignScaleFactor */
899 #define CID_AxisWeights 4002 /* +[0,26]*DesignScaleFactor */
900
901 #define CID_NDV 5002
902 #define CID_CDV 5003
903
904 /* CID_Explicit-CID_NewDesign already defined */
905 #define CID_ForceBoldThreshold 6005
906 #define CID_FamilyName 6006
907
908 #define CID_NamedDesigns 7001
909 #define CID_NamedNew 7002
910 #define CID_NamedEdit 7003
911 #define CID_NamedDelete 7004
912
913 struct esd {
914 GWindow gw;
915 MMW *mmw;
916 GGadget *list;
917 int index;
918 int done;
919 };
920
ESD_Close(struct esd * esd)921 static void ESD_Close(struct esd *esd) {
922 MacNameListFree(NameGadgetsGetNames(esd->gw));
923 esd->done = true;
924 }
925
ESD_Cancel(GGadget * g,GEvent * e)926 static int ESD_Cancel(GGadget *g, GEvent *e) {
927 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
928 struct esd *esd = GDrawGetUserData(GGadgetGetWindow(g));
929 ESD_Close(esd);
930 }
931 return( true );
932 }
933
ESD_OK(GGadget * g,GEvent * e)934 static int ESD_OK(GGadget *g, GEvent *e) {
935 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
936 struct esd *esd = GDrawGetUserData(GGadgetGetWindow(g));
937 int i,axis_count;
938 int err = false;
939 real coords[4];
940 struct macname *mn;
941 char buffer[120], *pt;
942 unichar_t *name; char *style;
943
944 for ( i=0; i<esd->mmw->axis_count && i<4; ++i )
945 coords[i] = rint(GetReal8(esd->gw,1000+i,_(axistablab[i]),&err)*8096)/8096;
946 if ( err )
947 return( true );
948 axis_count = i;
949 mn = NameGadgetsGetNames(esd->gw);
950 if ( mn==NULL ) {
951 ff_post_error(_("Bad Multiple Master Font"),_("You must provide at least one name here"));
952 return( true );
953 }
954 pt = buffer; *pt++ = ' '; *pt++ = '[';
955 for ( i=0; i<axis_count; ++i ) {
956 sprintf(pt, "%g ", (double) coords[i]);
957 pt += strlen(pt);
958 }
959 pt[-1] = ']';
960 *pt = '\0';
961 style = PickNameFromMacName(mn);
962 name = malloc(((pt-buffer) + strlen(style) + 1)*sizeof(unichar_t));
963 utf82u_strcpy(name,style);
964 uc_strcat(name,buffer);
965 free(style);
966 if ( esd->index==-1 )
967 GListAppendLine(esd->list,name,false)->userdata = mn;
968 else {
969 GTextInfo *ti = GGadgetGetListItem(esd->list,esd->index);
970 MacNameListFree(ti->userdata);
971 GListChangeLine(esd->list,esd->index,name)->userdata = mn;
972 }
973 esd->done = true;
974 free(name);
975 }
976 return( true );
977 }
978
esd_eh(GWindow gw,GEvent * event)979 static int esd_eh(GWindow gw, GEvent *event) {
980 if ( event->type==et_close ) {
981 struct esd *esd = GDrawGetUserData(gw);
982 ESD_Close(esd);
983 } else if ( event->type==et_char ) {
984 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
985 help("ui/dialogs/multiplemaster.html", "#multiplemaster-namedstyles");
986 return( true );
987 } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
988 MenuExit(NULL,NULL,NULL);
989 return( true );
990 } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
991 ESD_Close(GDrawGetUserData(gw));
992 return( true );
993 }
994 return( false );
995 }
996 return( true );
997 }
998
EditStyleName(MMW * mmw,int index)999 static void EditStyleName(MMW *mmw,int index) {
1000 GGadget *list = GWidgetGetControl(mmw->subwins[mmw_named],CID_NamedDesigns);
1001 GTextInfo *ti = NULL;
1002 int i,k;
1003 unichar_t *pt = NULL, *end;
1004 real axes[4];
1005 struct macname *mn = NULL;
1006 char axisval[4][24];
1007 char *axisnames[4];
1008 GGadgetCreateData gcd[17];
1009 GTextInfo label[17];
1010 GRect pos;
1011 GWindow gw;
1012 GWindowAttrs wattrs;
1013 struct esd esd;
1014
1015 for ( i=0; i<mmw->axis_count; ++i )
1016 axes[i] = mmw->mm->axismaps[i].def;
1017 if ( index != -1 ) {
1018 ti = GGadgetGetListItem(list,index);
1019 if ( ti!=NULL ) {
1020 pt = u_strchr(ti->text,'[');
1021 mn = ti->userdata;
1022 }
1023 if ( pt!=NULL ) {
1024 for ( i=0, ++pt; i<4 && (*pt!=']' && *pt!='\0'); ++i ) {
1025 axes[i] = u_strtod(pt,&end);
1026 pt = end;
1027 }
1028 }
1029 }
1030
1031 memset(&esd,0,sizeof(esd));
1032 esd.mmw = mmw;
1033 esd.index = index;
1034 esd.list = list;
1035
1036 memset(&wattrs,0,sizeof(wattrs));
1037 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1038 wattrs.event_masks = ~(1<<et_charup);
1039 wattrs.is_dlg = true;
1040 wattrs.restrict_input_to_me = true;
1041 wattrs.undercursor = 1;
1042 wattrs.cursor = ct_pointer;
1043 wattrs.utf8_window_title = _("Named Styles");
1044 pos.x = pos.y = 0;
1045 pos.width =GDrawPointsToPixels(NULL,GGadgetScale(ESD_Width));
1046 pos.height = GDrawPointsToPixels(NULL,ESD_Height);
1047 esd.gw = gw = GDrawCreateTopWindow(NULL,&pos,esd_eh,&esd,&wattrs);
1048
1049 memset(gcd,0,sizeof(gcd));
1050 memset(label,0,sizeof(label));
1051 k = 0;
1052
1053 k = GCDFillupMacWeights(gcd,label,k,axisnames,axisval,axes,
1054 mmw->axis_count,mmw->mm);
1055 k = GCDBuildNames(gcd,label,k,mn);
1056
1057 gcd[k].gd.pos.x = 20; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+33-3;
1058 gcd[k].gd.pos.width = -1; gcd[k].gd.pos.height = 0;
1059 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
1060 label[k].text = (unichar_t *) _("_OK");
1061 label[k].text_is_1byte = true;
1062 label[k].text_in_resource = true;
1063 gcd[k].gd.label = &label[k];
1064 gcd[k].gd.handle_controlevent = ESD_OK;
1065 gcd[k++].creator = GButtonCreate;
1066
1067 gcd[k].gd.pos.x = -20; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
1068 gcd[k].gd.pos.width = -1; gcd[k].gd.pos.height = 0;
1069 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1070 label[k].text = (unichar_t *) _("_Cancel");
1071 label[k].text_is_1byte = true;
1072 label[k].text_in_resource = true;
1073 gcd[k].gd.label = &label[k];
1074 gcd[k].gd.handle_controlevent = ESD_Cancel;
1075 gcd[k++].creator = GButtonCreate;
1076
1077 gcd[k].gd.pos.x = 2; gcd[k].gd.pos.y = 2;
1078 gcd[k].gd.pos.width = pos.width-4; gcd[k].gd.pos.height = pos.height-4;
1079 gcd[k].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
1080 gcd[k].creator = GGroupCreate;
1081
1082 GGadgetsCreate(gw,gcd);
1083
1084 for ( i=0; i<mmw->axis_count; ++i )
1085 free( axisnames[i]);
1086
1087 GDrawSetVisible(gw,true);
1088
1089 while ( !esd.done )
1090 GDrawProcessOneEvent(NULL);
1091
1092 GDrawDestroyWindow(gw);
1093 }
1094
SetMasterToAxis(MMW * mmw,int initial)1095 static void SetMasterToAxis(MMW *mmw, int initial) {
1096 int i, cnt, def, isadobe;
1097
1098 cnt = GGadgetGetFirstListSelectedItem(GWidgetGetControl(mmw->subwins[mmw_counts],CID_AxisCount))
1099 +1;
1100 isadobe = GGadgetIsChecked(GWidgetGetControl(mmw->subwins[mmw_counts],CID_Adobe));
1101 if ( cnt!=mmw->old_axis_count || isadobe!=mmw->old_adobe ) {
1102 GGadget *list = GWidgetGetControl(mmw->subwins[mmw_counts],CID_MasterCount);
1103 int32 len;
1104 GTextInfo **ti = GGadgetGetList(list,&len);
1105 if ( isadobe ) {
1106 for ( i=0; i<MmMax; ++i )
1107 ti[i]->disabled = (i+1) < (1<<cnt);
1108 for ( ; i<AppleMmMax+1 ; ++i )
1109 ti[i]->disabled = true;
1110 def = (1<<cnt);
1111 } else {
1112 for ( i=0; i<AppleMmMax+1; ++i )
1113 ti[i]->disabled = (i+1) < cnt;
1114 def = 1;
1115 for ( i=0; i<cnt; ++i )
1116 def *= 3;
1117 if ( def>AppleMmMax+1 )
1118 def = AppleMmMax+1;
1119 }
1120 if ( !initial )
1121 GGadgetSelectOneListItem(list,def-1);
1122 mmw->old_axis_count = cnt;
1123 mmw->old_adobe = isadobe;
1124 }
1125 }
1126
MMW_AxisCntChanged(GGadget * g,GEvent * e)1127 static int MMW_AxisCntChanged(GGadget *g, GEvent *e) {
1128
1129 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
1130 SetMasterToAxis(GDrawGetUserData(GGadgetGetWindow(g)),false);
1131 }
1132 return( true );
1133 }
1134
MMW_TypeChanged(GGadget * g,GEvent * e)1135 static int MMW_TypeChanged(GGadget *g, GEvent *e) {
1136 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
1137 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
1138 int isapple = GGadgetIsChecked(GWidgetGetControl(mmw->subwins[mmw_counts],CID_Apple));
1139 int i;
1140 SetMasterToAxis(mmw,false);
1141 for ( i=0; i<4; ++i ) {
1142 GGadgetSetEnabled(GWidgetGetControl(mmw->subwins[mmw_axes],CID_AxisDefault+i*100),isapple);
1143 GGadgetSetEnabled(GWidgetGetControl(mmw->subwins[mmw_axes],CID_AxisDefaultLabel+i*100),isapple);
1144 NameGadgetsSetEnabled(GTabSetGetSubwindow(
1145 GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),i),isapple);
1146 }
1147 }
1148 return( true );
1149 }
1150
MMUsurpNew(SplineFont * sf)1151 static void MMUsurpNew(SplineFont *sf) {
1152 /* This is a font that wasn't in the original MMSet */
1153 /* We ARE going to use it in the final result */
1154 /* So if it is attached to a fontview, we must close that window and */
1155 /* claim the splinefont for ourselves */
1156 FontView *fv, *nextfv;
1157
1158 if ( sf->fv!=NULL ) {
1159 if ( sf->kcld!=NULL )
1160 KCLD_End(sf->kcld);
1161 if ( sf->vkcld!=NULL )
1162 KCLD_End(sf->vkcld);
1163 sf->kcld = sf->vkcld = NULL;
1164
1165 for ( fv=(FontView *) sf->fv; fv!=NULL; fv=nextfv ) {
1166 nextfv = (FontView *) (fv->b.nextsame);
1167 fv->b.nextsame = NULL;
1168 _FVCloseWindows(fv);
1169 fv->b.sf = NULL;
1170 GDrawDestroyWindow(fv->gw);
1171 }
1172 sf->fv = NULL;
1173 SFClearAutoSave(sf);
1174 }
1175 }
1176
MMDetachNew(SplineFont * sf)1177 static void MMDetachNew(SplineFont *sf) {
1178 /* This is a font that wasn't in the original MMSet */
1179 /* We aren't going to use it in the final result */
1180 /* If it is attached to a fontview, then the fontview retains control */
1181 /* If not, then free it */
1182 if ( sf->fv==NULL )
1183 SplineFontFree(sf);
1184 }
1185
MMDetachOld(SplineFont * sf)1186 static void MMDetachOld(SplineFont *sf) {
1187 /* This is a font that was in the original MMSet */
1188 /* We aren't going to use it in the final result */
1189 /* So then free it */
1190 sf->mm = NULL;
1191 SplineFontFree(sf);
1192 }
1193
MMW_Close(MMW * mmw)1194 static void MMW_Close(MMW *mmw) {
1195 int i;
1196 GGadget *list = GWidgetGetControl(mmw->subwins[mmw_named],CID_NamedDesigns);
1197 int32 len;
1198 GTextInfo **ti = GGadgetGetList(list,&len);
1199
1200 for ( i=0; i<len; ++i )
1201 if ( ti[i]->userdata!=NULL )
1202 MacNameListFree(ti[i]->userdata);
1203 for ( i=0; i<4; ++i )
1204 MacNameListFree(NameGadgetsGetNames(GTabSetGetSubwindow(
1205 GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),i)));
1206 for ( i=0; i<mmw->lcnt; ++i )
1207 MMDetachNew(mmw->loaded[i]);
1208 free(mmw->loaded);
1209 for ( i=0; i<4; ++i )
1210 mmw->mm->axismaps[i].axisnames = NULL;
1211 MMSetFreeContents(mmw->mm);
1212 chunkfree(mmw->mm,sizeof(MMSet));
1213 mmw->done = true;
1214 }
1215
MMW_Cancel(GGadget * g,GEvent * e)1216 static int MMW_Cancel(GGadget *g, GEvent *e) {
1217 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1218 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
1219 MMW_Close(mmw);
1220 }
1221 return( true );
1222 }
1223
MMW_SetState(MMW * mmw)1224 static void MMW_SetState(MMW *mmw) {
1225 unsigned int i;
1226
1227 GDrawSetVisible(mmw->subwins[mmw->state],true);
1228 for ( i=mmw_counts; i<=mmw_others; ++i )
1229 if ( i!=mmw->state )
1230 GDrawSetVisible(mmw->subwins[i],false);
1231
1232 GGadgetSetEnabled(GWidgetGetControl(mmw->gw,CID_Prev),mmw->state!=mmw_counts);
1233 GGadgetSetEnabled(GWidgetGetControl(mmw->gw,CID_Next),
1234 mmw->state!=mmw_others && mmw->state!=mmw_named);
1235 GGadgetSetEnabled(GWidgetGetControl(mmw->gw,CID_OK),
1236 mmw->state==mmw_others || mmw->state==mmw_named);
1237 }
1238
ParseWeights(GWindow gw,int cid,char * str,real * list,int expected,int tabset_cid,int aspect)1239 static int ParseWeights(GWindow gw,int cid, char *str,
1240 real *list, int expected, int tabset_cid, int aspect ) {
1241 int cnt=0;
1242 const unichar_t *ret, *pt; unichar_t *endpt;
1243
1244 ret= _GGadgetGetTitle(GWidgetGetControl(gw,cid));
1245
1246 for ( pt=ret; *pt==' '; ++pt );
1247 for ( ; *pt; ) {
1248 list[cnt++] = u_strtod(pt,&endpt);
1249 if ( pt==endpt || ( *endpt!='\0' && *endpt!=' ' )) {
1250 if ( tabset_cid!=-1 )
1251 GTabSetSetSel(GWidgetGetControl(gw,tabset_cid),aspect);
1252 ff_post_error(_("Bad Axis"),_("Bad Number in %s"), str);
1253 return( 0 );
1254 }
1255 for ( pt = endpt; *pt==' '; ++pt );
1256 }
1257 if ( cnt!=expected && expected!=-1 ) {
1258 if ( tabset_cid!=-1 )
1259 GTabSetSetSel(GWidgetGetControl(gw,tabset_cid),aspect);
1260 ff_post_error(_("Bad Axis"),_("Wrong number of entries in %s"), str);
1261 return( 0 );
1262 }
1263
1264 return( cnt );
1265 }
1266
ParseList(GWindow gw,int cid,char * str8,int * err,real start,real def,real end,real ** _list,int tabset_cid,int aspect,int isapple)1267 static int ParseList(GWindow gw,int cid, char *str8, int *err, real start,
1268 real def, real end, real **_list, int tabset_cid, int aspect,
1269 int isapple ) {
1270 int i, cnt;
1271 const unichar_t *ret, *pt; unichar_t *endpt;
1272 real *list, val;
1273 int defdone = false;
1274
1275 *_list = NULL;
1276
1277 ret= _GGadgetGetTitle(GWidgetGetControl(gw,cid));
1278 for ( pt=ret; *pt==' '; ++pt );
1279 cnt = *pt=='\0'?0:1 ;
1280 for ( ; *pt; ++pt ) {
1281 if ( *pt==' ' ) ++cnt;
1282 while ( *pt==' ' ) ++pt;
1283 }
1284 if ( start!=end )
1285 cnt+=2;
1286 if ( isapple && start!=end )
1287 ++cnt;
1288 if ( !isapple || start==end )
1289 defdone = true;
1290 list = malloc(cnt*sizeof(real));
1291 if ( start==end )
1292 cnt = 0;
1293 else {
1294 list[0] = start;
1295 cnt = 1;
1296 }
1297
1298 for ( pt=ret; *pt==' '; ++pt );
1299 for ( ; *pt; ) {
1300 val = u_strtod(pt,&endpt);
1301 if ( !defdone && val>def ) {
1302 list[cnt++] = def;
1303 defdone = true;
1304 }
1305 list[cnt++] = val;
1306 if ( pt==endpt || ( *endpt!='\0' && *endpt!=' ' )) {
1307 GTabSetSetSel(GWidgetGetControl(gw,tabset_cid),aspect);
1308 free(list);
1309 ff_post_error(_("Bad Axis"),_("Bad Number in %s"), str8);
1310 *err = true;
1311 return( 0 );
1312 }
1313 for ( pt = endpt; *pt==' '; ++pt );
1314 }
1315 if ( start!=end )
1316 list[cnt++] = end;
1317 for ( i=1; i<cnt; ++i )
1318 if ( list[i-1]>list[i] ) {
1319 GTabSetSetSel(GWidgetGetControl(gw,tabset_cid),aspect);
1320 ff_post_error(_("Bad Axis"),_("The %s list is not ordered"), str8);
1321 free(list);
1322 *err = true;
1323 return( 0 );
1324 }
1325
1326 *_list = list;
1327 return( cnt );
1328 }
1329
_ChooseFonts(char * buffer,SplineFont ** sfs,real * positions,int i,int cnt)1330 static char *_ChooseFonts(char *buffer, SplineFont **sfs, real *positions,
1331 int i, int cnt) {
1332 char *elsepart=NULL, *ret;
1333 int pos;
1334 int k;
1335
1336 if ( i<cnt-2 )
1337 elsepart = _ChooseFonts(buffer,sfs,positions,i+1,cnt);
1338
1339 pos = 0;
1340 if ( positions[i]!=0 ) {
1341 sprintf(buffer, "%g sub ", (double) positions[i]);
1342 pos += strlen(buffer);
1343 }
1344 sprintf(buffer+pos, "%g div dup 1 sub exch ", (double) (positions[i+1]-positions[i]));
1345 pos += strlen( buffer+pos );
1346 for ( k=0; k<i; ++k ) {
1347 strcpy(buffer+pos, "0 ");
1348 pos += 2;
1349 }
1350 if ( i!=0 ) {
1351 sprintf(buffer+pos, "%d -2 roll ", i+2 );
1352 pos += strlen(buffer+pos);
1353 }
1354 for ( k=i+2; k<cnt; ++k ) {
1355 strcpy(buffer+pos, "0 ");
1356 pos += 2;
1357 }
1358
1359 if ( elsepart==NULL )
1360 return( copy(buffer));
1361
1362 ret = malloc(strlen(buffer)+strlen(elsepart)+40);
1363 sprintf(ret,"dup %g le {%s} {%s} ifelse", (double) positions[i+1], buffer, elsepart );
1364 free(elsepart);
1365 return( ret );
1366 }
1367
Figure1AxisCDV(MMW * mmw)1368 static unichar_t *Figure1AxisCDV(MMW *mmw) {
1369 real positions[MmMax];
1370 SplineFont *sfs[MmMax];
1371 int i;
1372 char *temp;
1373 unichar_t *ret;
1374 char buffer[400];
1375
1376 if ( mmw->axis_count!=1 )
1377 return( uc_copy(""));
1378 if ( mmw->instance_count==2 )
1379 return( uc_copy( standard_cdvs[1]));
1380
1381 for ( i=0; i<mmw->instance_count; ++i ) {
1382 positions[i] = mmw->mm->positions[4*i];
1383 sfs[i] = mmw->mm->instances[i];
1384 if ( i>0 && positions[i-1]>=positions[i] )
1385 return( uc_copy(""));
1386 }
1387 temp = _ChooseFonts(buffer,sfs,positions,0,mmw->instance_count);
1388 ret = uc_copy(temp);
1389 free(temp);
1390 return( ret );
1391 }
1392
_NormalizeAxis(char * buffer,struct axismap * axis,int i)1393 static char *_NormalizeAxis(char *buffer, struct axismap *axis, int i) {
1394 char *elsepart=NULL, *ret;
1395 int pos;
1396
1397 if ( i<axis->points-2 )
1398 elsepart = _NormalizeAxis(buffer,axis,i+1);
1399
1400 pos = 0;
1401 if ( axis->blends[i+1]==axis->blends[i] ) {
1402 sprintf( buffer, "%g ", (double) axis->blends[i] );
1403 pos = strlen(buffer);
1404 } else {
1405 if ( axis->designs[i]!=0 ) {
1406 sprintf(buffer, "%g sub ", (double) axis->designs[i]);
1407 pos += strlen(buffer);
1408 }
1409 sprintf(buffer+pos, "%g div ", (double) ((axis->designs[i+1]-axis->designs[i])/
1410 (axis->blends[i+1]-axis->blends[i])));
1411 pos += strlen( buffer+pos );
1412 if ( axis->blends[i]!=0 ) {
1413 sprintf(buffer+pos, "%g add ", (double) axis->blends[i]);
1414 pos += strlen(buffer+pos);
1415 }
1416 }
1417
1418 if ( elsepart==NULL )
1419 return( copy(buffer));
1420
1421 ret = malloc(strlen(buffer)+strlen(elsepart)+40);
1422 sprintf(ret,"dup %g le {%s} {%s} ifelse", (double) axis->designs[i+1], buffer, elsepart );
1423 free(elsepart);
1424 return( ret );
1425 }
1426
NormalizeAxis(char * header,struct axismap * axis)1427 static char *NormalizeAxis(char *header,struct axismap *axis) {
1428 char *ret;
1429 char buffer[200];
1430
1431 ret = _NormalizeAxis(buffer,axis,0);
1432 if ( *header ) {
1433 char *temp;
1434 temp = malloc(strlen(header)+strlen(ret)+2);
1435 strcpy(temp,header);
1436 strcat(temp,ret);
1437 strcat(temp,"\n");
1438 free(ret);
1439 ret = temp;
1440 }
1441 return( ret );
1442 }
1443
SameAxes(int cnt1,int cnt2,struct axismap * axismaps1,struct axismap * axismaps2)1444 static int SameAxes(int cnt1,int cnt2,struct axismap *axismaps1,struct axismap *axismaps2) {
1445 int i,j;
1446
1447 if ( cnt1!=cnt2 )
1448 return( false );
1449 for ( i=0; i<cnt1; ++i ) {
1450 if ( axismaps1[i].points!=axismaps2[i].points )
1451 return( false );
1452 for ( j=0; j<axismaps1[i].points; ++j ) {
1453 if ( axismaps1[i].designs[j]>=axismaps2[i].designs[j]+.01 ||
1454 axismaps1[i].designs[j]<=axismaps2[i].designs[j]-.01 )
1455 return( false );
1456 if ( axismaps1[i].blends[j]>=axismaps2[i].blends[j]+.001 ||
1457 axismaps1[i].blends[j]<=axismaps2[i].blends[j]-.001 )
1458 return( false );
1459 }
1460 }
1461 return( true );
1462 }
1463
AxisDataCopyFree(struct axismap * into,struct axismap * from,int count)1464 static void AxisDataCopyFree(struct axismap *into,struct axismap *from,int count) {
1465 int i;
1466
1467 for ( i=0; i<4; ++i ) {
1468 free(into->blends); free(into->designs);
1469 into->blends = NULL; into->designs = NULL;
1470 into->points = 0;
1471 }
1472 for ( i=0; i<count; ++i ) {
1473 into[i].points = from[i].points;
1474 into[i].blends = malloc(into[i].points*sizeof(real));
1475 memcpy(into[i].blends,from[i].blends,into[i].points*sizeof(real));
1476 into[i].designs = malloc(into[i].points*sizeof(real));
1477 memcpy(into[i].designs,from[i].designs,into[i].points*sizeof(real));
1478 }
1479 }
1480
PositionsMatch(MMSet * old,MMSet * mm)1481 static int PositionsMatch(MMSet *old,MMSet *mm) {
1482 int i,j;
1483
1484 for ( i=0; i<old->instance_count; ++i ) {
1485 for ( j=0; j<old->axis_count; ++j )
1486 if ( old->positions[i*old->axis_count+j] != mm->positions[i*mm->axis_count+j] )
1487 return( false );
1488 }
1489 return( true );
1490 }
1491
MMW_FuncsValid(MMW * mmw)1492 static void MMW_FuncsValid(MMW *mmw) {
1493 unichar_t *ut;
1494 int pos, i;
1495
1496 if ( !SameAxes(mmw->axis_count,mmw->last_axis_count,mmw->mm->axismaps,mmw->last_axismaps)) {
1497 if ( mmw->old!=NULL &&
1498 SameAxes(mmw->axis_count,mmw->old->axis_count,mmw->mm->axismaps,mmw->old->axismaps)) {
1499 ut = uc_copy(mmw->old->ndv);
1500 } else {
1501 char *header = mmw->axis_count==1 ? " " :
1502 mmw->axis_count==2 ? " exch " :
1503 mmw->axis_count==3 ? " 3 -1 roll " :
1504 " 4 -1 roll ";
1505 char *lines[4];
1506 for ( i=0; i<mmw->axis_count; ++i )
1507 lines[i] = NormalizeAxis(header,&mmw->mm->axismaps[i]);
1508 pos = 0;
1509 for ( i=0; i<mmw->axis_count; ++i )
1510 pos += strlen(lines[i]);
1511 ut = malloc((pos+20)*sizeof(unichar_t));
1512 uc_strcpy(ut,"{\n" ); pos = 2;
1513 for ( i=0; i<mmw->axis_count; ++i ) {
1514 uc_strcpy(ut+pos,lines[i]);
1515 pos += strlen(lines[i]);
1516 }
1517 uc_strcpy(ut+pos,"}" );
1518 }
1519 GGadgetSetTitle(GWidgetGetControl(mmw->subwins[mmw_funcs],CID_NDV),
1520 ut);
1521 free(ut);
1522 AxisDataCopyFree(mmw->last_axismaps,mmw->mm->axismaps,mmw->axis_count);
1523 mmw->last_axis_count = mmw->axis_count;
1524 }
1525 if ( mmw->last_instance_count!=mmw->instance_count ) {
1526 if ( standard_cdvs[4]==NULL ) {
1527 standard_cdvs[4] = malloc(strlen(cdv_4axis[0])+strlen(cdv_4axis[1])+
1528 strlen(cdv_4axis[2])+2);
1529 strcpy(standard_cdvs[4],cdv_4axis[0]);
1530 strcat(standard_cdvs[4],cdv_4axis[1]);
1531 strcat(standard_cdvs[4],cdv_4axis[2]);
1532 }
1533 if ( mmw->old!=NULL &&
1534 mmw->axis_count==mmw->old->axis_count &&
1535 mmw->instance_count==mmw->old->instance_count &&
1536 PositionsMatch(mmw->old,mmw->mm)) {
1537 ut = uc_copy(mmw->old->cdv);
1538 } else if ( mmw->instance_count==(1<<mmw->axis_count) &&
1539 StandardPositions(mmw->mm,mmw->instance_count,mmw->axis_count,false)) {
1540 ut = uc_copy(standard_cdvs[mmw->axis_count]);
1541 } else if ( mmw->axis_count==1 &&
1542 OrderedPositions(mmw->mm,mmw->instance_count,false)) {
1543 ut = Figure1AxisCDV(mmw);
1544 } else {
1545 ut = uc_copy("");
1546 }
1547 GGadgetSetTitle(GWidgetGetControl(mmw->subwins[mmw_funcs],CID_CDV),
1548 ut);
1549 free(ut);
1550 }
1551 mmw->last_instance_count = mmw->instance_count;
1552 }
1553
MMW_WeightsValid(MMW * mmw)1554 static void MMW_WeightsValid(MMW *mmw) {
1555 char *temp;
1556 unichar_t *ut, *utc;
1557 int pos, i;
1558 real axiscoords[4], weights[2*MmMax];
1559
1560 if ( mmw->lastw_instance_count!=mmw->instance_count ) {
1561 temp = malloc(mmw->instance_count*20+1);
1562 pos = 0;
1563 if ( mmw->old!=NULL && mmw->instance_count==mmw->old->instance_count ) {
1564 for ( i=0; i<mmw->instance_count; ++i ) {
1565 sprintf(temp+pos,"%g ", (double) mmw->old->defweights[i] );
1566 pos += strlen(temp+pos);
1567 }
1568 utc = MMDesignCoords(mmw->old);
1569 } else {
1570 for ( i=0; i<mmw->axis_count; ++i ) {
1571 if ( strcmp(mmw->mm->axes[i],"Weight")==0 &&
1572 400>=mmw->mm->axismaps[i].designs[0] &&
1573 400<=mmw->mm->axismaps[i].designs[mmw->mm->axismaps[i].points-1])
1574 axiscoords[i] = 400;
1575 else if ( strcmp(mmw->mm->axes[i],"OpticalSize")==0 &&
1576 12>=mmw->mm->axismaps[i].designs[0] &&
1577 12<=mmw->mm->axismaps[i].designs[mmw->mm->axismaps[i].points-1])
1578 axiscoords[i] = 12;
1579 else
1580 axiscoords[i] = (mmw->mm->axismaps[i].designs[0]+
1581 mmw->mm->axismaps[i].designs[mmw->mm->axismaps[i].points-1])/2;
1582 }
1583 i = ExecConvertDesignVector(axiscoords,mmw->axis_count,mmw->mm->ndv,mmw->mm->cdv,
1584 weights);
1585 if ( i!=mmw->instance_count ) { /* The functions don't work */
1586 for ( i=0; i<mmw->instance_count; ++i )
1587 weights[i] = 1.0/mmw->instance_count;
1588 utc = uc_copy("");
1589 } else {
1590 for ( i=0; i<mmw->axis_count; ++i ) {
1591 sprintf(temp+pos,"%g ", (double) axiscoords[i] );
1592 pos += strlen(temp+pos);
1593 }
1594 temp[pos-1] = '\0';
1595 utc = uc_copy(temp);
1596 pos = 0;
1597 }
1598 for ( i=0; i<mmw->instance_count; ++i ) {
1599 sprintf(temp+pos,"%g ", (double) weights[i] );
1600 pos += strlen(temp+pos);
1601 }
1602 }
1603 temp[pos-1] = '\0';
1604 ut = uc_copy(temp);
1605 GGadgetSetTitle(GWidgetGetControl(mmw->subwins[mmw_others],CID_NewBlends),
1606 ut);
1607 free(temp); free(ut);
1608
1609 GGadgetSetTitle(GWidgetGetControl(mmw->subwins[mmw_others],CID_NewDesign),utc);
1610 free(utc);
1611 mmw->lastw_instance_count = mmw->instance_count;
1612 }
1613 }
1614
NamedDesigns(MMW * mmw)1615 static GTextInfo *NamedDesigns(MMW *mmw) {
1616 int cnt, i, j;
1617 GTextInfo *ti;
1618 char buffer[120], *pt;
1619 char *ustyle;
1620
1621 if ( !mmw->mm->apple || mmw->old==NULL )
1622 return( NULL );
1623
1624 cnt = mmw->old->named_instance_count;
1625 ti = calloc((cnt+1),sizeof(GTextInfo));
1626 for ( i=0; i<mmw->old->named_instance_count; ++i ) {
1627 pt = buffer; *pt++='[';
1628 for ( j=0; j<mmw->old->axis_count; ++j ) {
1629 sprintf( pt, "%.4g ", (double) mmw->old->named_instances[i].coords[j]);
1630 pt += strlen(pt);
1631 }
1632 pt[-1] = ']';
1633 ustyle = PickNameFromMacName(mmw->old->named_instances[i].names);
1634 ti[i].bg = ti[i].fg = COLOR_DEFAULT;
1635 ti[i].text = malloc((strlen(buffer)+3+strlen(ustyle))*sizeof(unichar_t));
1636 utf82u_strcpy(ti[i].text,ustyle);
1637 uc_strcat(ti[i].text," ");
1638 uc_strcat(ti[i].text,buffer);
1639 ti[i].userdata = MacNameCopy(mmw->old->named_instances[i].names);
1640 free(ustyle);
1641 }
1642
1643 return(ti);
1644 }
1645
TiFromFont(SplineFont * sf)1646 static GTextInfo *TiFromFont(SplineFont *sf) {
1647 GTextInfo *ti = calloc(1,sizeof(GTextInfo));
1648 ti->text = uc_copy(sf->fontname);
1649 ti->fg = ti->bg = COLOR_DEFAULT;
1650 ti->userdata = sf;
1651 return( ti );
1652 }
1653
FontList(MMW * mmw,int instance,int * sel)1654 static GTextInfo **FontList(MMW *mmw, int instance, int *sel) {
1655 FontView *fv;
1656 int cnt, i, pos;
1657 GTextInfo **ti;
1658
1659 cnt = 0;
1660 if ( mmw->old!=NULL ) {
1661 cnt = mmw->old->instance_count;
1662 if ( mmw->old->apple )
1663 ++cnt;
1664 }
1665 for ( fv=fv_list; fv!=NULL; fv=(FontView *) (fv->b.next) ) {
1666 if ( fv->b.cidmaster==NULL && fv->b.sf->mm==NULL )
1667 ++cnt;
1668 }
1669 cnt += mmw->lcnt;
1670
1671 ++cnt; /* New */
1672 ++cnt; /* Browse... */
1673
1674 ti = malloc((cnt+1)*sizeof(GTextInfo *));
1675 pos = -1;
1676 cnt = 0;
1677 if ( mmw->old!=NULL ) {
1678 for ( i=0; i<mmw->old->instance_count; ++i ) {
1679 if ( mmw->old->instances[i]==mmw->mm->instances[instance] ) pos = cnt;
1680 ti[cnt++] = TiFromFont(mmw->old->instances[i]);
1681 }
1682 if ( mmw->old->apple ) {
1683 if ( mmw->old->normal==mmw->mm->instances[instance] ) pos = cnt;
1684 ti[cnt++] = TiFromFont(mmw->old->normal);
1685 }
1686 }
1687 for ( fv=fv_list; fv!=NULL; fv=(FontView *) (fv->b.next) ) {
1688 if ( fv->b.cidmaster==NULL && fv->b.sf->mm==NULL ) {
1689 if ( fv->b.sf==mmw->mm->instances[instance] ) pos = cnt;
1690 ti[cnt++] = TiFromFont(fv->b.sf);
1691 }
1692 }
1693 for ( i=0; i<mmw->lcnt; ++i ) {
1694 if ( mmw->loaded[i]==mmw->mm->instances[instance] ) pos = cnt;
1695 ti[cnt++] = TiFromFont( mmw->loaded[i]);
1696 }
1697 if ( pos==-1 ) pos=cnt;
1698 ti[cnt] = calloc(1,sizeof(GTextInfo));
1699 ti[cnt]->text = utf82u_copy(S_("Font|New"));
1700 ti[cnt]->bg = ti[cnt]->fg = COLOR_DEFAULT;
1701 ++cnt;
1702 ti[cnt] = calloc(1,sizeof(GTextInfo));
1703 ti[cnt]->text = utf82u_copy(_("Browse..."));
1704 ti[cnt]->bg = ti[cnt]->fg = COLOR_DEFAULT;
1705 ti[cnt]->userdata = (void *) (-1);
1706 ++cnt;
1707 ti[cnt] = calloc(1,sizeof(GTextInfo));
1708
1709 ti[pos]->selected = true;
1710 *sel = pos;
1711
1712 return(ti);
1713 }
1714
MMW_DesignsSetup(MMW * mmw)1715 static void MMW_DesignsSetup(MMW *mmw) {
1716 int i,j,sel;
1717 char buffer[80], *pt;
1718 unichar_t ubuf[80];
1719 GTextInfo **ti;
1720
1721 for ( i=0; i<mmw->instance_count; ++i ) {
1722 GGadget *list = GWidgetGetControl(mmw->subwins[mmw_designs],CID_DesignFonts+i*DesignScaleFactor);
1723 ti = FontList(mmw,i,&sel);
1724 GGadgetSetList(list, ti,false);
1725 GGadgetSetTitle(list, ti[sel]->text);
1726 pt = buffer;
1727 for ( j=0; j<mmw->axis_count; ++j ) {
1728 sprintf(pt,"%g ",(double) mmw->mm->positions[i*4+j]);
1729 pt += strlen(pt);
1730 }
1731 if ( pt>buffer ) pt[-1] = '\0';
1732 uc_strcpy(ubuf,buffer);
1733 GGadgetSetTitle(GWidgetGetControl(mmw->subwins[mmw_designs],CID_AxisWeights+i*DesignScaleFactor),
1734 ubuf);
1735 }
1736 }
1737
MMW_ParseNamedStyles(MMSet * setto,MMW * mmw)1738 static void MMW_ParseNamedStyles(MMSet *setto,MMW *mmw) {
1739 GGadget *list = GWidgetGetControl(mmw->subwins[mmw_named],CID_NamedDesigns);
1740 int32 i,j,len;
1741 GTextInfo **ti = GGadgetGetList(list,&len);
1742 unichar_t *upt, *end;
1743
1744 setto->named_instance_count = len;
1745 if ( len!=0 ) {
1746 setto->named_instances = calloc(len,sizeof(struct named_instance));
1747 for ( i=0; i<len; ++i ) {
1748 setto->named_instances[i].coords = calloc(setto->axis_count,sizeof(real));
1749 upt = u_strchr(ti[i]->text,'[');
1750 if ( upt!=NULL ) {
1751 for ( j=0, ++upt; j<setto->axis_count; ++j ) {
1752 setto->named_instances[i].coords[j] = rint(u_strtod(upt,&end)*8096)/8096;
1753 if ( *end==' ' ) ++end;
1754 upt = end;
1755 }
1756 }
1757 setto->named_instances[i].names = ti[i]->userdata;
1758 ti[i]->userdata = NULL;
1759 }
1760 }
1761 }
1762
MMW_DoOK(MMW * mmw)1763 static void MMW_DoOK(MMW *mmw) {
1764 real weights[AppleMmMax+1];
1765 real fbt;
1766 int err = false;
1767 char *familyname, *fn, *origname=NULL;
1768 int i,j;
1769 MMSet *setto, *dlgmm;
1770 FontView *fv = NULL;
1771 int isapple = GGadgetIsChecked(GWidgetGetControl(mmw->subwins[mmw_counts],CID_Apple));
1772 int defpos;
1773 struct psdict *oldprivate = NULL;
1774 Encoding *enc = NULL;
1775
1776 if ( !isapple ) {
1777 if ( !GetWeights(mmw->gw, weights, mmw->mm, mmw->instance_count, mmw->axis_count))
1778 return;
1779 fbt = GetReal8(mmw->subwins[mmw_others],CID_ForceBoldThreshold,
1780 _("Force Bold Threshold:"),&err);
1781 if ( err )
1782 return;
1783 }
1784
1785 familyname = cu_copy(_GGadgetGetTitle(GWidgetGetControl(mmw->subwins[mmw_counts],CID_FamilyName)));
1786 /* They only need specify a family name if there are new fonts */
1787 if ( *familyname=='\0' ) {
1788 free(familyname);
1789 for ( i=0; i<mmw->instance_count; ++i )
1790 if ( mmw->mm->instances[i]==NULL )
1791 break;
1792 else
1793 fn = mmw->mm->instances[i]->familyname;
1794 if ( i!=mmw->instance_count ) {
1795 ff_post_error(_("Bad Multiple Master Font"),_("A Font Family name is required"));
1796 return;
1797 }
1798 familyname = copy(fn);
1799 }
1800
1801 /* Did we have a fontview open on this mm? */
1802 if ( mmw->old!=NULL ) {
1803 for ( j=0; j<mmw->old->instance_count; ++j )
1804 if ( mmw->old->instances[j]->fv!=NULL ) {
1805 fv = (FontView *) mmw->old->instances[j]->fv;
1806 origname = copy(mmw->old->instances[j]->origname);
1807 enc = fv->b.map->enc;
1808 break;
1809 }
1810 }
1811
1812 /* Make sure we free all fonts that we have lying around and aren't going */
1813 /* to be using. (ones we opened, ones in the old version of the mm). Also */
1814 /* if any font we want to use is attached to a fontview, then close the */
1815 /* window */
1816 for ( i=0; i<mmw->instance_count; ++i ) if ( mmw->mm->instances[i]!=NULL ) {
1817 if ( mmw->old!=NULL ) {
1818 for ( j=0; j<mmw->old->instance_count; ++j )
1819 if ( mmw->mm->instances[i]==mmw->old->instances[j] )
1820 break;
1821 if ( j!=mmw->old->instance_count ) {
1822 mmw->old->instances[j] = NULL;
1823 continue;
1824 } else if ( mmw->old->normal==mmw->mm->instances[i] ) {
1825 mmw->old->normal = NULL;
1826 continue;
1827 }
1828 }
1829 for ( j=0; j<mmw->lcnt; ++j )
1830 if ( mmw->mm->instances[i]==mmw->loaded[j] )
1831 break;
1832 if ( j!=mmw->lcnt ) {
1833 mmw->loaded[j] = NULL;
1834 continue;
1835 }
1836 if ( enc==NULL && mmw->mm->instances[i]->fv!=NULL )
1837 enc = mmw->mm->instances[i]->fv->map->enc;
1838 MMUsurpNew(mmw->mm->instances[i]);
1839 }
1840 if ( mmw->old!=NULL ) {
1841 for ( j=0; j<mmw->old->instance_count; ++j )
1842 if ( mmw->old->instances[j]!=NULL ) {
1843 MMDetachOld(mmw->old->instances[j]);
1844 mmw->old->instances[j] = NULL;
1845 }
1846 if ( mmw->old->normal!=NULL ) {
1847 oldprivate = mmw->old->normal->private;
1848 mmw->old->normal->private = NULL;
1849 MMDetachOld(mmw->old->normal);
1850 mmw->old->normal = NULL;
1851 }
1852 }
1853 for ( j=0; j<mmw->lcnt; ++j ) {
1854 if ( mmw->loaded[j]!=NULL ) {
1855 MMDetachNew(mmw->loaded[j]);
1856 mmw->loaded[j] = NULL;
1857 }
1858 }
1859
1860 dlgmm = mmw->mm;
1861 setto = mmw->old;
1862 if ( setto!=NULL ) {
1863 MMSetFreeContents(setto);
1864 memset(setto,0,sizeof(MMSet));
1865 } else
1866 setto = chunkalloc(sizeof(MMSet));
1867 setto->apple = isapple;
1868 setto->axis_count = mmw->axis_count;
1869 setto->instance_count = mmw->instance_count;
1870 defpos = mmw->instance_count;
1871 if ( isapple ) {
1872 for ( defpos=0; defpos<mmw->instance_count; ++defpos ) {
1873 for ( j=0; j<mmw->axis_count; ++j )
1874 if ( dlgmm->positions[defpos*dlgmm->axis_count+j]!=0 )
1875 break;
1876 if ( j==mmw->axis_count )
1877 break;
1878 }
1879 if ( defpos==mmw->instance_count )
1880 --defpos;
1881 --setto->instance_count;
1882 setto->normal = dlgmm->instances[defpos];
1883 if ( setto->normal!=NULL )
1884 setto->normal->mm = setto;
1885 }
1886 for ( i=0; i<setto->axis_count; ++i )
1887 setto->axes[i] = dlgmm->axes[i];
1888 setto->axismaps = dlgmm->axismaps;
1889 setto->defweights = calloc(setto->instance_count,sizeof(real));
1890 if ( !isapple )
1891 memcpy(setto->defweights,weights,setto->instance_count*sizeof(real));
1892 free(dlgmm->defweights);
1893 setto->positions = malloc(setto->instance_count*setto->axis_count*sizeof(real));
1894 for ( i=0; i<setto->instance_count; ++i ) {
1895 int k = i<defpos ? i : i+1;
1896 memcpy(setto->positions+i*setto->axis_count,dlgmm->positions+k*dlgmm->axis_count,
1897 setto->axis_count*sizeof(real));
1898 }
1899 free(dlgmm->positions);
1900 setto->instances = calloc(setto->instance_count,sizeof(SplineFont *));
1901 for ( i=0; i<setto->instance_count; ++i ) {
1902 if ( dlgmm->instances[i]!=NULL ) {
1903 int k = i<defpos ? i : i+1;
1904 setto->instances[i] = dlgmm->instances[k];
1905 setto->instances[i]->mm = setto;
1906 }
1907 }
1908 MMMatchGlyphs(setto);
1909 if ( setto->normal==NULL ) {
1910 setto->normal = MMNewFont(setto,-1,familyname);
1911 setto->normal->private = oldprivate;
1912 }
1913 if ( !isapple ) {
1914 if ( fbt>0 && fbt<=1 ) {
1915 char buffer[20];
1916 sprintf(buffer,"%g", (double) fbt );
1917 if ( oldprivate==NULL )
1918 setto->normal->private = calloc(1,sizeof(struct psdict));
1919 PSDictChangeEntry(setto->normal->private,"ForceBoldThreshold",buffer);
1920 }
1921 }
1922 if ( !isapple ) {
1923 setto->cdv = dlgmm->cdv;
1924 setto->ndv = dlgmm->ndv;
1925 } else
1926 MMW_ParseNamedStyles(setto,mmw);
1927 for ( i=0; i<setto->instance_count; ++i ) {
1928 if ( setto->instances[i]==NULL )
1929 setto->instances[i] = MMNewFont(setto,i,familyname);
1930 setto->instances[i]->fv = (FontViewBase *) fv;
1931 }
1932 free(dlgmm->instances);
1933 chunkfree(dlgmm,sizeof(MMSet));
1934 if ( origname!=NULL ) {
1935 for ( i=0; i<setto->instance_count; ++i ) {
1936 free(setto->instances[i]->origname);
1937 setto->instances[i]->origname = copy(origname);
1938 }
1939 free(setto->normal->origname);
1940 setto->normal->origname = origname;
1941 } else {
1942 for ( i=0; i<setto->instance_count; ++i ) {
1943 free(setto->instances[i]->origname);
1944 setto->instances[i]->origname = copy(setto->normal->origname);
1945 }
1946 }
1947 if ( !isapple )
1948 MMReblend((FontViewBase *) fv,setto);
1949 if ( fv!=NULL ) {
1950 for ( i=0; i<setto->instance_count; ++i )
1951 if ( fv->b.sf==setto->instances[i])
1952 break;
1953 if ( i==setto->instance_count ) {
1954 SplineFont *sf = setto->normal;
1955 BDFFont *bdf;
1956 int same = fv->filled == fv->show;
1957 fv->b.sf = sf;
1958 bdf = SplineFontPieceMeal(fv->b.sf,ly_fore,sf->display_size<0?-sf->display_size:default_fv_font_size,72,
1959 (fv->antialias?pf_antialias:0)|(fv->bbsized?pf_bbsized:0),
1960 NULL);
1961 BDFFontFree(fv->filled);
1962 fv->filled = bdf;
1963 if ( same )
1964 fv->show = bdf;
1965 }
1966 }
1967 free(familyname);
1968
1969 /* Multi-Mastered bitmaps don't make much sense */
1970 /* Well, maybe grey-scaled could be interpolated, but yuck */
1971 for ( i=0; i<setto->instance_count; ++i ) {
1972 BDFFont *bdf, *bnext;
1973 for ( bdf = setto->instances[i]->bitmaps; bdf!=NULL; bdf = bnext ) {
1974 bnext = bdf->next;
1975 BDFFontFree(bdf);
1976 }
1977 setto->instances[i]->bitmaps = NULL;
1978 }
1979
1980 if ( fv==NULL )
1981 fv = (FontView *) FontViewCreate(setto->normal,false);
1982 if ( enc==NULL )
1983 enc = default_encoding;
1984 FVReencode((FontViewBase *) fv,enc);
1985 mmw->done = true;
1986 }
1987
MMW_DoNext(MMW * mmw)1988 static void MMW_DoNext(MMW *mmw) {
1989 int i, err;
1990 real start, end, def, *designs, *norm;
1991 int n, n2;
1992 int isapple = GGadgetIsChecked(GWidgetGetControl(mmw->subwins[mmw_counts],CID_Apple));
1993 char *yesno[3];
1994 yesno[0] = _("_Yes"); yesno[1] = _("_No"); yesno[2] = NULL;
1995
1996 if ( mmw->state==mmw_others )
1997 return;
1998
1999 if ( mmw->state==mmw_counts ) {
2000 mmw->axis_count = GGadgetGetFirstListSelectedItem(GWidgetGetControl(mmw->subwins[mmw_counts],CID_AxisCount))+1;
2001 mmw->instance_count = GGadgetGetFirstListSelectedItem(GWidgetGetControl(mmw->subwins[mmw_counts],CID_MasterCount))+1;
2002 /* Arrays are already allocated out to maximum, and we will just leave*/
2003 /* them there until user hits OK, then we make them the right size */
2004 for ( i=0; i<4; ++i )
2005 GTabSetSetEnabled(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),
2006 i,i<mmw->axis_count);
2007 for ( i=0; i<AppleMmMax+1; ++i )
2008 GTabSetSetEnabled(GWidgetGetControl(mmw->subwins[mmw_designs],CID_WhichDesign),
2009 i,i<mmw->instance_count);
2010 /* If we've changed the axis count, and the old selected axis isn't */
2011 /* available any more, choose another one */
2012 if ( GTabSetGetSel(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis))>=
2013 mmw->axis_count )
2014 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),
2015 0);
2016 if ( isapple ) {
2017 int cnt = 1;
2018 for ( i=0; i<mmw->axis_count; ++i ) cnt *= 3;
2019 if ( mmw->instance_count==cnt ) {
2020 for ( i=(mmw->old==NULL)?0:mmw->old->instance_count; i<mmw->instance_count-1; ++i ) {
2021 int j = (i>=(cnt-1)/2) ? i+1 : i;
2022 mmw->mm->positions[i*4 ] = (j%3==0) ? -1: (j%3==1) ? 0 : 1;
2023 mmw->mm->positions[i*4+1] = ((j/3)%3==0) ? -1: ((j/3)%3==1) ? 0 : 1;
2024 mmw->mm->positions[i*4+2] = ((j/9)%3==0) ? -1: ((j/9)%3==1) ? 0 : 1;
2025 mmw->mm->positions[i*4+3] = ((j/27)%3==0) ? -1: ((j/27)%3==1) ? 0 : 1;
2026 }
2027 /* Place the default psuedo-instance last */
2028 mmw->mm->positions[i*4 ] = 0;
2029 mmw->mm->positions[i*4+1] = 0;
2030 mmw->mm->positions[i*4+2] = 0;
2031 mmw->mm->positions[i*4+3] = 0;
2032 }
2033 } else {
2034 if ( mmw->instance_count==(1<<mmw->axis_count) ) {
2035 for ( i=(mmw->old==NULL)?0:mmw->old->instance_count; i<mmw->instance_count; ++i ) {
2036 mmw->mm->positions[i*4 ] = (i&1) ? 1 : 0;
2037 mmw->mm->positions[i*4+1] = (i&2) ? 1 : 0;
2038 mmw->mm->positions[i*4+2] = (i&4) ? 1 : 0;
2039 mmw->mm->positions[i*4+3] = (i&8) ? 1 : 0;
2040 }
2041 }
2042 }
2043 } else if ( mmw->state==mmw_axes ) {
2044 for ( i=0; i<mmw->axis_count; ++i ) {
2045 free(mmw->mm->axes[i]);
2046 mmw->mm->axes[i] = cu_copy(_GGadgetGetTitle(GWidgetGetControl(mmw->subwins[mmw_axes],CID_AxisType+i*100)));
2047 if ( *mmw->mm->axes[i]=='\0' ) {
2048 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),
2049 i);
2050 ff_post_error(_("Bad Axis"),_("Please set the Axis Type field"));
2051 return; /* Failure */
2052 }
2053 /* Don't free the current value. If it is non-null then it just */
2054 /* points into the data structure that the Names gadgets manipulate */
2055 /* and they will have done any freeing that needs doing. Freeing */
2056 /* it here would destroy the data they work on */
2057 /*MacNameListFree(mmw->mm->axismaps[i].axisnames);*/
2058 mmw->mm->axismaps[i].axisnames = NULL;
2059 if ( isapple ) {
2060 mmw->mm->axismaps[i].axisnames = NameGadgetsGetNames(GTabSetGetSubwindow(
2061 GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),i));
2062 if ( mmw->mm->axismaps[i].axisnames == NULL ) {
2063 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),
2064 i);
2065 ff_post_error(_("Bad Axis"),_("When building an Apple distortable font, you must specify at least one name for the axis"));
2066 return; /* Failure */
2067 }
2068 }
2069 err = false;
2070 start = GetReal8(mmw->subwins[mmw_axes],CID_AxisBegin+i*100,
2071 _("Begin:"),&err);
2072 end = GetReal8(mmw->subwins[mmw_axes],CID_AxisEnd+i*100,
2073 _("End:"),&err);
2074 if ( isapple ) {
2075 def = rint(GetReal8(mmw->subwins[mmw_axes],CID_AxisDefault+i*100,
2076 S_("AxisValue|Default"),&err)*8096)/8096;
2077 start = rint(start*8096)/8096;
2078 end = rint(end*8096)/8096;
2079 } else
2080 def = start;
2081 if ( start>=end || def<start || def>end ) {
2082 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),
2083 i);
2084 ff_post_error(_("Bad Axis"),_("Axis range not valid"));
2085 return; /* Failure */
2086 }
2087 n = ParseList(mmw->subwins[mmw_axes],CID_IntermediateDesign+i*100,
2088 _("Design Settings:"),&err,start,def,end,&designs,CID_WhichAxis,i,isapple);
2089 n2 = ParseList(mmw->subwins[mmw_axes],CID_IntermediateNormalized+i*100,
2090 _("Normalized Settings:"),&err,
2091 isapple?-1:0,0,1,&norm,CID_WhichAxis,i,isapple);
2092 if ( n!=n2 || err ) {
2093 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_axes],CID_WhichAxis),
2094 i);
2095 if ( !err )
2096 ff_post_error(_("Bad Axis"),_("The number of entries in the design settings must match the number in normalized settings"));
2097 free(designs); free(norm);
2098 return; /* Failure */
2099 }
2100 mmw->mm->axismaps[i].points = n;
2101 free(mmw->mm->axismaps[i].blends); free(mmw->mm->axismaps[i].designs);
2102 mmw->mm->axismaps[i].blends = norm; mmw->mm->axismaps[i].designs=designs;
2103 mmw->mm->axismaps[i].min = start;
2104 mmw->mm->axismaps[i].def = def;
2105 mmw->mm->axismaps[i].max = end;
2106 }
2107 } else if ( mmw->state==mmw_designs ) {
2108 real positions[AppleMmMax+1][4];
2109 int used[AppleMmMax+1];
2110 int j,k,mask, mul;
2111 SplineFont *sfs[AppleMmMax+1];
2112 GTextInfo *ti;
2113
2114 memset(used,0,sizeof(used));
2115 memset(positions,0,sizeof(positions));
2116 for ( i=0; i<mmw->instance_count; ++i ) {
2117 if ( !ParseWeights(mmw->subwins[mmw_designs],CID_AxisWeights+i*DesignScaleFactor,
2118 _("Normalized position of this design along each axis"),positions[i],mmw->axis_count,
2119 CID_WhichDesign,i))
2120 return;
2121 if ( isapple ) {
2122 mask = 0; mul = 1;
2123 for ( j=0; j<mmw->axis_count; ++j ) {
2124 if ( positions[i][j]==-1 )
2125 /* Do Nothing */;
2126 else if ( positions[i][j]==0.0 )
2127 mask += mul;
2128 else if ( positions[i][j]==1.0 )
2129 mask += 2*mul;
2130 else
2131 break;
2132 }
2133 } else {
2134 mask = 0;
2135 for ( j=0; j<mmw->axis_count; ++j ) {
2136 if ( positions[i][j]==0 )
2137 /* Do Nothing */;
2138 else if ( positions[i][j]==1.0 )
2139 mask |= (1<<j);
2140 else
2141 break;
2142 }
2143 }
2144 if ( j==mmw->axis_count )
2145 used[mask] = true;
2146 for ( j=0; j<i-1; ++j ) {
2147 for ( k=0; k<mmw->axis_count; ++k )
2148 if ( positions[j][k] != positions[i][k] )
2149 break;
2150 if ( k==mmw->axis_count ) {
2151 char *temp;
2152 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_designs],CID_WhichDesign),i);
2153 ff_post_error(_("Bad Multiple Master Font"),_("The set of positions, %.30s, is used more than once"),
2154 temp = GGadgetGetTitle8(GWidgetGetControl(mmw->subwins[mmw_designs],CID_AxisWeights+i*DesignScaleFactor)));
2155 free(temp);
2156 return;
2157 }
2158 }
2159 ti = GGadgetGetListItemSelected(GWidgetGetControl(mmw->subwins[mmw_designs],CID_DesignFonts+i*DesignScaleFactor));
2160 sfs[i] = ti->userdata;
2161 if ( sfs[i]!=NULL ) {
2162 for ( j=0; j<i; ++j )
2163 if ( sfs[i]==sfs[j] ) {
2164 GTabSetSetSel(GWidgetGetControl(mmw->subwins[mmw_designs],CID_WhichDesign),i);
2165 ff_post_error(_("Bad Multiple Master Font"),_("The font %.30s is assigned to two master designs"),sfs[i]->fontname);
2166 return;
2167 }
2168 }
2169 }
2170 for ( i=0; i<(1<<mmw->axis_count); ++i ) if ( !used[i] ) {
2171 char buffer[20], *pt = buffer;
2172 for ( j=0; j<mmw->axis_count; ++j ) {
2173 sprintf( pt, "%d ", (i&(1<<j))? 1: 0 );
2174 pt += 2;
2175 }
2176 if ( !isapple ) {
2177 ff_post_error(_("Bad Multiple Master Font"),_("The set of positions, %.30s, is not specified in any design (and should be)"), buffer );
2178 return;
2179 } else {
2180 if ( gwwv_ask(_("Bad Multiple Master Font"),(const char **) yesno,0,1,_("The set of positions, %.30s, is not specified in any design.\nIs that what you want?"),buffer)==1 )
2181 return;
2182 }
2183 }
2184 memcpy(mmw->mm->positions,positions,sizeof(positions));
2185 for ( i=0; i<mmw->instance_count; ++i )
2186 mmw->mm->instances[i] = sfs[i];
2187 if ( mmw->old!=NULL &&
2188 mmw->axis_count==mmw->old->axis_count &&
2189 mmw->instance_count==mmw->old->instance_count &&
2190 PositionsMatch(mmw->old,mmw->mm))
2191 /* It's what the font started with, don't complain, already has a cdv */;
2192 else if ( mmw->instance_count==(1<<mmw->axis_count) &&
2193 StandardPositions(mmw->mm,mmw->instance_count,mmw->axis_count,isapple))
2194 /* It's arranged as we expect it to be */;
2195 else if ( mmw->axis_count==1 &&
2196 OrderedPositions(mmw->mm,mmw->instance_count,isapple))
2197 /* It's arranged according to our secondary expectations */;
2198 else if ( !isapple && (mmw->instance_count==(1<<mmw->axis_count) ||
2199 mmw->axis_count==1 )) {
2200 if ( gwwv_ask(_("Disordered designs"),(const char **) yesno,0,1,_("The master designs are not positioned in the expected order. FontForge will be unable to suggest a ConvertDesignVector for you. Is this what you want?"))==1 )
2201 return;
2202 }
2203 } else if ( mmw->state==mmw_funcs ) {
2204 if ( *_GGadgetGetTitle(GWidgetGetControl(mmw->subwins[mmw_funcs],CID_NDV))=='\0' ||
2205 *_GGadgetGetTitle(GWidgetGetControl(mmw->subwins[mmw_funcs],CID_CDV))=='\0' ) {
2206 ff_post_error(_("Bad PostScript function"),_("Bad PostScript function"));
2207 return;
2208 }
2209 free(mmw->mm->ndv); free(mmw->mm->cdv);
2210 mmw->mm->ndv = cu_copy( _GGadgetGetTitle(GWidgetGetControl(mmw->subwins[mmw_funcs],CID_NDV)));
2211 mmw->mm->cdv = cu_copy( _GGadgetGetTitle(GWidgetGetControl(mmw->subwins[mmw_funcs],CID_CDV)));
2212 }
2213
2214 if ( mmw->state==mmw_designs && !isapple )
2215 mmw->state += 2;
2216 else
2217 ++mmw->state;
2218 if ( mmw->state==mmw_others )
2219 MMW_WeightsValid(mmw);
2220 else if ( mmw->state==mmw_funcs )
2221 MMW_FuncsValid(mmw);
2222 else if ( mmw->state==mmw_designs )
2223 MMW_DesignsSetup(mmw);
2224 MMW_SetState(mmw);
2225 }
2226
MMW_SimulateDefaultButton(MMW * mmw)2227 static void MMW_SimulateDefaultButton(MMW *mmw) {
2228 if ( mmw->state==mmw_others || mmw->state==mmw_named )
2229 MMW_DoOK(mmw);
2230 else
2231 MMW_DoNext(mmw);
2232 }
2233
MMW_OK(GGadget * g,GEvent * e)2234 static int MMW_OK(GGadget *g, GEvent *e) {
2235 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2236 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2237 MMW_DoOK(mmw);
2238 }
2239 return( true );
2240 }
2241
MMW_Next(GGadget * g,GEvent * e)2242 static int MMW_Next(GGadget *g, GEvent *e) {
2243 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2244 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2245 MMW_DoNext(mmw);
2246 }
2247 return( true );
2248 }
2249
MMW_Prev(GGadget * g,GEvent * e)2250 static int MMW_Prev(GGadget *g, GEvent *e) {
2251 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2252 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2253 if ( mmw->state!=mmw_counts ) {
2254 if ( mmw->state==mmw_funcs )
2255 mmw->state = mmw_designs;
2256 else
2257 --mmw->state;
2258 MMW_SetState(mmw);
2259 }
2260 }
2261 return( true );
2262 }
2263
MMW_NamedNew(GGadget * g,GEvent * e)2264 static int MMW_NamedNew(GGadget *g, GEvent *e) {
2265 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2266 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2267 EditStyleName(mmw,-1);
2268 }
2269 return( true );
2270 }
2271
MMW_NamedEdit(GGadget * g,GEvent * e)2272 static int MMW_NamedEdit(GGadget *g, GEvent *e) {
2273 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2274 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2275 EditStyleName(mmw,GGadgetGetFirstListSelectedItem(GWidgetGetControl(mmw->subwins[mmw_named],CID_NamedDesigns)));
2276 }
2277 return( true );
2278 }
2279
MMW_NamedDelete(GGadget * g,GEvent * e)2280 static int MMW_NamedDelete(GGadget *g, GEvent *e) {
2281 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2282 GWindow gw = GGadgetGetWindow(g);
2283 GGadget *list = GWidgetGetControl(gw,CID_NamedDesigns);
2284 int32 i,len;
2285 GTextInfo **ti = GGadgetGetList(list,&len);
2286 for ( i=0; i<len; ++i ) {
2287 if ( ti[i]->selected ) {
2288 MacNameListFree(ti[i]->userdata);
2289 ti[i]->userdata = NULL;
2290 }
2291 }
2292 GListDelSelected(list);
2293 GGadgetSetEnabled(GWidgetGetControl(gw,CID_NamedDelete),false);
2294 GGadgetSetEnabled(GWidgetGetControl(gw,CID_NamedEdit),false);
2295 }
2296 return( true );
2297 }
2298
MMW_NamedSel(GGadget * g,GEvent * e)2299 static int MMW_NamedSel(GGadget *g, GEvent *e) {
2300 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
2301 int32 len;
2302 GTextInfo **ti = GGadgetGetList(g,&len);
2303 GWindow gw = GGadgetGetWindow(g);
2304 int i, sel_cnt=0;
2305 for ( i=0; i<len; ++i )
2306 if ( ti[i]->selected ) ++sel_cnt;
2307 GGadgetSetEnabled(GWidgetGetControl(gw,CID_NamedDelete),sel_cnt!=0);
2308 GGadgetSetEnabled(GWidgetGetControl(gw,CID_NamedEdit),sel_cnt==1);
2309 } else if ( e->type==et_controlevent && e->u.control.subtype == et_listdoubleclick ) {
2310 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2311 EditStyleName(mmw,GGadgetGetFirstListSelectedItem(g));
2312 }
2313 return( true );
2314 }
2315
MMW_CheckOptical(GGadget * g,GEvent * e)2316 static int MMW_CheckOptical(GGadget *g, GEvent *e) {
2317 if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2318 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2319 char *top, *bottom, *def;
2320 unichar_t *ut;
2321 const unichar_t *ret = _GGadgetGetTitle(g);
2322 int di = (GGadgetGetCid(g)-CID_AxisType)/100;
2323 char buf1[20], buf2[20], buf3[20];
2324
2325 if ( mmw->old!=NULL && di<mmw->old->axis_count &&
2326 uc_strcmp(ret,mmw->old->axes[di])==0 ) {
2327 sprintf(buf1,"%g", (double) mmw->old->axismaps[di].designs[0]);
2328 sprintf(buf2,"%g", (double) mmw->old->axismaps[di].designs[mmw->old->axismaps[di].points-1]);
2329 sprintf(buf3,"%g", (double) mmw->old->axismaps[di].def);
2330 def = buf3;
2331 top = buf2;
2332 bottom = buf1;
2333 } else if ( uc_strcmp(ret,"OpticalSize")==0 ) {
2334 top = "72";
2335 def = "12";
2336 bottom = "6";
2337 } else if ( uc_strcmp(ret,"Slant")==0 ) {
2338 top = "22";
2339 def = "0";
2340 bottom = "-22";
2341 } else if ( GGadgetIsChecked(GWidgetGetControl(mmw->subwins[mmw_counts],CID_Apple)) ) {
2342 top = "2.0";
2343 bottom = "0.5";
2344 def = "1.0";
2345 } else {
2346 top = "999";
2347 bottom = "50";
2348 def = "400";
2349 }
2350 ut = uc_copy(top);
2351 GGadgetSetTitle(GWidgetGetControl(GGadgetGetWindow(g),
2352 GGadgetGetCid(g)-CID_AxisType + CID_AxisEnd), ut);
2353 free(ut);
2354 ut = uc_copy(bottom);
2355 GGadgetSetTitle(GWidgetGetControl(GGadgetGetWindow(g),
2356 GGadgetGetCid(g)-CID_AxisType + CID_AxisBegin), ut);
2357 free(ut);
2358 ut = uc_copy(def);
2359 GGadgetSetTitle(GWidgetGetControl(GGadgetGetWindow(g),
2360 GGadgetGetCid(g)-CID_AxisType + CID_AxisDefault), ut);
2361 free(ut);
2362 }
2363 return( true );
2364 }
2365
MMW_CheckBrowse(GGadget * g,GEvent * e)2366 static int MMW_CheckBrowse(GGadget *g, GEvent *e) {
2367 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
2368 MMW *mmw = GDrawGetUserData(GGadgetGetWindow(g));
2369 /*int di = (GGadgetGetCid(g)-CID_DesignFonts)/DesignScaleFactor;*/
2370 GTextInfo *ti = GGadgetGetListItemSelected(g);
2371 char *temp;
2372 SplineFont *sf;
2373 GTextInfo **tis;
2374 int i,sel,oldsel;
2375 unichar_t *ut;
2376
2377 if ( ti!=NULL && ti->userdata == (void *) -1 ) {
2378 temp = GetPostScriptFontName(NULL,false,true);
2379 if ( temp==NULL )
2380 return(true);
2381 sf = LoadSplineFont(temp,0);
2382 free(temp); temp = NULL;
2383 if ( sf==NULL )
2384 return(true);
2385 if ( sf->cidmaster!=NULL || sf->subfonts!=0 ) {
2386 ff_post_error(_("Bad Multiple Master Font"),_("CID keyed fonts may not be a master design of a multiple master font"));
2387 return(true);
2388 } else if ( sf->mm!=NULL ) {
2389 ff_post_error(_("Bad Multiple Master Font"),_("CID keyed fonts may not be a master design of a multiple master font"));
2390 return(true);
2391 }
2392 if ( sf->fv==NULL ) {
2393 if ( mmw->lcnt>=mmw->lmax ) {
2394 if ( mmw->lmax==0 )
2395 mmw->loaded = malloc((mmw->lmax=10)*sizeof(SplineFont *));
2396 else
2397 mmw->loaded = realloc(mmw->loaded,(mmw->lmax+=10)*sizeof(SplineFont *));
2398 }
2399 mmw->loaded[mmw->lcnt++] = sf;
2400 for ( i=0; i<mmw->instance_count; ++i ) {
2401 GGadget *list = GWidgetGetControl(mmw->subwins[mmw_designs],CID_DesignFonts+i*DesignScaleFactor);
2402 oldsel = GGadgetGetFirstListSelectedItem(list);
2403 tis = FontList(mmw,i,&sel);
2404 tis[sel]->selected = false;
2405 tis[oldsel]->selected = true;
2406 GGadgetSetList(list, tis, false);
2407 }
2408 }
2409 GGadgetSetTitle(g,ut = uc_copy(sf->fontname));
2410 free(ut);
2411 }
2412 }
2413 return( true );
2414 }
2415
mmwsub_e_h(GWindow gw,GEvent * event)2416 static int mmwsub_e_h(GWindow gw, GEvent *event) {
2417 if ( event->type==et_char ) {
2418 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
2419 help("ui/dialogs/multiplemaster.html", NULL);
2420 return( true );
2421 } else if ( event->u.chr.keysym=='q' && (event->u.chr.state&ksm_control)) {
2422 if ( event->u.chr.state&ksm_shift )
2423 MMW_Close(GDrawGetUserData(gw));
2424 return( true );
2425 } else if ( event->u.chr.chars[0]=='\r' ) {
2426 MMW_SimulateDefaultButton( (MMW *) GDrawGetUserData(gw));
2427 return( true );
2428 }
2429 return( false );
2430 }
2431 return( true );
2432 }
2433
mmw_e_h(GWindow gw,GEvent * event)2434 static int mmw_e_h(GWindow gw, GEvent *event) {
2435 if ( event->type==et_close ) {
2436 MMW *mmw = GDrawGetUserData(gw);
2437 MMW_Close(mmw);
2438 } else if ( event->type==et_char ) {
2439 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
2440 help("ui/dialogs/multiplemaster.html", NULL);
2441 return( true );
2442 } else if ( event->u.chr.keysym=='q' && (event->u.chr.state&ksm_control)) {
2443 if ( event->u.chr.state&ksm_shift )
2444 MMW_Close(GDrawGetUserData(gw));
2445 else
2446 MenuExit(NULL,NULL,NULL);
2447 return( true );
2448 } else if ( event->u.chr.chars[0]=='\r' ) {
2449 MMW_SimulateDefaultButton( (MMW *) GDrawGetUserData(gw));
2450 return( true );
2451 }
2452 return( false );
2453 }
2454 return( true );
2455 }
2456
MMCopy(MMSet * orig)2457 static MMSet *MMCopy(MMSet *orig) {
2458 MMSet *mm;
2459 int i;
2460 /* Allocate the arrays out to maximum, we'll fix them up later, and we */
2461 /* retain the proper counts in the mmw structure. This means we don't */
2462 /* lose data when they shrink and then restore a value */
2463
2464 mm = chunkalloc(sizeof(MMSet));
2465 mm->apple = orig->apple;
2466 mm->instance_count = AppleMmMax+1;
2467 mm->axis_count = 4;
2468 for ( i=0; i<orig->axis_count; ++i )
2469 mm->axes[i] = copy(orig->axes[i]);
2470 mm->instances = calloc(AppleMmMax+1,sizeof(SplineFont *));
2471 memcpy(mm->instances,orig->instances,orig->instance_count*sizeof(SplineFont *));
2472 if ( mm->apple )
2473 mm->instances[orig->instance_count] = orig->normal;
2474 mm->positions = calloc((AppleMmMax+1)*4,sizeof(real));
2475 for ( i=0; i<orig->instance_count; ++i )
2476 memcpy(mm->positions+i*4,orig->positions+i*orig->axis_count,orig->axis_count*sizeof(real));
2477 mm->defweights = calloc(AppleMmMax+1,sizeof(real));
2478 memcpy(mm->defweights,orig->defweights,orig->instance_count*sizeof(real));
2479 mm->axismaps = calloc(4,sizeof(struct axismap));
2480 for ( i=0; i<orig->axis_count; ++i ) {
2481 mm->axismaps[i].points = orig->axismaps[i].points;
2482 mm->axismaps[i].blends = malloc(mm->axismaps[i].points*sizeof(real));
2483 memcpy(mm->axismaps[i].blends,orig->axismaps[i].blends,mm->axismaps[i].points*sizeof(real));
2484 mm->axismaps[i].designs = malloc(mm->axismaps[i].points*sizeof(real));
2485 memcpy(mm->axismaps[i].designs,orig->axismaps[i].designs,mm->axismaps[i].points*sizeof(real));
2486 mm->axismaps[i].min = orig->axismaps[i].min;
2487 mm->axismaps[i].max = orig->axismaps[i].max;
2488 mm->axismaps[i].def = orig->axismaps[i].def;
2489 }
2490 mm->cdv = copy(orig->cdv);
2491 mm->ndv = copy(orig->ndv);
2492 return( mm );
2493 }
2494
MMWizard(MMSet * mm)2495 void MMWizard(MMSet *mm) {
2496 MMW mmw;
2497 GRect pos, subpos;
2498 GWindow gw;
2499 GWindowAttrs wattrs;
2500 GTabInfo axisaspects[5], designaspects[AppleMmMax+1+1];
2501 GGadgetCreateData bgcd[8], cntgcd[11], axisgcd[4][20], designgcd[AppleMmMax+1][5],
2502 agcd[2], dgcd[3], ogcd[7], ngcd[7];
2503 GTextInfo blabel[8], cntlabel[11], axislabel[4][20], designlabel[AppleMmMax+1][5],
2504 dlabel, olabels[7], nlabel[5];
2505 char axisbegins[4][20], axisends[4][20], axisdefs[4][20];
2506 char *normalized[4], *designs[4];
2507 char *pt, *freeme;
2508 int i,k;
2509 int isadobe = mm==NULL || !mm->apple;
2510 int space,blen= GIntGetResource(_NUM_Buttonsize)*100/GGadgetScale(100);
2511 static char *designtablab[] = { "1", "2", "3", "4", "5", "6", "7", "8",
2512 "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
2513 "20", "21", "22", "23", "24", "25", "26", "27", NULL };
2514 #if AppleMmMax!=26
2515 #error "The designtablab array needs to be expanded to match AppleMmMax"
2516 /* Actually it should be one bigger than AppleMmMax */
2517 #endif
2518
2519 memset(&mmw,0,sizeof(mmw));
2520 mmw.old = mm;
2521 if ( mm!=NULL ) {
2522 mmw.mm = MMCopy(mm);
2523 mmw.axis_count = mm->axis_count;
2524 mmw.instance_count = mm->instance_count;
2525 if ( mm->apple )
2526 ++mmw.instance_count; /* Normal (default) design is a master in the mac format */
2527 } else {
2528 mmw.mm = chunkalloc(sizeof(MMSet));
2529 mmw.axis_count = 1;
2530 mmw.instance_count = 2;
2531 mmw.mm->axis_count = 4; mmw.mm->instance_count = AppleMmMax+1;
2532 mmw.mm->instances = calloc(AppleMmMax+1,sizeof(SplineFont *));
2533 mmw.mm->positions = calloc((AppleMmMax+1)*4,sizeof(real));
2534 mmw.mm->defweights = calloc(AppleMmMax+1,sizeof(real));
2535 mmw.mm->axismaps = calloc(4,sizeof(struct axismap));
2536 mmw.isnew = true;
2537 }
2538
2539 memset(&wattrs,0,sizeof(wattrs));
2540 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2541 wattrs.event_masks = ~(1<<et_charup);
2542 wattrs.is_dlg = true;
2543 wattrs.restrict_input_to_me = true;
2544 wattrs.undercursor = 1;
2545 wattrs.cursor = ct_pointer;
2546 wattrs.utf8_window_title = mmw.isnew?_("Create MM"):_("MM _Info") ;
2547 pos.x = pos.y = 0;
2548 pos.width =GDrawPointsToPixels(NULL,GGadgetScale(MMW_Width));
2549 pos.height = GDrawPointsToPixels(NULL,MMW_Height);
2550 mmw.gw = gw = GDrawCreateTopWindow(NULL,&pos,mmw_e_h,&mmw,&wattrs);
2551
2552 memset(&blabel,0,sizeof(blabel));
2553 memset(&bgcd,0,sizeof(bgcd));
2554
2555 mmw.canceldrop = GDrawPointsToPixels(NULL,30);
2556 bgcd[0].gd.pos.x = 20; bgcd[0].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-33;
2557 bgcd[0].gd.pos.width = -1; bgcd[0].gd.pos.height = 0;
2558 bgcd[0].gd.flags = gg_visible | gg_enabled;
2559 blabel[0].text = (unichar_t *) _("_OK");
2560 blabel[0].text_is_1byte = true;
2561 blabel[0].text_in_resource = true;
2562 bgcd[0].gd.label = &blabel[0];
2563 bgcd[0].gd.cid = CID_OK;
2564 bgcd[0].gd.handle_controlevent = MMW_OK;
2565 bgcd[0].creator = GButtonCreate;
2566
2567 space = (MMW_Width-4*blen-40)/3;
2568 bgcd[1].gd.pos.x = bgcd[0].gd.pos.x+blen+space; bgcd[1].gd.pos.y = bgcd[0].gd.pos.y;
2569 bgcd[1].gd.pos.width = -1; bgcd[1].gd.pos.height = 0;
2570 bgcd[1].gd.flags = gg_visible;
2571 blabel[1].text = (unichar_t *) _("< _Prev");
2572 blabel[1].text_is_1byte = true;
2573 blabel[1].text_in_resource = true;
2574 bgcd[1].gd.label = &blabel[1];
2575 bgcd[1].gd.handle_controlevent = MMW_Prev;
2576 bgcd[1].gd.cid = CID_Prev;
2577 bgcd[1].creator = GButtonCreate;
2578
2579 bgcd[2].gd.pos.x = bgcd[1].gd.pos.x+blen+space; bgcd[2].gd.pos.y = bgcd[1].gd.pos.y;
2580 bgcd[2].gd.pos.width = -1; bgcd[2].gd.pos.height = 0;
2581 bgcd[2].gd.flags = gg_visible;
2582 blabel[2].text = (unichar_t *) _("_Next >");
2583 blabel[2].text_in_resource = true;
2584 blabel[2].text_is_1byte = true;
2585 bgcd[2].gd.label = &blabel[2];
2586 bgcd[2].gd.handle_controlevent = MMW_Next;
2587 bgcd[2].gd.cid = CID_Next;
2588 bgcd[2].creator = GButtonCreate;
2589
2590 bgcd[3].gd.pos.x = -20; bgcd[3].gd.pos.y = bgcd[1].gd.pos.y;
2591 bgcd[3].gd.pos.width = -1; bgcd[3].gd.pos.height = 0;
2592 bgcd[3].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
2593 blabel[3].text = (unichar_t *) _("_Cancel");
2594 blabel[3].text_in_resource = true;
2595 blabel[3].text_is_1byte = true;
2596 bgcd[3].gd.label = &blabel[3];
2597 bgcd[3].gd.handle_controlevent = MMW_Cancel;
2598 bgcd[3].gd.cid = CID_Cancel;
2599 bgcd[3].creator = GButtonCreate;
2600
2601 bgcd[4].gd.pos.x = 2; bgcd[4].gd.pos.y = 2;
2602 bgcd[4].gd.pos.width = pos.width-4; bgcd[4].gd.pos.height = pos.height-4;
2603 bgcd[4].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
2604 bgcd[4].gd.cid = CID_Group;
2605 bgcd[4].creator = GGroupCreate;
2606
2607 GGadgetsCreate(gw,bgcd);
2608
2609 subpos = pos;
2610 subpos.y = subpos.x = 4;
2611 subpos.width -= 8;
2612 mmw.subheightdiff = GDrawPointsToPixels(NULL,44)-8;
2613 subpos.height -= mmw.subheightdiff;
2614 wattrs.mask = wam_events;
2615 for ( i=mmw_counts; i<=mmw_others; ++i )
2616 mmw.subwins[i] = GWidgetCreateSubWindow(mmw.gw,&subpos,mmwsub_e_h,&mmw,&wattrs);
2617
2618 memset(&cntlabel,0,sizeof(cntlabel));
2619 memset(&cntgcd,0,sizeof(cntgcd));
2620
2621 k=0;
2622 cntlabel[k].text = (unichar_t *) _("Type of distortable font:");
2623 cntlabel[k].text_is_1byte = true;
2624 cntgcd[k].gd.label = &cntlabel[k];
2625 cntgcd[k].gd.pos.x = 5; cntgcd[k].gd.pos.y = 11;
2626 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2627 cntgcd[k++].creator = GLabelCreate;
2628
2629 cntlabel[k].text = (unichar_t *) _("Adobe");
2630 cntlabel[k].text_is_1byte = true;
2631 cntgcd[k].gd.label = &cntlabel[k];
2632 cntgcd[k].gd.pos.x = 10; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+12;
2633 cntgcd[k].gd.flags = isadobe ? (gg_visible | gg_enabled | gg_cb_on) :
2634 ( gg_visible | gg_enabled );
2635 cntgcd[k].gd.cid = CID_Adobe;
2636 cntgcd[k].gd.handle_controlevent = MMW_TypeChanged;
2637 cntgcd[k++].creator = GRadioCreate;
2638
2639 cntlabel[k].text = (unichar_t *) _("Apple");
2640 cntlabel[k].text_is_1byte = true;
2641 cntgcd[k].gd.label = &cntlabel[k];
2642 cntgcd[k].gd.pos.x = 70; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y;
2643 cntgcd[k].gd.flags = !isadobe ? (gg_visible | gg_enabled | gg_cb_on) :
2644 ( gg_visible | gg_enabled );
2645 cntgcd[k].gd.cid = CID_Apple;
2646 cntgcd[k].gd.handle_controlevent = MMW_TypeChanged;
2647 cntgcd[k++].creator = GRadioCreate;
2648
2649 cntlabel[k].text = (unichar_t *) _("Number of Axes:");
2650 cntlabel[k].text_is_1byte = true;
2651 cntgcd[k].gd.label = &cntlabel[k];
2652 cntgcd[k].gd.pos.x = 5; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+18;
2653 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2654 cntgcd[k++].creator = GLabelCreate;
2655
2656 cntgcd[k].gd.pos.x = 10; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+12;
2657 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2658 cntgcd[k].gd.u.list = axiscounts;
2659 cntgcd[k].gd.label = &axiscounts[mmw.axis_count-1];
2660 cntgcd[k].gd.cid = CID_AxisCount;
2661 cntgcd[k].gd.handle_controlevent = MMW_AxisCntChanged;
2662 cntgcd[k++].creator = GListButtonCreate;
2663 for ( i=0; i<4; ++i )
2664 axiscounts[i].selected = false;
2665 axiscounts[mmw.axis_count-1].selected = true;
2666
2667 cntlabel[k].text = (unichar_t *) _("Number of Master Designs:");
2668 cntlabel[k].text_is_1byte = true;
2669 cntgcd[k].gd.label = &cntlabel[k];
2670 cntgcd[k].gd.pos.x = 5; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+30;
2671 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2672 cntgcd[k++].creator = GLabelCreate;
2673
2674 cntgcd[k].gd.pos.x = 10; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+12;
2675 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2676 cntgcd[k].gd.u.list = mastercounts;
2677 cntgcd[k].gd.label = &mastercounts[mmw.instance_count-1];
2678 cntgcd[k].gd.cid = CID_MasterCount;
2679 cntgcd[k++].creator = GListButtonCreate;
2680 for ( i=0; i<AppleMmMax+1; ++i )
2681 mastercounts[i].selected = false;
2682 mastercounts[mmw.instance_count-1].selected = true;
2683
2684 cntlabel[k].text = (unichar_t *) _("_Family Name:");
2685 cntlabel[k].text_is_1byte = true;
2686 cntlabel[k].text_in_resource = true;
2687 cntgcd[k].gd.label = &cntlabel[k];
2688 cntgcd[k].gd.pos.x = 10; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+30;
2689 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2690 cntgcd[k++].creator = GLabelCreate;
2691
2692 freeme=NULL;
2693 if ( mmw.old!=NULL && mmw.old->normal->familyname!=NULL )
2694 cntlabel[k].text = (unichar_t *) (mmw.old->normal->familyname);
2695 else
2696 cntlabel[k].text = (unichar_t *) (freeme= GetNextUntitledName());
2697 cntlabel[k].text_is_1byte = true;
2698 cntgcd[k].gd.label = &cntlabel[k];
2699 cntgcd[k].gd.pos.x = 15; cntgcd[k].gd.pos.y = cntgcd[k-1].gd.pos.y+14;
2700 cntgcd[k].gd.pos.width = 150;
2701 cntgcd[k].gd.flags = gg_visible | gg_enabled;
2702 cntgcd[k].gd.cid = CID_FamilyName;
2703 cntgcd[k++].creator = GTextFieldCreate;
2704
2705 GGadgetsCreate(mmw.subwins[mmw_counts],cntgcd);
2706 SetMasterToAxis(&mmw,true);
2707 free(freeme);
2708
2709 memset(&axisgcd,0,sizeof(axisgcd));
2710 memset(&axislabel,0,sizeof(axislabel));
2711 memset(&agcd,0,sizeof(agcd));
2712 memset(&axisaspects,0,sizeof(axisaspects));
2713
2714 for ( i=0; i<4; ++i ) {
2715 k=0;
2716 axislabel[i][k].text = (unichar_t *) _("Axis Type:");
2717 axislabel[i][k].text_is_1byte = true;
2718 axisgcd[i][k].gd.label = &axislabel[i][k];
2719 axisgcd[i][k].gd.pos.x = 5; axisgcd[i][k].gd.pos.y = 11;
2720 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2721 axisgcd[i][k++].creator = GLabelCreate;
2722
2723 axisgcd[i][k].gd.pos.x = 120; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y-4;
2724 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2725 axisgcd[i][k].gd.u.list = axistypes;
2726 axisgcd[i][k].gd.cid = CID_AxisType+i*100;
2727 axisgcd[i][k].gd.handle_controlevent = MMW_CheckOptical;
2728 if ( i<mmw.axis_count && mmw.mm->axes[i]!=NULL ) {
2729 axislabel[i][k].text = uc_copy(mmw.mm->axes[i]);
2730 axisgcd[i][k].gd.label = &axislabel[i][k];
2731 }
2732 axisgcd[i][k++].creator = GListFieldCreate;
2733
2734 axislabel[i][k].text = (unichar_t *) _("Axis Range:");
2735 axislabel[i][k].text_is_1byte = true;
2736 axisgcd[i][k].gd.label = &axislabel[i][k];
2737 axisgcd[i][k].gd.pos.x = 5; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y+20;
2738 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2739 axisgcd[i][k++].creator = GLabelCreate;
2740
2741 if ( mmw.mm->axismaps[i].points<2 ) {
2742 strcpy(axisbegins[i],"50");
2743 strcpy(axisdefs[i],"400");
2744 strcpy(axisends[i],"999");
2745 } else {
2746 sprintf(axisbegins[i],"%.4g", (double) mmw.mm->axismaps[i].designs[0]);
2747 sprintf(axisends[i],"%.4g", (double) mmw.mm->axismaps[i].designs[mmw.mm->axismaps[i].points-1]);
2748 if ( mmw.mm->apple )
2749 sprintf(axisdefs[i],"%.4g", (double) mmw.mm->axismaps[i].def );
2750 else
2751 sprintf(axisdefs[i],"%g", (double) (mmw.mm->axismaps[i].designs[0]+
2752 mmw.mm->axismaps[i].designs[mmw.mm->axismaps[i].points-1])/2);
2753 }
2754
2755 axislabel[i][k].text = (unichar_t *) _("Begin:");
2756 axislabel[i][k].text_is_1byte = true;
2757 axisgcd[i][k].gd.label = &axislabel[i][k];
2758 axisgcd[i][k].gd.pos.x = 10; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y+16;
2759 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2760 axisgcd[i][k++].creator = GLabelCreate;
2761
2762 axislabel[i][k].text = (unichar_t *) axisbegins[i];
2763 axislabel[i][k].text_is_1byte = true;
2764 axisgcd[i][k].gd.label = &axislabel[i][k];
2765 axisgcd[i][k].gd.pos.x = 50; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y-4;
2766 axisgcd[i][k].gd.pos.width=50;
2767 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2768 axisgcd[i][k].gd.cid = CID_AxisBegin+i*100;
2769 axisgcd[i][k++].creator = GTextFieldCreate;
2770
2771 axislabel[i][k].text = (unichar_t *) _("Default:");
2772 axislabel[i][k].text_is_1byte = true;
2773 axisgcd[i][k].gd.label = &axislabel[i][k];
2774 axisgcd[i][k].gd.pos.x = 110; axisgcd[i][k].gd.pos.y = axisgcd[i][k-2].gd.pos.y;
2775 axisgcd[i][k].gd.flags = mmw.mm->apple ? (gg_visible | gg_enabled) : gg_visible;
2776 axisgcd[i][k].gd.cid = CID_AxisDefaultLabel+i*100;
2777 axisgcd[i][k++].creator = GLabelCreate;
2778
2779 axislabel[i][k].text = (unichar_t *) axisdefs[i];
2780 axislabel[i][k].text_is_1byte = true;
2781 axisgcd[i][k].gd.label = &axislabel[i][k];
2782 axisgcd[i][k].gd.pos.x = 148; axisgcd[i][k].gd.pos.y = axisgcd[i][k-2].gd.pos.y;
2783 axisgcd[i][k].gd.pos.width=50;
2784 axisgcd[i][k].gd.flags = mmw.mm->apple ? (gg_visible | gg_enabled) : gg_visible;
2785 axisgcd[i][k].gd.cid = CID_AxisDefault+i*100;
2786 axisgcd[i][k++].creator = GTextFieldCreate;
2787
2788 axislabel[i][k].text = (unichar_t *) _("End:");
2789 axislabel[i][k].text_is_1byte = true;
2790 axisgcd[i][k].gd.label = &axislabel[i][k];
2791 axisgcd[i][k].gd.pos.x = 210; axisgcd[i][k].gd.pos.y = axisgcd[i][k-2].gd.pos.y;
2792 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2793 axisgcd[i][k++].creator = GLabelCreate;
2794
2795 axislabel[i][k].text = (unichar_t *) axisends[i];
2796 axislabel[i][k].text_is_1byte = true;
2797 axisgcd[i][k].gd.label = &axislabel[i][k];
2798 axisgcd[i][k].gd.pos.x = 240; axisgcd[i][k].gd.pos.y = axisgcd[i][k-2].gd.pos.y;
2799 axisgcd[i][k].gd.pos.width=50;
2800 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2801 axisgcd[i][k].gd.cid = CID_AxisEnd+i*100;
2802 axisgcd[i][k++].creator = GTextFieldCreate;
2803
2804 axislabel[i][k].text = (unichar_t *) _("Intermediate Points:");
2805 axislabel[i][k].text_is_1byte = true;
2806 axisgcd[i][k].gd.label = &axislabel[i][k];
2807 axisgcd[i][k].gd.pos.x = 5; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y+26;
2808 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2809 axisgcd[i][k++].creator = GLabelCreate;
2810
2811 normalized[i]=NULL;
2812 designs[i]=NULL;
2813 if ( mmw.mm->axismaps[i].points>2+mmw.mm->apple ) {
2814 int l,j,len1, len2;
2815 char buffer[30];
2816 len1 = len2 = 0;
2817 for ( l=0; l<2; ++l ) {
2818 for ( j=1; j<mmw.mm->axismaps[i].points-1; ++j ) {
2819 if ( mmw.mm->apple && mmw.mm->axismaps[i].designs[j]==mmw.mm->axismaps[i].def )
2820 continue;
2821 /* I wanted to separate things with commas, but that isn't*/
2822 /* a good idea in Europe (comma==decimal point) */
2823 sprintf(buffer,"%g ",(double) mmw.mm->axismaps[i].designs[j]);
2824 if ( designs[i]!=NULL )
2825 strcpy(designs[i]+len1, buffer );
2826 len1 += strlen(buffer);
2827 sprintf(buffer,"%g ",(double) mmw.mm->axismaps[i].blends[j]);
2828 if ( normalized[i]!=NULL )
2829 strcpy(normalized[i]+len2, buffer );
2830 len2 += strlen(buffer);
2831 }
2832 if ( l==0 ) {
2833 normalized[i] = malloc(len2+2);
2834 designs[i] = malloc(len1+2);
2835 } else {
2836 normalized[i][len2-1] = '\0';
2837 designs[i][len1-1] = '\0';
2838 }
2839 }
2840 }
2841
2842 axislabel[i][k].text = (unichar_t *) _("Design Settings:");
2843 axislabel[i][k].text_is_1byte = true;
2844 axisgcd[i][k].gd.label = &axislabel[i][k];
2845 axisgcd[i][k].gd.pos.x = 10; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y+12;
2846 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2847 axisgcd[i][k++].creator = GLabelCreate;
2848
2849 if ( designs[i]!=NULL ) {
2850 axislabel[i][k].text = (unichar_t *) designs[i];
2851 axislabel[i][k].text_is_1byte = true;
2852 axisgcd[i][k].gd.label = &axislabel[i][k];
2853 }
2854 axisgcd[i][k].gd.pos.x = 120; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y-4;
2855 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2856 axisgcd[i][k].gd.cid = CID_IntermediateDesign+i*100;
2857 axisgcd[i][k++].creator = GTextFieldCreate;
2858
2859 axislabel[i][k].text = (unichar_t *) _("Normalized Settings:");
2860 axislabel[i][k].text_is_1byte = true;
2861 axisgcd[i][k].gd.label = &axislabel[i][k];
2862 axisgcd[i][k].gd.pos.x = 10; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y+28;
2863 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2864 axisgcd[i][k++].creator = GLabelCreate;
2865
2866 if ( normalized[i]!=NULL ) {
2867 axislabel[i][k].text = (unichar_t *) normalized[i];
2868 axislabel[i][k].text_is_1byte = true;
2869 axisgcd[i][k].gd.label = &axislabel[i][k];
2870 }
2871 axisgcd[i][k].gd.pos.x = 120; axisgcd[i][k].gd.pos.y = axisgcd[i][k-1].gd.pos.y-4;
2872 axisgcd[i][k].gd.flags = gg_visible | gg_enabled;
2873 axisgcd[i][k].gd.cid = CID_IntermediateNormalized+i*100;
2874 axisgcd[i][k++].creator = GTextFieldCreate;
2875
2876 k = GCDBuildNames(axisgcd[i],axislabel[i],k,mm==NULL || i>=mm->axis_count ? NULL :
2877 mm->axismaps[i].axisnames);
2878
2879 axisaspects[i].text = (unichar_t *) _(axistablab[i]);
2880 axisaspects[i].text_is_1byte = true;
2881 axisaspects[i].gcd = axisgcd[i];
2882 }
2883 axisaspects[0].selected = true;
2884
2885 agcd[0].gd.pos.x = 3; agcd[0].gd.pos.y = 3;
2886 agcd[0].gd.pos.width = MMW_Width-10;
2887 agcd[0].gd.pos.height = MMW_Height-45;
2888 agcd[0].gd.u.tabs = axisaspects;
2889 agcd[0].gd.flags = gg_visible | gg_enabled;
2890 agcd[0].gd.cid = CID_WhichAxis;
2891 agcd[0].creator = GTabSetCreate;
2892
2893 GGadgetsCreate(mmw.subwins[mmw_axes],agcd);
2894 for ( i=0; i<4; ++i ) {
2895 free(axislabel[i][1].text);
2896 free(normalized[i]);
2897 free(designs[i]);
2898 }
2899
2900 memset(&designgcd,0,sizeof(designgcd));
2901 memset(&designlabel,0,sizeof(designlabel));
2902 memset(&dgcd,0,sizeof(dgcd));
2903 memset(&dlabel,0,sizeof(dlabel));
2904 memset(&designaspects,0,sizeof(designaspects));
2905
2906 for ( i=0; i<AppleMmMax+1; ++i ) {
2907 designlabel[i][0].text = (unichar_t *) _("Source from which this design is to be taken");
2908 designlabel[i][0].text_is_1byte = true;
2909 designgcd[i][0].gd.label = &designlabel[i][0];
2910 designgcd[i][0].gd.pos.x = 3; designgcd[i][0].gd.pos.y = 4;
2911 designgcd[i][0].gd.flags = gg_visible | gg_enabled;
2912 designgcd[i][0].creator = GLabelCreate;
2913
2914 designgcd[i][1].gd.pos.x = 15; designgcd[i][1].gd.pos.y = 18;
2915 designgcd[i][1].gd.pos.width = 200;
2916 designgcd[i][1].gd.flags = gg_visible | gg_enabled;
2917 designgcd[i][1].gd.cid = CID_DesignFonts + i*DesignScaleFactor;
2918 designgcd[i][1].gd.handle_controlevent = MMW_CheckBrowse;
2919 designgcd[i][1].creator = GListButtonCreate;
2920
2921 designlabel[i][2].text = (unichar_t *) _("Normalized position of this design along each axis");
2922 designlabel[i][2].text_is_1byte = true;
2923 designgcd[i][2].gd.label = &designlabel[i][2];
2924 designgcd[i][2].gd.pos.x = 3; designgcd[i][2].gd.pos.y = 50;
2925 designgcd[i][2].gd.flags = gg_visible | gg_enabled;
2926 designgcd[i][2].creator = GLabelCreate;
2927
2928 designgcd[i][3].gd.pos.x = 15; designgcd[i][3].gd.pos.y = 64;
2929 designgcd[i][3].gd.pos.width = 200;
2930 designgcd[i][3].gd.flags = gg_visible | gg_enabled;
2931 designgcd[i][3].gd.cid = CID_AxisWeights + i*DesignScaleFactor;
2932 designgcd[i][3].creator = GTextFieldCreate;
2933
2934 designaspects[i].text = (unichar_t *) designtablab[i];
2935 designaspects[i].text_is_1byte = true;
2936 designaspects[i].gcd = designgcd[i];
2937 }
2938 designaspects[0].selected = true;
2939
2940 dlabel.text = (unichar_t *) _("Master Designs");
2941 dlabel.text_is_1byte = true;
2942 dgcd[0].gd.label = &dlabel;
2943 dgcd[0].gd.pos.x = 3; dgcd[0].gd.pos.y = 4;
2944 dgcd[0].gd.flags = gg_visible | gg_enabled;
2945 dgcd[0].creator = GLabelCreate;
2946
2947 dgcd[1].gd.pos.x = 3; dgcd[1].gd.pos.y = 18;
2948 dgcd[1].gd.pos.width = MMW_Width-10;
2949 dgcd[1].gd.pos.height = MMW_Height-60;
2950 dgcd[1].gd.u.tabs = designaspects;
2951 dgcd[1].gd.flags = gg_visible | gg_enabled;
2952 dgcd[1].gd.cid = CID_WhichDesign;
2953 dgcd[1].creator = GTabSetCreate;
2954
2955 GGadgetsCreate(mmw.subwins[mmw_designs],dgcd);
2956
2957 memset(&ngcd,0,sizeof(ngcd));
2958 memset(&nlabel,0,sizeof(nlabel));
2959
2960 nlabel[0].text = (unichar_t *) _("Named Styles");
2961 nlabel[0].text_is_1byte = true;
2962 ngcd[0].gd.label = &nlabel[0];
2963 ngcd[0].gd.pos.x = 3; ngcd[0].gd.pos.y = 4;
2964 ngcd[0].gd.flags = gg_visible | gg_enabled;
2965 ngcd[0].creator = GLabelCreate;
2966
2967 ngcd[1].gd.pos.x = 3; ngcd[1].gd.pos.y = 18;
2968 ngcd[1].gd.pos.width = MMW_Width-10;
2969 ngcd[1].gd.pos.height = MMW_Height-100;
2970 ngcd[1].gd.u.list = NamedDesigns(&mmw);
2971 ngcd[1].gd.flags = gg_visible | gg_enabled | gg_list_multiplesel;
2972 ngcd[1].gd.cid = CID_NamedDesigns;
2973 ngcd[1].gd.handle_controlevent = MMW_NamedSel;
2974 ngcd[1].creator = GListCreate;
2975
2976 ngcd[2].gd.pos.x = 20; ngcd[2].gd.pos.y = ngcd[1].gd.pos.y + ngcd[1].gd.pos.height+5;
2977 ngcd[2].gd.pos.width = -1;
2978 ngcd[2].gd.flags = gg_visible | gg_enabled;
2979 nlabel[2].text = (unichar_t *) S_("Design|_New...");
2980 nlabel[2].text_is_1byte = true;
2981 nlabel[2].text_in_resource = true;
2982 ngcd[2].gd.label = &nlabel[2];
2983 ngcd[2].gd.cid = CID_NamedNew;
2984 ngcd[2].gd.handle_controlevent = MMW_NamedNew;
2985 ngcd[2].creator = GButtonCreate;
2986
2987 ngcd[3].gd.pos.x = 20+blen+10; ngcd[3].gd.pos.y = ngcd[2].gd.pos.y;
2988 ngcd[3].gd.pos.width = -1;
2989 ngcd[3].gd.flags = gg_visible;
2990 nlabel[3].text = (unichar_t *) _("_Delete");
2991 nlabel[3].text_is_1byte = true;
2992 nlabel[3].text_in_resource = true;
2993 ngcd[3].gd.label = &nlabel[3];
2994 ngcd[3].gd.cid = CID_NamedDelete;
2995 ngcd[3].gd.handle_controlevent = MMW_NamedDelete;
2996 ngcd[3].creator = GButtonCreate;
2997
2998 ngcd[4].gd.pos.x = 20+2*blen+20; ngcd[4].gd.pos.y = ngcd[2].gd.pos.y;
2999 ngcd[4].gd.pos.width = -1;
3000 ngcd[4].gd.flags = gg_visible;
3001 nlabel[4].text = (unichar_t *) _("_Edit...");
3002 nlabel[4].text_is_1byte = true;
3003 nlabel[4].text_in_resource = true;
3004 ngcd[4].gd.label = &nlabel[4];
3005 ngcd[4].gd.cid = CID_NamedEdit;
3006 ngcd[4].gd.handle_controlevent = MMW_NamedEdit;
3007 ngcd[4].creator = GButtonCreate;
3008
3009 GGadgetsCreate(mmw.subwins[mmw_named],ngcd);
3010 if ( ngcd[1].gd.u.list!=NULL )
3011 GTextInfoListFree(ngcd[1].gd.u.list);
3012
3013 memset(&ogcd,0,sizeof(ogcd));
3014 memset(&olabels,0,sizeof(olabels));
3015
3016 k=0;
3017 olabels[k].text = (unichar_t *) _("Normalize Design Vector Function:");
3018 olabels[k].text_is_1byte = true;
3019 ogcd[k].gd.label = &olabels[k];
3020 ogcd[k].gd.pos.x = 3; ogcd[k].gd.pos.y = 4;
3021 ogcd[k].gd.flags = gg_visible | gg_enabled;
3022 ogcd[k++].creator = GLabelCreate;
3023
3024 ogcd[k].gd.pos.x = 3; ogcd[k].gd.pos.y = ogcd[k-1].gd.pos.y+15;
3025 ogcd[k].gd.pos.width = MMW_Width-10;
3026 ogcd[k].gd.pos.height = 8*12+10;
3027 ogcd[k].gd.flags = gg_visible | gg_enabled;
3028 ogcd[k].gd.cid = CID_NDV;
3029 ogcd[k++].creator = GTextAreaCreate;
3030
3031 olabels[k].text = (unichar_t *) _("Convert Design Vector Function:");
3032 olabels[k].text_is_1byte = true;
3033 ogcd[k].gd.label = &olabels[k];
3034 ogcd[k].gd.pos.x = 3; ogcd[k].gd.pos.y = ogcd[k-1].gd.pos.y+ogcd[k-1].gd.pos.height+5;
3035 ogcd[k].gd.flags = gg_visible | gg_enabled;
3036 ogcd[k++].creator = GLabelCreate;
3037
3038 ogcd[k].gd.pos.x = 3; ogcd[k].gd.pos.y = ogcd[k-1].gd.pos.y+15;
3039 ogcd[k].gd.pos.width = MMW_Width-10;
3040 ogcd[k].gd.pos.height = 8*12+10;
3041 ogcd[k].gd.flags = gg_visible | gg_enabled;
3042 ogcd[k].gd.cid = CID_CDV;
3043 ogcd[k++].creator = GTextAreaCreate;
3044
3045 GGadgetsCreate(mmw.subwins[mmw_funcs],ogcd);
3046
3047 memset(&ogcd,0,sizeof(ogcd));
3048 memset(&olabels,0,sizeof(olabels));
3049
3050 k=0;
3051 olabels[k].text = (unichar_t *) _("Contribution of each master design");
3052 olabels[k].text_is_1byte = true;
3053 ogcd[k].gd.label = &olabels[k];
3054 ogcd[k].gd.pos.x = 10; ogcd[k].gd.pos.y = 4;
3055 ogcd[k].gd.flags = gg_visible | gg_enabled | gg_cb_on;
3056 ogcd[k].gd.cid = CID_Explicit;
3057 ogcd[k].gd.handle_controlevent = MMCB_Changed;
3058 ogcd[k++].creator = GRadioCreate;
3059
3060 olabels[k].text = (unichar_t *) _("Design Axis Values");
3061 olabels[k].text_is_1byte = true;
3062 ogcd[k].gd.label = &olabels[k];
3063 ogcd[k].gd.pos.x = 10; ogcd[k].gd.pos.y = ogcd[k-1].gd.pos.y+45;
3064 ogcd[k].gd.flags = gg_visible | gg_enabled;
3065 ogcd[k].gd.cid = CID_ByDesign;
3066 ogcd[k].gd.handle_controlevent = MMCB_Changed;
3067 ogcd[k++].creator = GRadioCreate;
3068
3069 ogcd[k].gd.pos.x = 15; ogcd[k].gd.pos.y = ogcd[k-2].gd.pos.y+18;
3070 ogcd[k].gd.pos.width = 240;
3071 ogcd[k].gd.flags = gg_visible | gg_enabled;
3072 ogcd[k].gd.cid = CID_NewBlends;
3073 ogcd[k++].creator = GTextFieldCreate;
3074
3075 ogcd[k].gd.pos.x = 15; ogcd[k].gd.pos.y = ogcd[k-2].gd.pos.y+18;
3076 ogcd[k].gd.pos.width = 240;
3077 ogcd[k].gd.flags = gg_visible;
3078 ogcd[k].gd.cid = CID_NewDesign;
3079 ogcd[k++].creator = GTextFieldCreate;
3080
3081 olabels[k].text = (unichar_t *) _("Force Bold Threshold:");
3082 olabels[k].text_is_1byte = true;
3083 ogcd[k].gd.label = &olabels[k];
3084 ogcd[k].gd.pos.x = 10; ogcd[k].gd.pos.y = ogcd[k-1].gd.pos.y+45;
3085 ogcd[k].gd.flags = gg_visible | gg_enabled;
3086 ogcd[k++].creator = GLabelCreate;
3087
3088 if ( mmw.old!=NULL &&
3089 (pt = PSDictHasEntry(mmw.old->normal->private,"ForceBoldThreshold"))!=NULL )
3090 olabels[k].text = (unichar_t *) pt;
3091 else
3092 olabels[k].text = (unichar_t *) ".3";
3093 olabels[k].text_is_1byte = true;
3094 ogcd[k].gd.label = &olabels[k];
3095 ogcd[k].gd.pos.x = 15; ogcd[k].gd.pos.y = ogcd[k-1].gd.pos.y+13;
3096 ogcd[k].gd.flags = gg_visible | gg_enabled;
3097 ogcd[k].gd.cid = CID_ForceBoldThreshold;
3098 ogcd[k++].creator = GTextFieldCreate;
3099
3100 GGadgetsCreate(mmw.subwins[mmw_others],ogcd);
3101
3102 mmw.state = mmw_counts;
3103 MMW_SetState(&mmw);
3104 GDrawSetVisible(mmw.subwins[mmw.state],true);
3105 GDrawSetVisible(mmw.gw,true);
3106
3107 while ( !mmw.done )
3108 GDrawProcessOneEvent(NULL);
3109
3110 GDrawDestroyWindow(gw);
3111 }
3112