Line data Source code
1 : /* -*- coding: utf-8 -*- */
2 : /* Copyright (C) 2003-2012 by George Williams */
3 : /*
4 : * Redistribution and use in source and binary forms, with or without
5 : * modification, are permitted provided that the following conditions are met:
6 :
7 : * Redistributions of source code must retain the above copyright notice, this
8 : * list of conditions and the following disclaimer.
9 :
10 : * Redistributions in binary form must reproduce the above copyright notice,
11 : * this list of conditions and the following disclaimer in the documentation
12 : * and/or other materials provided with the distribution.
13 :
14 : * The name of the author may not be used to endorse or promote products
15 : * derived from this software without specific prior written permission.
16 :
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : */
28 : #include "fontforgeui.h"
29 : #include "lookups.h"
30 : #include "ttf.h"
31 : #include <chardata.h>
32 : #include <utype.h>
33 : #include <ustring.h>
34 : #include <gkeysym.h>
35 :
36 : #define CID_Classes 305
37 :
38 :
39 : #define CID_Ok 307
40 : #define CID_Cancel 308
41 :
42 : #define CID_Line1 309
43 : #define CID_Line2 310
44 : #define CID_Group 311
45 :
46 : #define CID_Set 313
47 : #define CID_Select 314
48 :
49 : #define CID_RightToLeft 318
50 : #define CID_VertOnly 319
51 :
52 : #define SMD_WIDTH 350
53 : #define SMD_HEIGHT 400
54 : #define SMD_CANCELDROP 32
55 : #define SMD_DIRDROP 88
56 :
57 : #define CID_NextState 400
58 : #define CID_Flag4000 401
59 : #define CID_Flag8000 402
60 : #define CID_Flag2000 403
61 : #define CID_Flag1000 404
62 : #define CID_Flag0800 405
63 : #define CID_Flag0400 406
64 : #define CID_IndicVerb 407
65 : #define CID_InsCur 408
66 : #define CID_InsMark 409
67 : #define CID_TagCur 410
68 : #define CID_TagMark 411
69 : #define CID_Kerns 412
70 : #define CID_StateClass 413
71 :
72 : #define CID_Up 420
73 : #define CID_Down 421
74 : #define CID_Left 422
75 : #define CID_Right 423
76 :
77 : #define SMDE_WIDTH 200
78 : #define SMDE_HEIGHT (SMD_DIRDROP+200)
79 :
80 : extern int _GScrollBar_Width;
81 :
82 : typedef struct statemachinedlg {
83 : GWindow gw, editgw;
84 : int state_cnt, class_cnt, index;
85 : struct asm_state *states;
86 : GGadget *hsb, *vsb;
87 : ASM *sm;
88 : SplineFont *sf;
89 : struct gfi_data *d;
90 : int isnew;
91 : GFont *font;
92 : int fh, as;
93 : int stateh, statew;
94 : int xstart, ystart; /* This is where the headers start */
95 : int xstart2, ystart2; /* This is where the data start */
96 : int width, height;
97 : int offleft, offtop;
98 : int canceldrop, sbdrop;
99 : GTextInfo *mactags;
100 : int isedit;
101 : int st_pos;
102 : int edit_done, edit_ok;
103 : int done;
104 : } SMD;
105 :
106 : static int SMD_SBReset(SMD *smd);
107 : static void SMD_HShow(SMD *smd,int pos);
108 :
109 : static char *indicverbs[2][16] = {
110 : { "", "Ax", "xD", "AxD", "ABx", "ABx", "xCD", "xCD",
111 : "AxCD", "AxCD", "ABxD", "ABxD", "ABxCD", "ABxCD", "ABxCD", "ABxCD" },
112 : { "", "xA", "Dx", "DxA", "xAB", "xBA", "CDx", "DCx",
113 : "CDxA", "DCxA", "DxAB", "DxBA", "CDxAB", "CDxBA", "DCxAB", "DCxBA" }};
114 :
115 0 : static void StatesFree(struct asm_state *old,int old_class_cnt,int old_state_cnt,
116 : enum asm_type type) {
117 : int i, j;
118 :
119 0 : if ( type==asm_insert ) {
120 0 : for ( i=0; i<old_state_cnt ; ++i ) {
121 0 : for ( j=0; j<old_class_cnt; ++j ) {
122 0 : struct asm_state *this = &old[i*old_class_cnt+j];
123 0 : free(this->u.insert.mark_ins);
124 0 : free(this->u.insert.cur_ins);
125 : }
126 : }
127 0 : } else if ( type==asm_kern ) {
128 0 : for ( i=0; i<old_state_cnt ; ++i ) {
129 0 : for ( j=0; j<old_class_cnt; ++j ) {
130 0 : struct asm_state *this = &old[i*old_class_cnt+j];
131 0 : free(this->u.kern.kerns);
132 : }
133 : }
134 : }
135 0 : free(old);
136 0 : }
137 :
138 0 : static struct asm_state *StateCopy(struct asm_state *old,int old_class_cnt,int old_state_cnt,
139 : int new_class_cnt,int new_state_cnt, enum asm_type type,int freeold) {
140 0 : struct asm_state *new = calloc(new_class_cnt*new_state_cnt,sizeof(struct asm_state));
141 : int i,j;
142 0 : int minclass = new_class_cnt<old_class_cnt ? new_class_cnt : old_class_cnt;
143 :
144 0 : for ( i=0; i<old_state_cnt && i<new_state_cnt; ++i ) {
145 0 : memcpy(new+i*new_class_cnt, old+i*old_class_cnt, minclass*sizeof(struct asm_state));
146 0 : if ( type==asm_insert ) {
147 0 : for ( j=0; j<minclass; ++j ) {
148 0 : struct asm_state *this = &new[i*new_class_cnt+j];
149 0 : this->u.insert.mark_ins = copy(this->u.insert.mark_ins);
150 0 : this->u.insert.cur_ins = copy(this->u.insert.cur_ins);
151 : }
152 0 : } else if ( type==asm_kern ) {
153 0 : for ( j=0; j<minclass; ++j ) {
154 0 : struct asm_state *this = &new[i*new_class_cnt+j];
155 : int16 *temp;
156 0 : temp = malloc(this->u.kern.kcnt*sizeof(int16));
157 0 : memcpy(temp,this->u.kern.kerns,this->u.kern.kcnt*sizeof(int16));
158 0 : this->u.kern.kerns = temp;
159 : }
160 : }
161 : }
162 0 : for ( ; i<new_state_cnt; ++i )
163 0 : new[i*new_class_cnt+2].next_state = i; /* Deleted glyphs should be treated as noops */
164 :
165 0 : if ( freeold )
166 0 : StatesFree(old,old_class_cnt,old_state_cnt,type);
167 :
168 0 : return( new );
169 : }
170 :
171 0 : static void StateRemoveClasses(SMD *smd, int removeme ) {
172 : struct asm_state *new;
173 : int i,j,k;
174 :
175 0 : if ( removeme<4 )
176 0 : return;
177 :
178 0 : new = calloc((smd->class_cnt-1)*smd->state_cnt,sizeof(struct asm_state));
179 0 : for ( i=0; i<smd->state_cnt ; ++i ) {
180 0 : for ( j=k=0; j<smd->class_cnt; ++j ) {
181 0 : if ( j!=removeme )
182 0 : new[i*(smd->class_cnt-1)+k++] = smd->states[i*smd->class_cnt+j];
183 0 : else if ( smd->sm->type==asm_insert ) {
184 0 : free(smd->states[i*smd->class_cnt+j].u.insert.mark_ins);
185 0 : free(smd->states[i*smd->class_cnt+j].u.insert.cur_ins);
186 0 : } else if ( smd->sm->type==asm_kern ) {
187 0 : free(smd->states[i*smd->class_cnt+j].u.kern.kerns);
188 : }
189 : }
190 : }
191 :
192 0 : free(smd->states);
193 0 : smd->states = new;
194 0 : --smd->class_cnt;
195 : }
196 :
197 0 : static int FindMaxReachableStateCnt(SMD *smd) {
198 0 : int max_reachable = 1;
199 : int i, j, ns;
200 :
201 0 : for ( i=0; i<=max_reachable && i<smd->state_cnt; ++i ) {
202 0 : for ( j=0; j<smd->class_cnt; ++j ) {
203 0 : ns = smd->states[i*smd->class_cnt+j].next_state;
204 0 : if ( ns>max_reachable )
205 0 : max_reachable = ns;
206 : }
207 : }
208 0 : return( max_reachable+1 ); /* The count is one more than the max */
209 : }
210 :
211 : /* ************************************************************************** */
212 : /* ****************************** Edit a State ****************************** */
213 : /* ************************************************************************** */
214 : GTextInfo indicverbs_list[] = {
215 : { (unichar_t *) N_("No Change"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
216 : { (unichar_t *) N_("Ax => xA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
217 : { (unichar_t *) N_("xD => Dx"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
218 : { (unichar_t *) N_("AxD => DxA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
219 : { (unichar_t *) N_("ABx => xAB"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
220 : { (unichar_t *) N_("ABx => xBA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
221 : { (unichar_t *) N_("xCD => CDx"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
222 : { (unichar_t *) N_("xCD => DCx"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
223 : { (unichar_t *) N_("AxCD => CDxA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
224 : { (unichar_t *) N_("AxCD => DCxA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
225 : { (unichar_t *) N_("ABxD => DxAB"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
226 : { (unichar_t *) N_("ABxD => DxBA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
227 : { (unichar_t *) N_("ABxCD => CDxAB"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
228 : { (unichar_t *) N_("ABxCD => CDxBA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
229 : { (unichar_t *) N_("ABxCD => DCxAB"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
230 : { (unichar_t *) N_("ABxCD => DCxBA"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
231 : GTEXTINFO_EMPTY
232 : };
233 :
234 0 : static char *copy_count(GWindow gw,int cid,int *cnt) {
235 0 : const unichar_t *u = _GGadgetGetTitle(GWidgetGetControl(gw,cid)), *upt;
236 : char *ret, *pt;
237 : int c;
238 :
239 0 : while ( *u==' ' ) ++u;
240 0 : if ( *u=='\0' ) {
241 0 : *cnt = 0;
242 0 : return( NULL );
243 : }
244 :
245 0 : ret = pt = malloc(u_strlen(u)+1);
246 0 : c = 0;
247 0 : for ( upt=u; *upt; ) {
248 0 : if ( *upt==' ' ) {
249 0 : while ( *upt==' ' ) ++upt;
250 0 : if ( *upt!='\0' ) {
251 0 : ++c;
252 0 : *pt++ = ' ';
253 : }
254 : } else
255 0 : *pt++ = *upt++;
256 : }
257 0 : *pt = '\0';
258 0 : *cnt = c+1;
259 0 : return( ret );
260 : }
261 :
262 0 : static void SMD_Fillup(SMD *smd) {
263 0 : int state = smd->st_pos/smd->class_cnt;
264 0 : int class = smd->st_pos%smd->class_cnt;
265 0 : struct asm_state *this = &smd->states[smd->st_pos];
266 : char buffer[100];
267 : char buf[100], *temp;
268 : int j;
269 0 : GGadget *list = GWidgetGetControl( smd->gw, CID_Classes );
270 : int rows;
271 0 : struct matrix_data *classes = GMatrixEditGet(list,&rows);
272 :
273 0 : snprintf(buffer,sizeof(buffer)/sizeof(buffer[0]),
274 0 : _("State %d, %.40s"), state, classes[class*1+0].u.md_str );
275 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_StateClass),buffer);
276 0 : sprintf(buf,"%d", this->next_state );
277 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_NextState),buf);
278 :
279 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag4000),
280 0 : this->flags&0x4000?0:1);
281 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag8000),
282 0 : this->flags&0x8000?1:0);
283 0 : if ( smd->sm->type==asm_indic ) {
284 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag2000),
285 0 : this->flags&0x2000?1:0);
286 0 : GGadgetSelectOneListItem(GWidgetGetControl(smd->editgw,CID_IndicVerb),
287 0 : this->flags&0xf);
288 0 : } else if ( smd->sm->type==asm_insert ) {
289 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag2000),
290 0 : this->flags&0x2000?1:0);
291 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag1000),
292 0 : this->flags&0x1000?1:0);
293 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag0800),
294 0 : this->flags&0x0800?1:0);
295 0 : GGadgetSetChecked(GWidgetGetControl(smd->editgw,CID_Flag0400),
296 0 : this->flags&0x0400?1:0);
297 0 : temp = this->u.insert.mark_ins;
298 0 : buffer[0]='\0';
299 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_InsMark),temp==NULL?buffer:temp);
300 0 : temp = this->u.insert.cur_ins;
301 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_InsCur),temp==NULL?buffer:temp);
302 0 : } else if ( smd->sm->type==asm_kern ) {
303 0 : buf[0] = '\0';
304 0 : for ( j=0; j<this->u.kern.kcnt; ++j )
305 0 : sprintf( buf+strlen(buf), "%d ", this->u.kern.kerns[j]);
306 0 : if ( buf[0]!='\0' && buf[strlen(buf)-1]==' ' )
307 0 : buf[strlen(buf)-1] = '\0';
308 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_Kerns),buf);
309 : } else {
310 0 : if ( this->u.context.mark_lookup != NULL )
311 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_TagMark),this->u.context.mark_lookup->lookup_name);
312 0 : if ( this->u.context.cur_lookup != NULL )
313 0 : GGadgetSetTitle8(GWidgetGetControl(smd->editgw,CID_TagCur),this->u.context.cur_lookup->lookup_name);
314 : }
315 :
316 0 : GGadgetSetEnabled(GWidgetGetControl(smd->editgw,CID_Up), state!=0 );
317 0 : GGadgetSetEnabled(GWidgetGetControl(smd->editgw,CID_Left), class!=0 );
318 0 : GGadgetSetEnabled(GWidgetGetControl(smd->editgw,CID_Right), class<smd->class_cnt-1 );
319 0 : GGadgetSetEnabled(GWidgetGetControl(smd->editgw,CID_Down), state<smd->state_cnt-1 );
320 0 : }
321 :
322 0 : static int SMD_DoChange(SMD *smd) {
323 0 : struct asm_state *this = &smd->states[smd->st_pos];
324 0 : int err=false, ns, flags, cnt;
325 : char *mins, *cins;
326 : OTLookup *mlook, *clook;
327 : const unichar_t *ret;
328 : unichar_t *end;
329 : char *ret8;
330 : int16 kbuf[9];
331 : int kerns;
332 0 : int oddcomplain=false;
333 :
334 0 : ns = GetInt8(smd->editgw,CID_NextState,_("Next State:"),&err);
335 0 : if ( err )
336 0 : return( false );
337 0 : flags = 0;
338 0 : if ( !GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag4000)) ) flags |= 0x4000;
339 0 : if ( GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag8000)) ) flags |= 0x8000;
340 0 : if ( smd->sm->type==asm_indic ) {
341 0 : if ( GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag2000)) ) flags |= 0x2000;
342 0 : flags |= GGadgetGetFirstListSelectedItem(GWidgetGetControl(smd->editgw,CID_IndicVerb));
343 0 : this->next_state = ns;
344 0 : this->flags = flags;
345 0 : } else if ( smd->sm->type==asm_kern ) {
346 0 : ret = _GGadgetGetTitle(GWidgetGetControl(smd->editgw,CID_Kerns));
347 0 : kerns=0;
348 0 : while ( *ret!='\0' ) {
349 0 : while ( *ret==' ' ) ++ret;
350 0 : if ( *ret=='\0' )
351 0 : break;
352 0 : kbuf[kerns] = u_strtol(ret,&end,10);
353 0 : if ( end==ret ) {
354 0 : GGadgetProtest8(_("Kern Values:"));
355 0 : return( false );
356 0 : } else if ( kerns>=8 ) {
357 0 : ff_post_error(_("Too Many Kerns"),_("At most 8 kerning values may be specified here"));
358 0 : return( false );
359 0 : } else if ( kbuf[kerns]&1 ) {
360 0 : kbuf[kerns] &= ~1;
361 0 : if ( !oddcomplain )
362 0 : ff_post_notice(_("Kerning values must be even"),_("Kerning values must be even"));
363 0 : oddcomplain = true;
364 : }
365 0 : ++kerns;
366 0 : ret = end;
367 : }
368 0 : this->next_state = ns;
369 0 : this->flags = flags;
370 0 : free(this->u.kern.kerns);
371 0 : this->u.kern.kcnt = kerns;
372 0 : if ( kerns==0 )
373 0 : this->u.kern.kerns = NULL;
374 : else {
375 0 : this->u.kern.kerns = malloc(kerns*sizeof(int16));
376 0 : memcpy(this->u.kern.kerns,kbuf,kerns*sizeof(int16));
377 : }
378 0 : } else if ( smd->sm->type==asm_context ) {
379 0 : ret8 = GGadgetGetTitle8(GWidgetGetControl(smd->editgw,CID_TagMark));
380 0 : if ( *ret8=='\0' )
381 0 : mlook = NULL; /* That's ok */
382 0 : else if ( (mlook=SFFindLookup(smd->sf,ret8))==NULL ) {
383 0 : ff_post_error(_("Unknown lookup"),_("Lookup, %s, does not exist"), ret8 );
384 0 : free(ret8);
385 0 : return( false );
386 0 : } else if ( mlook->lookup_type!=gsub_single ) {
387 0 : ff_post_error(_("Bad lookup type"),_("Lookups in contextual state machines must be simple substitutions,\n, but %s is not"), ret8 );
388 0 : free(ret8);
389 0 : return( false );
390 : }
391 0 : free(ret8);
392 0 : ret8 = GGadgetGetTitle8(GWidgetGetControl(smd->editgw,CID_TagCur));
393 0 : if ( *ret8=='\0' )
394 0 : clook = NULL; /* That's ok */
395 0 : else if ( (clook=SFFindLookup(smd->sf,ret8))==NULL ) {
396 0 : ff_post_error(_("Unknown lookup"),_("Lookup, %s, does not exist"), ret8 );
397 0 : free(ret8);
398 0 : return( false );
399 0 : } else if ( clook->lookup_type!=gsub_single ) {
400 0 : ff_post_error(_("Bad lookup type"),_("Lookups in contextual state machines must be simple substitutions,\n, but %s is not"), ret8 );
401 0 : free(ret8);
402 0 : return( false );
403 : }
404 0 : this->next_state = ns;
405 0 : this->flags = flags;
406 0 : this->u.context.mark_lookup = mlook;
407 0 : this->u.context.cur_lookup = clook;
408 : } else {
409 :
410 0 : if ( GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag2000)) ) flags |= 0x2000;
411 0 : if ( GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag1000)) ) flags |= 0x1000;
412 0 : if ( GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag0800)) ) flags |= 0x0800;
413 0 : if ( GGadgetIsChecked(GWidgetGetControl(smd->editgw,CID_Flag0400)) ) flags |= 0x0400;
414 :
415 0 : mins = copy_count(smd->editgw,CID_InsMark,&cnt);
416 0 : if ( cnt>31 ) {
417 0 : ff_post_error(_("Too Many Glyphs"),_("At most 31 glyphs may be specified in an insert list"));
418 0 : free(mins);
419 0 : return( false );
420 : }
421 0 : flags |= cnt<<5;
422 :
423 0 : cins = copy_count(smd->editgw,CID_InsCur,&cnt);
424 0 : if ( cnt>31 ) {
425 0 : ff_post_error(_("Too Many Glyphs"),_("At most 31 glyphs may be specified in an insert list"));
426 0 : free(mins);
427 0 : free(cins);
428 0 : return( false );
429 : }
430 0 : flags |= cnt;
431 0 : this->next_state = ns;
432 0 : this->flags = flags;
433 0 : free(this->u.insert.mark_ins);
434 0 : free(this->u.insert.cur_ins);
435 0 : this->u.insert.mark_ins = mins;
436 0 : this->u.insert.cur_ins = cins;
437 : }
438 :
439 : /* Show changes in main window */
440 0 : GDrawRequestExpose(smd->gw,NULL,false);
441 0 : return( true );
442 : }
443 :
444 0 : static int SMDE_Arrow(GGadget *g, GEvent *e) {
445 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
446 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
447 0 : int state = smd->st_pos/smd->class_cnt;
448 0 : int class = smd->st_pos%smd->class_cnt;
449 0 : switch( GGadgetGetCid(g)) {
450 : case CID_Up:
451 0 : if ( state!=0 ) --state;
452 0 : break;
453 : case CID_Left:
454 0 : if ( class!=0 ) --class;
455 0 : break;
456 : case CID_Right:
457 0 : if ( class<smd->class_cnt-1 ) ++class;
458 0 : break;
459 : case CID_Down:
460 0 : if ( state<smd->state_cnt-1 ) ++state;
461 0 : break;
462 : }
463 0 : if ( state!=smd->st_pos/smd->class_cnt || class!=smd->st_pos%smd->class_cnt ) {
464 0 : if ( SMD_DoChange(smd)) {
465 0 : smd->st_pos = state*smd->class_cnt+class;
466 0 : SMD_Fillup(smd);
467 : }
468 : }
469 : }
470 0 : return( true );
471 : }
472 :
473 0 : static int smdedit_e_h(GWindow gw, GEvent *event) {
474 0 : SMD *smd = GDrawGetUserData(gw);
475 :
476 0 : switch ( event->type ) {
477 : case et_close:
478 0 : smd->edit_done = true;
479 0 : smd->edit_ok = false;
480 0 : break;
481 : case et_char:
482 0 : if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
483 0 : help("statemachine.html#EditTransition");
484 0 : return( true );
485 0 : } else if ( event->u.chr.keysym == GK_Escape ) {
486 0 : smd->edit_done = true;
487 0 : return( true );
488 0 : } else if ( event->u.chr.chars[0] == '\r' ) {
489 0 : smd->edit_done = SMD_DoChange(smd);
490 0 : return( true );
491 : }
492 0 : return( false );
493 : case et_controlevent:
494 0 : switch( event->u.control.subtype ) {
495 : case et_buttonactivate:
496 0 : if ( GGadgetGetCid(event->u.control.g)==CID_Ok )
497 0 : smd->edit_done = SMD_DoChange(smd);
498 : else
499 0 : smd->edit_done = true;
500 0 : break;
501 : }
502 0 : break;
503 : }
504 0 : return( true );
505 : }
506 :
507 0 : static void SMD_EditState(SMD *smd) {
508 : GWindow gw;
509 : GWindowAttrs wattrs;
510 : GGadgetCreateData gcd[23];
511 : GTextInfo label[23];
512 : GRect pos;
513 : int k, listk, new_cnt;
514 : char stateclass[100];
515 : static int indicv_done = false;
516 :
517 0 : smd->edit_done = false;
518 :
519 0 : memset(&wattrs,0,sizeof(wattrs));
520 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
521 0 : wattrs.event_masks = ~(1<<et_charup);
522 0 : wattrs.is_dlg = true;
523 0 : wattrs.restrict_input_to_me = true;
524 0 : wattrs.undercursor = 1;
525 0 : wattrs.cursor = ct_pointer;
526 0 : wattrs.utf8_window_title = _("Edit State Transition");
527 0 : pos.x = pos.y = 0;
528 0 : pos.width = GDrawPointsToPixels(NULL,GGadgetScale(SMDE_WIDTH));
529 0 : pos.height = GDrawPointsToPixels(NULL,SMDE_HEIGHT);
530 0 : smd->editgw = gw = GDrawCreateTopWindow(NULL,&pos,smdedit_e_h,smd,&wattrs);
531 :
532 0 : memset(gcd,0,sizeof(gcd));
533 0 : memset(label,0,sizeof(label));
534 0 : k = 0; listk = -1;
535 :
536 0 : snprintf(stateclass,sizeof(stateclass), _("State %d, %.40s"),
537 : 999, _("Class 1: {Everything Else}" ));
538 0 : label[k].text = (unichar_t *) stateclass;
539 0 : label[k].text_is_1byte = true;
540 0 : gcd[k].gd.label = &label[k];
541 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = 5;
542 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
543 0 : gcd[k].gd.cid = CID_StateClass;
544 0 : gcd[k++].creator = GLabelCreate;
545 :
546 0 : label[k].text = (unichar_t *) _("Next State:");
547 0 : label[k].text_is_1byte = true;
548 0 : gcd[k].gd.label = &label[k];
549 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+13+4;
550 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
551 0 : gcd[k++].creator = GLabelCreate;
552 :
553 0 : gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
554 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
555 0 : gcd[k].gd.cid = CID_NextState;
556 0 : gcd[k++].creator = GTextFieldCreate;
557 :
558 0 : label[k].text = (unichar_t *) _("Advance To Next Glyph");
559 0 : label[k].text_is_1byte = true;
560 0 : gcd[k].gd.label = &label[k];
561 0 : gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+24;
562 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
563 0 : gcd[k].gd.cid = CID_Flag4000;
564 0 : gcd[k++].creator = GCheckBoxCreate;
565 :
566 0 : label[k].text = (unichar_t *) (smd->sm->type==asm_kern?_("Push Current Glyph"):
567 0 : smd->sm->type!=asm_indic?_("Mark Current Glyph"):
568 : _("Mark Current Glyph As First"));
569 0 : label[k].text_is_1byte = true;
570 0 : gcd[k].gd.label = &label[k];
571 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
572 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
573 0 : gcd[k].gd.cid = CID_Flag8000;
574 0 : gcd[k++].creator = GCheckBoxCreate;
575 :
576 0 : if ( smd->sm->type==asm_indic ) {
577 0 : if ( !indicv_done ) {
578 : int i;
579 0 : for ( i=0; indicverbs_list[i].text!=NULL; ++i )
580 0 : indicverbs_list[i].text = (unichar_t *) _((char *) indicverbs_list[i].text );
581 0 : indicv_done = true;
582 : }
583 0 : label[k].text = (unichar_t *) _("Mark Current Glyph As Last");
584 0 : label[k].text_is_1byte = true;
585 0 : gcd[k].gd.label = &label[k];
586 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
587 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
588 0 : gcd[k].gd.cid = CID_Flag2000;
589 0 : gcd[k++].creator = GCheckBoxCreate;
590 :
591 0 : gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+24;
592 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
593 0 : gcd[k].gd.u.list = indicverbs_list;
594 0 : gcd[k].gd.cid = CID_IndicVerb;
595 0 : gcd[k++].creator = GListButtonCreate;
596 0 : } else if ( smd->sm->type==asm_insert ) {
597 0 : label[k].text = (unichar_t *) _("Current Glyph Is Kashida Like");
598 0 : label[k].text_is_1byte = true;
599 0 : gcd[k].gd.label = &label[k];
600 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
601 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
602 0 : gcd[k].gd.cid = CID_Flag2000;
603 0 : gcd[k++].creator = GCheckBoxCreate;
604 :
605 0 : label[k].text = (unichar_t *) _("Marked Glyph Is Kashida Like");
606 0 : label[k].text_is_1byte = true;
607 0 : gcd[k].gd.label = &label[k];
608 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
609 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
610 0 : gcd[k].gd.cid = CID_Flag1000;
611 0 : gcd[k++].creator = GCheckBoxCreate;
612 :
613 0 : label[k].text = (unichar_t *) _("Insert Before Current Glyph");
614 0 : label[k].text_is_1byte = true;
615 0 : gcd[k].gd.label = &label[k];
616 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
617 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
618 0 : gcd[k].gd.cid = CID_Flag0800;
619 0 : gcd[k++].creator = GCheckBoxCreate;
620 :
621 0 : label[k].text = (unichar_t *) _("Insert Before Marked Glyph");
622 0 : label[k].text_is_1byte = true;
623 0 : gcd[k].gd.label = &label[k];
624 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16;
625 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
626 0 : gcd[k].gd.cid = CID_Flag0400;
627 0 : gcd[k++].creator = GCheckBoxCreate;
628 :
629 0 : label[k].text = (unichar_t *) _("Mark Insert:");
630 0 : label[k].text_is_1byte = true;
631 0 : gcd[k].gd.label = &label[k];
632 0 : gcd[k].gd.pos.x = gcd[k-1].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+26;
633 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
634 0 : gcd[k++].creator = GLabelCreate;
635 :
636 0 : gcd[k].gd.pos.x = gcd[2].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
637 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
638 0 : gcd[k].gd.cid = CID_InsMark;
639 0 : gcd[k++].creator = GTextFieldCreate;
640 :
641 0 : label[k].text = (unichar_t *) _("Current Insert:");
642 0 : label[k].text_is_1byte = true;
643 0 : gcd[k].gd.label = &label[k];
644 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+30;
645 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
646 0 : gcd[k++].creator = GLabelCreate;
647 :
648 0 : gcd[k].gd.pos.x = gcd[2].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
649 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
650 0 : gcd[k].gd.cid = CID_InsCur;
651 0 : gcd[k++].creator = GTextFieldCreate;
652 0 : } else if ( smd->sm->type==asm_kern ) {
653 0 : label[k].text = (unichar_t *) _("Kern Values:");
654 0 : label[k].text_is_1byte = true;
655 0 : gcd[k].gd.label = &label[k];
656 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+26;
657 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
658 0 : gcd[k++].creator = GLabelCreate;
659 :
660 0 : gcd[k].gd.pos.x = gcd[2].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
661 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
662 0 : gcd[k].gd.cid = CID_Kerns;
663 0 : gcd[k++].creator = GTextFieldCreate;
664 : } else {
665 0 : label[k].text = (unichar_t *) _("Mark Subs:");
666 0 : label[k].text_is_1byte = true;
667 0 : gcd[k].gd.label = &label[k];
668 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+26;
669 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
670 0 : gcd[k++].creator = GLabelCreate;
671 :
672 0 : listk = k;
673 0 : gcd[k].gd.pos.x = gcd[2].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
674 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
675 0 : gcd[k].gd.cid = CID_TagMark;
676 0 : gcd[k++].creator = GListFieldCreate;
677 :
678 0 : label[k].text = (unichar_t *) _("Current Subs:");
679 0 : label[k].text_is_1byte = true;
680 0 : gcd[k].gd.label = &label[k];
681 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+30;
682 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
683 0 : gcd[k++].creator = GLabelCreate;
684 :
685 0 : gcd[k].gd.pos.x = gcd[2].gd.pos.x; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;
686 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
687 0 : gcd[k].gd.cid = CID_TagCur;
688 0 : gcd[k].gd.u.list = gcd[k-2].gd.u.list;
689 0 : gcd[k++].creator = GListFieldCreate;
690 : }
691 :
692 0 : label[k].text = (unichar_t *) U_("_Up↑");
693 0 : label[k].text_is_1byte = true;
694 0 : label[k].text_in_resource = true;
695 0 : gcd[k].gd.label = &label[k];
696 0 : gcd[k].gd.pos.x = (SMDE_WIDTH-GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor))/2;
697 0 : gcd[k].gd.pos.y = SMDE_HEIGHT-SMD_DIRDROP;
698 0 : gcd[k].gd.pos.width = -1;
699 0 : gcd[k].gd.flags = gg_visible|gg_enabled;
700 0 : gcd[k].gd.cid = CID_Up;
701 0 : gcd[k].gd.handle_controlevent = SMDE_Arrow;
702 0 : gcd[k++].creator = GButtonCreate;
703 :
704 0 : label[k].text = (unichar_t *) U_("←_Left");
705 0 : label[k].text_is_1byte = true;
706 0 : label[k].text_in_resource = true;
707 0 : gcd[k].gd.label = &label[k];
708 0 : gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = SMDE_HEIGHT-SMD_DIRDROP+13;
709 0 : gcd[k].gd.pos.width = -1;
710 0 : gcd[k].gd.flags = gg_visible|gg_enabled;
711 0 : gcd[k].gd.cid = CID_Left;
712 0 : gcd[k].gd.handle_controlevent = SMDE_Arrow;
713 0 : gcd[k++].creator = GButtonCreate;
714 :
715 0 : label[k].text = (unichar_t *) U_("_Right→");
716 0 : label[k].text_is_1byte = true;
717 0 : label[k].text_in_resource = true;
718 0 : gcd[k].gd.label = &label[k];
719 0 : gcd[k].gd.pos.x = -10; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y;
720 0 : gcd[k].gd.pos.width = -1;
721 0 : gcd[k].gd.flags = gg_visible|gg_enabled;
722 0 : gcd[k].gd.cid = CID_Right;
723 0 : gcd[k].gd.handle_controlevent = SMDE_Arrow;
724 0 : gcd[k++].creator = GButtonCreate;
725 :
726 0 : label[k].text = (unichar_t *) U_("↓_Down");
727 0 : label[k].text_is_1byte = true;
728 0 : label[k].text_in_resource = true;
729 0 : gcd[k].gd.label = &label[k];
730 0 : gcd[k].gd.pos.x = gcd[k-3].gd.pos.x; gcd[k].gd.pos.y = SMDE_HEIGHT-SMD_DIRDROP+26;
731 0 : gcd[k].gd.pos.width = -1;
732 0 : gcd[k].gd.flags = gg_visible|gg_enabled;
733 0 : gcd[k].gd.cid = CID_Down;
734 0 : gcd[k].gd.handle_controlevent = SMDE_Arrow;
735 0 : gcd[k++].creator = GButtonCreate;
736 :
737 0 : label[k].text = (unichar_t *) _("_OK");
738 0 : label[k].text_is_1byte = true;
739 0 : label[k].text_in_resource = true;
740 0 : gcd[k].gd.label = &label[k];
741 0 : gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = SMDE_HEIGHT-SMD_CANCELDROP-3;
742 0 : gcd[k].gd.pos.width = -1;
743 0 : gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
744 0 : gcd[k].gd.cid = CID_Ok;
745 0 : gcd[k++].creator = GButtonCreate;
746 :
747 0 : label[k].text = (unichar_t *) _("_Cancel");
748 0 : label[k].text_is_1byte = true;
749 0 : label[k].text_in_resource = true;
750 0 : gcd[k].gd.label = &label[k];
751 0 : gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
752 0 : gcd[k].gd.pos.width = -1;
753 0 : gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
754 0 : gcd[k].gd.cid = CID_Cancel;
755 0 : gcd[k++].creator = GButtonCreate;
756 :
757 0 : gcd[k].gd.pos.x = 2; gcd[k].gd.pos.y = 2;
758 0 : gcd[k].gd.pos.width = pos.width-4;
759 0 : gcd[k].gd.pos.height = pos.height-4;
760 0 : gcd[k].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
761 0 : gcd[k++].creator = GGroupCreate;
762 :
763 0 : GGadgetsCreate(gw,gcd);
764 :
765 0 : if ( listk!=-1 ) {
766 0 : GGadgetSetList(gcd[listk].ret,
767 : SFLookupListFromType(smd->sf,gsub_single),false);
768 0 : GGadgetSetList(gcd[listk+2].ret,
769 : SFLookupListFromType(smd->sf,gsub_single),false);
770 : }
771 :
772 0 : SMD_Fillup(smd);
773 :
774 0 : GDrawSetVisible(gw,true);
775 :
776 0 : smd->edit_done = false;
777 0 : while ( !smd->edit_done )
778 0 : GDrawProcessOneEvent(NULL);
779 :
780 0 : new_cnt = FindMaxReachableStateCnt(smd);
781 0 : if ( new_cnt!=smd->state_cnt ) {
782 0 : smd->states = StateCopy(smd->states,smd->class_cnt,smd->state_cnt,
783 : smd->class_cnt,new_cnt,
784 0 : smd->sm->type,true);
785 0 : smd->state_cnt = new_cnt;
786 0 : SMD_SBReset(smd);
787 0 : GDrawRequestExpose(smd->gw,NULL,false);
788 : }
789 0 : smd->st_pos = -1;
790 0 : GDrawDestroyWindow(gw);
791 0 : return;
792 : }
793 :
794 : /* ************************************************************************** */
795 : /* ****************************** Main Dialog ******************************* */
796 : /* ************************************************************************** */
797 :
798 0 : static void _SMD_Finish(SMD *smd, int success) {
799 :
800 0 : GDrawDestroyWindow(smd->gw);
801 :
802 0 : GFI_FinishSMNew(smd->d,smd->sm,success,smd->isnew);
803 :
804 0 : GTextInfoListFree(smd->mactags);
805 0 : smd->done = true;
806 0 : }
807 :
808 0 : static void _SMD_Cancel(SMD *smd) {
809 :
810 0 : StatesFree(smd->states,smd->state_cnt,smd->class_cnt,smd->sm->type);
811 0 : _SMD_Finish(smd,false);
812 0 : }
813 :
814 0 : static int SMD_Cancel(GGadget *g, GEvent *e) {
815 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
816 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
817 :
818 0 : _SMD_Cancel(smd);
819 : }
820 0 : return( true );
821 : }
822 :
823 0 : static int SMD_Ok(GGadget *g, GEvent *e) {
824 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
825 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
826 : int i;
827 0 : struct ggadget * classControl = GWidgetGetControl(smd->gw,CID_Classes);
828 : int rows;
829 0 : struct matrix_data *classes = GMatrixEditGet(classControl,&rows);
830 :
831 0 : ASM *sm = smd->sm;
832 : char *upt;
833 :
834 0 : for ( i=4; i<sm->class_cnt; ++i )
835 0 : free(sm->classes[i]);
836 0 : free(sm->classes);
837 0 : sm->classes = malloc(smd->class_cnt*sizeof(char *));
838 0 : sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
839 0 : sm->class_cnt = smd->class_cnt;
840 0 : for ( i=4; i<sm->class_cnt; ++i ) {
841 0 : upt = strstr(classes[i].u.md_str,": ");
842 0 : if ( upt==NULL ) upt = classes[i].u.md_str; else upt += 2;
843 0 : sm->classes[i] = copy(GlyphNameListDeUnicode(upt));
844 : }
845 :
846 0 : StatesFree(sm->state,sm->state_cnt,sm->class_cnt,
847 0 : sm->type);
848 0 : sm->state_cnt = smd->state_cnt;
849 0 : sm->state = smd->states;
850 0 : sm->flags = (sm->flags & ~0xc000) |
851 0 : (GGadgetIsChecked(GWidgetGetControl(smd->gw,CID_RightToLeft))?0x4000:0) |
852 0 : (GGadgetIsChecked(GWidgetGetControl(smd->gw,CID_VertOnly))?0x8000:0);
853 0 : _SMD_Finish(smd,true);
854 : }
855 0 : return( true );
856 : }
857 :
858 0 : static void SMD_Mouse(SMD *smd,GEvent *event) {
859 : static unichar_t space[100];
860 : char *pt;
861 : char buf[30];
862 : int len;
863 : struct matrix_data *classes;
864 0 : int pos = ((event->u.mouse.y-smd->ystart2)/smd->stateh+smd->offtop) * smd->class_cnt +
865 0 : (event->u.mouse.x-smd->xstart2)/smd->statew + smd->offleft;
866 :
867 0 : GGadgetEndPopup();
868 :
869 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
870 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
871 0 : GGadgetDispatchEvent(smd->vsb,event);
872 0 : return;
873 : }
874 :
875 0 : if ( event->u.mouse.x<smd->xstart || event->u.mouse.x>smd->xstart2+smd->width ||
876 0 : event->u.mouse.y<smd->ystart || event->u.mouse.y>smd->ystart2+smd->height )
877 0 : return;
878 :
879 0 : if ( event->type==et_mousemove ) {
880 0 : int c = (event->u.mouse.x - smd->xstart2)/smd->statew + smd->offleft;
881 0 : int s = (event->u.mouse.y - smd->ystart2)/smd->stateh + smd->offtop;
882 0 : space[0] = '\0';
883 0 : if ( event->u.mouse.y>=smd->ystart2 && s<smd->state_cnt ) {
884 0 : sprintf( buf, "State %d\n", s );
885 0 : uc_strcpy(space,buf);
886 : }
887 0 : if ( event->u.mouse.x>=smd->xstart2 && c<smd->class_cnt ) {
888 0 : sprintf( buf, "Class %d\n", c );
889 0 : uc_strcat(space,buf);
890 0 : classes = GMatrixEditGet(GWidgetGetControl(smd->gw,CID_Classes),&len);
891 0 : len = u_strlen(space);
892 0 : pt = strstr(classes[c].u.md_str,": ");
893 0 : if ( pt==NULL ) pt = classes[c].u.md_str;
894 0 : else pt += 2;
895 0 : utf82u_strncpy(space+len,pt,(sizeof(space)/sizeof(space[0]))-1 - len);
896 0 : } else if ( event->u.mouse.x<smd->xstart2 ) {
897 0 : if ( s==0 )
898 0 : utf82u_strcat(space,_("{Start of Input}"));
899 0 : else if ( s==1 )
900 0 : utf82u_strcat(space,_("{Start of Line}"));
901 : }
902 0 : if ( space[0]=='\0' )
903 0 : return;
904 0 : if ( space[u_strlen(space)-1]=='\n' )
905 0 : space[u_strlen(space)-1]='\0';
906 0 : GGadgetPreparePopup(smd->gw,space);
907 0 : } else if ( event->u.mouse.x<smd->xstart2 || event->u.mouse.y<smd->ystart2 )
908 0 : return;
909 0 : else if ( event->type==et_mousedown )
910 0 : smd->st_pos = pos;
911 0 : else if ( event->type==et_mouseup ) {
912 0 : if ( pos==smd->st_pos )
913 0 : SMD_EditState(smd);
914 : }
915 : }
916 :
917 0 : static void SMD_Expose(SMD *smd,GWindow pixmap,GEvent *event) {
918 0 : GRect *area = &event->u.expose.rect;
919 : GRect rect;
920 : GRect clip,old1,old2;
921 0 : int len, off, i, j, x, y, kddd=false;
922 : unichar_t ubuf[8];
923 : char buf[101];
924 :
925 0 : if ( area->y+area->height<smd->ystart )
926 0 : return;
927 0 : if ( area->y>smd->ystart2+smd->height )
928 0 : return;
929 :
930 0 : GDrawPushClip(pixmap,area,&old1);
931 0 : GDrawSetFont(pixmap,smd->font);
932 0 : GDrawSetLineWidth(pixmap,0);
933 0 : rect.x = smd->xstart; rect.y = smd->ystart;
934 0 : rect.width = smd->width+(smd->xstart2-smd->xstart);
935 0 : rect.height = smd->height+(smd->ystart2-smd->ystart);
936 0 : clip = rect;
937 0 : GDrawPushClip(pixmap,&clip,&old2);
938 0 : for ( i=0 ; smd->offtop+i<=smd->state_cnt && (i-1)*smd->stateh<smd->height; ++i ) {
939 0 : GDrawDrawLine(pixmap,smd->xstart,smd->ystart2+i*smd->stateh,smd->xstart+rect.width,smd->ystart2+i*smd->stateh,
940 : 0x808080);
941 0 : if ( i+smd->offtop<smd->state_cnt ) {
942 0 : sprintf( buf, i+smd->offtop<100 ? "St%d" : "%d", i+smd->offtop );
943 0 : len = strlen( buf );
944 0 : off = (smd->stateh-len*smd->fh)/2;
945 0 : for ( j=0; j<len; ++j ) {
946 0 : ubuf[0] = buf[j];
947 0 : GDrawDrawText(pixmap,smd->xstart+3,smd->ystart2+i*smd->stateh+off+j*smd->fh+smd->as,
948 : ubuf,1,0xff0000);
949 : }
950 : }
951 : }
952 0 : for ( i=0 ; smd->offleft+i<=smd->class_cnt && (i-1)*smd->statew<smd->width; ++i ) {
953 0 : GDrawDrawLine(pixmap,smd->xstart2+i*smd->statew,smd->ystart,smd->xstart2+i*smd->statew,smd->ystart+rect.height,
954 : 0x808080);
955 0 : if ( i+smd->offleft<smd->class_cnt ) {
956 0 : GDrawDrawText8(pixmap,smd->xstart2+i*smd->statew+1,smd->ystart+smd->as+1,
957 : "Class",-1,0xff0000);
958 0 : sprintf( buf, "%d", i+smd->offleft );
959 0 : len = GDrawGetText8Width(pixmap,buf,-1);
960 0 : GDrawDrawText8(pixmap,smd->xstart2+i*smd->statew+(smd->statew-len)/2,smd->ystart+smd->fh+smd->as+1,
961 : buf,-1,0xff0000);
962 : }
963 : }
964 :
965 0 : for ( i=0 ; smd->offtop+i<smd->state_cnt && (i-1)*smd->stateh<smd->height; ++i ) {
966 0 : y = smd->ystart2+i*smd->stateh;
967 0 : if ( y>area->y+area->height )
968 0 : break;
969 0 : if ( y+smd->stateh<area->y )
970 0 : continue;
971 0 : for ( j=0 ; smd->offleft+j<smd->class_cnt && (j-1)*smd->statew<smd->width; ++j ) {
972 0 : struct asm_state *this = &smd->states[(i+smd->offtop)*smd->class_cnt+j+smd->offleft];
973 0 : x = smd->xstart2+j*smd->statew;
974 0 : if ( x>area->x+area->width )
975 0 : break;
976 0 : if ( x+smd->statew<area->x )
977 0 : continue;
978 :
979 0 : sprintf( buf, "%d", this->next_state );
980 0 : len = GDrawGetText8Width(pixmap,buf,-1);
981 0 : GDrawDrawText8(pixmap,x+(smd->statew-len)/2,y+smd->as+1,
982 : buf,-1,0x000000);
983 :
984 0 : ubuf[0] = (this->flags&0x8000)? 'M' : ' ';
985 0 : if ( smd->sm->type==asm_kern && (this->flags&0x8000))
986 0 : ubuf[0] = 'P';
987 0 : ubuf[1] = (this->flags&0x4000)? ' ' : 'A';
988 0 : ubuf[2] = '\0';
989 0 : if ( smd->sm->type==asm_indic ) {
990 0 : ubuf[2] = (this->flags&0x2000) ? 'L' : ' ';
991 0 : ubuf[3] = '\0';
992 : }
993 0 : len = GDrawGetTextWidth(pixmap,ubuf,-1);
994 0 : GDrawDrawText(pixmap,x+(smd->statew-len)/2,y+smd->fh+smd->as+1,
995 : ubuf,-1,0x000000);
996 :
997 0 : buf[0]='\0';
998 0 : if ( smd->sm->type==asm_indic ) {
999 0 : strcpy(buf,indicverbs[0][this->flags&0xf]);
1000 0 : } else if ( smd->sm->type==asm_context ) {
1001 0 : if ( this->u.context.mark_lookup!=NULL ) {
1002 0 : strncpy(buf,this->u.context.mark_lookup->lookup_name,6);
1003 0 : buf[6] = '\0';
1004 : }
1005 0 : } else if ( smd->sm->type==asm_insert ) {
1006 0 : if ( this->u.insert.mark_ins!=NULL )
1007 0 : strncpy(buf,this->u.insert.mark_ins,5);
1008 : } else { /* kern */
1009 0 : if ( this->u.kern.kerns!=NULL ) {
1010 : int j;
1011 0 : buf[0] = '\0';
1012 0 : for ( j=0; j<this->u.kern.kcnt; ++j )
1013 0 : sprintf(buf+strlen(buf),"%d ", this->u.kern.kerns[j]);
1014 0 : kddd = ( strlen(buf)>5 );
1015 0 : buf[5] = '\0';
1016 : } else
1017 0 : kddd = false;
1018 : }
1019 0 : len = GDrawGetText8Width(pixmap,buf,-1);
1020 0 : GDrawDrawText8(pixmap,x+(smd->statew-len)/2,y+2*smd->fh+smd->as+1,
1021 : buf,-1,0x000000);
1022 :
1023 0 : buf[0] = '\0';
1024 0 : if ( smd->sm->type==asm_indic ) {
1025 0 : strncpy(buf,indicverbs[1][this->flags&0xf],sizeof(buf)-1);
1026 0 : } else if ( smd->sm->type==asm_context ) {
1027 0 : if ( this->u.context.cur_lookup!=NULL ) {
1028 0 : strncpy(buf,this->u.context.cur_lookup->lookup_name,6);
1029 0 : buf[6] = '\0';
1030 : }
1031 0 : } else if ( smd->sm->type==asm_insert ) {
1032 0 : if ( this->u.insert.cur_ins!=NULL )
1033 0 : strncpy(buf,this->u.insert.cur_ins,5);
1034 : } else { /* kern */
1035 0 : if ( kddd ) strcpy(buf,"...");
1036 0 : else buf[0] = '\0';
1037 : }
1038 0 : len = GDrawGetText8Width(pixmap,buf,-1);
1039 0 : GDrawDrawText8(pixmap,x+(smd->statew-len)/2,y+3*smd->fh+smd->as+1,
1040 : buf,-1,0x000000);
1041 : }
1042 : }
1043 :
1044 0 : GDrawDrawLine(pixmap,smd->xstart,smd->ystart2,smd->xstart+rect.width,smd->ystart2,
1045 : 0x000000);
1046 0 : GDrawDrawLine(pixmap,smd->xstart2,smd->ystart,smd->xstart2,smd->ystart+rect.height,
1047 : 0x000000);
1048 0 : GDrawPopClip(pixmap,&old2);
1049 0 : GDrawPopClip(pixmap,&old1);
1050 0 : GDrawDrawRect(pixmap,&rect,0x000000);
1051 0 : rect.y += rect.height;
1052 0 : rect.x += rect.width;
1053 0 : LogoExpose(pixmap,event,&rect,dm_fore);
1054 : }
1055 :
1056 0 : static int SMD_SBReset(SMD *smd) {
1057 0 : int oldtop = smd->offtop, oldleft = smd->offleft;
1058 :
1059 0 : GScrollBarSetBounds(smd->vsb,0,smd->state_cnt, smd->height/smd->stateh);
1060 0 : GScrollBarSetBounds(smd->hsb,0,smd->class_cnt, smd->width/smd->statew);
1061 0 : if ( smd->offtop + (smd->height/smd->stateh) >= smd->state_cnt )
1062 0 : smd->offtop = smd->state_cnt - (smd->height/smd->stateh);
1063 0 : if ( smd->offtop < 0 ) smd->offtop = 0;
1064 0 : if ( smd->offleft + (smd->width/smd->statew) >= smd->class_cnt )
1065 0 : smd->offleft = smd->class_cnt - (smd->width/smd->statew);
1066 0 : if ( smd->offleft < 0 ) smd->offleft = 0;
1067 0 : GScrollBarSetPos(smd->vsb,smd->offtop);
1068 0 : GScrollBarSetPos(smd->hsb,smd->offleft);
1069 :
1070 0 : return( oldtop!=smd->offtop || oldleft!=smd->offleft );
1071 : }
1072 :
1073 0 : static void SMD_HShow(SMD *smd, int pos) {
1074 0 : if ( pos<0 || pos>=smd->class_cnt )
1075 0 : return;
1076 0 : --pos; /* One line of context */
1077 0 : if ( pos + (smd->width/smd->statew) >= smd->class_cnt )
1078 0 : pos = smd->class_cnt - (smd->width/smd->statew);
1079 0 : if ( pos < 0 ) pos = 0;
1080 0 : smd->offleft = pos;
1081 0 : GScrollBarSetPos(smd->hsb,pos);
1082 0 : GDrawRequestExpose(smd->gw,NULL,false);
1083 : }
1084 :
1085 0 : static void SMD_HScroll(SMD *smd,struct sbevent *sb) {
1086 0 : int newpos = smd->offleft;
1087 : GRect rect;
1088 :
1089 0 : switch( sb->type ) {
1090 : case et_sb_top:
1091 0 : newpos = 0;
1092 0 : break;
1093 : case et_sb_uppage:
1094 0 : if ( smd->width/smd->statew == 1 )
1095 0 : --newpos;
1096 : else
1097 0 : newpos -= smd->width/smd->statew - 1;
1098 0 : break;
1099 : case et_sb_up:
1100 0 : --newpos;
1101 0 : break;
1102 : case et_sb_down:
1103 0 : ++newpos;
1104 0 : break;
1105 : case et_sb_downpage:
1106 0 : if ( smd->width/smd->statew == 1 )
1107 0 : ++newpos;
1108 : else
1109 0 : newpos += smd->width/smd->statew - 1;
1110 0 : break;
1111 : case et_sb_bottom:
1112 0 : newpos = smd->class_cnt - (smd->width/smd->statew);
1113 0 : break;
1114 : case et_sb_thumb:
1115 : case et_sb_thumbrelease:
1116 0 : newpos = sb->pos;
1117 0 : break;
1118 : }
1119 0 : if ( newpos + (smd->width/smd->statew) >= smd->class_cnt )
1120 0 : newpos = smd->class_cnt - (smd->width/smd->statew);
1121 0 : if ( newpos < 0 ) newpos = 0;
1122 0 : if ( newpos!=smd->offleft ) {
1123 0 : int diff = newpos-smd->offleft;
1124 0 : smd->offleft = newpos;
1125 0 : GScrollBarSetPos(smd->hsb,newpos);
1126 0 : rect.x = smd->xstart2+1; rect.y = smd->ystart;
1127 0 : rect.width = smd->width-1;
1128 0 : rect.height = smd->height+(smd->ystart2-smd->ystart);
1129 0 : GDrawScroll(smd->gw,&rect,-diff*smd->statew,0);
1130 : }
1131 0 : }
1132 :
1133 0 : static void SMD_VScroll(SMD *smd,struct sbevent *sb) {
1134 0 : int newpos = smd->offtop;
1135 : GRect rect;
1136 :
1137 0 : switch( sb->type ) {
1138 : case et_sb_top:
1139 0 : newpos = 0;
1140 0 : break;
1141 : case et_sb_uppage:
1142 0 : if ( smd->height/smd->stateh == 1 )
1143 0 : --newpos;
1144 : else
1145 0 : newpos -= smd->height/smd->stateh - 1;
1146 0 : break;
1147 : case et_sb_up:
1148 0 : --newpos;
1149 0 : break;
1150 : case et_sb_down:
1151 0 : ++newpos;
1152 0 : break;
1153 : case et_sb_downpage:
1154 0 : if ( smd->height/smd->stateh == 1 )
1155 0 : ++newpos;
1156 : else
1157 0 : newpos += smd->height/smd->stateh - 1;
1158 0 : break;
1159 : case et_sb_bottom:
1160 0 : newpos = smd->state_cnt - (smd->height/smd->stateh);
1161 0 : break;
1162 : case et_sb_thumb:
1163 : case et_sb_thumbrelease:
1164 0 : newpos = sb->pos;
1165 0 : break;
1166 : }
1167 0 : if ( newpos + (smd->height/smd->stateh) >= smd->state_cnt )
1168 0 : newpos = smd->state_cnt - (smd->height/smd->stateh);
1169 0 : if ( newpos < 0 ) newpos = 0;
1170 0 : if ( newpos!=smd->offtop ) {
1171 0 : int diff = newpos-smd->offtop;
1172 0 : smd->offtop = newpos;
1173 0 : GScrollBarSetPos(smd->vsb,newpos);
1174 0 : rect.x = smd->xstart; rect.y = smd->ystart2+1;
1175 0 : rect.width = smd->width+(smd->xstart2-smd->xstart);
1176 0 : rect.height = smd->height-1;
1177 0 : GDrawScroll(smd->gw,&rect,0,diff*smd->stateh);
1178 : }
1179 0 : }
1180 :
1181 0 : static int smd_e_h(GWindow gw, GEvent *event) {
1182 0 : SMD *smd = GDrawGetUserData(gw);
1183 :
1184 0 : switch ( event->type ) {
1185 : case et_close:
1186 0 : _SMD_Cancel(smd);
1187 0 : break;
1188 : case et_char:
1189 0 : if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1190 0 : help("statemachine.html");
1191 0 : return( true );
1192 0 : } else if ( event->u.chr.keysym=='q' && (event->u.chr.state&ksm_control)) {
1193 0 : if ( event->u.chr.state&ksm_shift )
1194 0 : _SMD_Cancel(smd);
1195 : else
1196 0 : MenuExit(NULL,NULL,NULL);
1197 0 : return( true );
1198 : }
1199 0 : return( false );
1200 : case et_expose:
1201 0 : SMD_Expose(smd,gw,event);
1202 0 : break;
1203 : case et_resize: {
1204 0 : int blen = GDrawPointsToPixels(NULL,GIntGetResource(_NUM_Buttonsize));
1205 : GRect wsize, csize;
1206 :
1207 0 : GDrawGetSize(smd->gw,&wsize);
1208 0 : GGadgetResize(GWidgetGetControl(smd->gw,CID_Group),wsize.width-4,wsize.height-4);
1209 0 : GGadgetResize(GWidgetGetControl(smd->gw,CID_Line1),wsize.width-20,1);
1210 0 : GGadgetResize(GWidgetGetControl(smd->gw,CID_Line2),wsize.width-20,1);
1211 :
1212 0 : GGadgetGetSize(GWidgetGetControl(smd->gw,CID_Ok),&csize);
1213 0 : GGadgetMove(GWidgetGetControl(smd->gw,CID_Ok),csize.x,wsize.height-smd->canceldrop-3);
1214 0 : GGadgetGetSize(GWidgetGetControl(smd->gw,CID_Cancel),&csize);
1215 0 : GGadgetMove(GWidgetGetControl(smd->gw,CID_Cancel),wsize.width-blen-30,wsize.height-smd->canceldrop);
1216 :
1217 0 : GGadgetGetSize(GWidgetGetControl(smd->gw,CID_Classes),&csize);
1218 0 : GGadgetResize(GWidgetGetControl(smd->gw,CID_Classes),wsize.width-GDrawPointsToPixels(NULL,10),csize.height);
1219 :
1220 0 : GGadgetGetSize(smd->hsb,&csize);
1221 0 : smd->width = wsize.width-csize.height-smd->xstart2-5;
1222 0 : GGadgetResize(smd->hsb,smd->width,csize.height);
1223 0 : GGadgetMove(smd->hsb,smd->xstart2,wsize.height-smd->sbdrop-csize.height);
1224 0 : GGadgetGetSize(smd->vsb,&csize);
1225 0 : smd->height = wsize.height-smd->sbdrop-smd->ystart2-csize.width;
1226 0 : GGadgetResize(smd->vsb,csize.width,wsize.height-smd->sbdrop-smd->ystart2-csize.width);
1227 0 : GGadgetMove(smd->vsb,wsize.width-csize.width-5,smd->ystart2);
1228 0 : SMD_SBReset(smd);
1229 :
1230 0 : GDrawRequestExpose(smd->gw,NULL,false);
1231 0 : } break;
1232 : case et_mouseup: case et_mousemove: case et_mousedown:
1233 0 : SMD_Mouse(smd,event);
1234 0 : break;
1235 : case et_controlevent:
1236 0 : switch( event->u.control.subtype ) {
1237 : case et_scrollbarchange:
1238 0 : if ( event->u.control.g == smd->hsb )
1239 0 : SMD_HScroll(smd,&event->u.control.u.sb);
1240 : else
1241 0 : SMD_VScroll(smd,&event->u.control.u.sb);
1242 0 : break;
1243 : }
1244 0 : break;
1245 : }
1246 0 : return( true );
1247 : }
1248 :
1249 0 : static char *SMD_PickGlyphsForClass(GGadget *g,int r, int c) {
1250 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
1251 0 : int rows, cols = GMatrixEditGetColCnt(g);
1252 0 : struct matrix_data *classes = _GMatrixEditGet(g,&rows);
1253 0 : char *new = GlyphSetFromSelection(smd->sf,ly_fore,classes[r*cols+c].u.md_str);
1254 0 : return( new );
1255 : }
1256 :
1257 0 : static void SMD_NewClassRow(GGadget *g,int r) {
1258 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
1259 :
1260 0 : smd->states = StateCopy(smd->states,smd->class_cnt,smd->state_cnt,
1261 0 : smd->class_cnt+1,smd->state_cnt,
1262 0 : smd->sm->type,true);
1263 0 : ++smd->class_cnt;
1264 0 : SMD_SBReset(smd);
1265 0 : }
1266 :
1267 0 : static void SMD_FinishEdit(GGadget *g,int r, int c, int wasnew) {
1268 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
1269 :
1270 0 : ME_ClassCheckUnique(g, r, c, smd->sf);
1271 0 : }
1272 :
1273 0 : static int SMD_EnableDeleteClass(GGadget *g,int whichclass) {
1274 0 : return( whichclass>=4 );
1275 : }
1276 :
1277 0 : static void SMD_DeleteClass(GGadget *g,int whichclass) {
1278 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
1279 :
1280 0 : StateRemoveClasses(smd,whichclass);
1281 0 : SMD_SBReset(smd);
1282 0 : GDrawRequestExpose(smd->gw,NULL,false);
1283 0 : }
1284 :
1285 0 : static void SMD_ClassSelectionChanged(GGadget *g,int whichclass, int c) {
1286 0 : SMD *smd = GDrawGetUserData(GGadgetGetWindow(g));
1287 0 : SMD_HShow(smd,whichclass);
1288 0 : }
1289 :
1290 0 : static unichar_t **SMD_GlyphListCompletion(GGadget *t,int from_tab) {
1291 0 : SMD *smd = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
1292 0 : SplineFont *sf = smd->sf;
1293 :
1294 0 : return( SFGlyphNameCompletion(sf,t,from_tab,true));
1295 : }
1296 :
1297 : static struct col_init class_ci[] = {
1298 : { me_funcedit, SMD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the classes") },
1299 : };
1300 0 : void StateMachineEdit(SplineFont *sf,ASM *sm,struct gfi_data *d) {
1301 : static char *titles[2][4] = {
1302 : { N_("Edit Indic Rearrangement"), N_("Edit Contextual Substitution"), N_("Edit Contextual Glyph Insertion"), N_("Edit Contextual Kerning") },
1303 : { N_("New Indic Rearrangement"), N_("New Contextual Substitution"), N_("New Contextual Glyph Insertion"), N_("New Contextual Kerning") }};
1304 : SMD smd;
1305 : GRect pos;
1306 : GWindow gw;
1307 : GWindowAttrs wattrs;
1308 : GGadgetCreateData gcd[20];
1309 : GTextInfo label[20];
1310 : int i, k, vk;
1311 : int as, ds, ld, sbsize;
1312 : FontRequest rq;
1313 : static unichar_t statew[] = { '1', '2', '3', '4', '5', 0 };
1314 : static GFont *font = NULL;
1315 : struct matrix_data *md;
1316 : struct matrixinit mi;
1317 : static char *specialclasses[4] = { N_("{End of Text}"),
1318 : N_("{Everything Else}"),
1319 : N_("{Deleted Glyph}"),
1320 : N_("{End of Line}") };
1321 :
1322 0 : memset(&smd,0,sizeof(smd));
1323 0 : smd.sf = sf;
1324 0 : smd.sm = sm;
1325 0 : smd.d = d;
1326 0 : smd.isnew = (sm->class_cnt==0);
1327 0 : if ( smd.isnew ) {
1328 0 : smd.class_cnt = 4; /* 4 built in classes */
1329 0 : smd.state_cnt = 2; /* 2 built in states */
1330 0 : smd.states = calloc(smd.class_cnt*smd.state_cnt,sizeof(struct asm_state));
1331 0 : smd.states[1*4+2].next_state = 1; /* deleted glyph is a noop */
1332 : } else {
1333 0 : smd.class_cnt = sm->class_cnt;
1334 0 : smd.state_cnt = sm->state_cnt;
1335 0 : smd.states = StateCopy(sm->state,sm->class_cnt,sm->state_cnt,
1336 0 : smd.class_cnt,smd.state_cnt,sm->type,false);
1337 : }
1338 0 : smd.index = sm->type==asm_indic ? 0 : sm->type==asm_context ? 1 : sm->type==asm_insert ? 2 : 3;
1339 :
1340 0 : memset(&wattrs,0,sizeof(wattrs));
1341 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1342 0 : wattrs.event_masks = ~(1<<et_charup);
1343 0 : wattrs.is_dlg = true;
1344 0 : wattrs.restrict_input_to_me = true;
1345 0 : wattrs.undercursor = 1;
1346 0 : wattrs.cursor = ct_pointer;
1347 0 : wattrs.utf8_window_title = _(titles[smd.isnew][smd.index]);
1348 0 : pos.x = pos.y = 0;
1349 0 : pos.width =GDrawPointsToPixels(NULL,GGadgetScale(SMD_WIDTH));
1350 0 : pos.height = GDrawPointsToPixels(NULL,SMD_HEIGHT);
1351 0 : smd.gw = gw = GDrawCreateTopWindow(NULL,&pos,smd_e_h,&smd,&wattrs);
1352 :
1353 0 : memset(gcd,0,sizeof(gcd));
1354 0 : memset(label,0,sizeof(label));
1355 0 : k = 0;
1356 :
1357 0 : label[k].text = (unichar_t *) _("Right To Left");
1358 0 : label[k].text_is_1byte = true;
1359 0 : gcd[k].gd.label = &label[k];
1360 0 : gcd[k].gd.pos.x = 150; gcd[k].gd.pos.y = 5;
1361 0 : gcd[k].gd.flags = gg_enabled|gg_visible | (sm->flags&0x4000?gg_cb_on:0);
1362 0 : gcd[k].gd.cid = CID_RightToLeft;
1363 0 : gcd[k++].creator = GCheckBoxCreate;
1364 0 : if ( smd.sm->type == asm_kern ) {
1365 0 : gcd[k-1].gd.flags = gg_enabled; /* I'm not sure why kerning doesn't have an r2l bit */
1366 : }
1367 :
1368 0 : label[k].text = (unichar_t *) _("Vertical Only");
1369 0 : label[k].text_is_1byte = true;
1370 0 : gcd[k].gd.label = &label[k];
1371 0 : gcd[k].gd.pos.x = 150; gcd[k].gd.pos.y = 5+16;
1372 0 : gcd[k].gd.flags = gg_enabled|gg_visible | (sm->flags&0x8000?gg_cb_on:0);
1373 0 : gcd[k].gd.cid = CID_VertOnly;
1374 0 : gcd[k++].creator = GCheckBoxCreate;
1375 :
1376 0 : gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = GDrawPointsToPixels(gw,gcd[k-1].gd.pos.y+15);
1377 0 : gcd[k].gd.pos.width = pos.width-20;
1378 0 : gcd[k].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
1379 0 : gcd[k].gd.cid = CID_Line1;
1380 0 : gcd[k++].creator = GLineCreate;
1381 :
1382 0 : memset(&mi,0,sizeof(mi));
1383 0 : mi.col_cnt = 1;
1384 0 : mi.col_init = class_ci;
1385 :
1386 0 : if ( sm->class_cnt<4 ) sm->class_cnt=4;
1387 0 : md = calloc(sm->class_cnt+1,sizeof(struct matrix_data));
1388 0 : for ( i=0; i<sm->class_cnt; ++i ) {
1389 0 : if ( i<4 ) {
1390 0 : md[i+0].u.md_str = copy( _(specialclasses[i]) );
1391 0 : md[i+0].frozen = true;
1392 : } else
1393 0 : if (sm->classes[i])
1394 0 : md[i+0].u.md_str = SFNameList2NameUni(sf,sm->classes[i]);
1395 : }
1396 0 : mi.matrix_data = md;
1397 0 : mi.initial_row_cnt = i;
1398 0 : mi.initrow = SMD_NewClassRow;
1399 0 : mi.finishedit = SMD_FinishEdit;
1400 0 : mi.candelete = SMD_EnableDeleteClass;
1401 :
1402 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = GDrawPixelsToPoints(gw,gcd[k-1].gd.pos.y)+5;
1403 0 : gcd[k].gd.pos.width = SMD_WIDTH-10;
1404 0 : gcd[k].gd.pos.height = 8*12+34;
1405 0 : gcd[k].gd.flags = gg_visible | gg_enabled;
1406 0 : gcd[k].gd.cid = CID_Classes;
1407 0 : gcd[k].gd.u.matrix = &mi;
1408 0 : gcd[k++].creator = GMatrixEditCreate;
1409 :
1410 0 : gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = GDrawPointsToPixels(gw,gcd[k-1].gd.pos.y+gcd[k-1].gd.pos.height+5);
1411 0 : gcd[k].gd.pos.width = pos.width-20;
1412 0 : gcd[k].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
1413 0 : gcd[k].gd.cid = CID_Line2;
1414 0 : gcd[k++].creator = GLineCreate;
1415 :
1416 0 : smd.canceldrop = GDrawPointsToPixels(gw,SMD_CANCELDROP);
1417 0 : smd.sbdrop = smd.canceldrop+GDrawPointsToPixels(gw,7);
1418 :
1419 0 : vk = k;
1420 0 : gcd[k].gd.pos.width = sbsize = GDrawPointsToPixels(gw,_GScrollBar_Width);
1421 0 : gcd[k].gd.pos.x = pos.width-sbsize;
1422 0 : gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+8;
1423 0 : gcd[k].gd.pos.height = pos.height-gcd[k].gd.pos.y-sbsize-smd.sbdrop;
1424 0 : gcd[k].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
1425 0 : gcd[k++].creator = GScrollBarCreate;
1426 0 : smd.height = gcd[k-1].gd.pos.height;
1427 0 : smd.ystart = gcd[k-1].gd.pos.y;
1428 :
1429 0 : gcd[k].gd.pos.height = sbsize;
1430 0 : gcd[k].gd.pos.y = pos.height-sbsize-8;
1431 0 : gcd[k].gd.pos.x = 4;
1432 0 : gcd[k].gd.pos.width = pos.width-sbsize;
1433 0 : gcd[k].gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
1434 0 : gcd[k++].creator = GScrollBarCreate;
1435 0 : smd.width = gcd[k-1].gd.pos.width;
1436 0 : smd.xstart = 5;
1437 :
1438 0 : label[k].text = (unichar_t *) _("_OK");
1439 0 : label[k].text_is_1byte = true;
1440 0 : label[k].text_in_resource = true;
1441 0 : gcd[k].gd.label = &label[k];
1442 0 : gcd[k].gd.pos.x = 30-3; gcd[k].gd.pos.y = SMD_HEIGHT-SMD_CANCELDROP-3;
1443 0 : gcd[k].gd.pos.width = -1;
1444 0 : gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
1445 0 : gcd[k].gd.handle_controlevent = SMD_Ok;
1446 0 : gcd[k].gd.cid = CID_Ok;
1447 0 : gcd[k++].creator = GButtonCreate;
1448 :
1449 0 : label[k].text = (unichar_t *) _("_Cancel");
1450 0 : label[k].text_is_1byte = true;
1451 0 : label[k].text_in_resource = true;
1452 0 : gcd[k].gd.label = &label[k];
1453 0 : gcd[k].gd.pos.x = -30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
1454 0 : gcd[k].gd.pos.width = -1;
1455 0 : gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
1456 0 : gcd[k].gd.handle_controlevent = SMD_Cancel;
1457 0 : gcd[k].gd.cid = CID_Cancel;
1458 0 : gcd[k++].creator = GButtonCreate;
1459 :
1460 0 : gcd[k].gd.pos.x = 2; gcd[k].gd.pos.y = 2;
1461 0 : gcd[k].gd.pos.width = pos.width-4;
1462 0 : gcd[k].gd.pos.height = pos.height-4;
1463 0 : gcd[k].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
1464 0 : gcd[k].gd.cid = CID_Group;
1465 0 : gcd[k++].creator = GGroupCreate;
1466 :
1467 0 : GGadgetsCreate(gw,gcd);
1468 0 : smd.vsb = gcd[vk].ret;
1469 0 : smd.hsb = gcd[vk+1].ret;
1470 :
1471 : {
1472 0 : GGadget *list = GWidgetGetControl(smd.gw,CID_Classes);
1473 0 : GMatrixEditSetBeforeDelete(list, SMD_DeleteClass);
1474 : /* When the selection changes */
1475 0 : GMatrixEditSetOtherButtonEnable(list, SMD_ClassSelectionChanged);
1476 0 : GMatrixEditSetColumnCompletion(list,0,SMD_GlyphListCompletion);
1477 : }
1478 :
1479 0 : if ( font==NULL ) {
1480 0 : memset(&rq,'\0',sizeof(rq));
1481 0 : rq.point_size = 12;
1482 0 : rq.weight = 400;
1483 0 : rq.utf8_family_name = MONO_UI_FAMILIES;
1484 0 : font = GDrawInstanciateFont(gw,&rq);
1485 0 : font = GResourceFindFont("StateMachine.Font",font);
1486 : }
1487 0 : smd.font = font;
1488 0 : GDrawWindowFontMetrics(gw,smd.font,&as,&ds,&ld);
1489 0 : smd.fh = as+ds; smd.as = as;
1490 0 : GDrawSetFont(gw,smd.font);
1491 :
1492 0 : smd.stateh = 4*smd.fh+3;
1493 0 : smd.statew = GDrawGetTextWidth(gw,statew,-1)+3;
1494 0 : smd.xstart2 = smd.xstart+smd.statew/2;
1495 0 : smd.ystart2 = smd.ystart+2*smd.fh+1;
1496 :
1497 0 : GDrawSetVisible(gw,true);
1498 0 : while ( !smd.done )
1499 0 : GDrawProcessOneEvent(NULL);
1500 0 : }
|