1 /* Copyright (C) 2001-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "cvundoes.h"
31 #include "fontforgeui.h"
32 #include "gkeysym.h"
33 #include "splineutil.h"
34 #include "ttf.h"
35 #include "ttfinstrs.h"
36 #include "ustring.h"
37 #include "utype.h"
38 
39 extern GBox _ggadget_Default_Box;
40 #define ACTIVE_BORDER   (_ggadget_Default_Box.active_border)
41 #define MAIN_FOREGROUND (_ggadget_Default_Box.main_foreground)
42 
43 extern int _GScrollBar_Width;
44 #define EDGE_SPACING	2
45 
46 #define ttf_width 16
47 #define ttf_height 16
48 static unsigned char ttf_bits[] = {
49    0xff, 0x07, 0x21, 0x04, 0x20, 0x00, 0xfc, 0x7f, 0x24, 0x40, 0xf4, 0x5e,
50    0xbc, 0x72, 0xa0, 0x02, 0xa0, 0x02, 0xa0, 0x02, 0xf0, 0x02, 0x80, 0x02,
51    0xc0, 0x06, 0x40, 0x04, 0xc0, 0x07, 0x00, 0x00};
52 GWindow ttf_icon = NULL;
53 
54 static char *instrhelppopup[256];
55 
ihaddr(int bottom,int top,char * msg)56 static void ihaddr(int bottom,int top,char *msg) {
57     while ( bottom<=top )
58         instrhelppopup[bottom++] = msg;
59 }
60 
ihadd(int p,char * msg)61 static void ihadd(int p,char *msg) {
62     ihaddr(p,p,msg);
63 }
64 
instrhelpsetup(void)65 static void instrhelpsetup(void) {
66     if ( instrhelppopup[0]!=NULL )
67 return;
68     ihadd(0x7f,N_("Adjust Angle\nObsolete instruction\nPops one value"));
69     ihadd(0x64,N_("ABSolute Value\nReplaces top of stack with its abs"));
70     ihadd(0x60,N_("ADD\nPops two 26.6 fixed numbers from stack\nadds them, pushes result"));
71     ihadd(0x27,N_("ALIGN PoinTS\nAligns (&pops) the two points which are on the stack\nby moving along freedom vector to the average of their\npositions on projection vector"));
72     ihadd(0x3c,N_("ALIGN to Reference Point\nPops as many points as specified in loop counter\nAligns points with RP0 by moving each\nalong freedom vector until distance to\nRP0 on projection vector is 0"));
73     ihadd(0x5a,N_("logical AND\nPops two values, ands them, pushes result"));
74     ihadd(0x2b,N_("CALL function\nPops a value, calls the function represented by it"));
75     ihadd(0x67,N_("CEILING\nPops one 26.6 value, rounds upward to an int\npushes result"));
76     ihadd(0x25,N_("Copy INDEXed element to stack\nPops an index & copies stack\nelement[index] to top of stack"));
77     ihadd(0x22,N_("CLEAR\nPops all elements on stack"));
78     ihadd(0x4f,N_("DEBUG call\nPops a value and executes a debugging interpreter\n(if available)"));
79     ihadd(0x73,N_("DELTA exception C1\nPops a value n & then n exception specifications & cvt entries\nchanges each cvt entry at a given size by the pixel amount"));
80     ihadd(0x74,N_("DELTA exception C2\nPops a value n & then n exception specifications & cvt entries\nchanges each cvt entry at a given size by the amount"));
81     ihadd(0x75,N_("DELTA exception C3\nPops a value n & then n exception specifications & cvt entries\nchanges each cvt entry at a given size by the amount"));
82     ihadd(0x5D,N_("DELTA exception P1\nPops a value n & then n exception specifications & points\nmoves each point at a given size by the amount"));
83     ihadd(0x71,N_("DELTA exception P2\nPops a value n & then n exception specifications & points\nmoves each point at a given size by the amount"));
84     ihadd(0x72,N_("DELTA exception P3\nPops a value n & then n exception specifications & points\nmoves each point at a given size by the amount"));
85     ihadd(0x24,N_("DEPTH of stack\nPushes the number of elements on the stack"));
86     ihadd(0x62,N_("DIVide\nPops two 26.6 numbers, divides them, pushes result"));
87     ihadd(0x20,N_("DUPlicate top stack element\nPushes the top stack element again"));
88     ihadd(0x59,N_("End IF\nEnds an IF or IF-ELSE sequence"));
89     ihadd(0x1b,N_("ELSE clause\nStart of Else clause of preceding IF"));
90     ihadd(0x2d,N_("END Function definition"));
91     ihadd(0x54,N_("EQual\nPops two values, tests for equality, pushes result(0/1)"));
92     ihadd(0x57,N_("EVEN\nPops one value, rounds it and tests if it is even(0/1)"));
93     ihadd(0x2C,N_("Function DEFinition\nPops a value (n) and starts the nth\nfunction definition"));
94     ihadd(0x4e,N_("set the auto FLIP boolean to OFF"));
95     ihadd(0x4d,N_("set the auto FLIP boolean to ON"));
96     ihadd(0x80,N_("FLIP PoinT\nPops as many points as specified in loop counter\nFlips whether each point is on/off curve"));
97     ihadd(0x82,N_("FLIP RanGe OFF\nPops two point numbers\nsets all points between to be off curve points"));
98     ihadd(0x81,N_("FLIP RanGe ON\nPops two point numbers\nsets all points between to be on curve points"));
99     ihadd(0x66,N_("FLOOR\nPops a value, rounds to lowest int, pushes result"));
100     ihaddr(0x46,0x47,N_("Get Coordinate[a] projected onto projection vector\n 0=>use current pos\n 1=>use original pos\nPops one point, pushes the coordinate of\nthe point along projection vector"));
101     ihadd(0x88,N_("GET INFOrmation\nPops information type, pushes result"));
102     ihadd(0x0d,N_("Get Freedom Vector\nDecomposes freedom vector, pushes its\ntwo coordinates onto stack as 2.14"));
103     ihadd(0x0c,N_("Get Projection Vector\nDecomposes projection vector, pushes its\ntwo coordinates onto stack as 2.14"));
104     ihadd(0x52,N_("Greater Than\nPops two values, pushes (0/1) if bottom el > top"));
105     ihadd(0x53,N_("Greater Than or EQual\nPops two values, pushes (0/1) if bottom el >= top"));
106     ihadd(0x89,N_("Instruction DEFinition\nPops a value which becomes the opcode\nand begins definition of new instruction"));
107     ihadd(0x58,N_("IF test\nPops an integer,\nif 0 (false) next instruction is ELSE or EIF\nif non-0 execution continues normally\n(unless there's an ELSE)"));
108     ihadd(0x8e,N_("INSTRuction execution ConTRoL\nPops a selector and value\nSets a state variable"));
109     ihadd(0x39,N_("Interpolate Point\nPops as many points as specified in loop counter\nInterpolates each point to preserve original status\nwith respect to RP1 and RP2"));
110     ihadd(0x0f,N_("moves point to InterSECTion of two lines\nPops start,end start,end points of two lines\nand a point to move. Point is moved to\nintersection"));
111     ihaddr(0x30,0x31,N_("Interpolate Untouched Points[a]\n 0=> interpolate in y direction\n 1=> x direction"));
112     ihadd(0x1c,N_("JuMP Relative\nPops offset (in bytes) to move the instruction pointer"));
113     ihadd(0x79,N_("Jump Relative On False\nPops a boolean and an offset\nChanges instruction pointer by offset bytes\nif boolean is false"));
114     ihadd(0x78,N_("Jump Relative On True\nPops a boolean and an offset\nChanges instruction pointer by offset bytes\nif boolean is true"));
115     ihadd(0x2a,N_("LOOP and CALL function\nPops a function number & count\nCalls function count times"));
116     ihadd(0x50,N_("Less Than\nPops two values, pushes (0/1) if bottom el < top"));
117     ihadd(0x51,N_("Less Than or EQual\nPops two values, pushes (0/1) if bottom el <= top"));
118     ihadd(0x8b,N_("MAXimum of top two stack entries\nPops two values, pushes the maximum back"));
119     ihaddr(0x49,0x4a,N_("Measure Distance[a]\n 0=>distance with current positions\n 1=>distance with original positions\nPops two point numbers, pushes distance between them"));
120     ihaddr(0x2e,0x2f,N_("Move Direct Absolute Point[a]\n 0=>do not round\n 1=>round\nPops a point number, touches that point\nand perhaps rounds it to the grid along\nthe projection vector. Sets rp0&rp1 to the point"));
121     ihaddr(0xc0,0xdf,N_("Move Direct Relative Point[abcde]\n a=0=>don't set rp0\n a=1=>set rp0 to p\n b=0=>do not keep distance more than minimum\n b=1=>keep distance at least minimum\n c=0 do not round\n c=1 round\n de=0 => grey distance\n de=1 => black distance\n de=2 => white distance\nPops a point moves it so that it maintains\nits original distance to the rp0. Sets\nrp1 to rp0, rp2 to point, sometimes rp0 to point"));
122     ihaddr(0x3e,0x3f,N_("Move Indirect Absolute Point[a]\n 0=>do not round, don't use cvt cutin\n 1=>round\nPops a point number & a cvt entry,\ntouches the point and moves it to the coord\nspecified in the cvt (along the projection vector).\nSets rp0&rp1 to the point"));
123     ihadd(0x8c,N_("Minimum of top two stack entries\nPops two values, pushes the minimum back"));
124     ihadd(0x26,N_("Move INDEXed element to stack\nPops an index & moves stack\nelement[index] to top of stack\n(removing it from where it was)"));
125     ihaddr(0xe0,0xff,N_("Move Indirect Relative Point[abcde]\n a=0=>don't set rp0\n a=1=>set rp0 to p\n b=0=>do not keep distance more than minimum\n b=1=>keep distance at least minimum\n c=0 do not round nor use cvt cutin\n c=1 round & use cvt cutin\n de=0 => grey distance\n de=1 => black distance\n de=2 => white distance\nPops a cvt index and a point moves it so that it\nis cvt[index] from rp0. Sets\nrp1 to rp0, rp2 to point, sometimes rp0 to point"));
126     ihadd(0x4b,N_("Measure Pixels Per EM\nPushs the pixels per em (for current rasterization)"));
127     ihadd(0x4c,N_("Measure Point Size\nPushes the current point size"));
128     ihaddr(0x3a,0x3b,N_("Move Stack Indirect Relative Point[a]\n 0=>do not set rp0\n 1=>set rp0 to point\nPops a 26.6 distance and a point\nMoves point so it is distance from rp0"));
129     ihadd(0x63,N_("MULtiply\nPops two 26.6 numbers, multiplies them, pushes result"));
130     ihadd(0x65,N_("NEGate\nNegates the top of the stack"));
131     ihadd(0x55,N_("Not EQual\nPops two values, tests for inequality, pushes result(0/1)"));
132     ihadd(0x5c,N_("logical NOT\nPops a number, if 0 pushes 1, else pushes 0"));
133     ihadd(0x40,N_("N PUSH Bytes\nReads an (unsigned) count byte from the\ninstruction stream, then reads and pushes\nthat many unsigned bytes"));
134     ihadd(0x41,N_("N PUSH Words\nReads an (unsigned) count byte from the\ninstruction stream, then reads and pushes\nthat many signed 2byte words"));
135     ihaddr(0x6c,0x6f,N_("No ROUNDing of value[ab]\n ab=0 => grey distance\n ab=1 => black distance\n ab=2 => white distance\nPops a coordinate (26.6), changes it (without\nrounding) to compensate for engine effects\npushes it back"));
136     ihadd(0x56,N_("ODD\nPops one value, rounds it and tests if it is odd(0/1)"));
137     ihadd(0x5b,N_("logical OR\nPops two values, ors them, pushes result"));
138     ihadd(0x21,N_("POP top stack element"));
139     ihaddr(0xb0,0xb7,N_("PUSH Byte[abc]\n abc is the number-1 of bytes to push\nReads abc+1 unsigned bytes from\nthe instruction stream and pushes them"));
140     ihaddr(0xb8,0xbf,N_("PUSH Word[abc]\n abc is the number-1 of words to push\nReads abc+1 signed words from\nthe instruction stream and pushes them"));
141     ihadd(0x45,N_("Read Control Value Table entry\nPops an index to the CVT and\npushes it in 26.6 format"));
142     ihadd(0x7d,N_("Round Down To Grid\n\nSets round state to the obvious"));
143     ihadd(0x7a,N_("Round OFF\nSets round state so that no rounding occurs\nbut engine compensation does"));
144     ihadd(0x8a,N_("ROLL the top three stack elements"));
145     ihaddr(0x68,0x6b,N_("ROUND value[ab]\n ab=0 => grey distance\n ab=1 => black distance\n ab=2 => white distance\nRounds a coordinate (26.6) at top of stack\nand compensates for engine effects"));
146     ihadd(0x43,N_("Read Store\nPops an index into store array\nPushes value at that index"));
147     ihadd(0x3d,N_("Round To Double Grid\nSets the round state (round to closest .5/int)"));
148     ihadd(0x18,N_("Round To Grid\nSets the round state"));
149     ihadd(0x19,N_("Round To Half Grid\nSets the round state (round to closest .5 not int)"));
150     ihadd(0x7c,N_("Round Up To Grid\nSets the round state"));
151     ihadd(0x77,N_("Super 45\302\260 ROUND\nToo complicated. Look it up"));
152     ihadd(0x7e,N_("Set ANGle Weight\nPops an int, and sets the angle\nweight state variable to it\nObsolete"));
153     ihadd(0x85,N_("SCAN conversion ConTRoL\nPops a number which sets the\ndropout control mode"));
154     ihadd(0x8d,N_("SCANTYPE\nPops number which sets which scan\nconversion rules to use"));
155     ihadd(0x48,N_("Sets Coordinate From Stack using projection & freedom vectors\nPops a coordinate 26.6 and a point\nMoves point to given coordinate"));
156     ihadd(0x1d,N_("Sets Control Value Table Cut-In\nPops 26.6 from stack, sets cvt cutin"));
157     ihadd(0x5e,N_("Set Delta Base\nPops value sets delta base"));
158     ihaddr(0x86,0x87,N_("Set Dual Projection Vector To Line[a]\n 0 => parallel to line\n 1=>orthogonal to line\nPops two points used to establish the line\nSets a second projection vector based on original\npositions of points"));
159     ihadd(0x5F,N_("Set Delta Shift\nPops a new value for delta shift"));
160     ihadd(0x0b,N_("Set Freedom Vector From Stack\npops 2 2.14 values (x,y) from stack\nmust be a unit vector"));
161     ihaddr(0x04,0x05,N_("Set Freedom Vector To Coordinate Axis[a]\n 0=>y axis\n 1=>x axis\n"));
162     ihaddr(0x08,0x09,N_("Set Freedom Vector To Line[a]\n 0 => parallel to line\n 1=>orthogonal to line\nPops two points used to establish the line\nSets the freedom vector"));
163     ihadd(0x0e,N_("Set Freedom Vector To Projection Vector"));
164     ihaddr(0x34,0x35,N_("SHift Contour using reference point[a]\n 0=>uses rp2 in zp1\n 1=>uses rp1 in zp0\nPops number of contour to be shifted\nShifts the entire contour by the amount\nreference point was shifted"));
165     ihaddr(0x32,0x33,N_("SHift Point using reference point[a]\n 0=>uses rp2 in zp1\n 1=>uses rp1 in zp0\nPops as many points as specified by the loop count\nShifts each by the amount the reference\npoint was shifted"));
166     ihadd(0x38,N_("SHift point by a PIXel amount\nPops an amount (26.6) and as many points\nas the loop counter specifies\neach point is shifted along the FREEDOM vector"));
167     ihaddr(0x36,0x37,N_("SHift Zone using reference point[a]\n 0=>uses rp2 in zp1\n 1=>uses rp1 in zp0\nPops the zone to be shifted\nShifts all points in zone by the amount\nthe reference point was shifted"));
168     ihadd(0x17,N_("Set LOOP variable\nPops the new value for the loop counter\nDefaults to 1 after each use"));
169     ihadd(0x1a,N_("Set Minimum Distance\nPops a 26.6 value from stack to be new minimum distance"));
170     ihadd(0x0a,N_("Set Projection Vector From Stack\npops 2 2.14 values (x,y) from stack\nmust be a unit vector"));
171     ihaddr(0x02,0x03,N_("Set Projection Vector To Coordinate Axis[a]\n 0=>y axis\n 1=>x axis\n" ));
172     ihaddr(0x06,0x07,N_("Set Projection Vector To Line[a]\n 0 => parallel to line\n 1=>orthogonal to line\nPops two points used to establish the line\nSets the projection vector" ));
173     ihadd(0x76,N_("Super ROUND\nToo complicated. Look it up"));
174     ihadd(0x10,N_("Set Reference Point 0\nPops a point which becomes the new rp0"));
175     ihadd(0x11,N_("Set Reference Point 1\nPops a point which becomes the new rp1"));
176     ihadd(0x12,N_("Set Reference Point 2\nPops a point which becomes the new rp2"));
177     ihadd(0x1f,N_("Set Single Width\nPops value for single width value (FUnit)"));
178     ihadd(0x1e,N_("Set Single Width Cut-In\nPops value for single width cut-in value (26.6)"));
179     ihadd(0x61,N_("SUBtract\nPops two 26.6 fixed numbers from stack\nsubtracts them, pushes result"));
180     ihaddr(0x00,0x01,N_("Set freedom & projection Vectors To Coordinate Axis[a]\n 0=>both to y axis\n 1=>both to x axis\n" ));
181     ihadd(0x23,N_("SWAP top two elements on stack"));
182     ihadd(0x13,N_("Set Zone Pointer 0\nPops the zone number into zp0"));
183     ihadd(0x14,N_("Set Zone Pointer 1\nPops the zone number into zp1"));
184     ihadd(0x15,N_("Set Zone Pointer 2\nPops the zone number into zp2"));
185     ihadd(0x16,N_("Set Zone PointerS\nPops the zone number into zp0,zp1 and zp2"));
186     ihadd(0x29,N_("UnTouch Point\nPops a point number and marks it untouched"));
187     ihadd(0x70,N_("Write Control Value Table in Funits\nPops a number(Funits) and a\nCVT index and writes the number to cvt[index]"));
188     ihadd(0x44,N_("Write Control Value Table in Pixel units\nPops a number(26.6) and a\nCVT index and writes the number to cvt[index]"));
189     ihadd(0x42,N_("Write Store\nPops a value and an index and writes the value to storage[index]"));
190 }
191 
192 typedef struct instrdlg /* : InstrBase */{
193     unsigned int inedit: 1;
194     struct instrdata *instrdata;
195     struct instrinfo instrinfo;
196     int oc_height;
197     GWindow gw, v;
198     GGadget *ok, *cancel, *edit, *parse, *text, *topbox;
199 } InstrDlg;
200 
instr_info_init(struct instrinfo * instrinfo)201 static void instr_info_init(struct instrinfo *instrinfo) {
202 
203     instrinfo->lheight = instr_typify(instrinfo->instrdata);
204     if ( instrinfo->fh!=0 ) {
205 	if ( instrinfo->lpos > instrinfo->lheight-instrinfo->vheight/instrinfo->fh )
206 	    instrinfo->lpos = instrinfo->lheight-instrinfo->vheight/instrinfo->fh;
207 	if ( instrinfo->lpos<0 )
208 	    instrinfo->lpos = 0;
209     }
210 }
211 
instr_resize(InstrDlg * iv,GEvent * event)212 static void instr_resize(InstrDlg *iv,GEvent *event) {
213     GRect size;
214     int lh;
215     struct instrinfo *ii = &iv->instrinfo;
216 
217     GGadgetGetSize(iv->text,&size);
218     GDrawMove(ii->v,size.x,size.y);
219     GDrawResize(ii->v,size.width,size.height);
220     ii->vheight = size.height; ii->vwidth = size.width;
221     lh = ii->lheight;
222 
223     GScrollBarSetBounds(ii->vsb,0,lh+2,ii->vheight<ii->fh ? 1 : ii->vheight/ii->fh);
224     if ( ii->lpos + ii->vheight/ii->fh > lh )
225 	ii->lpos = lh-ii->vheight/ii->fh;
226     if ( ii->lpos<0 ) ii->lpos = 0;
227     GScrollBarSetPos(ii->vsb,ii->lpos);
228     GDrawRequestExpose(iv->gw,NULL,false);
229 }
230 
IVError(void * _iv,char * msg,int offset)231 static void IVError(void *_iv,char *msg,int offset) {
232     InstrDlg *iv = _iv;
233 
234     if ( iv!=NULL ) {
235 	GTextFieldSelect(iv->text,offset,offset);
236 	GTextFieldShow(iv->text,offset);
237 	GWidgetIndicateFocusGadget(iv->text);
238     }
239     ff_post_error(_("Parse Error"),msg);
240 }
241 
IVParse(InstrDlg * iv)242 static int IVParse(InstrDlg *iv) {
243     char *text = GGadgetGetTitle8(iv->text);
244     int icnt=0, i;
245     uint8 *instrs;
246 
247     instrs = _IVParse(iv->instrdata->sf, text, &icnt, IVError, iv);
248     free(text);
249 
250     if ( instrs==NULL )
251 return( false );
252     if ( icnt!=iv->instrdata->instr_cnt )
253 	iv->instrdata->changed = true;
254     else {
255 	for ( i=0; i<icnt; ++i )
256 	    if ( instrs[i]!=iv->instrdata->instrs[i])
257 	break;
258 	if ( i==icnt ) {		/* Unchanged */
259 	    free(instrs);
260 return( true );
261 	}
262     }
263     free( iv->instrdata->instrs );
264     iv->instrdata->instrs = instrs;
265     iv->instrdata->instr_cnt = icnt;
266     iv->instrdata->max = icnt;
267     iv->instrdata->changed = true;
268     free(iv->instrdata->bts );
269     iv->instrdata->bts = NULL;
270     instr_info_init(&iv->instrinfo);
271     GScrollBarSetBounds(iv->instrinfo.vsb,0,iv->instrinfo.lheight+2,
272 	    iv->instrinfo.vheight<iv->instrinfo.fh? 1 : iv->instrinfo.vheight/iv->instrinfo.fh);
273 return( true );
274 }
275 
IVOk(InstrDlg * iv)276 static void IVOk(InstrDlg *iv) {
277     struct instrdata *id = iv->instrdata;
278 
279     /* We need to update bits like instructions_out_of_date even if they */
280     /* make no change. */
281     if ( /*id->changed*/true ) {
282 	if ( id->sc!=NULL ) {
283 	    SplineChar *sc = id->sc;
284 	    CharView *cv;
285 	    free(sc->ttf_instrs);
286 	    sc->ttf_instrs_len = id->instr_cnt;
287 	    if ( id->instr_cnt==0 )
288 		sc->ttf_instrs = NULL;
289 	    else {
290 		sc->ttf_instrs = malloc( id->instr_cnt );
291 		memcpy(sc->ttf_instrs,id->instrs,id->instr_cnt );
292 	    }
293 	    for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
294 		cv->showpointnumbers = false;
295 	    sc->instructions_out_of_date = true;
296 	    SCCharChangedUpdate(sc,ly_none);
297 	    sc->instructions_out_of_date = false;
298 	    FVRefreshAll(sc->parent);
299 	} else {
300 	    struct ttf_table *tab, *prev;
301 	    if ( id->instr_cnt==0 ) {
302 		for ( prev=NULL, tab=id->sf->ttf_tables; tab!=NULL && tab->tag!=id->tag; prev=tab, tab=tab->next );
303 		if ( tab==NULL )
304 		    /* Nothing to be done */;
305 		else if ( prev==NULL )
306 		    id->sf->ttf_tables = tab->next;
307 		else
308 		    prev->next = tab->next;
309 		if ( tab!=NULL ) {
310 		    tab->next = NULL;
311 		    TtfTablesFree(tab);
312 		}
313 	    } else {
314 		tab = SFFindTable(id->sf,id->tag);
315 		if ( tab==NULL ) {
316 		    tab = chunkalloc(sizeof(struct ttf_table));
317 		    tab->next = id->sf->ttf_tables;
318 		    id->sf->ttf_tables = tab;
319 		    tab->tag = id->tag;
320 		}
321 		free( tab->data );
322 		tab->data = malloc( id->instr_cnt );
323 		memcpy(tab->data,id->instrs,id->instr_cnt );
324 		tab->len = id->instr_cnt;
325 	    }
326 	}
327     }
328     /* Instructions get freed in et_destroy */
329 }
330 
IVBuildEdit(InstrDlg * iv)331 static void IVBuildEdit(InstrDlg *iv) {
332     char *ret;
333     ret = __IVUnParseInstrs((InstrBase *) iv);
334     if ( iv->text!=NULL ) {
335 	GGadgetSetTitle8(iv->text,ret);
336 	GTextFieldSelect(iv->text,iv->instrinfo.offset-ret,iv->instrinfo.offset-ret);
337 	GTextFieldShow(iv->text,iv->instrinfo.scroll-ret);
338     }
339 }
340 
instr_expose(struct instrinfo * ii,GWindow pixmap,GRect * rect)341 static void instr_expose(struct instrinfo *ii,GWindow pixmap,GRect *rect) {
342     int low, high;
343     int i,x,y;
344     char loc[8], ins[8], val[8]; unichar_t uins[8], uname[30];
345     int addr_end, num_end;
346     static unichar_t nums[] = { '0', '0', '0', '0', '0', '0', '\0' };
347     int indent;
348     extern GBox _ggadget_Default_Box;
349 
350     GDrawSetFont(pixmap,ii->gfont);
351     GDrawSetLineWidth(pixmap,0);
352     addr_end = 0;
353     if ( ii->showaddr )
354 	addr_end = GDrawGetTextWidth(pixmap,nums,4)+EDGE_SPACING;
355     num_end = addr_end;
356     if ( ii->showhex )
357 	num_end = addr_end + GDrawGetTextWidth(pixmap,nums,5)+4;
358     else if ( addr_end<36+2*EDGE_SPACING )
359 	num_end = addr_end = 36+2*EDGE_SPACING;
360 
361     low = ( (rect->y-EDGE_SPACING)/ii->fh ) * ii->fh +EDGE_SPACING;
362     high = ( (rect->y+rect->height+ii->fh-1-EDGE_SPACING)/ii->fh ) * ii->fh +EDGE_SPACING;
363 
364     if ( ii->isel_pos!=-1 ) {
365 	GRect r;
366 	r.x = 0; r.width = ii->vwidth;
367 	r.y = (ii->isel_pos-ii->lpos)*ii->fh+EDGE_SPACING; r.height = ii->fh;
368 	GDrawFillRect(pixmap,&r,ACTIVE_BORDER);
369     }
370 
371     if ( ii->showaddr )
372 	GDrawDrawLine(pixmap,addr_end,rect->y,addr_end,rect->y+rect->height,0x000000);
373     if ( ii->showhex )
374 	GDrawDrawLine(pixmap,num_end,rect->y,num_end,rect->y+rect->height,0x000000);
375 
376     indent = 0;
377     for ( i=0, y=EDGE_SPACING-ii->lpos*ii->fh; y<low && i<ii->instrdata->instr_cnt; ++i ) {
378 	if ( ii->instrdata->bts[i]==bt_instr ) {
379 	    int instr = ii->instrdata->instrs[i];
380 	    if ( instr == ttf_if || instr==ttf_idef || instr == ttf_fdef )
381 		++indent;
382 	    else if ( instr == ttf_eif || instr==ttf_endf )
383 		--indent;
384 	} else if ( ii->instrdata->bts[i]==bt_wordhi )
385 	    ++i;
386 	y += ii->fh;
387     }
388     if ( y<=high && ii->instrdata->instr_cnt==0 && i==0 ) {
389 	if ( ii->instrdata->in_composit ) {
390 	    GDrawDrawText8(pixmap,num_end+EDGE_SPACING,y+ii->as,_("<instrs inherited>"),-1,0xff0000);
391 	    y += ii->fh;
392 	}
393 	GDrawDrawText8(pixmap,num_end+EDGE_SPACING,y+ii->as,_("<no instrs>"),-1,0xff0000);
394     } else {
395 	int temp_indent;
396 	for ( ; y<=high && i<ii->instrdata->instr_cnt+1; ++i ) {
397 	    temp_indent = indent;
398 	    sprintf( loc, "%d", i );
399 	    if ( ii->instrdata->bts[i]==bt_wordhi ) {
400 		sprintf( ins, " %02x%02x", ii->instrdata->instrs[i], ii->instrdata->instrs[i+1]); uc_strcpy(uins,ins);
401 		sprintf( val, " %d", (short) ((ii->instrdata->instrs[i]<<8) | ii->instrdata->instrs[i+1]) );
402 		uc_strcpy(uname,val);
403 		++i;
404 	    } else if ( ii->instrdata->bts[i]==bt_cnt || ii->instrdata->bts[i]==bt_byte ) {
405 		sprintf( ins, " %02x", ii->instrdata->instrs[i] ); uc_strcpy(uins,ins);
406 		sprintf( val, " %d", ii->instrdata->instrs[i]);
407 		uc_strcpy(uname,val);
408 	    } else if ( ii->instrdata->bts[i]==bt_impliedreturn ) {
409 		uc_strcpy(uname,_("<return>"));
410 		uins[0] = '\0';
411 	    } else {
412 		int instr = ii->instrdata->instrs[i];
413 		if ( instr == ttf_eif || instr==ttf_endf )
414 		    --indent;
415 		temp_indent = indent;
416 		if ( instr == ttf_else )
417 		    --temp_indent;
418 		sprintf( ins, "%02x", instr ); uc_strcpy(uins,ins);
419 		uc_strcpy(uname, ff_ttf_instrnames[instr]);
420 		if ( instr == ttf_if || instr==ttf_idef || instr == ttf_fdef )
421 		    ++indent;
422 	    }
423 
424 	    if ( ii->showaddr ) {
425 		GRect size;
426 		GDrawLayoutInit(pixmap,loc,-1,NULL);
427 		GDrawLayoutExtents(pixmap,&size);
428 		x = addr_end - EDGE_SPACING - size.width;
429 		GDrawLayoutDraw(pixmap,x,y+ii->as,MAIN_FOREGROUND);
430 		if ( ii->bpcheck && ii->bpcheck(ii,i))
431 		    GDrawDrawImage(pixmap,&GIcon_Stop,NULL,EDGE_SPACING,
432 			    y+(ii->fh-8)/2-5);
433 	    }
434 	    x = addr_end + EDGE_SPACING;
435 	    if ( ii->showhex )
436 		GDrawDrawText(pixmap,x,y+ii->as,uins,-1,MAIN_FOREGROUND);
437 	    GDrawDrawText(pixmap,num_end+EDGE_SPACING+temp_indent*4,y+ii->as,uname,-1,MAIN_FOREGROUND);
438 	    y += ii->fh;
439 	}
440 	if ( ii->showaddr && ii->lstopped!=-1 ) {
441 	    GDrawDrawImage(pixmap,&GIcon_Stopped,NULL,EDGE_SPACING,
442 		    (ii->lstopped-ii->lpos)*ii->fh+(ii->fh-8)/2);
443 	}
444     }
445 }
446 
instr_mousedown(struct instrinfo * ii,int pos)447 static void instr_mousedown(struct instrinfo *ii,int pos) {
448     int i,l;
449 
450     pos = (pos-2)/ii->fh + ii->lpos;
451     if ( pos>=ii->lheight )
452 	pos = -1;
453 
454     for ( i=l=0; l<pos && i<ii->instrdata->instr_cnt; ++i, ++l ) {
455 	if ( ii->instrdata->bts[i]==bt_wordhi )
456 	    ++i;
457     }
458 
459     ii->isel_pos=pos;
460     if ( ii->selection_callback!=NULL )
461 	(ii->selection_callback)(ii,i);
462     GDrawRequestExpose(ii->v,NULL,false);
463 }
464 
instr_mousemove(struct instrinfo * ii,int pos)465 static void instr_mousemove(struct instrinfo *ii,int pos) {
466     int i,y;
467     char *msg;
468 
469     if ( ii->mousedown ) {
470 	instr_mousedown(ii,pos);
471 return;
472     }
473     if ( ii->instrdata->bts==NULL )
474 return;
475 
476     pos = ((pos-2)/ii->fh) * ii->fh + 2;
477 
478     for ( i=0, y=2-ii->lpos*ii->fh; y<pos && i<ii->instrdata->instr_cnt; ++i ) {
479 	if ( ii->instrdata->bts[i]==bt_wordhi )
480 	    ++i;
481 	y += ii->fh;
482     }
483     switch ( ii->instrdata->bts[i] ) {
484       case bt_wordhi: case bt_wordlo:
485 	msg = _("A short to be pushed on the stack");
486       break;
487       case bt_cnt:
488 	msg = _("A count specifying how many bytes/shorts\nshould be pushed on the stack");
489       break;
490       case bt_byte:
491 	msg = _("An unsigned byte to be pushed on the stack");
492       break;
493       case bt_instr:
494 	msg = _(instrhelppopup[ii->instrdata->instrs[i]]);
495 	if ( msg==NULL ) msg = "???";
496       break;
497       default:
498 	msg = "???";
499       break;
500     }
501     GGadgetPreparePopup8(GDrawGetParentWindow(ii->v),msg);
502 }
503 
instr_scroll(struct instrinfo * ii,struct sbevent * sb)504 void instr_scroll(struct instrinfo *ii,struct sbevent *sb) {
505     int newpos = ii->lpos;
506 
507     switch( sb->type ) {
508       case et_sb_top:
509         newpos = 0;
510       break;
511       case et_sb_uppage:
512         newpos -= ii->vheight/ii->fh;
513       break;
514       case et_sb_up:
515         --newpos;
516       break;
517       case et_sb_down:
518         ++newpos;
519       break;
520       case et_sb_downpage:
521         newpos += ii->vheight/ii->fh;
522       break;
523       case et_sb_bottom:
524         newpos = ii->lheight-ii->vheight/ii->fh;
525       break;
526       case et_sb_thumb:
527       case et_sb_thumbrelease:
528         newpos = sb->pos;
529       break;
530     }
531     if ( newpos>ii->lheight+1-ii->vheight/ii->fh )
532         newpos = ii->lheight+1-ii->vheight/ii->fh;
533     if ( newpos<0 ) newpos =0;
534     if ( newpos!=ii->lpos ) {
535 	GRect r;
536 	int diff = newpos-ii->lpos;
537 	ii->lpos = newpos;
538 	GScrollBarSetPos(ii->vsb,ii->lpos);
539 	r.x=0; r.y = EDGE_SPACING; r.width=ii->vwidth; r.height=ii->vheight-2*EDGE_SPACING;
540 	GDrawScroll(ii->v,&r,0,diff*ii->fh);
541     }
542 }
543 
IIChar(struct instrinfo * ii,GEvent * event)544 static int IIChar(struct instrinfo *ii,GEvent *event) {
545     int pos = ii->isel_pos;
546 
547     if ( ii->handle_char )
548 return( (ii->handle_char)(ii,event));
549 
550     if ( event->u.chr.keysym == GK_Up || event->u.chr.keysym == GK_KP_Up )
551 	--pos;
552     else if ( event->u.chr.keysym == GK_Down || event->u.chr.keysym == GK_KP_Down )
553 	++pos;
554     else if ( event->u.chr.keysym == GK_Home || event->u.chr.keysym == GK_KP_Home ||
555 	    event->u.chr.keysym == GK_Begin || event->u.chr.keysym == GK_KP_Begin )
556 	pos = 0;
557     else if ( event->u.chr.keysym == GK_End || event->u.chr.keysym == GK_KP_End ) {
558 	pos = ii->lheight-1;
559     } else
560 return( false );
561     if ( pos==-2 ) pos = -1;
562     if ( pos!=ii->isel_pos ) {
563 	ii->isel_pos = pos;
564 	if ( pos!=-1 && (pos<ii->lpos || pos>=ii->lpos+ii->vheight/ii->fh )) {
565 	    ii->lpos = pos-(ii->vheight/(3*ii->fh));
566 	    if ( ii->lpos>=ii->lheight-ii->vheight/ii->fh )
567 		ii->lpos = ii->lheight-ii->vheight/ii->fh-1;
568 	    if ( ii->lpos<0 ) ii->lpos = 0;
569 	    GScrollBarSetPos(ii->vsb,ii->lpos);
570 	}
571     }
572     if ( ii->selection_callback!=NULL ) {
573 	int i,l;
574 	for ( i=l=0; l<pos && i<ii->instrdata->instr_cnt; ++i, ++l ) {
575 	    if ( ii->instrdata->bts[i]==bt_wordhi )
576 		++i;
577 	}
578 	(ii->selection_callback)(ii,i);
579     }
580     GDrawRequestExpose(ii->v,NULL,false);
581 return( true );
582 }
583 
ii_v_e_h(GWindow gw,GEvent * event)584 int ii_v_e_h(GWindow gw, GEvent *event) {
585     struct instrinfo *ii = (struct instrinfo *) GDrawGetUserData(gw);
586 
587     switch ( event->type ) {
588       case et_expose:
589 	instr_expose(ii,gw,&event->u.expose.rect);
590       break;
591       case et_char:
592 	if ( IIChar(ii,event)) {
593 	    /* All Done */
594 	    ;
595 	} else if ( event->u.chr.keysym == GK_Help || event->u.chr.keysym == GK_F1 ) {
596 	    help("ui/dialogs/ttfinstrs.html", NULL);
597 	}
598       break;
599       case et_mousemove: case et_mousedown: case et_mouseup:
600 	GGadgetEndPopup();
601 	if ( event->type==et_mousemove ) {
602 	    instr_mousemove(ii,event->u.mouse.y);
603 	} else if ( event->type==et_mousedown ) {
604 	    instr_mousedown(ii,event->u.mouse.y);
605 	    if ( event->u.mouse.clicks==2 ) {
606 		/*InstrModCreate(ii)*/
607 		;
608             }
609 	} else {
610 	    instr_mousemove(ii,event->u.mouse.y);
611 	    ii->mousedown = false;
612 	}
613       break;
614       case et_timer:
615       break;
616       case et_focus:
617       break;
618     }
619 return( true );
620 }
621 
iv_e_h(GWindow gw,GEvent * event)622 static int iv_e_h(GWindow gw, GEvent *event) {
623     InstrDlg *iv = (InstrDlg *) GDrawGetUserData(gw);
624 
625     switch ( event->type ) {
626       case et_expose:
627       break;
628       case et_resize:
629 	instr_resize(iv,event);
630       break;
631       case et_char:
632 	if ( event->u.chr.keysym == GK_Help || event->u.chr.keysym == GK_F1 )
633 	    help("ui/dialogs/ttfinstrs.html", NULL);
634       break;
635       case et_controlevent:
636 	switch ( event->u.control.subtype ) {
637 	  case et_scrollbarchange:
638 	    instr_scroll(&iv->instrinfo,&event->u.control.u.sb);
639 	  break;
640 	  case et_buttonactivate:
641 	    if ( event->u.control.g==iv->ok || event->u.control.g==iv->cancel ) {
642 		if ( event->u.control.g == iv->ok ) {
643 		    if ( iv->inedit )
644 			if ( !IVParse(iv))
645       break;
646 		    IVOk(iv);
647 		}
648 		GDrawDestroyWindow(iv->gw);
649 	    } else if ( event->u.control.g==iv->edit || event->u.control.g==iv->parse ) {
650 		int toedit = event->u.control.g==iv->edit;
651 		GRect size;
652 		if ( toedit ) {
653 		    IVBuildEdit(iv);
654 		    GGadgetGetSize(iv->instrinfo.vsb,&size);
655 		    size.width = -1;
656 		    GGadgetSetDesiredSize(iv->text,&size,NULL);
657 		} else if ( !IVParse(iv))
658       break;
659 		GGadgetSetVisible(iv->parse,toedit);
660 		/*GGadgetSetVisible(iv->text,toedit);*/
661 		GGadgetSetVisible(iv->edit,!toedit);
662 		GGadgetSetVisible(iv->instrinfo.vsb,!toedit);
663 		GDrawSetVisible(iv->instrinfo.v,!toedit);
664 		GHVBoxFitWindow(iv->topbox);
665 		iv->inedit = toedit;
666 	    }
667 	  break;
668 	}
669       break;
670       case et_close:
671 	GDrawDestroyWindow(iv->gw);
672       break;
673       case et_destroy: {
674         SplineFont *sf = iv->instrdata->sf;
675 	struct instrdata *id, *prev;
676 	for ( prev = NULL, id=sf->instr_dlgs; id!=iv->instrdata && id!=NULL; prev=id, id=id->next );
677 	if ( prev==NULL )
678 	    sf->instr_dlgs = iv->instrdata->next;
679 	else
680 	    prev->next = iv->instrdata->next;
681 	free(iv->instrdata->instrs);
682 	free(iv->instrdata->bts);
683 	free(iv->instrdata);
684 	free(iv);
685       } break;
686     }
687 return( true );
688 }
689 
InstrDlgCreate(struct instrdata * id,char * title)690 static void InstrDlgCreate(struct instrdata *id,char *title) {
691     InstrDlg *iv = calloc(1,sizeof(*iv));
692     GRect pos;
693     GWindow gw;
694     GWindowAttrs wattrs;
695     FontRequest rq;
696     int as,ds,ld, lh;
697     GGadgetCreateData gcd[11], *butarray[9], *harray[3], *varray[8];
698     GTextInfo label[6];
699     static GFont *font=NULL;
700 
701     instrhelpsetup();
702 
703     id->next = id->sf->instr_dlgs;
704     id->sf->instr_dlgs = id;
705     id->id = iv;
706 
707     iv->instrdata = id;
708     iv->instrinfo.instrdata = id;
709     iv->instrinfo.showhex = iv->instrinfo.showaddr = true;
710     iv->instrinfo.lstopped = -1;
711     instr_info_init(&iv->instrinfo);
712 
713     if ( ttf_icon==NULL )
714 	ttf_icon = GDrawCreateBitmap(NULL,ttf_width,ttf_height,ttf_bits);
715 
716     memset(&wattrs,0,sizeof(wattrs));
717     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_icon;
718     wattrs.event_masks = ~(1<<et_charup);
719     wattrs.restrict_input_to_me = 1;
720     wattrs.undercursor = 1;
721     wattrs.cursor = ct_pointer;
722     wattrs.utf8_window_title = title;
723     wattrs.icon = ttf_icon;
724     pos.x = pos.y = 0;
725     if ( GIntGetResource(_NUM_Buttonsize)>65 )
726 	pos.width = GDrawPointsToPixels(NULL,3*GIntGetResource(_NUM_Buttonsize)+40);
727     else
728 	pos.width = GDrawPointsToPixels(NULL,250);
729     iv->oc_height = GDrawPointsToPixels(NULL,37);
730     pos.height = GDrawPointsToPixels(NULL,100) + iv->oc_height;
731     iv->gw = gw = GDrawCreateTopWindow(NULL,&pos,iv_e_h,iv,&wattrs);
732 
733     memset(&label,0,sizeof(label));
734     memset(&gcd,0,sizeof(gcd));
735     gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 105;
736     gcd[0].gd.pos.width = -1;
737     label[0].text = (unichar_t *) _("_OK");
738     label[0].text_is_1byte = true;
739     label[0].text_in_resource = true;
740     gcd[0].gd.label = &label[0];
741     gcd[0].gd.flags = gg_visible|gg_enabled|gg_but_default;
742     gcd[0].creator = GButtonCreate;
743     gcd[0].data = iv;
744 
745     gcd[1].gd.pos.x = -8; gcd[1].gd.pos.y = 3;
746     gcd[1].gd.pos.width = -1;
747     label[1].text = (unichar_t *) _("_Cancel");
748     label[1].text_is_1byte = true;
749     label[1].text_in_resource = true;
750     gcd[1].gd.label = &label[1];
751     gcd[1].gd.flags = gg_visible|gg_enabled|gg_but_cancel;
752     gcd[1].creator = GButtonCreate;
753     gcd[1].data = iv;
754 
755     gcd[2] = gcd[1];
756     label[2].text = (unichar_t *) _("_Edit");
757     label[2].text_is_1byte = true;
758     label[2].text_in_resource = true;
759     gcd[2].gd.flags = gg_visible|gg_enabled;
760     gcd[2].gd.label = &label[2];
761     gcd[2].creator = GButtonCreate;
762     gcd[2].data = iv;
763 
764     gcd[3] = gcd[1];
765     label[3] = label[2];
766     label[3].text = (unichar_t *) _("_Parse");
767     gcd[3].gd.flags = gg_enabled;
768     gcd[3].gd.label = &label[3];
769     gcd[3].creator = GButtonCreate;
770     gcd[3].data = iv;
771 
772     butarray[0] = GCD_Glue; butarray[1] = &gcd[0];
773     butarray[2] = GCD_Glue; butarray[3] = &gcd[2];
774     butarray[4] = &gcd[3]; butarray[5] = GCD_Glue;
775     butarray[6] = &gcd[1]; butarray[7] = GCD_Glue;
776     butarray[8] = NULL;
777     gcd[4].gd.flags = gg_enabled|gg_visible;
778     gcd[4].gd.u.boxelements = butarray;
779     gcd[4].creator = GHBoxCreate;
780 
781     gcd[5].gd.pos.x = 0; gcd[5].gd.pos.y = 0;
782     gcd[5].gd.pos.width = pos.width; gcd[5].gd.pos.height = pos.height-GDrawPointsToPixels(NULL,40);
783     gcd[5].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_textarea_wrap|gg_pos_use0;
784     gcd[5].creator = GTextAreaCreate;
785     gcd[5].data = iv;
786     harray[0] = &gcd[5];
787 
788     gcd[6].gd.pos.y = 0; gcd[6].gd.pos.height = pos.height-GDrawPointsToPixels(NULL,40);
789     gcd[6].gd.pos.width = GDrawPointsToPixels(gw,_GScrollBar_Width);
790     gcd[6].gd.pos.x = pos.width-gcd[6].gd.pos.width;
791     gcd[6].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
792     gcd[6].creator = GScrollBarCreate;
793     gcd[6].data = iv;
794     harray[1] = &gcd[6]; harray[2] = NULL;
795 
796     gcd[7].gd.flags = gg_enabled|gg_visible;
797     gcd[7].gd.u.boxelements = harray;
798     gcd[7].creator = GHBoxCreate;
799 
800     varray[0] = &gcd[7]; varray[1] = NULL;
801     varray[2] = &gcd[8]; varray[3] = NULL;
802     varray[4] = &gcd[4]; varray[5] = NULL;
803     varray[6] = NULL;
804 
805     gcd[8].gd.flags = gg_enabled|gg_visible;
806     gcd[8].gd.pos.width = 100;
807     gcd[8].creator = GLineCreate;
808 
809     gcd[9].gd.pos.x = gcd[9].gd.pos.y = 2;
810     gcd[9].gd.flags = gg_enabled|gg_visible;
811     gcd[9].gd.u.boxelements = varray;
812     gcd[9].creator = GHVGroupCreate;
813 
814     GGadgetsCreate(gw,&gcd[9]);
815     GHVBoxSetExpandableRow(gcd[9].ret,0);
816     GHVBoxSetExpandableCol(gcd[7].ret,0);
817     GHVBoxSetExpandableCol(gcd[4].ret,gb_expandgluesame);
818 
819     iv->ok = gcd[0].ret;
820     iv->cancel = gcd[1].ret;
821     iv->edit = gcd[2].ret;
822     iv->parse = gcd[3].ret;
823     iv->text = gcd[5].ret;
824     iv->instrinfo.vsb = gcd[6].ret;
825     iv->topbox = gcd[9].ret;
826 
827     wattrs.mask = wam_events|wam_cursor;
828     pos = gcd[5].gd.pos;
829     iv->instrinfo.v = GWidgetCreateSubWindow(gw,&pos,ii_v_e_h,&iv->instrinfo,&wattrs);
830     GDrawSetVisible(iv->instrinfo.v,true);
831 
832     if ( font==NULL ) {
833 	memset(&rq,0,sizeof(rq));
834 	rq.utf8_family_name = MONO_UI_FAMILIES;
835 	rq.point_size = -12;
836 	rq.weight = 400;
837 	font = GDrawInstanciateFont(gw,&rq);
838 	font = GResourceFindFont("TTInstruction.Font",font);
839     }
840     iv->instrinfo.gfont = font;
841     GDrawSetFont(iv->instrinfo.v,iv->instrinfo.gfont);
842     GGadgetSetFont(iv->text,iv->instrinfo.gfont);
843     GDrawWindowFontMetrics(iv->instrinfo.v,iv->instrinfo.gfont,&as,&ds,&ld);
844     iv->instrinfo.as = as+1;
845     iv->instrinfo.fh = iv->instrinfo.as+ds;
846     iv->instrinfo.isel_pos = -1;
847 
848     lh = iv->instrinfo.lheight;
849     if ( lh>40 ) lh = 40;
850     if ( lh<4 ) lh = 4;
851     GDrawResize(iv->gw,pos.width+gcd[6].gd.pos.width,iv->oc_height+lh*iv->instrinfo.fh+4);
852 
853     GDrawSetVisible(gw,true);
854 }
855 
SCEditInstructions(SplineChar * sc)856 void SCEditInstructions(SplineChar *sc) {
857     struct instrdata *id;
858     char title[100];
859     CharView *cv;
860     RefChar *ref;
861 
862     /* In a multiple master font, the instructions for all glyphs reside in */
863     /*  the "normal" instance of the font. The instructions are the same for */
864     /*  all instances (the cvt table might be different) */
865     if ( sc->parent->mm!=NULL && sc->parent->mm->apple )
866 	sc = sc->parent->mm->normal->glyphs[sc->orig_pos];
867 
868     for ( id = sc->parent->instr_dlgs; id!=NULL && id->sc!=sc; id=id->next );
869     if ( id!=NULL ) {
870 	GDrawSetVisible(id->id->gw,true);
871 	GDrawRaise(id->id->gw);
872 return;
873     }
874 
875     if ( sc->layers[ly_fore].refs!=NULL && sc->layers[ly_fore].splines!=NULL ) {
876 	ff_post_error(_("Can't instruct this glyph"),
877 		_("TrueType does not support mixed references and contours.\nIf you want instructions for %.30s you should either:\n * Unlink the reference(s)\n * Copy the inline contours into their own (unencoded\n    glyph) and make a reference to that."),
878 		sc->name );
879 return;
880     }
881     for ( ref = sc->layers[ly_fore].refs; ref!=NULL; ref=ref->next ) {
882 	if ( ref->transform[0]>=2 || ref->transform[0]<-2 ||
883 		ref->transform[1]>=2 || ref->transform[1]<-2 ||
884 		ref->transform[2]>=2 || ref->transform[2]<-2 ||
885 		ref->transform[3]>=2 || ref->transform[3]<-2 )
886     break;
887     }
888     if ( ref!=NULL ) {
889 	ff_post_error(_("Can't instruct this glyph"),
890 		_("TrueType does not support references which\nare scaled by more than 200%%.  But %1$.30s\nhas been in %2$.30s. Any instructions\nadded would be meaningless."),
891 		ref->sc->name, sc->name );
892 return;
893     }
894 
895     for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
896 	sc = cv->b.sc;
897 	cv->showpointnumbers = true;
898 	SCNumberPoints(sc,CVLayer((CharViewBase *) cv));
899 	GDrawRequestExpose(cv->v,NULL,false);
900     }
901     id = calloc(1,sizeof(*id));
902     id->instr_cnt = id->max = sc->ttf_instrs_len;
903     id->sf = sc->parent;
904     id->sc = sc;
905     id->instrs = malloc(id->max+1);
906     if ( sc->ttf_instrs!=NULL )
907 	memcpy(id->instrs,sc->ttf_instrs,id->instr_cnt);
908     sprintf(title,_("TrueType Instructions for %.50s"),sc->name);
909     InstrDlgCreate(id,title);
910 }
911 
SC_MarkInstrDlgAsChanged(SplineChar * sc)912 void SC_MarkInstrDlgAsChanged(SplineChar *sc) {
913     struct instrdata *id;
914 
915     for ( id = sc->parent->instr_dlgs; id!=NULL && id->sc!=sc; id=id->next );
916     if ( id!=NULL )
917 	id->changed = true;
918 }
919 
IIScrollTo(struct instrinfo * ii,int ip,int mark_stop)920 void IIScrollTo(struct instrinfo *ii,int ip,int mark_stop) {
921     int l, i;
922 
923     for ( i=l=0; i<ip && i<ii->instrdata->instr_cnt; ++i, ++l ) {
924 	if ( ii->instrdata->bts[i]==bt_wordhi || ii->instrdata->bts[i]==bt_wordlo )
925 	    ++i;
926     }
927     if ( ip==-1 )
928 	ii->lstopped = -1;
929     else {
930 	if ( mark_stop )
931 	    ii->lstopped = l;
932 	if ( l<ii->lpos || l>=ii->lpos+ii->vheight/ii->fh-1 ) {
933 	    if ( l+ii->vheight/ii->fh-1 >= ii->lheight+1 )
934 		l = ii->lheight+2-(ii->vheight/ii->fh);
935 	    if ( l<0 )
936 		l = 0;
937 	    ii->lpos = l;
938 	    GScrollBarSetPos(ii->vsb,l);
939 	}
940     }
941     GDrawRequestExpose(ii->v,NULL,false);
942 }
943 
IIReinit(struct instrinfo * ii,int ip)944 void IIReinit(struct instrinfo *ii,int ip) {
945     instrhelpsetup();
946     free(ii->instrdata->bts);
947     ii->instrdata->bts = NULL;
948     instr_info_init(ii);
949     GScrollBarSetBounds(ii->vsb,0,ii->lheight+2, ii->vheight<ii->fh ? 1 : ii->vheight/ii->fh);
950     IIScrollTo(ii,ip,true);
951 }
952 
953 /* ************************************************************************** */
954 /* **************************** CVT table editor **************************** */
955 /* ************************************************************************** */
956 
957 #define ADDR_SPACER	4
958 #define EDGE_SPACER	2
959 
960 typedef struct shortview /* : tableview */ {
961     struct ttf_table *table;
962     GWindow gw, v;
963     SplineFont *sf;
964     unsigned int destroyed: 1;		/* window has been destroyed */
965     unsigned int changed: 1;
966     GGadget *vsb, *tf;
967     GGadget *ok, *cancel, *setsize;
968     int lpos, lheight;
969     int16 as, fh;
970     int16 vheight, vwidth;
971     int16 sbw, bh;
972     GFont *gfont;
973     int16 chrlen, addrend, valend;
974     int16 active;
975     int16 which;
976     int16 *edits;
977     char **comments;
978     uint8 *data;
979     int32 len;
980     uint32 tag;
981 } ShortView;
982 
sfinishup(ShortView * sv,int showerr)983 static int sfinishup(ShortView *sv,int showerr) {
984     const unichar_t *ret = _GGadgetGetTitle(sv->tf);
985     unichar_t *end;
986     int val, oldval;
987 
988     if ( sv->active==-1 )
989 return( true );
990 
991     if ( sv->which ) {
992 	if ( *ret=='\0' ) {
993 	    if ( sv->comments[sv->active]!=NULL ) {
994 		free(sv->comments[sv->active]);
995 		sv->comments[sv->active] = NULL;
996 		sv->changed = true;
997 	    }
998 	} else {
999 	    char *new = GGadgetGetTitle8(sv->tf);
1000 	    if ( sv->comments[sv->active]==NULL ) {
1001 		sv->changed = true;
1002 	    } else {
1003 		if ( strcmp(sv->comments[sv->active],new)!=0 )
1004 		    sv->changed = true;
1005 		free(sv->comments[sv->active]);
1006 	    }
1007 	    sv->comments[sv->active] = new;
1008 	}
1009     } else {
1010 	val = u_strtol(ret,&end,10);
1011 	if ( *ret=='\0' || *end!='\0' || val<-32768 || val>32767 ) {
1012 	    if ( showerr )
1013 		ff_post_error(_("Bad Number"),_("Bad Number"));
1014 return( false );
1015 	}
1016 	oldval = sv->edits[sv->active];
1017 	if ( val != oldval ) {
1018 	    sv->changed = true;
1019 	    sv->edits[sv->active] = val;
1020 	}
1021     }
1022     sv->active = -1;
1023     GGadgetMove(sv->tf,sv->addrend,-100);
1024 return( true );
1025 }
1026 
SV_SetScrollBar(ShortView * sv)1027 static void SV_SetScrollBar(ShortView *sv) {
1028     int lh;
1029     sv->lheight = lh = sv->len/2;
1030 
1031     GScrollBarSetBounds(sv->vsb,0,lh,sv->vheight<sv->fh ? 1 : sv->vheight/sv->fh);
1032     if ( sv->lpos + sv->vheight/sv->fh > lh ) {
1033 	int lpos = lh-sv->vheight/sv->fh;
1034 	if ( lpos<0 ) lpos = 0;
1035 	if ( sv->lpos!=lpos && sv->active!=-1 )
1036 	    GGadgetMove(sv->tf,sv->addrend,(sv->active-lpos)*sv->fh);
1037 	sv->lpos = lpos;
1038     }
1039     GScrollBarSetPos(sv->vsb,sv->lpos);
1040 }
1041 
SV_ChangeLength(GGadget * g,GEvent * e)1042 static int SV_ChangeLength(GGadget *g, GEvent *e) {
1043     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1044 	ShortView *sv = GDrawGetUserData(GGadgetGetWindow(g));
1045 	char buffer[12];
1046 	char *ret, *e;
1047 	int val,i;
1048 
1049 	sprintf( buffer, "%d", (int) (sv->len/2) );
1050 	ret = gwwv_ask_string(_("Change Length"), buffer,_("How many entries should there be in the cvt table?"));
1051 	if ( ret==NULL )
1052 return( true );		/* Cancelled */
1053 	val = strtol(ret,&e,10);
1054 	if ( *e || val<0 || val>65535 ) {
1055 	    free(ret);
1056 	    ff_post_error(_("Bad Number"),_("Bad Number"));
1057 return( false );
1058 	}
1059 	free(ret);
1060 	if ( val*2>sv->len ) {
1061 	    sv->edits = realloc(sv->edits,val*2);
1062 	    for ( i=sv->len/2; i<val; ++i )
1063 		sv->edits[i] = 0;
1064 	    sv->comments = realloc(sv->comments,val*sizeof(char *));
1065 	    for ( i=sv->len/2; i<val; ++i )
1066 		sv->comments[i] = NULL;
1067 	} else {
1068 	    for ( i=val; i<sv->len/2; ++i ) {
1069 		free(sv->comments[i]);
1070 		sv->comments[i] = NULL;
1071 	    }
1072 	}
1073 	sv->len = 2*val;
1074 	SV_SetScrollBar(sv);
1075 	GDrawRequestExpose(sv->v,NULL,true);
1076     }
1077 return( true );
1078 }
1079 
_SV_DoClose(ShortView * sv)1080 static void _SV_DoClose(ShortView *sv) {
1081 
1082     sv->destroyed = true;
1083     GDrawDestroyWindow(sv->gw);
1084 }
1085 
SV_Cancel(GGadget * g,GEvent * e)1086 static int SV_Cancel(GGadget *g, GEvent *e) {
1087     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1088 	ShortView *sv = GDrawGetUserData(GGadgetGetWindow(g));
1089 
1090 	_SV_DoClose(sv);
1091     }
1092 return( true );
1093 }
1094 
SV_OK(GGadget * g,GEvent * e)1095 static int SV_OK(GGadget *g, GEvent *e) {
1096     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1097 	ShortView *sv = GDrawGetUserData(GGadgetGetWindow(g));
1098 	int i;
1099 	struct ttf_table *prev, *tab;
1100 	SplineFont *sf = sv->sf;
1101 
1102 	if ( !sfinishup(sv,true) )
1103 return( true );
1104 	if ( sf->cvt_names!=NULL ) {
1105 	    for ( i=0; sf->cvt_names[i]!=END_CVT_NAMES; ++i )
1106 		free(sf->cvt_names[i]);
1107 	    free(sf->cvt_names);
1108 	    sf->cvt_names = NULL;
1109 	}
1110 	if ( sv->len==0 ) {
1111 	    if ( sv->table!=NULL ) {
1112 		prev = NULL;
1113 		for ( tab=sf->ttf_tables; tab!=NULL && tab!=sv->table; prev=tab, tab=tab->next );
1114 		if ( prev!=NULL )
1115 		    prev->next = tab->next;
1116 		else
1117 		    sf->ttf_tables = tab->next;
1118 		free(sv->table->data);
1119 		chunkfree(sv->table,sizeof(struct ttf_table));
1120 		sv->table = NULL;
1121 	    }
1122 	} else {
1123 	    if ( sv->table!=NULL )
1124 		free(sv->table->data);
1125 	    else {
1126 		tab = chunkalloc(sizeof(struct ttf_table));
1127 		tab->next = sf->ttf_tables;
1128 		sf->ttf_tables = tab;
1129 		tab->tag = sv->tag;
1130 		sv->table = tab;
1131 	    }
1132 	    sv->table->data = malloc(sv->len);
1133 	    sf->cvt_names = malloc(((sv->len>>1)+1)*sizeof(char *));
1134 	    for ( i=0; i<sv->len/2; ++i ) {
1135 		sv->table->data[i<<1] = (sv->edits[i]>>8)&0xff;
1136 		sv->table->data[(i<<1)+1] = sv->edits[i]&0xff;
1137 		sf->cvt_names[i] = sv->comments[i];
1138 		sv->comments[i] = NULL;
1139 	    }
1140 	    sf->cvt_names[i] = END_CVT_NAMES;
1141 	    sv->table->len = sv->len;
1142 	}
1143 	sf->changed = true;
1144 	_SV_DoClose(sv);
1145     }
1146 return( true );
1147 }
1148 
short_resize(ShortView * sv,GEvent * event)1149 static void short_resize(ShortView *sv,GEvent *event) {
1150     GRect pos, gsize;
1151     int width;
1152 
1153     /* height must be a multiple of the line height */
1154     if ( (event->u.resize.size.height-2*EDGE_SPACER-sv->bh)%sv->fh!=0 ||
1155 	    (event->u.resize.size.height-2*EDGE_SPACER-sv->fh-sv->bh)<0 ) {
1156 	int lc = (event->u.resize.size.height+sv->fh/2-EDGE_SPACER)/sv->fh;
1157 	if ( lc<=0 ) lc = 1;
1158 	GDrawResize(sv->gw, event->u.resize.size.width,
1159 		lc*sv->fh+2*EDGE_SPACER+sv->bh);
1160 return;
1161     }
1162 
1163     pos.width = GDrawPointsToPixels(sv->gw,_GScrollBar_Width);
1164     pos.height = event->u.resize.size.height-sv->bh-sv->fh;
1165     pos.x = event->u.resize.size.width-pos.width; pos.y = sv->fh;
1166     GGadgetResize(sv->vsb,pos.width,pos.height+1);
1167     GGadgetMove(sv->vsb,pos.x,pos.y);
1168     pos.width = pos.x; pos.x = 0;
1169     GDrawResize(sv->v,pos.width,pos.height);
1170     GDrawMove(sv->v,0,sv->fh);
1171 
1172     sv->vheight = pos.height; sv->vwidth = pos.width;
1173     SV_SetScrollBar(sv);
1174 
1175     width = pos.width-sv->addrend;
1176     if ( width < 5 ) width = 5;
1177     GGadgetResize(sv->tf,width,sv->fh);
1178 
1179     GGadgetGetSize(sv->ok,&gsize);
1180     GGadgetMove(sv->ok,gsize.x,event->u.resize.size.height-GDrawPointsToPixels(sv->gw,33));
1181     GGadgetMove(sv->cancel,event->u.resize.size.width-gsize.x-gsize.width,event->u.resize.size.height-GDrawPointsToPixels(sv->gw,30));
1182     GGadgetGetSize(sv->setsize,&gsize);
1183     GGadgetMove(sv->setsize,(event->u.resize.size.width-gsize.width)/2,
1184 	    event->u.resize.size.height-GDrawPointsToPixels(sv->gw,60));
1185 
1186     GDrawRequestExpose(sv->gw,NULL,true);
1187 }
1188 
short_expose(ShortView * sv,GWindow pixmap,GRect * rect)1189 static void short_expose(ShortView *sv,GWindow pixmap,GRect *rect) {
1190     int low, high;
1191     int x,y;
1192     char cval[8], caddr[8];
1193     int index;
1194 
1195     GDrawSetFont(pixmap,sv->gfont);
1196 
1197     low = ( (rect->y-EDGE_SPACER)/sv->fh ) * sv->fh + EDGE_SPACER;
1198     high = ( (rect->y+rect->height+sv->fh-1-EDGE_SPACER)/sv->fh ) * sv->fh +EDGE_SPACER;
1199     if ( high>sv->vheight-EDGE_SPACER ) high = sv->vheight-EDGE_SPACER;
1200 
1201     GDrawDrawLine(pixmap,sv->addrend-ADDR_SPACER/2,rect->y,sv->addrend-ADDR_SPACER/2,rect->y+rect->height,0x000000);
1202     GDrawDrawLine(pixmap,sv->valend-ADDR_SPACER/2,rect->y,sv->valend-ADDR_SPACER/2,rect->y+rect->height,0x000000);
1203 
1204     index = (sv->lpos+(low-EDGE_SPACER)/sv->fh);
1205     y = low;
1206     for ( ; y<=high && index<sv->len/2; ++index ) {
1207 	sprintf( caddr, "%d", index );
1208 	x = sv->addrend - ADDR_SPACER - GDrawGetText8Width(pixmap,caddr,-1);
1209 	GDrawDrawText8(pixmap,x,y+sv->as,caddr,-1,MAIN_FOREGROUND);
1210 
1211 	sprintf( cval, "%d", sv->edits[index] );
1212 	GDrawDrawText8(pixmap,sv->addrend,y+sv->as,cval,-1,MAIN_FOREGROUND);
1213 
1214 	if ( sv->comments[index]!=NULL )
1215 	    GDrawDrawText8(pixmap,sv->valend,y+sv->as,sv->comments[index],-1,MAIN_FOREGROUND);
1216 	y += sv->fh;
1217     }
1218 }
1219 
short_mousemove(ShortView * sv,int pos)1220 static void short_mousemove(ShortView *sv,int pos) {
1221     /*GGadgetPreparePopup(sv->gw,msg);*/
1222 }
1223 
short_scroll(ShortView * sv,struct sbevent * sb)1224 static void short_scroll(ShortView *sv,struct sbevent *sb) {
1225     int newpos = sv->lpos;
1226 
1227     switch( sb->type ) {
1228       case et_sb_top:
1229         newpos = 0;
1230       break;
1231       case et_sb_uppage:
1232         newpos -= sv->vheight/sv->fh;
1233       break;
1234       case et_sb_up:
1235         --newpos;
1236       break;
1237       case et_sb_down:
1238         ++newpos;
1239       break;
1240       case et_sb_downpage:
1241         newpos += sv->vheight/sv->fh;
1242       break;
1243       case et_sb_bottom:
1244         newpos = sv->lheight-sv->vheight/sv->fh;
1245       break;
1246       case et_sb_thumb:
1247       case et_sb_thumbrelease:
1248         newpos = sb->pos;
1249       break;
1250     }
1251     if ( newpos>sv->lheight-sv->vheight/sv->fh )
1252         newpos = sv->lheight-sv->vheight/sv->fh;
1253     if ( newpos<0 ) newpos =0;
1254     if ( newpos!=sv->lpos ) {
1255 	int diff = newpos-sv->lpos;
1256 	sv->lpos = newpos;
1257 	GScrollBarSetPos(sv->vsb,sv->lpos);
1258 	if ( sv->active!=-1 ) {
1259 	    GRect pos;
1260 	    GGadgetGetSize(sv->tf,&pos);
1261 	    GGadgetMove(sv->tf,sv->addrend,pos.y+diff*sv->fh);
1262 	}
1263 	GDrawScroll(sv->v,NULL,0,diff*sv->fh);
1264     }
1265 }
1266 
ShortViewFree(ShortView * sv)1267 static void ShortViewFree(ShortView *sv) {
1268     sv->sf->cvt_dlg = NULL;
1269     free(sv->edits);
1270     free(sv);
1271 }
1272 
sv_v_e_h(GWindow gw,GEvent * event)1273 static int sv_v_e_h(GWindow gw, GEvent *event) {
1274     ShortView *sv = (ShortView *) GDrawGetUserData(gw);
1275 
1276     switch ( event->type ) {
1277       case et_expose:
1278 	short_expose(sv,gw,&event->u.expose.rect);
1279       break;
1280       case et_char:
1281 	if ( event->u.chr.keysym == GK_Help || event->u.chr.keysym == GK_F1 )
1282 	    help("ui/dialogs/ttfinstrs.html", "#ttfinstrs-cvt");
1283       break;
1284       case et_mousemove: case et_mousedown: case et_mouseup:
1285 	GGadgetEndPopup();
1286 	if ( event->type==et_mousemove )
1287 	    short_mousemove(sv,event->u.mouse.y);
1288 	else if ( event->type == et_mousedown ) {
1289 	    int l = (event->u.mouse.y-EDGE_SPACER)/sv->fh + sv->lpos;
1290 	    int which = event->u.mouse.x > sv->valend;
1291 	    char buf[20];
1292 	    int old = sv->active;
1293 	    if ( sfinishup(sv,true) && event->u.mouse.x>sv->addrend &&
1294 		    l<sv->len/2 && l!=old ) {
1295 		sv->active = l;
1296 		sv->which = which;
1297 		if ( !which ) {
1298 		    /* Change the value */
1299 		    GGadgetResize(sv->tf,sv->valend-sv->addrend-EDGE_SPACER,sv->fh);
1300 		    GGadgetMove(sv->tf, sv->addrend,
1301 					    (l-sv->lpos)*sv->fh+EDGE_SPACER+1);
1302 		    sprintf( buf, "%d", sv->edits[sv->active] );
1303 		    GGadgetSetTitle8(sv->tf,buf);
1304 		} else {
1305 		    GGadgetResize(sv->tf,sv->vwidth-sv->valend-EDGE_SPACER,sv->fh);
1306 		    GGadgetMove(sv->tf, sv->valend,
1307 					    (l-sv->lpos)*sv->fh+EDGE_SPACER+1);
1308 		    GGadgetSetTitle8(sv->tf,sv->comments[l]==NULL?"":sv->comments[l]);
1309 		}
1310 		GDrawRequestExpose(sv->v,NULL,true);
1311 		GDrawPostEvent(event);	/* And we hope the tf catches it this time */
1312 	    }
1313 	}
1314       break;
1315       case et_resize:
1316 	GDrawRequestExpose(gw,NULL,true);
1317       break;
1318       case et_timer:
1319       break;
1320       case et_focus:
1321       break;
1322     }
1323 return( true );
1324 }
1325 
sv_e_h(GWindow gw,GEvent * event)1326 static int sv_e_h(GWindow gw, GEvent *event) {
1327     ShortView *sv = (ShortView *) GDrawGetUserData(gw);
1328     GRect r;
1329     int x;
1330 
1331     switch ( event->type ) {
1332       case et_expose:
1333 	r.x = r.y = 0; r.width = sv->vwidth+40; r.height = sv->fh-1;
1334 	GDrawFillRect(gw,&r,0x808080);
1335 	GDrawSetFont(gw,sv->gfont);
1336 	x = sv->addrend - ADDR_SPACER - 2 - GDrawGetText8Width(gw,_("Index"),-1);
1337 	GDrawDrawText8(gw,x,sv->as,_("Index"),-1,0xffffff);
1338 	GDrawDrawText8(gw,sv->addrend,sv->as,_("Value"),-1,0xffffff);
1339 	GDrawDrawText8(gw,sv->valend,sv->as,_("Comment"),-1,0xffffff);
1340 
1341 	GDrawDrawLine(gw,0,sv->fh-1,r.width,sv->fh-1,0x000000);
1342 	GDrawDrawLine(gw,0,sv->vheight+sv->fh,sv->vwidth,sv->vheight+sv->fh,0x000000);
1343       break;
1344       case et_resize:
1345 	short_resize(sv,event);
1346       break;
1347       case et_char:
1348 	if ( event->u.chr.keysym == GK_Help || event->u.chr.keysym == GK_F1 )
1349 	    help("ui/dialogs/ttfinstrs.html", "#ttfinstrs-cvt");
1350       break;
1351       case et_controlevent:
1352 	switch ( event->u.control.subtype ) {
1353 	  case et_scrollbarchange:
1354 	    short_scroll(sv,&event->u.control.u.sb);
1355 	  break;
1356 	}
1357       break;
1358       case et_close:
1359 	_SV_DoClose(sv);
1360       break;
1361       case et_destroy:
1362 	ShortViewFree(sv);
1363       break;
1364     }
1365 return( true );
1366 }
1367 
1368 /* cvt table */
cvtCreateEditor(struct ttf_table * tab,SplineFont * sf,uint32 tag)1369 static void cvtCreateEditor(struct ttf_table *tab,SplineFont *sf,uint32 tag) {
1370     ShortView *sv = calloc(1,sizeof(ShortView));
1371     char title[60];
1372     GRect pos, subpos, gsize;
1373     GWindow gw;
1374     GWindowAttrs wattrs;
1375     FontRequest rq;
1376     int as,ds,ld, lh;
1377     GGadgetCreateData gcd[9], *butarray[8], *harray[4], *harray2[3], *varray[7];
1378     GTextInfo label[5], lab;
1379     GGadgetData gd;
1380     static unichar_t num[] = { '0',  '\0' };
1381     int numlen;
1382     static GBox tfbox;
1383     int i;
1384     static GFont *font = NULL;
1385 
1386     sv->table = tab;
1387     sv->sf = sf;
1388     sf->cvt_dlg = sv;
1389     sv->tag = tag;
1390 
1391     if ( tab==NULL && sf->mm!=NULL && sf->mm->apple )
1392 	tab = SFFindTable(sf->mm->normal,tag);
1393     if ( tab!=NULL ) {
1394 	sv->len = tab->len;
1395 	sv->edits = malloc(tab->len+1);
1396 	sv->comments = calloc((tab->len/2+1),sizeof(char *));
1397 	for ( i=0; i<tab->len/2; ++i )
1398 	    sv->edits[i] = (tab->data[i<<1]<<8) | tab->data[(i<<1)+1];
1399 	if ( sf->cvt_names!=NULL )
1400 	    for ( i=0; i<tab->len/2 && sf->cvt_names[i]!=END_CVT_NAMES; ++i )
1401 		sv->comments[i] = copy(sf->cvt_names[i]);
1402     } else {
1403 	sv->edits = malloc(2);
1404 	sv->len = 0;
1405 	sv->comments = calloc(1,sizeof(char *));
1406     }
1407 
1408     title[0] = (tag>>24)&0xff;
1409     title[1] = (tag>>16)&0xff;
1410     title[2] = (tag>>8 )&0xff;
1411     title[3] = (tag    )&0xff;
1412     title[4] = ' ';
1413     strncpy(title+5, sf->fontname, sizeof(title)/sizeof(title[0])-6);
1414 
1415     memset(&wattrs,0,sizeof(wattrs));
1416     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_icon;
1417     wattrs.event_masks = ~(1<<et_charup);
1418     wattrs.undercursor = 1;
1419     wattrs.cursor = ct_pointer;
1420     wattrs.utf8_window_title = title;
1421     wattrs.icon = ttf_icon;
1422     pos.x = pos.y = 0;
1423     if ( GIntGetResource(_NUM_Buttonsize)>60 )
1424 	pos.width = GDrawPointsToPixels(NULL,2*GIntGetResource(_NUM_Buttonsize)+30);
1425     else
1426 	pos.width = GDrawPointsToPixels(NULL,150);
1427     pos.height = GDrawPointsToPixels(NULL,200);
1428     sv->gw = gw = GDrawCreateTopWindow(NULL,&pos,sv_e_h,sv,&wattrs);
1429 
1430     memset(&gcd,0,sizeof(gcd));
1431     memset(&label,0,sizeof(label));
1432 
1433     gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 105;
1434     gcd[0].gd.pos.width = -1;
1435     label[0].text = (unichar_t *) _("_OK");
1436     label[0].text_is_1byte = true;
1437     label[0].text_in_resource = true;
1438     gcd[0].gd.label = &label[0];
1439     gcd[0].gd.flags = gg_visible|gg_enabled|gg_but_default;
1440     gcd[0].creator = GButtonCreate;
1441     gcd[0].data = sv;
1442     gcd[0].gd.handle_controlevent = SV_OK;
1443 
1444     gcd[1].gd.pos.x = -8; gcd[1].gd.pos.y = 3;
1445     gcd[1].gd.pos.width = -1;
1446     label[1].text = (unichar_t *) _("_Cancel");
1447     label[1].text_is_1byte = true;
1448     label[1].text_in_resource = true;
1449     gcd[1].gd.label = &label[1];
1450     gcd[1].gd.flags = gg_visible|gg_enabled|gg_but_cancel;
1451     gcd[1].creator = GButtonCreate;
1452     gcd[1].data = sv;
1453     gcd[1].gd.handle_controlevent = SV_Cancel;
1454 
1455     gcd[2] = gcd[1];
1456     label[2].text = (unichar_t *) _("Change Length");
1457     label[2].text_is_1byte = true;
1458     label[2].text_in_resource = true;
1459     gcd[2].gd.flags = gg_visible|gg_enabled;
1460     gcd[2].gd.label = &label[2];
1461     gcd[2].creator = GButtonCreate;
1462     gcd[2].data = sv;
1463     gcd[2].gd.handle_controlevent = SV_ChangeLength;
1464 
1465     butarray[0] = GCD_Glue; butarray[1] = &gcd[0]; butarray[2] = GCD_Glue;
1466     butarray[3] = GCD_Glue; butarray[4] = &gcd[1]; butarray[5] = GCD_Glue;
1467     butarray[6] = NULL;
1468 
1469     harray[0] = GCD_Glue; harray[1] = &gcd[2]; harray[2] = GCD_Glue;
1470     harray[3] = NULL;
1471 
1472     gcd[3].gd.flags = gg_enabled|gg_visible;
1473     gcd[3].gd.u.boxelements = butarray;
1474     gcd[3].creator = GHBoxCreate;
1475 
1476     gcd[4].gd.flags = gg_enabled|gg_visible;
1477     gcd[4].gd.u.boxelements = harray;
1478     gcd[4].creator = GHBoxCreate;
1479 
1480     sv->bh = GDrawPointsToPixels(gw,64);
1481 
1482     gcd[5].gd.pos.y = sv->fh; gcd[5].gd.pos.height = pos.height-sv->bh;
1483     gcd[5].gd.pos.width = GDrawPointsToPixels(gw,_GScrollBar_Width);
1484     gcd[5].gd.pos.x = pos.width-gcd[5].gd.pos.width;
1485     gcd[5].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
1486     gcd[5].gd.handle_controlevent = NULL;
1487     gcd[5].creator = GScrollBarCreate;
1488     gcd[5].data = sv;
1489     harray2[0] = GCD_Glue; harray2[1] = &gcd[5]; harray2[2] = NULL;
1490 
1491     gcd[6].gd.flags = gg_enabled|gg_visible;
1492     gcd[6].gd.u.boxelements = harray2;
1493     gcd[6].creator = GHBoxCreate;
1494 
1495     varray[0] = &gcd[6]; varray[1] = NULL;
1496     varray[2] = &gcd[4]; varray[3] = NULL;
1497     varray[4] = &gcd[3]; varray[5] = NULL;
1498     varray[6] = NULL;
1499 
1500     /*gcd[7].gd.pos.x = gcd[7].gd.pos.y = 2;*/
1501     gcd[7].gd.flags = gg_enabled|gg_visible;
1502     gcd[7].gd.u.boxelements = varray;
1503     gcd[7].creator = GHVBoxCreate;
1504 
1505     GGadgetsCreate(gw,&gcd[7]);
1506     GHVBoxSetExpandableRow(gcd[7].ret,0);
1507     GHVBoxSetExpandableCol(gcd[6].ret,0);
1508     GHVBoxSetExpandableCol(gcd[3].ret,gb_expandgluesame);
1509     GHVBoxSetExpandableCol(gcd[4].ret,gb_expandglue);
1510 
1511     sv->vsb = gcd[5].ret;
1512     sv->ok = gcd[0].ret;
1513     sv->cancel = gcd[1].ret;
1514     sv->setsize = gcd[2].ret;
1515     GGadgetGetSize(sv->vsb,&gsize);
1516     sv->sbw = gsize.width;
1517 
1518     wattrs.mask = wam_events|wam_cursor;
1519     subpos.x = 0; subpos.y = sv->fh;
1520     subpos.width = 100; subpos.height = pos.height - sv->bh - sv->fh;
1521     sv->v = GWidgetCreateSubWindow(gw,&subpos,sv_v_e_h,sv,&wattrs);
1522     GDrawSetVisible(sv->v,true);
1523 
1524     if ( font==NULL ) {
1525 	memset(&rq,0,sizeof(rq));
1526 	rq.utf8_family_name = MONO_UI_FAMILIES;
1527 	rq.point_size = -12;
1528 	rq.weight = 400;
1529 	font = GDrawInstanciateFont(gw,&rq);
1530 	font = GResourceFindFont("CVT.Font",font);
1531     }
1532     sv->gfont = font;
1533     GDrawSetFont(sv->v,sv->gfont);
1534     GDrawSetFont(sv->gw,sv->gfont);
1535     GDrawWindowFontMetrics(sv->gw,sv->gfont,&as,&ds,&ld);
1536     sv->as = as+1;
1537     sv->fh = sv->as+ds;
1538 
1539     sv->chrlen = numlen = GDrawGetTextWidth(sv->v,num,1);
1540     sv->addrend = 6*numlen + ADDR_SPACER + EDGE_SPACER;
1541     sv->valend = sv->addrend + 7*numlen + ADDR_SPACER + EDGE_SPACER;
1542 
1543     tfbox.main_background = tfbox.main_foreground = COLOR_DEFAULT;
1544     memset(&gd,0,sizeof(gd));
1545     gd.pos.y = -100; gd.pos.height = sv->fh;
1546     gd.pos.x = sv->addrend;
1547     memset(&lab,'\0',sizeof(lab));
1548     lab.text = num+1;
1549     lab.font = sv->gfont;
1550     gd.label = &lab;
1551     gd.box = &tfbox;
1552     gd.flags = gg_visible|gg_enabled|gg_sb_vert|gg_dontcopybox;
1553     sv->tf = GTextFieldCreate(sv->v,&gd,NULL);
1554     sv->active = -1;
1555 
1556     lh = sv->len/2;
1557     if ( lh>40 ) lh = 40;
1558     if ( lh<4 ) lh = 4;
1559     if ( pos.width<sv->valend+6*numlen+EDGE_SPACER+sv->sbw )
1560 	pos.width = sv->valend+6*numlen+EDGE_SPACER+sv->sbw;
1561     GDrawResize(sv->gw,pos.width,lh*sv->fh+2*EDGE_SPACER);
1562 
1563     GDrawSetVisible(gw,true);
1564 }
1565 
SF_CloseAllInstrs(SplineFont * sf)1566 int SF_CloseAllInstrs(SplineFont *sf) {
1567     struct instrdata *id, *next;
1568     int changed;
1569     char name[12], *npt;
1570     static char *buts[3];
1571     static int done = false;
1572 
1573     if ( !done ) {
1574 	buts[0] = _("_OK");
1575 	buts[1] = _("_Cancel");
1576 	done = true;
1577     }
1578 
1579     for ( id = sf->instr_dlgs; id!=NULL; id=next ) {
1580 	next = id->next;
1581 	changed = id->changed;
1582 	if ( !changed && id->id->inedit ) {
1583 	    if ( !IVParse(id->id))
1584 		changed = true;
1585 	    else
1586 		changed = id->changed;
1587 	}
1588 	if ( changed ) {
1589 	    if ( id->tag==0 )
1590 		npt = id->sc->name;
1591 	    else {
1592 		name[0] = name[5] = '\'';
1593 		name[1] = id->tag>>24; name[2] = (id->tag>>16)&0xff; name[3] = (id->tag>>8)&0xff; name[4] = id->tag&0xff;
1594 		name[6] = 0;
1595 		npt = name;
1596 	    }
1597 	    GDrawRaise(id->id->gw);
1598 	    if ( gwwv_ask(_("Instructions were changed"),(const char **) buts,0,1,_("The instructions for %.80s have changed. Do you want to lose those changes?"),npt)==1 )
1599 return( false );
1600 	}
1601 	GDrawDestroyWindow(id->id->gw);
1602     }
1603     if ( sf->cvt_dlg!=NULL ) {
1604 	if ( sf->cvt_dlg->changed ) {
1605 	    name[0] = name[5] = '\'';
1606 	    name[1] = id->tag>>24; name[2] = (id->tag>>16)&0xff; name[3] = (id->tag>>8)&0xff; name[4] = id->tag&0xff;
1607 	    name[6] = 0;
1608 	    npt = name;
1609 	    GDrawRaise(sf->cvt_dlg->gw);
1610 	    if ( gwwv_ask(_("Instructions were changed"),(const char **) buts,0,1,_("The instructions for %.80s have changed. Do you want to lose those changes?"),npt)==1 )
1611 return( false );
1612 	}
1613 	GDrawDestroyWindow(sf->cvt_dlg->gw);
1614     }
1615     if ( !no_windowing_ui ) {
1616 	GDrawSync(NULL);
1617 	GDrawProcessPendingEvents(NULL);
1618     }
1619 return( true );
1620 }
1621 
1622 /* Maxp table editor (or that subset of it that ff can't figure out) */
1623 struct maxp_data {
1624     GWindow gw;
1625     SplineFont *sf;
1626     struct ttf_table *tab;
1627     int done;
1628 };
1629 
1630 #define CID_Zones	1006
1631 #define CID_TPoints	1007
1632 #define CID_Storage	1008
1633 #define CID_FDefs	1009
1634 #define CID_IDefs	1010
1635 #define CID_SEl		1011
1636 
MP_DoClose(struct maxp_data * mp)1637 static void MP_DoClose(struct maxp_data *mp) {
1638     mp->done = true;
1639 }
1640 
Maxp_Cancel(GGadget * g,GEvent * e)1641 static int Maxp_Cancel(GGadget *g, GEvent *e) {
1642 
1643     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1644 	MP_DoClose(GDrawGetUserData(GGadgetGetWindow(g)));
1645     }
1646 return( true );
1647 }
1648 
Maxp_OK(GGadget * g,GEvent * e)1649 static int Maxp_OK(GGadget *g, GEvent *e) {
1650     struct maxp_data *mp;
1651     int zones, tp, store, stack, fd, id, err=0;
1652 
1653     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1654 	mp = GDrawGetUserData(GGadgetGetWindow(g));
1655 	zones = GetInt8(mp->gw,CID_Zones,_("Zones"),&err);
1656 	tp = GetInt8(mp->gw,CID_TPoints,_("Twilight Zone Point Count"),&err);
1657 	store = GetInt8(mp->gw,CID_Storage,_("Storage"),&err);
1658 	stack = GetInt8(mp->gw,CID_SEl,_("Max Stack Depth"),&err);
1659 	fd = GetInt8(mp->gw,CID_FDefs,_("Max # Functions"),&err);
1660 	id = GetInt8(mp->gw,CID_IDefs,_("Max Instruction Defines"),&err);
1661 	if ( err )
1662 return( true );
1663 	mp->done = true;
1664 	if ( mp->tab==NULL ) {
1665 	    mp->tab = chunkalloc(sizeof(struct ttf_table));
1666 	    mp->tab->tag = CHR('m','a','x','p');
1667 	    mp->tab->len = 32;
1668 	    mp->tab->data = calloc(32,1);
1669 	    mp->tab->next = mp->sf->ttf_tables;
1670 	    mp->sf->ttf_tables = mp->tab;
1671 	} else if ( mp->tab->len<32 ) {
1672 	    free(mp->tab->data);
1673 	    mp->tab->len = 32;
1674 	    mp->tab->data = calloc(32,1);
1675 	}
1676 	mp->tab->data[14] = zones>>8; mp->tab->data[15] = zones&0xff;
1677 	mp->tab->data[16] = tp>>8; mp->tab->data[17] = tp&0xff;
1678 	mp->tab->data[18] = store>>8; mp->tab->data[19] = store&0xff;
1679 	mp->tab->data[20] = fd>>8; mp->tab->data[21] = fd&0xff;
1680 	mp->tab->data[22] = id>>8; mp->tab->data[23] = id&0xff;
1681 	mp->tab->data[24] = stack>>8; mp->tab->data[25] = stack&0xff;
1682 	mp->sf->changed = true;
1683 	mp->done = true;
1684     }
1685 return( true );
1686 }
1687 
mp_e_h(GWindow gw,GEvent * event)1688 static int mp_e_h(GWindow gw, GEvent *event) {
1689     struct maxp_data *mp = (struct maxp_data *) GDrawGetUserData(gw);
1690 
1691     switch ( event->type ) {
1692       case et_char:
1693 	if ( event->u.chr.keysym == GK_Help || event->u.chr.keysym == GK_F1 )
1694 	    help("ui/dialogs/ttfinstrs.html", "#ttfinstrs-maxp");
1695 	else
1696 return( false );
1697       break;
1698       case et_close:
1699 	MP_DoClose(mp);
1700       break;
1701     }
1702 return( true );
1703 }
1704 
maxpCreateEditor(struct ttf_table * tab,SplineFont * sf,uint32 tag)1705 static void maxpCreateEditor(struct ttf_table *tab,SplineFont *sf,uint32 tag) {
1706     char title[60];
1707     GRect pos;
1708     GWindow gw;
1709     GWindowAttrs wattrs;
1710     struct maxp_data mp;
1711     GGadgetCreateData gcd[17], boxes[4], *hvarray[16], *butarray[8], *varray[7];
1712     GTextInfo label[17];
1713     uint8 dummy[32], *data;
1714     char buffer[6][20];
1715     int k, hv;
1716 
1717     if ( tab==NULL && sf->mm!=NULL && sf->mm->apple ) {
1718 	sf = sf->mm->normal;
1719 	tab = SFFindTable(sf,tag);
1720     }
1721     memset(&mp,0,sizeof(mp));
1722     mp.sf = sf;
1723     mp.tab = tab;
1724     if ( tab==NULL || tab->len<32 ) {
1725 	memset(dummy,0,sizeof(dummy));
1726 	dummy[15]=2;	/* default Zones to 2 */
1727 	data = dummy;
1728     } else
1729 	data = tab->data;
1730 
1731     title[0] = (tag>>24)&0xff;
1732     title[1] = (tag>>16)&0xff;
1733     title[2] = (tag>>8 )&0xff;
1734     title[3] = (tag    )&0xff;
1735     title[4] = ' ';
1736     strncpy(title+5, sf->fontname, sizeof(title)-6);
1737 
1738     memset(&wattrs,0,sizeof(wattrs));
1739     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1740     wattrs.event_masks = ~(1<<et_charup);
1741     wattrs.undercursor = 1;
1742     wattrs.cursor = ct_pointer;
1743     wattrs.utf8_window_title = title;
1744     wattrs.restrict_input_to_me = 1;
1745     wattrs.undercursor = 1;
1746     wattrs.is_dlg = true;
1747     pos.x = pos.y = 0;
1748     pos.width = GDrawPointsToPixels(NULL,260);
1749     pos.height = GDrawPointsToPixels(NULL,125);
1750     mp.gw = gw = GDrawCreateTopWindow(NULL,&pos,mp_e_h,&mp,&wattrs);
1751 
1752     memset(label,0,sizeof(label));
1753     memset(gcd,0,sizeof(gcd));
1754     memset(boxes,0,sizeof(boxes));
1755 
1756 	k=hv=0;
1757 	label[k].text = (unichar_t *) _("_Zones:");
1758 	label[k].text_is_1byte = true;
1759 	label[k].text_in_resource = true;
1760 	gcd[k].gd.label = &label[k];
1761 	gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = 16;
1762 	gcd[k].gd.flags = gg_enabled|gg_visible;
1763 	gcd[k].gd.cid = CID_Zones+1000;
1764 	gcd[k++].creator = GLabelCreate;
1765 	hvarray[hv++] = &gcd[k-1];
1766 
1767 	sprintf( buffer[0], "%d", (data[14]<<8)|data[14+1] );
1768 	label[k].text = (unichar_t *) buffer[0];
1769 	label[k].text_is_1byte = true;
1770 	gcd[k].gd.label = &label[k];
1771 	gcd[k].gd.pos.x = 60; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-6;
1772 	gcd[k].gd.pos.width = 50;
1773 	gcd[k].gd.flags = gg_enabled|gg_visible;
1774 	gcd[k].gd.cid = CID_Zones;
1775 	gcd[k++].creator = GTextFieldCreate;
1776 	hvarray[hv++] = &gcd[k-1];
1777 
1778 	label[k].text = (unichar_t *) _("_Twilight Pnt Cnt:");
1779 	label[k].text_is_1byte = true;
1780 	label[k].text_in_resource = true;
1781 	gcd[k].gd.label = &label[k];
1782 	gcd[k].gd.pos.x = 120; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
1783 	gcd[k].gd.flags = gg_enabled|gg_visible;
1784 	gcd[k].gd.cid = CID_TPoints+1000;
1785 	gcd[k++].creator = GLabelCreate;
1786 	hvarray[hv++] = &gcd[k-1];
1787 
1788 	sprintf( buffer[1], "%d", (data[16]<<8)|data[16+1] );
1789 	label[k].text = (unichar_t *) buffer[1];
1790 	label[k].text_is_1byte = true;
1791 	gcd[k].gd.label = &label[k];
1792 	gcd[k].gd.pos.x = 202; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-6;
1793 	gcd[k].gd.pos.width = 50;
1794 	gcd[k].gd.flags = gg_enabled|gg_visible;
1795 	gcd[k].gd.cid = CID_TPoints;
1796 	gcd[k++].creator = GTextFieldCreate;
1797 	hvarray[hv++] = &gcd[k-1]; hvarray[hv++] = NULL;
1798 
1799 	label[k].text = (unichar_t *) _("St_orage:");
1800 	label[k].text_in_resource = true;
1801 	label[k].text_is_1byte = true;
1802 	gcd[k].gd.label = &label[k];
1803 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-3].gd.pos.y+24+6;
1804 	gcd[k].gd.flags = gg_enabled|gg_visible;
1805 	gcd[k].gd.cid = CID_Storage;
1806 	gcd[k++].creator = GLabelCreate;
1807 	hvarray[hv++] = &gcd[k-1];
1808 
1809 	sprintf( buffer[2], "%d", (data[18]<<8)|data[18+1] );
1810 	label[k].text = (unichar_t *) buffer[2];
1811 	label[k].text_is_1byte = true;
1812 	gcd[k].gd.label = &label[k];
1813 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-6;
1814 	gcd[k].gd.pos.width = 50;
1815 	gcd[k].gd.flags = gg_enabled|gg_visible;
1816 	gcd[k].gd.cid = CID_Storage;
1817 	gcd[k++].creator = GTextFieldCreate;
1818 	hvarray[hv++] = &gcd[k-1];
1819 
1820 	label[k].text = (unichar_t *) _("Max _Stack Depth:");
1821 	label[k].text_in_resource = true;
1822 	label[k].text_is_1byte = true;
1823 	gcd[k].gd.label = &label[k];
1824 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
1825 	gcd[k].gd.flags = gg_enabled|gg_visible;
1826 	gcd[k].gd.cid = CID_SEl+1000;
1827 	gcd[k++].creator = GLabelCreate;
1828 	hvarray[hv++] = &gcd[k-1];
1829 
1830 	sprintf( buffer[3], "%d", (data[24]<<8)|data[24+1] );
1831 	label[k].text = (unichar_t *) buffer[3];
1832 	label[k].text_is_1byte = true;
1833 	gcd[k].gd.label = &label[k];
1834 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
1835 	gcd[k].gd.pos.width = 50;
1836 	gcd[k].gd.flags = gg_enabled|gg_visible;
1837 	gcd[k].gd.cid = CID_SEl;
1838 	gcd[k++].creator = GTextFieldCreate;
1839 	hvarray[hv++] = &gcd[k-1]; hvarray[hv++] = NULL;
1840 
1841 	label[k].text = (unichar_t *) _("_FDEF");
1842 	label[k].text_in_resource = true;
1843 	label[k].text_is_1byte = true;
1844 	gcd[k].gd.label = &label[k];
1845 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-3].gd.pos.y+24+6;
1846 	gcd[k].gd.flags = gg_enabled|gg_visible;
1847 	gcd[k].gd.cid = CID_FDefs+1000;
1848 	gcd[k++].creator = GLabelCreate;
1849 	hvarray[hv++] = &gcd[k-1];
1850 
1851 	sprintf( buffer[4], "%d", (data[20]<<8)|data[20+1] );
1852 	label[k].text = (unichar_t *) buffer[4];
1853 	label[k].text_is_1byte = true;
1854 	gcd[k].gd.label = &label[k];
1855 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-6;  gcd[k].gd.pos.width = 50;
1856 	gcd[k].gd.flags = gg_enabled|gg_visible;
1857 	gcd[k].gd.cid = CID_FDefs;
1858 	gcd[k++].creator = GTextFieldCreate;
1859 	hvarray[hv++] = &gcd[k-1];
1860 
1861 	label[k].text = (unichar_t *) _("_IDEFs");
1862 	label[k].text_in_resource = true;
1863 	label[k].text_is_1byte = true;
1864 	gcd[k].gd.label = &label[k];
1865 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
1866 	gcd[k].gd.flags = gg_enabled|gg_visible;
1867 	gcd[k].gd.cid = CID_IDefs+1000;
1868 	gcd[k++].creator = GLabelCreate;
1869 	hvarray[hv++] = &gcd[k-1];
1870 
1871 	sprintf( buffer[5], "%d", (data[22]<<8)|data[22+1] );
1872 	label[k].text = (unichar_t *) buffer[5];
1873 	label[k].text_is_1byte = true;
1874 	gcd[k].gd.label = &label[k];
1875 	gcd[k].gd.pos.x = gcd[k-4].gd.pos.x; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;  gcd[k].gd.pos.width = 50;
1876 	gcd[k].gd.flags = gg_enabled|gg_visible;
1877 	gcd[k].gd.cid = CID_IDefs;
1878 	gcd[k++].creator = GTextFieldCreate;
1879 	hvarray[hv++] = &gcd[k-1]; hvarray[hv++] = NULL; hvarray[hv++] = NULL;
1880 
1881 	boxes[2].gd.flags = gg_enabled|gg_visible;
1882 	boxes[2].gd.u.boxelements = hvarray;
1883 	boxes[2].creator = GHVBoxCreate;
1884 	varray[0] = &boxes[2]; varray[1] = NULL;
1885 	varray[2] = GCD_Glue; varray[3] = NULL;
1886 
1887     gcd[k].gd.pos.x = 20-3; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+35-3;
1888     gcd[k].gd.pos.width = -1; gcd[k].gd.pos.height = 0;
1889     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
1890     label[k].text = (unichar_t *) _("_OK");
1891     label[k].text_in_resource = true;
1892     label[k].text_is_1byte = true;
1893     gcd[k].gd.label = &label[k];
1894     gcd[k].gd.handle_controlevent = Maxp_OK;
1895     gcd[k++].creator = GButtonCreate;
1896     butarray[0] = GCD_Glue; butarray[1] = &gcd[k-1]; butarray[2] = GCD_Glue;
1897 
1898     gcd[k].gd.pos.x = -20; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
1899     gcd[k].gd.pos.width = -1; gcd[k].gd.pos.height = 0;
1900     gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1901     label[k].text = (unichar_t *) _("_Cancel");
1902     label[k].text_is_1byte = true;
1903     label[k].text_in_resource = true;
1904     gcd[k].gd.label = &label[k];
1905     gcd[k].gd.handle_controlevent = Maxp_Cancel;
1906     gcd[k++].creator = GButtonCreate;
1907     butarray[3] = GCD_Glue; butarray[4] = &gcd[k-1]; butarray[5] = GCD_Glue;
1908     butarray[6] = NULL;
1909 
1910     boxes[3].gd.flags = gg_enabled|gg_visible;
1911     boxes[3].gd.u.boxelements = butarray;
1912     boxes[3].creator = GHBoxCreate;
1913     varray[4] = &boxes[3]; varray[5] = NULL;
1914     varray[6] = NULL;
1915 
1916     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
1917     boxes[0].gd.flags = gg_enabled|gg_visible;
1918     boxes[0].gd.u.boxelements = varray;
1919     boxes[0].creator = GHVGroupCreate;
1920 
1921     GGadgetsCreate(gw,boxes);
1922     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
1923     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandgluesame);
1924     GHVBoxFitWindow(boxes[0].ret);
1925     GDrawSetVisible(gw,true);
1926     while ( !mp.done )
1927 	GDrawProcessOneEvent(NULL);
1928     GDrawDestroyWindow(gw);
1929 }
1930 
SFEditTable(SplineFont * sf,uint32 tag)1931 void SFEditTable(SplineFont *sf, uint32 tag) {
1932     struct instrdata *id;
1933     struct ttf_table *tab;
1934     char name[12];
1935     char title[100];
1936 
1937     /* In multiple master fonts the 'fpgm' and 'prep' tables are stored in the*/
1938     /*  normal instance of the font. The other instances must share it */
1939     /* On the other hand, everyone can have their own cvt table */
1940     if ( tag!=CHR('c','v','t',' ') )
1941 	if ( sf->mm!=NULL && sf->mm->apple )
1942 	    sf = sf->mm->normal;
1943 
1944     tab = SFFindTable(sf,tag);
1945     if ( tag==CHR('m','a','x','p') ) {
1946 	maxpCreateEditor(tab,sf,tag);
1947     } else if ( tag!=CHR('c','v','t',' ') ) {
1948 	for ( id = sf->instr_dlgs; id!=NULL && id->tag!=tag; id=id->next );
1949 	if ( id!=NULL ) {
1950 	    GDrawSetVisible(id->id->gw,true);
1951 	    GDrawRaise(id->id->gw);
1952 return;
1953 	}
1954 
1955 	id = calloc(1,sizeof(*id));
1956 	id->sf = sf;
1957 	id->tag = tag;
1958 	id->instr_cnt = id->max = tab==NULL ? 0 : tab->len;
1959 	id->instrs = malloc(id->max+1);
1960 	if ( tab!=NULL && tab->data!=NULL )
1961 	    memcpy(id->instrs,tab->data,id->instr_cnt);
1962 	else
1963 	    id->instrs[0]='\0';
1964 	name[0] = name[5] = '\'';
1965 	name[1] = tag>>24; name[2] = (tag>>16)&0xff; name[3] = (tag>>8)&0xff; name[4] = tag&0xff;
1966 	name[6] = 0;
1967 	sprintf(title,_("TrueType Instructions for %.50s"),name);
1968 	InstrDlgCreate(id,title);
1969     } else {
1970 	if ( sf->cvt_dlg!=NULL ) {
1971 	    GDrawSetVisible(sf->cvt_dlg->gw,true);
1972 	    GDrawRaise(sf->cvt_dlg->gw);
1973 return;
1974 	}
1975 	cvtCreateEditor(tab,sf,tag);
1976     }
1977 }
1978