Line data Source code
1 : /* Copyright (C) 2003-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "asmfpst.h"
28 : #include "fontforgeui.h"
29 : #include "lookups.h"
30 : #include "splineutil.h"
31 : #include <chardata.h>
32 : #include <utype.h>
33 : #include <ustring.h>
34 : #include <gkeysym.h>
35 :
36 : /* Currently uses class numbers rather than names!!!!!! */
37 :
38 : /* ************************************************************************** */
39 : /* ************************ Context/Chaining Dialog ************************* */
40 : /* ************************************************************************** */
41 : enum activewindow { aw_formats, aw_coverage, aw_grules, aw_glyphs,
42 : aw_classrules, aw_classnumber,
43 : aw_coverage_simple, aw_glyphs_simple, aw_classes_simple };
44 : struct contextchaindlg {
45 : struct gfi_data *gfi;
46 : SplineFont *sf;
47 : FPST *fpst;
48 : unichar_t *newname;
49 : int isnew;
50 : GWindow gw;
51 : GWindow formats, coverage, grules, glyphs, classrules, classnumber;
52 : GWindow coverage_simple, glyphs_simple, classes_simple;
53 : enum activewindow aw;
54 : /* Wizard panes:
55 : formats -- gives user a choice between by glyph/class/coverage table
56 : Simple version:
57 : glyphs_simple -- user picked glyph format, shows a matrix edit of glyph lists
58 : and lookups.
59 : classes_simple -- user picked class format. shows a matrix edit of class lists
60 : with lookups. Also the three sets of classes_simple.
61 : coverage_simple -- user picked coverage table format. shows a matrix edit with
62 : a bunch of coverage tables and lookups/replacements.
63 : [coverage_simple format only accepts 1 rule]
64 : Complex version:
65 : grules -- user picked glyph format, shows a list of glyph lists and with
66 : lookups. Editing a glyph list takes us to the glyphs pane
67 : classrules -- user picked class format. shows a list of class lists with
68 : lookups. Also a tabbed widget showing the three sets of
69 : classes.
70 : coverage -- user picked coverage table format. shows a tabbed widget with
71 : three lists of coverage tables. (for match also shows a
72 : set of sequence #/lookup pairs.
73 : [There is no coveragerules pane because coverage format
74 : only accepts 1 rule]
75 : glyphs -- from grules, user asked for a new rule. Shows tabbed widget
76 : with three lists of glyphs (for match, also shows a set of
77 : sequence #/lookups
78 : classnumber - from class rules, tabbed pane describing one class based rule
79 : */
80 : int row_being_edited;
81 : int subheightdiff, canceldrop;
82 : int done;
83 : int layer;
84 : };
85 :
86 : #define CID_OK 100
87 : #define CID_Cancel 101
88 : #define CID_Next 102
89 : #define CID_Prev 103
90 : #define CID_SubSize 104
91 :
92 : #define CID_ByGlyph 200
93 : #define CID_ByClass 201
94 : #define CID_ByCoverage 202
95 :
96 : #define CID_Simple 205
97 : #define CID_Complex 206
98 :
99 : /* There are more CIDs used in this file than those listed here */
100 : /* The CIDs given here are for glyph lists (aw_glyphs & aw_grules) */
101 : /* similar controls refering to coverage tables have 100 added to them */
102 : /* The CIDs here are also for the "match" aspect of the tabsets */
103 : /* those in backtrack get 20 added, those in lookahead get 40 */
104 : #define CID_GList 305
105 :
106 : #define CID_MatchType 1003
107 : #define CID_Set 1004
108 : #define CID_Select 1005
109 : #define CID_GlyphList 1006
110 : #define CID_Set2 1007
111 : #define CID_Select2 1008
112 : #define CID_RplList 1009
113 : #define CID_LookupList 1010
114 : #define CID_LNew 1011
115 : #define CID_LEdit 1012
116 : #define CID_LDelete 1013
117 : #define CID_LUp 1014
118 : #define CID_LDown 1015
119 :
120 : #define CID_ClassNumbers 2000
121 : #define CID_ClassList 2001
122 : #define CID_ClassType 2002
123 : #define CID_SameAsClasses 2003
124 :
125 : /* And for the simple dlg... */
126 :
127 : #define CID_GList_Simple 4000
128 : #define CID_GNewSection 4001
129 : #define CID_GAddLookup 4002
130 :
131 : #define CID_CList_Simple (CID_GList_Simple+100)
132 : #define CID_CNewSection (CID_GNewSection+100)
133 : #define CID_CAddLookup (CID_GAddLookup+100)
134 :
135 : #define CID_MatchClasses (CID_GList_Simple+300+0*20)
136 : #define CID_BackClasses (CID_MatchClasses+1*20)
137 : #define CID_ForeClasses (CID_MatchClasses+2*20)
138 : #define CID_SameAsClasses_S (CID_MatchClasses+1) /* Not actually used itself */
139 : #define CID_BackClassesSameAs_S (CID_SameAsClasses_S+1*20)
140 : #define CID_ForeClassesSameAs_S (CID_SameAsClasses_S+2*20)
141 :
142 : #define CID_ClassMatchType 4500
143 :
144 : #define CID_Covers 4600
145 :
146 0 : char *cu_copybetween(const unichar_t *start, const unichar_t *end) {
147 0 : char *ret = malloc(end-start+1);
148 0 : cu_strncpy(ret,start,end-start);
149 0 : ret[end-start] = '\0';
150 0 : return( ret );
151 : }
152 :
153 0 : static char *reversenames(char *str) {
154 : char *ret;
155 : char *rpt, *pt, *start, *spt;
156 :
157 0 : if ( str==NULL )
158 0 : return( NULL );
159 :
160 0 : rpt = ret = malloc(strlen(str)+1);
161 0 : *ret = '\0';
162 0 : for ( pt=str+strlen(str); pt>str; pt=start ) {
163 0 : for ( start = pt-1; start>=str && *start!=' '; --start );
164 0 : for ( spt=start+1; spt<pt; )
165 0 : *rpt++ = *spt++;
166 0 : *rpt++ = ' ';
167 : }
168 0 : if ( rpt>ret )
169 0 : rpt[-1] = '\0';
170 0 : return( ret );
171 : }
172 :
173 0 : static char *rpl(const char *src, const char *find, const char *rpl) {
174 : const char *pt, *start;
175 : char *ret, *rpt;
176 0 : int found_cnt=0;
177 0 : int flen = strlen(find);
178 :
179 0 : for ( pt=src; *pt; ) {
180 0 : while ( isspace(*pt)) ++pt;
181 0 : if ( *pt=='\0' )
182 0 : break;
183 0 : for ( start=pt; !isspace(*pt) && *pt!='\0'; ++pt );
184 0 : if ( pt-start==flen && strncmp(find,start,flen)==0 )
185 0 : ++found_cnt;
186 : }
187 0 : if ( found_cnt==0 )
188 0 : return( copy(src));
189 :
190 0 : rpt = ret = malloc(strlen(src)+found_cnt*(strlen(rpl)-flen)+1);
191 0 : for ( pt=src; *pt; ) {
192 0 : while ( isspace(*pt))
193 0 : *rpt++ = *pt++;
194 0 : if ( *pt=='\0' )
195 0 : break;
196 0 : for ( start=pt; !isspace(*pt) && *pt!='\0'; ++pt );
197 0 : if ( pt-start==flen && strncmp(find,start,flen)==0 ) {
198 0 : strcpy(rpt,rpl);
199 0 : rpt += strlen(rpt);
200 : } else {
201 0 : strncpy(rpt,start,pt-start);
202 0 : rpt += (pt-start);
203 : }
204 : }
205 0 : *rpt = '\0';
206 0 : return( ret );
207 : }
208 :
209 0 : static char *classnumbers(int cnt,uint16 *classes, struct matrix_data *classnames, int rows, int cols) {
210 : char buf[20];
211 : int i, len;
212 : char *pt, *ret;
213 :
214 0 : len = 0;
215 0 : for ( i=0; i<cnt; ++i ) {
216 0 : if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
217 0 : sprintf( buf, "%d ", classes[i]);
218 0 : len += strlen(buf);
219 : } else {
220 0 : len += strlen(classnames[cols*classes[i]+0].u.md_str)+1;
221 : }
222 : }
223 0 : ret = pt = malloc(len+3);
224 0 : *pt = '\0'; /* In case it is empty */
225 :
226 0 : for ( i=0; i<cnt; ++i ) {
227 0 : if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
228 0 : sprintf( pt, "%d ", classes[i]);
229 0 : pt += strlen(pt);
230 : } else {
231 0 : strcpy(pt, classnames[cols*classes[i]+0].u.md_str);
232 0 : pt += strlen(pt);
233 0 : *pt++ = ' ';
234 : }
235 : }
236 0 : if ( pt>ret && pt[-1]==' ' )
237 0 : pt[-1] = '\0';
238 0 : return( ret );
239 : }
240 :
241 0 : static char *rclassnumbers(int cnt,uint16 *classes, struct matrix_data *classnames, int rows, int cols) {
242 : char buf[20];
243 : int i, len;
244 : char *pt, *ret;
245 :
246 0 : len = 0;
247 0 : for ( i=0; i<cnt; ++i ) {
248 0 : if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
249 0 : sprintf( buf, "%d ", classes[i]);
250 0 : len += strlen(buf);
251 : } else {
252 0 : len += strlen(classnames[cols*classes[i]+0].u.md_str)+1;
253 : }
254 : }
255 0 : ret = pt = malloc(len+3);
256 0 : *pt = '\0';
257 0 : for ( i=cnt-1; i>=0; --i ) {
258 0 : if ( classnames[cols*classes[i]+0].u.md_str==NULL ) {
259 0 : sprintf( pt, "%d ", classes[i]);
260 0 : pt += strlen(pt);
261 : } else {
262 0 : strcpy(pt, classnames[cols*classes[i]+0].u.md_str);
263 0 : pt += strlen(pt);
264 0 : *pt++ = ' ';
265 : }
266 : }
267 0 : if ( pt>ret && pt[-1]==' ' )
268 0 : pt[-1] = '\0';
269 0 : return( ret );
270 : }
271 :
272 0 : static int CCD_GlyphNameCnt(const char *pt) {
273 0 : int cnt = 0;
274 :
275 0 : while ( *pt ) {
276 0 : while ( isspace( *pt )) ++pt;
277 0 : if ( *pt=='\0' )
278 0 : return( cnt );
279 0 : ++cnt;
280 0 : while ( !isspace(*pt) && *pt!='\0' ) ++pt;
281 : }
282 0 : return( cnt );
283 : }
284 :
285 0 : static int seqlookuplen(struct fpst_rule *r) {
286 0 : int i, len=0;
287 : char buf[20];
288 :
289 0 : len += 4; /* for the arrow, takes 3 bytes in utf8 */
290 0 : for ( i=0; i<r->lookup_cnt; ++i ) {
291 0 : sprintf( buf," %d \"\",", r->lookups[i].seq );
292 0 : len += strlen(buf) + strlen( r->lookups[i].lookup->lookup_name );
293 : }
294 0 : return( len );
295 : }
296 :
297 0 : static char *addseqlookups(char *pt, struct fpst_rule *r) {
298 : int i;
299 :
300 0 : pt = utf8_idpb(pt, 0x21d2,0);
301 0 : for ( i=0; i<r->lookup_cnt; ++i ) {
302 0 : sprintf( pt," %d <%s>,", r->lookups[i].seq, r->lookups[i].lookup->lookup_name);
303 0 : pt += strlen(pt);
304 : }
305 0 : if ( pt[-1]==',' ) --pt;
306 0 : *pt = '\0';
307 0 : return( pt );
308 : }
309 :
310 0 : static void parseseqlookups(SplineFont *sf, const char *solooks, struct fpst_rule *r) {
311 : int cnt;
312 : const char *pt;
313 :
314 0 : for ( pt = solooks, cnt=0; *pt!='\0'; ) {
315 0 : ++cnt;
316 0 : while ( *pt!='<' && *pt!='\0' ) ++pt;
317 0 : if ( *pt=='<' ) {
318 0 : ++pt;
319 0 : while ( *pt!='>' && *pt!='\0' ) ++pt;
320 0 : if ( *pt=='>' ) ++pt;
321 : }
322 0 : if ( *pt==',' ) ++pt;
323 : }
324 0 : r->lookup_cnt = cnt;
325 0 : r->lookups = calloc(cnt,sizeof(struct seqlookup));
326 0 : cnt = 0;
327 0 : pt = solooks;
328 : for (;;) {
329 : char *end;
330 0 : r->lookups[cnt].seq = strtol(pt,&end,10);
331 0 : for ( pt = end+1; isspace( *pt ); ++pt );
332 0 : if ( *pt=='<' ) {
333 : const char *eoname; char *temp;
334 0 : ++pt;
335 0 : for ( eoname = pt; *eoname!='\0' && *eoname!='>'; ++eoname );
336 0 : temp = copyn(pt,eoname-pt);
337 0 : r->lookups[cnt].lookup = SFFindLookup(sf,temp);
338 0 : if ( r->lookups[cnt].lookup==NULL )
339 0 : IError("No lookup in parseseqlookups");
340 0 : free(temp);
341 0 : pt = eoname;
342 0 : if ( *pt=='>' ) ++pt;
343 : } else
344 0 : IError("No lookup in parseseqlookups");
345 0 : ++cnt;
346 0 : if ( *pt!=',' )
347 0 : break;
348 0 : ++pt;
349 0 : }
350 0 : }
351 :
352 0 : static char *gruleitem(struct fpst_rule *r) {
353 : char *ret, *pt;
354 : int len;
355 :
356 0 : len = (r->u.glyph.back==NULL ? 0 : strlen(r->u.glyph.back)) +
357 0 : strlen(r->u.glyph.names) +
358 0 : (r->u.glyph.fore==0 ? 0 : strlen(r->u.glyph.fore)) +
359 0 : seqlookuplen(r);
360 :
361 0 : ret = pt = malloc(len+8);
362 0 : if ( r->u.glyph.back!=NULL && *r->u.glyph.back!='\0' ) {
363 0 : char *temp = reversenames(r->u.glyph.back);
364 0 : strcpy(pt,temp);
365 0 : pt += strlen(temp);
366 0 : free(temp);
367 0 : *pt++ = ' ';
368 : }
369 0 : *pt++ = '|';
370 0 : *pt++ = ' ';
371 0 : strcpy(pt,r->u.glyph.names);
372 0 : pt += strlen(r->u.glyph.names);
373 0 : *pt++ = ' ';
374 0 : *pt++ = '|';
375 0 : *pt++ = ' ';
376 0 : if ( r->u.glyph.fore!=NULL && *r->u.glyph.fore!='\0' ) {
377 0 : strcpy(pt,r->u.glyph.fore);
378 0 : pt += strlen(r->u.glyph.fore);
379 0 : *pt++ = ' ';
380 : }
381 0 : pt = addseqlookups(pt, r);
382 0 : return( ret );
383 : }
384 :
385 0 : static void gruleitem2rule(SplineFont *sf, const char *ruletext,struct fpst_rule *r) {
386 : const char *pt, *pt2;
387 : char *temp, *freeme;
388 : int ch;
389 :
390 0 : if ( ruletext==NULL )
391 0 : return;
392 0 : for ( pt=ruletext; *pt!='\0' && *pt!='|'; ++pt );
393 0 : if ( *pt=='\0' )
394 0 : return;
395 0 : if ( pt>ruletext ) {
396 0 : temp = GlyphNameListDeUnicode(freeme = copyn(ruletext,pt-1-ruletext));
397 0 : r->u.glyph.back = reversenames(temp);
398 0 : free(temp); free(freeme);
399 : }
400 0 : ruletext = pt+2;
401 0 : for ( pt=ruletext; *pt!='\0' && *pt!='|'; ++pt );
402 0 : if ( *pt=='\0' )
403 0 : return;
404 0 : r->u.glyph.names = GlyphNameListDeUnicode(freeme = copyn(ruletext,pt-1-ruletext));
405 0 : free(freeme);
406 0 : ruletext = pt+2;
407 0 : for ( pt2=ruletext; (ch=utf8_ildb((const char **) &pt2))!='\0' && ch!=0x21d2; );
408 0 : if ( ch=='\0' )
409 0 : return;
410 0 : if ( pt2!=ruletext ) {
411 0 : r->u.glyph.fore = GlyphNameListDeUnicode(freeme = copyn(ruletext,pt2-3-ruletext));
412 0 : free(freeme);
413 : }
414 0 : parseseqlookups(sf,pt2+2,r);
415 : }
416 :
417 0 : static char *classruleitem(struct fpst_rule *r,struct matrix_data **classes, int clen[3], int cols) {
418 : char *ret, *pt;
419 : int len, i, k;
420 : char buf[20];
421 :
422 0 : len = 0;
423 0 : for ( i=0; i<3; ++i ) {
424 0 : for ( k=0; k<(&r->u.class.ncnt)[i]; ++k ) {
425 0 : int c = (&r->u.class.nclasses)[i][k];
426 0 : if ( classes[i][cols*c+0].u.md_str!=NULL && *classes[i][cols*c+0].u.md_str!='\0' )
427 0 : len += strlen(classes[i][cols*c+0].u.md_str)+1;
428 : else {
429 0 : sprintf( buf, "%d ", c);
430 0 : len += strlen(buf);
431 : }
432 : }
433 : }
434 :
435 0 : ret = pt = malloc((len+8+seqlookuplen(r)) * sizeof(unichar_t));
436 0 : for ( k=r->u.class.bcnt-1; k>=0; --k ) {
437 0 : int c = r->u.class.bclasses[k];
438 0 : if ( classes[1][cols*c+0].u.md_str!=NULL && *classes[1][cols*c+0].u.md_str!='\0' ) {
439 0 : strcpy(pt,classes[1][cols*c+0].u.md_str);
440 0 : pt += strlen( pt );
441 0 : *pt++ = ' ';
442 : } else {
443 0 : sprintf( pt, "%d ", c);
444 0 : pt += strlen(pt);
445 : }
446 : }
447 0 : *pt++ = '|';
448 0 : for ( k=0; k<r->u.class.ncnt; ++k ) {
449 0 : int c = r->u.class.nclasses[k];
450 0 : if ( classes[0][cols*c+0].u.md_str!=NULL && *classes[0][cols*c+0].u.md_str!='\0' ) {
451 0 : strcpy(pt,classes[0][cols*c+0].u.md_str);
452 0 : pt += strlen( pt );
453 0 : *pt++ = ' ';
454 : } else {
455 0 : sprintf( pt, "%d ", c);
456 0 : pt += strlen(pt);
457 : }
458 : }
459 0 : if ( pt[-1]==' ' ) --pt;
460 0 : *pt++ = '|';
461 0 : for ( k=0; k<r->u.class.fcnt; ++k ) {
462 0 : int c = r->u.class.fclasses[k];
463 0 : if ( classes[2][cols*c+0].u.md_str!=NULL && *classes[2][cols*c+0].u.md_str!='\0' ) {
464 0 : strcpy(pt,classes[2][cols*c+0].u.md_str);
465 0 : pt += strlen( pt );
466 0 : *pt++ = ' ';
467 : } else {
468 0 : sprintf( pt, "%d ", c);
469 0 : pt += strlen(pt);
470 : }
471 : }
472 :
473 0 : *pt++ = ' ';
474 0 : pt = addseqlookups(pt, r);
475 0 : return( ret );
476 : }
477 :
478 0 : static void classruleitem2rule(SplineFont *sf,const char *ruletext,struct fpst_rule *r,
479 : struct matrix_data **classes, int clen[3], int cols) {
480 : const char *pt, *start, *nstart; char *end;
481 : int len, i, ch, k;
482 :
483 0 : memset(r,0,sizeof(*r));
484 :
485 0 : len = 0; i=1;
486 0 : for ( pt=ruletext; *pt; ) {
487 0 : ch = utf8_ildb((const char **) &pt);
488 0 : while ( ch!='|' && ch!=0x21d2 && ch!='\0' ) {
489 0 : while ( isspace(ch))
490 0 : ch = utf8_ildb((const char **) &pt);
491 0 : if ( ch=='|' || ch== 0x21d2 || ch=='\0' )
492 : break;
493 0 : ++len;
494 0 : while ( !isspace(ch) && ch!='|' && ch!=0x21d2 && ch!='\0' )
495 0 : ch = utf8_ildb((const char **) &pt);
496 : }
497 0 : (&r->u.class.ncnt)[i] = len;
498 0 : (&r->u.class.nclasses)[i] = malloc(len*sizeof(uint16));
499 0 : len = 0;
500 0 : if ( ch=='\0' || ch==0x21d2 )
501 : break;
502 0 : if ( ch=='|' ) {
503 0 : if ( i==1 ) i=0;
504 0 : else if ( i==0 ) i=2;
505 : }
506 : }
507 0 : len = 0; i=1;
508 0 : for ( pt=ruletext; *pt; ) {
509 0 : start = pt;
510 0 : ch = utf8_ildb((const char **) &pt);
511 0 : while ( ch!='|' && ch!=0x21d2 && ch!='\0' ) {
512 0 : while ( isspace(ch)) {
513 0 : start = pt;
514 0 : ch = utf8_ildb((const char **) &pt);
515 : }
516 0 : if ( ch=='|' || ch== 0x21d2 || ch=='\0' )
517 : break;
518 0 : nstart = start;
519 0 : while ( !isspace(ch) && ch!='|' && ch!=0x21d2 && ch!='\0' ) {
520 0 : nstart = pt;
521 0 : ch = utf8_ildb((const char **) &pt);
522 : }
523 0 : (&r->u.class.nclasses)[i][len] = strtol(start,&end,10);
524 0 : if ( end<nstart ) { /* Not a number, must be a class name */
525 0 : for ( k=0; k<clen[i]; ++k ) {
526 0 : if ( classes[i][cols*k+0].u.md_str==NULL )
527 0 : continue;
528 0 : if ( strlen(classes[i][cols*k+0].u.md_str)==nstart-start &&
529 0 : strncmp(classes[i][cols*k+0].u.md_str,start,nstart-start)==0 ) {
530 0 : (&r->u.class.nclasses)[i][len] = k;
531 0 : break;
532 : }
533 : }
534 : }
535 0 : start = nstart;
536 0 : ++len;
537 : }
538 0 : len = 0;
539 0 : if ( ch=='\0' || ch==0x21d2 )
540 : break;
541 0 : if ( ch=='|' ) {
542 0 : if ( i==1 ) i=0;
543 0 : else if ( i==0 ) i=2;
544 : }
545 : }
546 : /* reverse the backtrack */
547 0 : for ( i=0; i<r->u.class.bcnt/2; ++i ) {
548 0 : int temp = r->u.class.bclasses[i];
549 0 : r->u.class.bclasses[i] = r->u.class.bclasses[r->u.class.bcnt-1-i];
550 0 : r->u.class.bclasses[r->u.class.bcnt-1-i] = temp;
551 : }
552 :
553 0 : if ( ch=='\0' || *pt=='\0' )
554 0 : return;
555 0 : parseseqlookups(sf,pt,r);
556 : }
557 :
558 0 : static void CCD_ParseLookupList(SplineFont *sf, struct fpst_rule *r,GGadget *list) {
559 : int len, i;
560 0 : struct matrix_data *classes = GMatrixEditGet(list,&len);
561 :
562 0 : r->lookup_cnt = len;
563 0 : r->lookups = malloc(len*sizeof(struct seqlookup));
564 0 : for ( i=0; i<len; ++i ) {
565 0 : r->lookups[i].seq = classes[2*i+1].u.md_ival;
566 0 : r->lookups[i].lookup = (OTLookup *) classes[2*i+0].u.md_ival;
567 : }
568 0 : }
569 :
570 0 : static void CCD_EnableNextPrev(struct contextchaindlg *ccd) {
571 : /* Cancel is always enabled, Not so for OK or Next or Prev */
572 0 : switch ( ccd->aw ) {
573 : case aw_formats:
574 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),false);
575 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),true);
576 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),false);
577 0 : break;
578 : case aw_glyphs:
579 : case aw_classnumber:
580 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),true);
581 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),true);
582 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),false);
583 0 : break;
584 : case aw_coverage:
585 : case aw_grules:
586 : case aw_classrules:
587 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),ccd->fpst->format!=pst_reversecoverage);
588 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),false);
589 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),true);
590 0 : break;
591 : case aw_glyphs_simple:
592 : case aw_classes_simple:
593 : case aw_coverage_simple:
594 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Prev),ccd->fpst->type!=pst_reversesub);
595 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_Next),false);
596 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_OK),true);
597 0 : break;
598 : default:
599 0 : IError("Can't get here");
600 0 : break;
601 : }
602 0 : }
603 :
604 0 : static int CCD_ReasonableClassNum(const unichar_t *umatch,GGadget *list,
605 : struct fpst_rule *r, int which ) {
606 : int cols, len;
607 : struct matrix_data *classes;
608 0 : char *match = u2utf8_copy(umatch);
609 : char *pt, *start, *end;
610 : int doit;
611 : int any,val;
612 :
613 0 : cols = GMatrixEditGetColCnt(list);
614 0 : classes = GMatrixEditGet(list,&len);
615 :
616 0 : for ( doit = 0; doit<2; ++doit ) {
617 0 : any = 0;
618 0 : for ( pt=match;; ) {
619 0 : while ( *pt==' ' ) ++pt;
620 0 : if ( *pt=='\0' )
621 0 : break;
622 0 : for ( start=pt; *pt!=' ' && *pt!='\0'; ++pt );
623 0 : val = strtol(start,&end,10);
624 0 : if ( *end!='\0' ) {
625 0 : for ( val=len-1; val>=0; --val )
626 0 : if ( classes[cols*val+0].u.md_str!=NULL &&
627 0 : strlen(classes[cols*val+0].u.md_str)==pt-start &&
628 0 : strncasecmp(start,classes[cols*val+0].u.md_str,pt-start)==0 )
629 0 : break;
630 : }
631 0 : if ( val<0 || val>=len ) {
632 0 : ff_post_error(_("Bad Class"),_("%.*s is not a valid class name (or number)"), pt-start, start);
633 0 : return( false );
634 : }
635 0 : if ( doit )
636 0 : (&r->u.class.nclasses)[which][any] = val;
637 0 : ++any;
638 0 : }
639 0 : if ( !doit ) {
640 0 : (&r->u.class.ncnt)[which] = any;
641 0 : (&r->u.class.nclasses)[which] = malloc(any*sizeof(uint16));
642 : }
643 : }
644 0 : return( true );
645 : }
646 :
647 0 : static int ClassNamePrep(struct contextchaindlg *ccd,struct matrix_data **classes,int clen[3]) {
648 : int i;
649 :
650 0 : for ( i=0; i<3; ++i ) {
651 0 : if ( i==0 || !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_SameAsClasses+i*20)) )
652 0 : classes[i] = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300+i*20),&clen[i]);
653 : else
654 0 : classes[i] = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300),&clen[i]);
655 : }
656 0 : return( GMatrixEditGetColCnt(GWidgetGetControl(ccd->gw,CID_GList+300+0*20)) );
657 : }
658 :
659 0 : static void CCD_FinishRule(struct contextchaindlg *ccd) {
660 : struct fpst_rule dummy;
661 : GGadget *list;
662 : int i,tot;
663 : char *buts[3];
664 0 : buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL;
665 : struct matrix_data *md;
666 : int len;
667 : int clen[3], ccols;
668 : struct matrix_data *classes[3];
669 :
670 0 : if ( ccd->aw==aw_classnumber ) {
671 : char *ret;
672 0 : memset(&dummy,0,sizeof(dummy));
673 0 : CCD_ParseLookupList(ccd->sf,&dummy,GWidgetGetControl(ccd->gw,CID_LookupList+500));
674 0 : if ( dummy.lookup_cnt==0 ) {
675 0 : int ans = gwwv_ask(_("No Sequence/Lookups"),
676 : (const char **) buts,0,1,
677 0 : _("There are no entries in the Sequence/Lookup List, was this intentional?"));
678 0 : if ( ans==1 )
679 0 : return;
680 : }
681 0 : ccols = ClassNamePrep(ccd,classes,clen);
682 0 : if ( !CCD_ReasonableClassNum(
683 0 : _GGadgetGetTitle(GWidgetGetControl(ccd->gw,CID_ClassNumbers)),
684 0 : GWidgetGetControl(ccd->gw,CID_ClassList),
685 0 : &dummy,0) ||
686 0 : !CCD_ReasonableClassNum(
687 0 : _GGadgetGetTitle(GWidgetGetControl(ccd->gw,CID_ClassNumbers+20)),
688 0 : GWidgetGetControl(ccd->gw,CID_ClassList+20),
689 0 : &dummy,1) ||
690 0 : !CCD_ReasonableClassNum(
691 0 : _GGadgetGetTitle(GWidgetGetControl(ccd->gw,CID_ClassNumbers+40)),
692 0 : GWidgetGetControl(ccd->gw,CID_ClassList+40),
693 : &dummy,2)) {
694 0 : FPSTRuleContentsFree(&dummy,pst_class);
695 0 : return;
696 : }
697 : /* reverse the backtrack */
698 0 : for ( i=0; i<dummy.u.class.bcnt/2; ++i ) {
699 0 : int temp = dummy.u.class.bclasses[i];
700 0 : dummy.u.class.bclasses[i] = dummy.u.class.bclasses[dummy.u.class.bcnt-1-i];
701 0 : dummy.u.class.bclasses[dummy.u.class.bcnt-1-i] = temp;
702 : }
703 0 : for ( i=0; i<dummy.lookup_cnt; ++i ) {
704 0 : if ( dummy.lookups[i].seq >= dummy.u.class.ncnt ) {
705 0 : ff_post_error(_("Bad Sequence/Lookup List"),_("Sequence number out of bounds, must be less than %d (number of classes in list above)"), dummy.u.class.ncnt );
706 0 : return;
707 : }
708 : }
709 0 : ret = classruleitem(&dummy,classes,clen,ccols);
710 0 : FPSTRuleContentsFree(&dummy,pst_class);
711 0 : list = GWidgetGetControl(ccd->gw,CID_GList+200);
712 0 : md = GMatrixEditGet(list,&len);
713 0 : free(md[ccd->row_being_edited].u.md_str);
714 0 : md[ccd->row_being_edited].u.md_str = ret;
715 0 : GMatrixEditSet(list,md,len,false);
716 0 : ccd->aw = aw_classrules;
717 0 : GDrawSetVisible(ccd->classnumber,false);
718 0 : GDrawSetVisible(ccd->classrules,true);
719 0 : } else if ( ccd->aw==aw_glyphs ) { /* It's from glyph list */
720 : char *ret, *temp, *freeme;
721 :
722 0 : memset(&dummy,0,sizeof(dummy));
723 0 : CCD_ParseLookupList(ccd->sf,&dummy,GWidgetGetControl(ccd->gw,CID_LookupList));
724 0 : if ( dummy.lookup_cnt==0 ) {
725 0 : int ans = gwwv_ask(_("No Sequence/Lookups"),
726 : (const char **) buts,0,1,
727 0 : _("There are no entries in the Sequence/Lookup List, was this intentional?"));
728 0 : if ( ans==1 )
729 0 : return;
730 : }
731 0 : temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList));
732 0 : dummy.u.glyph.names = GlyphNameListDeUnicode(temp);
733 0 : free(temp);
734 0 : tot = CCD_GlyphNameCnt( temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList)));
735 0 : free(temp);
736 0 : for ( i=0; i<dummy.lookup_cnt; ++i ) {
737 0 : if ( dummy.lookups[i].seq >= tot ) {
738 0 : ff_post_error(_("Bad Sequence/Lookup List"),_("Sequence number out of bounds, must be less than %d (number of glyphs, classes or coverage tables)"), tot );
739 0 : return;
740 : }
741 : }
742 0 : temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+20));
743 0 : freeme = GlyphNameListDeUnicode(temp);
744 0 : dummy.u.glyph.back = reversenames(freeme);
745 0 : free(temp); free(freeme);
746 0 : temp = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+40));
747 0 : dummy.u.glyph.fore = GlyphNameListDeUnicode(temp);
748 0 : free(temp);
749 0 : ret = gruleitem(&dummy);
750 0 : FPSTRuleContentsFree(&dummy,pst_glyphs);
751 0 : list = GWidgetGetControl(ccd->gw,CID_GList+0);
752 0 : md = GMatrixEditGet(list,&len);
753 0 : free(md[ccd->row_being_edited].u.md_str);
754 0 : md[ccd->row_being_edited].u.md_str = ret;
755 0 : GMatrixEditSet(list,md,len,false);
756 0 : ccd->aw = aw_grules;
757 0 : GDrawSetVisible(ccd->glyphs,false);
758 0 : GDrawSetVisible(ccd->grules,true);
759 : } else {
760 0 : IError("Bad format in CCD_FinishRule");
761 : }
762 : }
763 :
764 0 : static int isEverythingElse(char *text) {
765 : /* GT: The string "{Everything Else}" is used in the context of a list */
766 : /* GT: of classes (a set of kerning classes) where class 0 designates the */
767 : /* GT: default class containing all glyphs not specified in the other classes */
768 0 : int ret = strcmp(text,_("{Everything Else}"));
769 0 : return( ret==0 );
770 : }
771 :
772 0 : static char *CCD_PickGlyphsForClass(GGadget *g,int r, int c) {
773 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
774 0 : int rows, cols = GMatrixEditGetColCnt(g);
775 0 : struct matrix_data *classes = _GMatrixEditGet(g,&rows);
776 0 : char *new = GlyphSetFromSelection(ccd->sf,ccd->layer,classes[r*cols+c].u.md_str);
777 0 : return( new );
778 : }
779 :
780 0 : static void _CCD_FromSelection(struct contextchaindlg *ccd,int cid ) {
781 0 : char *curval = GGadgetGetTitle8(GWidgetGetControl(ccd->gw,cid));
782 0 : char *new = GlyphSetFromSelection(ccd->sf,ccd->layer,curval);
783 :
784 0 : free(curval);
785 0 : if ( new==NULL )
786 0 : return;
787 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,cid),new);
788 0 : free(new);
789 : }
790 :
791 0 : static int CCD_FromSelection(GGadget *g, GEvent *e) {
792 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
793 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
794 0 : int cid = (intpt) GGadgetGetUserData(g);
795 :
796 0 : _CCD_FromSelection(ccd,cid);
797 : }
798 0 : return( true );
799 : }
800 :
801 0 : static struct matrix_data *MD2MD(struct matrix_data *md,int len) {
802 0 : struct matrix_data *newmd = calloc(2*len,sizeof(struct matrix_data));
803 : int i;
804 :
805 0 : for ( i=0; i<len; ++i ) {
806 0 : newmd[2*i+0].u.md_str = copy(md[3*i+0].u.md_str);
807 0 : newmd[2*i+1].u.md_str = copy(md[3*i+1].u.md_str);
808 : }
809 0 : return( newmd );
810 : }
811 :
812 0 : static void CCD_NewGlyphRule(GGadget *glyphrules,int r,int c) {
813 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(glyphrules));
814 : int rows;
815 0 : struct matrix_data *rulelist = GMatrixEditGet(glyphrules,&rows);
816 : struct fpst_rule dummy;
817 0 : GGadget *lookuplist = GWidgetGetControl(ccd->glyphs,CID_LookupList+0);
818 : struct matrix_data *md;
819 : char *temp2;
820 : int j;
821 :
822 0 : memset(&dummy,0,sizeof(dummy));
823 0 : gruleitem2rule(ccd->sf,rulelist[r].u.md_str,&dummy);
824 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList),dummy.u.glyph.names==NULL?"":dummy.u.glyph.names);
825 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+20),(temp2 = reversenames(dummy.u.glyph.back))==NULL ? "" : temp2);
826 0 : free(temp2);
827 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_GlyphList+40),dummy.u.glyph.fore!=NULL?dummy.u.glyph.fore:"");
828 :
829 0 : md = calloc(2*dummy.lookup_cnt,sizeof(struct matrix_data));
830 0 : for ( j=0; j<dummy.lookup_cnt; ++j ) {
831 0 : md[2*j+0].u.md_ival = (intpt) (void *) dummy.lookups[j].lookup;
832 0 : md[2*j+1].u.md_ival = (intpt) dummy.lookups[j].seq;
833 : }
834 0 : GMatrixEditSet(lookuplist,md,dummy.lookup_cnt,false);
835 0 : ccd->aw = aw_glyphs;
836 0 : ccd->row_being_edited = r;
837 0 : GDrawSetVisible(ccd->grules,false);
838 0 : GDrawSetVisible(ccd->glyphs,true);
839 0 : CCD_EnableNextPrev(ccd);
840 0 : }
841 :
842 0 : static char *_CCD_NewGlyphRule(GGadget *glyphrules,int r,int c) {
843 : int rows;
844 0 : struct matrix_data *rulelist = GMatrixEditGet(glyphrules,&rows);
845 0 : CCD_NewGlyphRule(glyphrules,r,c);
846 0 : return( copy( rulelist[r].u.md_str ) ); /* We change the display to get the new value, but we must return something... */
847 : }
848 :
849 0 : static void CCD_NewClassRule(GGadget *classrules,int r,int c) {
850 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(classrules));
851 : int rows;
852 0 : struct matrix_data *rulelist = GMatrixEditGet(classrules,&rows);
853 : struct fpst_rule dummy;
854 0 : GGadget *lookuplist = GWidgetGetControl(ccd->classnumber,CID_LookupList+500);
855 : struct matrix_data *md, *classes[3];
856 : int len, clen[3], ccols;
857 : int i,j;
858 : char *temp;
859 :
860 0 : ccols = ClassNamePrep(ccd,classes,clen);
861 0 : memset(&dummy,0,sizeof(dummy));
862 0 : classruleitem2rule(ccd->sf,rulelist[r].u.md_str,&dummy,classes,clen,ccols);
863 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_ClassNumbers),
864 0 : (temp=classnumbers(dummy.u.class.ncnt,dummy.u.class.nclasses,classes[0],clen[0],ccols)));
865 0 : free(temp);
866 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_ClassNumbers+20),
867 0 : (temp=rclassnumbers(dummy.u.class.bcnt,dummy.u.class.bclasses,classes[1],clen[1],ccols)));
868 0 : free(temp);
869 0 : GGadgetSetTitle8(GWidgetGetControl(ccd->gw,CID_ClassNumbers+40),
870 0 : (temp=classnumbers(dummy.u.class.fcnt,dummy.u.class.fclasses,classes[2],clen[2],ccols)));
871 0 : free(temp);
872 :
873 0 : md = calloc(2*dummy.lookup_cnt,sizeof(struct matrix_data));
874 0 : for ( j=0; j<dummy.lookup_cnt; ++j ) {
875 0 : md[2*j+0].u.md_ival = (intpt) (void *) dummy.lookups[j].lookup;
876 0 : md[2*j+1].u.md_ival = (intpt) dummy.lookups[j].seq;
877 : }
878 0 : GMatrixEditSet(lookuplist,md,dummy.lookup_cnt,false);
879 0 : FPSTRuleContentsFree(&dummy,pst_class);
880 0 : GWidgetIndicateFocusGadget(GWidgetGetControl(ccd->gw,CID_ClassNumbers));
881 0 : for ( i=0; i<3; ++i ) {
882 0 : if ( i!=0 && GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_SameAsClasses+i*20)) )
883 0 : md = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300),&len);
884 : else
885 0 : md = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+300+i*20),&len);
886 0 : GMatrixEditSet(GWidgetGetControl(ccd->gw,CID_ClassList+i*20),MD2MD(md,len),len,false);
887 : }
888 0 : ccd->aw = aw_classnumber;
889 0 : ccd->row_being_edited = r;
890 0 : GDrawSetVisible(ccd->classrules,false);
891 0 : GDrawSetVisible(ccd->classnumber,true);
892 0 : CCD_EnableNextPrev(ccd);
893 0 : }
894 :
895 0 : static char *_CCD_NewClassRule(GGadget *classrules,int r,int c) {
896 : int rows;
897 0 : struct matrix_data *rulelist = GMatrixEditGet(classrules,&rows);
898 0 : CCD_NewClassRule(classrules,r,c);
899 0 : return( copy( rulelist[r].u.md_str ) ); /* We change the display to get the new value, but we must return something... */
900 : }
901 :
902 0 : static int CCD_SameAsClasses(GGadget *g, GEvent *e) {
903 0 : int ison = GGadgetIsChecked(g);
904 0 : int cid = GGadgetGetCid(g);
905 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
906 :
907 0 : if ( cid < CID_SameAsClasses_S ) {
908 0 : int off = cid-CID_SameAsClasses;
909 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_GList+300+off),!ison);
910 0 : return( true );
911 : } else {
912 0 : int off = cid-CID_SameAsClasses_S;
913 0 : GGadgetSetEnabled(GWidgetGetControl(ccd->gw,CID_CList_Simple+off),!ison);
914 0 : return( true );
915 : }
916 : }
917 :
918 0 : static void CCD_ClassSelected(GGadget *g, int r, int c) {
919 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
920 0 : int off = GGadgetGetCid(g)-CID_ClassList;
921 0 : int rows, cols = GMatrixEditGetColCnt(g);
922 0 : struct matrix_data *classes = GMatrixEditGet(g,&rows);
923 0 : GGadget *tf = GWidgetGetControl(ccd->gw,CID_ClassNumbers+off);
924 : char buf[20];
925 : unichar_t ubuf[80];
926 :
927 0 : if ( r<0 || r>=rows )
928 0 : return;
929 0 : if ( classes[cols*r+0].u.md_str == NULL || classes[cols*r+0].u.md_str[0]=='\0' ) {
930 0 : sprintf( buf, " %d ", r );
931 0 : uc_strcpy(ubuf,buf);
932 : } else {
933 0 : ubuf[0]=' ';
934 0 : utf82u_strncpy(ubuf+1,classes[cols*r+0].u.md_str,sizeof(ubuf)/sizeof(ubuf[0])-2 );
935 0 : ubuf[sizeof(ubuf)/sizeof(ubuf[0])-2] = '\0';
936 0 : uc_strcat(ubuf," ");
937 : }
938 0 : GTextFieldReplace(tf,ubuf);
939 0 : return;
940 : }
941 :
942 0 : static void CCD_Close(struct contextchaindlg *ccd) {
943 0 : if ( ccd->isnew )
944 0 : GFI_FinishContextNew(ccd->gfi,ccd->fpst,false);
945 0 : ccd->done = true;
946 0 : }
947 :
948 0 : static char **CCD_ParseCoverageList(struct contextchaindlg *ccd,int cid,int *cnt) {
949 : int i;
950 : int _cnt;
951 0 : struct matrix_data *covers = GMatrixEditGet(GWidgetGetControl(ccd->gw,cid),&_cnt);
952 : char **ret;
953 :
954 0 : *cnt = _cnt;
955 0 : if ( _cnt==0 )
956 0 : return( NULL );
957 0 : ret = malloc(*cnt*sizeof(char *));
958 0 : for ( i=0; i<_cnt; ++i )
959 0 : ret[i] = GlyphNameListDeUnicode(covers[i].u.md_str);
960 0 : return( ret );
961 : }
962 :
963 0 : static void CoverageReverse(char **bcovers,int bcnt) {
964 : int i;
965 : char *temp;
966 :
967 0 : for ( i=0; i<bcnt/2; ++i ) {
968 0 : temp = bcovers[i];
969 0 : bcovers[i] = bcovers[bcnt-i-1];
970 0 : bcovers[bcnt-i-1] = temp;
971 : }
972 0 : }
973 :
974 0 : static void _CCD_Ok(struct contextchaindlg *ccd) {
975 0 : FPST *fpst = ccd->fpst, *dummyfpst;
976 : int len, i, k, had_class0, clen[3], ccols;
977 : struct matrix_data *old, *classes[3], *classes_simple;
978 : struct fpst_rule dummy;
979 : char *msg;
980 : int ans, cnt, cols, first, last, forward_start;
981 : int iswarning;
982 : char *temp;
983 : int has[3];
984 : char *buts[3];
985 :
986 0 : buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL;
987 :
988 0 : switch ( ccd->aw ) {
989 : case aw_grules: {
990 0 : old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList),&len);
991 0 : if ( len==0 ) {
992 0 : ff_post_error(_("Missing rules"),_(" There must be at least one contextual rule"));
993 0 : return;
994 : }
995 0 : FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
996 0 : fpst->format = pst_glyphs;
997 0 : fpst->rule_cnt = len;
998 0 : fpst->rules = calloc(len,sizeof(struct fpst_rule));
999 0 : for ( i=0; i<len; ++i )
1000 0 : gruleitem2rule(ccd->sf,old[i].u.md_str,&fpst->rules[i]);
1001 0 : } break;
1002 : case aw_classrules: {
1003 0 : old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+200),&len);
1004 0 : if ( len==0 ) {
1005 0 : ff_post_error(_("Missing rules"),_(" There must be at least one contextual rule"));
1006 0 : return;
1007 : }
1008 0 : FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
1009 0 : fpst->format = pst_class;
1010 0 : fpst->rule_cnt = len;
1011 0 : fpst->rules = calloc(len,sizeof(struct fpst_rule));
1012 0 : fpst->nccnt = fpst->bccnt = fpst->fccnt = 0;
1013 0 : fpst->nclass = fpst->bclass = fpst->fclass = NULL;
1014 0 : has[1] = has[2] = false; has[0] = true;
1015 0 : ccols = ClassNamePrep(ccd,classes,clen);
1016 0 : for ( i=0; i<len; ++i ) {
1017 0 : classruleitem2rule(ccd->sf,old[i].u.md_str,&fpst->rules[i],classes,clen,ccols);
1018 0 : if ( fpst->rules[i].u.class.bcnt!=0 ) has[1] = true;
1019 0 : if ( fpst->rules[i].u.class.fcnt!=0 ) has[2] = true;
1020 : }
1021 0 : for ( i=0; i<3; ++i ) {
1022 0 : if ( i!=0 && !has[i] )
1023 0 : continue;
1024 0 : (&fpst->nccnt)[i] = clen[i];
1025 0 : (&fpst->nclass)[i] = malloc(clen[i]*sizeof(char*));
1026 0 : (&fpst->nclass)[i][0] = NULL;
1027 0 : had_class0 = i==0 && !isEverythingElse(classes[i][0].u.md_str);
1028 0 : for ( k=had_class0 ? 0 : 1 ; k<clen[i]; ++k )
1029 0 : (&fpst->nclass)[i][k] = GlyphNameListDeUnicode(classes[i][ccols*k+1].u.md_str);
1030 0 : for ( k=0; k<clen[i]; ++k )
1031 0 : (&fpst->nclassnames)[i][k] = copy(classes[i][ccols*k+0].u.md_str);
1032 : }
1033 0 : } break;
1034 : case aw_coverage:
1035 0 : old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_GList+100),&len);
1036 0 : if ( len==0 ) {
1037 0 : ff_post_error(_("Bad Coverage Table"),_("There must be at least one match coverage table"));
1038 0 : return;
1039 : }
1040 0 : if ( fpst->format==pst_reversecoverage ) {
1041 0 : if ( len!=1 ) {
1042 0 : ff_post_error(_("Bad Coverage Table"),_("In a Reverse Chaining Substitution there must be exactly one coverage table to match"));
1043 0 : return;
1044 : }
1045 0 : if ( CCD_GlyphNameCnt(old[0].u.md_str)!=CCD_GlyphNameCnt(
1046 0 : temp=GGadgetGetTitle8(GWidgetGetControl(ccd->gw,CID_RplList+100))) ) {
1047 0 : free(temp);
1048 0 : ff_post_error(_("Replacement mismatch"),_("In a Reverse Chaining Substitution there must be exactly as many replacements as there are glyph names in the match coverage table"));
1049 0 : return;
1050 : }
1051 0 : dummy.u.rcoverage.replacements = GlyphNameListDeUnicode(temp);
1052 0 : free(temp);
1053 : } else {
1054 0 : CCD_ParseLookupList(ccd->sf,&dummy,GWidgetGetControl(ccd->gw,CID_LookupList+100));
1055 0 : if ( dummy.lookup_cnt==0 ) {
1056 0 : int ans = gwwv_ask(_("No Sequence/Lookups"),
1057 : (const char **) buts,0,1,
1058 0 : _("There are no entries in the Sequence/Lookup List, was this intentional?"));
1059 0 : if ( ans==1 )
1060 0 : return;
1061 : }
1062 : }
1063 0 : FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
1064 0 : fpst->format = fpst->type==pst_reversesub ? pst_reversecoverage : pst_coverage;
1065 0 : fpst->rule_cnt = 1;
1066 0 : fpst->rules = calloc(1,sizeof(struct fpst_rule));
1067 0 : fpst->rules[0].u.coverage.ncovers = CCD_ParseCoverageList(ccd,CID_GList+100,&fpst->rules[0].u.coverage.ncnt);
1068 0 : fpst->rules[0].u.coverage.bcovers = CCD_ParseCoverageList(ccd,CID_GList+100+20,&fpst->rules[0].u.coverage.bcnt);
1069 0 : CoverageReverse(fpst->rules[0].u.coverage.bcovers,fpst->rules[0].u.coverage.bcnt);
1070 0 : fpst->rules[0].u.coverage.fcovers = CCD_ParseCoverageList(ccd,CID_GList+100+40,&fpst->rules[0].u.coverage.fcnt);
1071 0 : if ( fpst->format==pst_reversecoverage )
1072 0 : fpst->rules[0].u.rcoverage.replacements = dummy.u.rcoverage.replacements;
1073 : else {
1074 0 : fpst->rules[0].lookup_cnt = dummy.lookup_cnt;
1075 0 : fpst->rules[0].lookups = dummy.lookups;
1076 0 : for ( i=0; i<dummy.lookup_cnt; ++i ) {
1077 0 : if ( dummy.lookups[i].seq >= fpst->rules[0].u.coverage.ncnt ) {
1078 0 : ff_post_error(_("Bad Sequence/Lookup List"),
1079 0 : _("Sequence number out of bounds, must be less than %d (number of classes in list above)"),
1080 0 : fpst->rules[0].u.coverage.ncnt );
1081 0 : return;
1082 : }
1083 : }
1084 : }
1085 0 : break;
1086 : case aw_classes_simple:
1087 : case aw_glyphs_simple: {
1088 0 : old = GMatrixEditGet(GWidgetGetControl(ccd->gw,ccd->aw==aw_glyphs_simple?CID_GList_Simple:CID_CList_Simple),&len);
1089 0 : if ( len==0 ) {
1090 0 : ff_post_error(_("Missing rules"),_(" There must be at least one contextual rule"));
1091 0 : return;
1092 : }
1093 0 : dummyfpst = chunkalloc(sizeof(FPST));
1094 0 : *dummyfpst = *fpst;
1095 0 : dummyfpst->format = pst_glyphs;
1096 0 : if ( ccd->aw==aw_classes_simple ) {
1097 0 : dummyfpst->format = pst_class;
1098 0 : for ( i=0; i<3; ++i ) { int clen;
1099 0 : if ( i==0 || !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_SameAsClasses_S+i*20)) )
1100 0 : classes_simple = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_MatchClasses+i*20),&clen);
1101 : else /* If SameAs the reparse the match classes_simple */
1102 0 : classes_simple = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_MatchClasses),&clen);
1103 0 : (&dummyfpst->nccnt)[i] = clen;
1104 0 : if ( clen!=0 ) {
1105 0 : (&dummyfpst->nclass)[i] = malloc(clen*sizeof(char*));
1106 0 : (&dummyfpst->nclassnames)[i] = malloc(clen*sizeof(char*));
1107 0 : (&dummyfpst->nclass)[i][0] = NULL;
1108 0 : (&dummyfpst->nclassnames)[i][0] = NULL;
1109 0 : had_class0 = i==0 && !isEverythingElse(classes_simple[3*0+1].u.md_str);
1110 0 : if ( !had_class0 )
1111 0 : (&dummyfpst->nclassnames)[i][0] = copy(classes_simple[3*0+0].u.md_str);
1112 0 : for ( k=had_class0 ? 0 : 1 ; k<clen; ++k ) {
1113 0 : (&dummyfpst->nclassnames)[i][k] = copy(classes_simple[3*k+0].u.md_str);
1114 0 : (&dummyfpst->nclass)[i][k] = GlyphNameListDeUnicode(classes_simple[3*k+1].u.md_str);
1115 : }
1116 : }
1117 : }
1118 : } else {
1119 0 : dummyfpst->nccnt = dummyfpst->bccnt = dummyfpst->fccnt = 0;
1120 0 : dummyfpst->nclass = dummyfpst->bclass = dummyfpst->fclass = NULL;
1121 0 : dummyfpst->nclassnames = dummyfpst->bclassnames = dummyfpst->fclassnames = NULL;
1122 : }
1123 0 : dummyfpst->rule_cnt = len;
1124 0 : dummyfpst->rules = calloc(len,sizeof(struct fpst_rule));
1125 0 : for ( i=0; i<len; ++i ) {
1126 0 : char *temp = old[i].u.md_str;
1127 0 : if ( ccd->aw==aw_glyphs_simple )
1128 0 : temp = GlyphNameListDeUnicode(temp);
1129 0 : msg = FPSTRule_From_Str(ccd->sf,dummyfpst,&dummyfpst->rules[i],temp,&iswarning);
1130 0 : if ( temp!=old[i].u.md_str )
1131 0 : free(temp);
1132 0 : if ( msg!=NULL ) {
1133 0 : if ( !iswarning ) {
1134 0 : ff_post_error(_("Bad rule"), "%s", msg );
1135 0 : free(msg);
1136 0 : FPSTClassesFree(dummyfpst);
1137 0 : FPSTRulesFree(dummyfpst->rules,dummyfpst->format,dummyfpst->rule_cnt);
1138 0 : chunkfree(dummyfpst,sizeof(FPST));
1139 0 : return;
1140 : } else {
1141 0 : ans = gwwv_ask(_("Warning"),
1142 : (const char **) buts,0,1,
1143 0 : _("%s\nProceed anyway?"), msg);
1144 0 : free(msg);
1145 0 : if ( ans==1 ) {
1146 0 : FPSTClassesFree(dummyfpst);
1147 0 : FPSTRulesFree(dummyfpst->rules,dummyfpst->format,dummyfpst->rule_cnt);
1148 0 : chunkfree(dummyfpst,sizeof(FPST));
1149 0 : return;
1150 : }
1151 : }
1152 : }
1153 : }
1154 0 : FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
1155 0 : fpst->format = dummyfpst->format;
1156 0 : fpst->rule_cnt = dummyfpst->rule_cnt;
1157 0 : fpst->rules = dummyfpst->rules;
1158 0 : if ( fpst->format==pst_class ) {
1159 0 : FPSTClassesFree(fpst);
1160 0 : fpst->nccnt = dummyfpst->nccnt; fpst->bccnt = dummyfpst->bccnt; fpst->fccnt = dummyfpst->fccnt;
1161 0 : fpst->nclass = dummyfpst->nclass; fpst->bclass = dummyfpst->bclass; fpst->fclass = dummyfpst->fclass;
1162 0 : fpst->nclassnames = dummyfpst->nclassnames; fpst->bclassnames = dummyfpst->bclassnames; fpst->fclassnames = dummyfpst->fclassnames;
1163 : }
1164 0 : chunkfree(dummyfpst,sizeof(FPST));
1165 0 : } break;
1166 : case aw_coverage_simple:
1167 0 : old = GMatrixEditGet(GWidgetGetControl(ccd->gw,CID_Covers),&len);
1168 0 : cols = GMatrixEditGetColCnt(GWidgetGetControl(ccd->gw,CID_Covers));
1169 0 : if ( len==0 ) {
1170 0 : ff_post_error(_("Bad Coverage Table"),_("There must be at least one match coverage table"));
1171 0 : return;
1172 : }
1173 0 : memset(&dummy,0,sizeof(dummy));
1174 0 : if ( fpst->format==pst_reversecoverage ) {
1175 0 : first = last = -1;
1176 0 : for ( i=0; i<len; ++i ) {
1177 0 : if ( old[cols*i+1].u.md_str!=NULL && *old[cols*i+1].u.md_str!='\0' ) {
1178 0 : if ( first==-1 )
1179 0 : first = last = i;
1180 : else {
1181 0 : ff_post_error(_("Bad Coverage Table"),_("In a Reverse Chaining Substitution there must be exactly one coverage table with replacements"));
1182 0 : return;
1183 : }
1184 : }
1185 : }
1186 0 : if ( first==-1 ) {
1187 0 : ff_post_error(_("Bad Coverage Table"),_("In a Reverse Chaining Substitution there must be exactly one coverage table with replacements"));
1188 0 : return;
1189 : }
1190 0 : if ( GlyphNameCnt(old[cols*first+0].u.md_str)!=GlyphNameCnt(old[cols*first+1].u.md_str) ) {
1191 0 : ff_post_error(_("Replacement mismatch"),_("In a Reverse Chaining Substitution there must be exactly as many replacements as there are glyph names in the match coverage table"));
1192 0 : return;
1193 : }
1194 0 : forward_start = last+1;
1195 : } else {
1196 0 : first = last = forward_start = -1;
1197 0 : if ( fpst->type == pst_contextpos || fpst->type == pst_contextsub ) {
1198 0 : first = 0;
1199 0 : forward_start = len;
1200 : /* No check here to see if any lookups invoked. It's only a warning */
1201 : /* Do we need to add it???? */
1202 : } else {
1203 0 : for ( i=0; i<len; ++i ) {
1204 0 : if ( old[cols*i+2].u.md_ival ) {
1205 0 : if ( first==-1 )
1206 0 : first = last = i;
1207 0 : else if ( forward_start==-1 ) {
1208 0 : if ( old[cols*i+1].u.md_addr!=NULL ) {
1209 0 : ff_post_error(_("Bad Sections"),_("The sections specified do not make sense. All lookups must lie in the middle section."));
1210 0 : return;
1211 : }
1212 0 : forward_start = i;
1213 : } else {
1214 0 : ff_post_error(_("Bad Sections"),_("The sections specified do not make sense. All lookups must lie in the middle section."));
1215 0 : return;
1216 : }
1217 0 : } else if ( old[cols*i+1].u.md_addr!=NULL ) {
1218 0 : if ( first==-1 )
1219 0 : first = last = i;
1220 0 : else if ( forward_start!=-1 ) {
1221 0 : ff_post_error(_("Bad Sections"),_("The sections specified do not make sense. All lookups must lie in the middle section."));
1222 0 : return;
1223 : }
1224 : }
1225 : }
1226 0 : if ( forward_start==-1 && last!=-1 )
1227 0 : forward_start = last+1;
1228 0 : if ( first==-1 ) {
1229 0 : ans = gwwv_ask(_("Warning"),
1230 : (const char **) buts,0,1,
1231 0 : _("This rule activates no lookups.\nProceed anyway?"));
1232 0 : if ( ans==1 )
1233 0 : return;
1234 0 : first = 0;
1235 0 : forward_start = len;
1236 : }
1237 : }
1238 0 : for ( i=first, cnt=0; i<forward_start; ++i )
1239 0 : if ( old[cols*i+1].u.md_addr!=NULL )
1240 0 : ++cnt;
1241 0 : dummy.lookup_cnt = cnt;
1242 0 : if ( cnt!=0 ) {
1243 0 : dummy.lookups = calloc(cnt,sizeof(struct seqlookup));
1244 0 : for ( i=first, cnt=0; i<forward_start; ++i ) {
1245 0 : if ( old[cols*i+1].u.md_addr!=NULL ) {
1246 0 : dummy.lookups[cnt].lookup = old[cols*i+1].u.md_addr;
1247 0 : dummy.lookups[cnt].seq = i-first;
1248 0 : ++cnt;
1249 : }
1250 : }
1251 : }
1252 : }
1253 0 : dummy.u.coverage.bcnt = first;
1254 0 : dummy.u.coverage.ncnt = forward_start-first;
1255 0 : dummy.u.coverage.fcnt = len-forward_start;
1256 0 : dummy.u.coverage.ncovers = malloc(dummy.u.coverage.ncnt*sizeof(char *));
1257 0 : if ( dummy.u.coverage.bcnt!=0 )
1258 0 : dummy.u.coverage.bcovers = malloc(dummy.u.coverage.bcnt*sizeof(char *));
1259 0 : if ( dummy.u.coverage.fcnt!=0 )
1260 0 : dummy.u.coverage.fcovers = malloc(dummy.u.coverage.fcnt*sizeof(char *));
1261 0 : for ( i=0; i<first; ++i )
1262 0 : dummy.u.coverage.bcovers[first-1-i] = GlyphNameListDeUnicode( old[cols*i+0].u.md_str );
1263 0 : for ( i=0; i<dummy.u.coverage.ncnt; ++i )
1264 0 : dummy.u.coverage.ncovers[i] = GlyphNameListDeUnicode( old[cols*(first+i)+0].u.md_str );
1265 0 : for ( i=forward_start; i<len; ++i )
1266 0 : dummy.u.coverage.fcovers[i-forward_start] = GlyphNameListDeUnicode( old[cols*i+0].u.md_str );
1267 0 : FPSTClassesFree(fpst);
1268 0 : FPSTRulesFree(fpst->rules,fpst->format,fpst->rule_cnt);
1269 0 : fpst->format = fpst->type==pst_reversesub ? pst_reversecoverage : pst_coverage;
1270 0 : fpst->rule_cnt = 1;
1271 0 : fpst->rules = calloc(1,sizeof(struct fpst_rule));
1272 0 : fpst->rules[0] = dummy;
1273 0 : break;
1274 : default:
1275 0 : IError("The OK button should not be enabled here");
1276 0 : return;
1277 : }
1278 0 : if ( ccd->isnew )
1279 0 : GFI_FinishContextNew(ccd->gfi,ccd->fpst,true);
1280 0 : ccd->done = true;
1281 : }
1282 :
1283 0 : static int CCD_OK(GGadget *g, GEvent *e) {
1284 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1285 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1286 0 : _CCD_Ok(ccd);
1287 : }
1288 0 : return( true );
1289 : }
1290 :
1291 0 : static int CCD_Cancel(GGadget *g, GEvent *e) {
1292 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1293 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1294 0 : CCD_Close(ccd);
1295 : }
1296 0 : return( true );
1297 : }
1298 :
1299 0 : static int CCD_Next(GGadget *g, GEvent *e) {
1300 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1301 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1302 0 : switch ( ccd->aw ) {
1303 : case aw_formats:
1304 0 : GDrawSetVisible(ccd->formats,false);
1305 0 : if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_Simple)) ) {
1306 0 : if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByGlyph)) ) {
1307 0 : ccd->aw = aw_glyphs_simple;
1308 0 : GDrawSetVisible(ccd->glyphs_simple,true);
1309 0 : } else if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByClass)) ) {
1310 0 : ccd->aw = aw_classes_simple;
1311 0 : GDrawSetVisible(ccd->classes_simple,true);
1312 : } else {
1313 0 : ccd->aw = aw_coverage_simple;
1314 0 : GDrawSetVisible(ccd->coverage_simple,true);
1315 : }
1316 : } else {
1317 0 : if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByGlyph)) ) {
1318 0 : ccd->aw = aw_grules;
1319 0 : GDrawSetVisible(ccd->grules,true);
1320 0 : } else if ( GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ByClass)) ) {
1321 0 : ccd->aw = aw_classrules;
1322 0 : GDrawSetVisible(ccd->classrules,true);
1323 : } else {
1324 0 : ccd->aw = aw_coverage;
1325 0 : GDrawSetVisible(ccd->coverage,true);
1326 : }
1327 : }
1328 0 : break;
1329 : case aw_glyphs:
1330 : case aw_classnumber:
1331 0 : CCD_FinishRule(ccd);
1332 0 : break;
1333 : default:
1334 0 : IError("The next button should not be enabled here");
1335 0 : break;
1336 : }
1337 0 : CCD_EnableNextPrev(ccd);
1338 : }
1339 0 : return( true );
1340 : }
1341 :
1342 0 : static int CCD_Prev(GGadget *g, GEvent *e) {
1343 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1344 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1345 0 : switch ( ccd->aw ) {
1346 : case aw_formats:
1347 0 : CCD_Cancel(g,e);
1348 0 : break;
1349 : case aw_glyphs:
1350 0 : ccd->aw = aw_grules;
1351 0 : GDrawSetVisible(ccd->glyphs,false);
1352 0 : GDrawSetVisible(ccd->grules,true);
1353 0 : break;
1354 : case aw_classnumber:
1355 0 : ccd->aw = aw_classrules;
1356 0 : GDrawSetVisible(ccd->classnumber,false);
1357 0 : GDrawSetVisible(ccd->classrules,true);
1358 0 : break;
1359 : case aw_coverage:
1360 : case aw_classrules:
1361 : case aw_grules:
1362 0 : ccd->aw = aw_formats;
1363 0 : GDrawSetVisible(ccd->coverage,false);
1364 0 : GDrawSetVisible(ccd->classrules,false);
1365 0 : GDrawSetVisible(ccd->grules,false);
1366 0 : GDrawSetVisible(ccd->formats,true);
1367 0 : break;
1368 : case aw_coverage_simple:
1369 : case aw_classes_simple:
1370 : case aw_glyphs_simple:
1371 0 : ccd->aw = aw_formats;
1372 0 : GDrawSetVisible(ccd->coverage_simple,false);
1373 0 : GDrawSetVisible(ccd->classes_simple,false);
1374 0 : GDrawSetVisible(ccd->glyphs_simple,false);
1375 0 : GDrawSetVisible(ccd->formats,true);
1376 0 : break;
1377 : default:
1378 0 : IError("Can't get here");
1379 0 : break;
1380 : }
1381 0 : CCD_EnableNextPrev(ccd);
1382 : }
1383 0 : return( true );
1384 : }
1385 :
1386 0 : static void CCD_SimulateDefaultButton( struct contextchaindlg *ccd ) {
1387 : GEvent ev;
1388 :
1389 : /* figure out what the default action should be */
1390 0 : memset(&ev,0,sizeof(ev));
1391 0 : ev.type = et_controlevent;
1392 0 : ev.u.control.subtype = et_buttonactivate;
1393 0 : if ( ccd->aw==aw_formats || ccd->aw == aw_glyphs ) {
1394 0 : ev.u.control.g = GWidgetGetControl(ccd->gw,CID_Next);
1395 0 : CCD_Next(ev.u.control.g,&ev);
1396 : /* For the glyph list and the coverage list, the [Next] button is disabled */
1397 : /* I think [OK] is probably inappropriate, so let's do either [New] or [Edit] */
1398 : /* (which are what [Next] would logically do) depending on which of the two */
1399 : /* is more appropriate */
1400 : /* ev.u.control.g = GWidgetGetControl(ccd->gw,CID_OK); */
1401 : /* CCD_OK(ev.u.control.g,&ev); */
1402 : } else {
1403 : }
1404 0 : }
1405 :
1406 0 : static int CCD_NewSection(GGadget *g, GEvent *e) {
1407 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1408 0 : int off = GGadgetGetCid(g)-CID_GNewSection;
1409 0 : GGadget *gme = GWidgetGetControl(GGadgetGetWindow(g),CID_GList_Simple+off);
1410 0 : GGadget *tf = _GMatrixEditGetActiveTextField(gme);
1411 : static const unichar_t section_mark[] = { ' ', '|', ' ', '\0' };
1412 :
1413 0 : if ( tf!=NULL )
1414 0 : GTextFieldReplace(tf,section_mark);
1415 : }
1416 0 : return( true );
1417 : }
1418 :
1419 0 : static int CCD_AddLookup(GGadget *g, GEvent *e) {
1420 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
1421 0 : int off = GGadgetGetCid(g)-CID_GAddLookup;
1422 0 : GGadget *gme = GWidgetGetControl(GGadgetGetWindow(g),CID_GList_Simple+off);
1423 0 : GGadget *tf = _GMatrixEditGetActiveTextField(gme);
1424 0 : GTextInfo *lookup_ti = GGadgetGetListItemSelected(g);
1425 : OTLookup *otl;
1426 :
1427 0 : if ( tf!=NULL && lookup_ti!=NULL && lookup_ti->userdata!=NULL) {
1428 : char *space;
1429 : unichar_t *temp;
1430 0 : otl = lookup_ti->userdata;
1431 0 : space = malloc(strlen(otl->lookup_name)+8);
1432 0 : sprintf( space, " @<%s> ", otl->lookup_name );
1433 0 : temp = utf82u_copy(space);
1434 0 : GTextFieldReplace(tf,temp);
1435 0 : free(space);
1436 0 : free(temp);
1437 : }
1438 0 : GGadgetSelectOneListItem(g,0);
1439 : }
1440 0 : return( true );
1441 : }
1442 :
1443 0 : static int subccd_e_h(GWindow gw, GEvent *event) {
1444 0 : if ( event->type==et_char ) {
1445 0 : if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1446 0 : help("contextchain.html");
1447 0 : return( true );
1448 0 : } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
1449 0 : MenuExit(NULL,NULL,NULL);
1450 0 : return( true );
1451 0 : } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
1452 0 : CCD_Close(GDrawGetUserData(gw));
1453 0 : return( true );
1454 0 : } else if ( event->u.chr.chars[0]=='\r' ) {
1455 0 : CCD_SimulateDefaultButton( (struct contextchaindlg *) GDrawGetUserData(gw));
1456 0 : return( true );
1457 : }
1458 0 : return( false );
1459 : }
1460 0 : return( true );
1461 : }
1462 :
1463 0 : static int ccd_e_h(GWindow gw, GEvent *event) {
1464 0 : if ( event->type==et_close ) {
1465 0 : struct contextchaindlg *ccd = GDrawGetUserData(gw);
1466 0 : CCD_Close(ccd);
1467 0 : } else if ( event->type==et_destroy ) {
1468 0 : struct contextchaindlg *ccd = GDrawGetUserData(gw);
1469 0 : chunkfree(ccd,sizeof(struct contextchaindlg));
1470 0 : } else if ( event->type==et_char ) {
1471 0 : if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1472 0 : help("contextchain.html");
1473 0 : return( true );
1474 0 : } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
1475 0 : MenuExit(NULL,NULL,NULL);
1476 0 : return( true );
1477 0 : } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
1478 0 : CCD_Close(GDrawGetUserData(gw));
1479 0 : return( true );
1480 0 : } else if ( event->u.chr.chars[0]=='\r' ) {
1481 0 : CCD_SimulateDefaultButton( (struct contextchaindlg *) GDrawGetUserData(gw));
1482 0 : return( true );
1483 : }
1484 0 : return( false );
1485 0 : } else if ( event->type==et_resize ) {
1486 : /* int blen = GDrawPointsToPixels(NULL,GIntGetResource(_NUM_Buttonsize)),*/
1487 : GRect wsize;
1488 0 : struct contextchaindlg *ccd = GDrawGetUserData(gw);
1489 :
1490 0 : GGadgetGetSize(GWidgetGetControl(ccd->gw,CID_SubSize),&wsize);
1491 :
1492 0 : GDrawResize(ccd->formats,wsize.width,wsize.height);
1493 0 : GDrawResize(ccd->coverage,wsize.width,wsize.height);
1494 0 : GDrawResize(ccd->grules,wsize.width,wsize.height);
1495 0 : GDrawResize(ccd->glyphs,wsize.width,wsize.height);
1496 0 : GDrawResize(ccd->classrules,wsize.width,wsize.height);
1497 0 : GDrawResize(ccd->classnumber,wsize.width,wsize.height);
1498 0 : GDrawResize(ccd->coverage_simple,wsize.width,wsize.height);
1499 0 : GDrawResize(ccd->glyphs_simple,wsize.width,wsize.height);
1500 0 : GDrawResize(ccd->classes_simple,wsize.width,wsize.height);
1501 :
1502 0 : GDrawRequestExpose(ccd->gw,NULL,false);
1503 0 : GDrawRequestExpose(ccd->aw==aw_formats ? ccd->formats :
1504 0 : ccd->aw==aw_coverage ? ccd->coverage :
1505 0 : ccd->aw==aw_grules ? ccd->grules :
1506 0 : ccd->aw==aw_glyphs ? ccd->glyphs :
1507 0 : ccd->aw==aw_classrules ? ccd->classrules :
1508 0 : ccd->aw==aw_classnumber ? ccd->classnumber :
1509 0 : ccd->aw==aw_coverage_simple ? ccd->coverage_simple :
1510 0 : ccd->aw==aw_classes_simple ? ccd->classes_simple :
1511 : ccd->glyphs_simple, NULL,false);
1512 : }
1513 0 : return( true );
1514 : }
1515 :
1516 : #define CCD_WIDTH 340
1517 : #define CCD_HEIGHT 340
1518 :
1519 0 : static unichar_t **CCD_GlyphListCompletion(GGadget *t,int from_tab) {
1520 0 : struct contextchaindlg *ccd = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
1521 0 : SplineFont *sf = ccd->sf;
1522 :
1523 0 : return( SFGlyphNameCompletion(sf,t,from_tab,true));
1524 : }
1525 :
1526 0 : static unichar_t **CCD_ClassListCompletion(GGadget *t,int from_tab) {
1527 0 : struct contextchaindlg *ccd = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
1528 : unichar_t *pt, *spt, *basept, *wild; unichar_t **ret;
1529 : int i, cnt, doit, match_len;
1530 : int do_wildcards;
1531 : int section;
1532 : int namecnt;
1533 : int cid;
1534 : struct matrix_data *classnames;
1535 :
1536 0 : section = 0;
1537 :
1538 0 : pt = spt = basept = (unichar_t *) _GGadgetGetTitle(t);
1539 0 : if ( pt==NULL || *pt=='\0' )
1540 0 : return( NULL );
1541 :
1542 0 : if ( ccd->fpst->type==pst_contextsub || ccd->fpst->type==pst_contextpos )
1543 0 : section=1;
1544 : else {
1545 0 : for ( pt=basept; *pt ; ++pt )
1546 0 : if ( *pt=='|' )
1547 0 : ++section;
1548 0 : if ( section>2 )
1549 0 : section=2;
1550 : }
1551 0 : if ( section==0 && !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_BackClassesSameAs_S)) )
1552 0 : cid = CID_BackClasses;
1553 0 : else if ( section==2 && !GGadgetIsChecked(GWidgetGetControl(ccd->gw,CID_ForeClassesSameAs_S)) )
1554 0 : cid = CID_ForeClasses;
1555 : else
1556 0 : cid = CID_MatchClasses;
1557 0 : classnames = GMatrixEditGet(GWidgetGetControl(ccd->gw,cid),&namecnt);
1558 0 : if ( namecnt==0 ) /* No classes_simple specified yet, can't help */
1559 0 : return( NULL );
1560 :
1561 0 : if (( spt = u_strrchr(spt,' '))== NULL )
1562 0 : spt = basept;
1563 : else {
1564 0 : pt = ++spt;
1565 0 : if ( *pt=='\0' )
1566 0 : return( NULL );
1567 : }
1568 0 : while ( *pt && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
1569 0 : ++pt;
1570 0 : do_wildcards = *pt!='\0';
1571 :
1572 0 : if ( do_wildcards && !from_tab )
1573 0 : return( NULL );
1574 :
1575 0 : wild = NULL;
1576 0 : if ( do_wildcards ) {
1577 0 : pt = spt;
1578 0 : wild = malloc((u_strlen(spt)+2)*sizeof(unichar_t));
1579 0 : u_strcpy(wild,pt);
1580 0 : uc_strcat(wild,"*");
1581 : }
1582 :
1583 0 : match_len = u_strlen(spt);
1584 0 : ret = NULL;
1585 0 : for ( doit=0; doit<2; ++doit ) {
1586 0 : cnt=0;
1587 0 : for ( i=0; i<namecnt; ++i ) if ( classnames[3*i+0].u.md_str!=NULL ) {
1588 : int matched;
1589 0 : char *str = classnames[3*i+0].u.md_str;
1590 0 : if ( do_wildcards ) {
1591 0 : unichar_t *temp = utf82u_copy(str);
1592 0 : matched = GGadgetWildMatch((unichar_t *) wild,temp,false);
1593 0 : free(temp);
1594 : } else
1595 0 : matched = uc_strncmp(spt,str,match_len)==0;
1596 0 : if ( matched ) {
1597 0 : if ( doit ) {
1598 0 : if ( spt==basept ) {
1599 0 : ret[cnt] = utf82u_copy(str);
1600 : } else {
1601 0 : unichar_t *temp = malloc((spt-basept+strlen(str)+4)*sizeof(unichar_t));
1602 : int len;
1603 0 : u_strncpy(temp,basept,spt-basept);
1604 0 : utf82u_strcpy(temp+(spt-basept),str);
1605 0 : len = u_strlen(temp);
1606 0 : ret[cnt] = temp;
1607 : }
1608 : }
1609 0 : ++cnt;
1610 : }
1611 : }
1612 0 : if ( doit )
1613 0 : ret[cnt] = NULL;
1614 0 : else if ( cnt==0 )
1615 0 : break;
1616 : else
1617 0 : ret = malloc((cnt+1)*sizeof(unichar_t *));
1618 : }
1619 0 : free(wild);
1620 0 : return( ret );
1621 : }
1622 :
1623 0 : static void CCD_FinishCoverageEdit(GGadget *g,int r, int c, int wasnew) {
1624 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1625 :
1626 0 : ME_SetCheckUnique(g, r, c, ccd->sf);
1627 0 : }
1628 :
1629 0 : static void CCD_FinishCoverageSimpleEdit(GGadget *g,int r, int c, int wasnew) {
1630 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1631 0 : int cols = GMatrixEditGetColCnt(g);
1632 : int first, last, i;
1633 : int rows;
1634 0 : struct matrix_data *covers = _GMatrixEditGet(g,&rows);
1635 :
1636 :
1637 0 : if ( c==0 )
1638 0 : ME_SetCheckUnique(g, r, c, ccd->sf);
1639 0 : else if ( c==1 && cols==2 ) { /* The replacement list in a reverse coverage_simple */
1640 0 : ME_ListCheck(g, r, c, ccd->sf);
1641 0 : } else if ( c==1 && cols==4 ) { /* The lookup in a coverage_simple line (not reverse coverage_simple) */
1642 0 : if ( covers[cols*r+c].u.md_addr== (void *) (intpt) -1 ) {
1643 : /* They asked to remove the lookup that was there */
1644 0 : covers[cols*r+c].u.md_addr = NULL;
1645 0 : } else if ( covers[cols*r+c].u.md_addr==NULL ) {
1646 : /* The selected the "Add Lookup" item which should be a no-op */
1647 : /* but actually sets the thing to 0 */
1648 0 : covers[cols*r+c].u.md_addr = covers[cols*r+3].u.md_addr;
1649 : }
1650 : /* Save the new value somewhere safe */
1651 0 : covers[cols*r+3].u.md_addr = covers[cols*r+c].u.md_addr;
1652 0 : first = last = -1;
1653 0 : for ( i=0; i<rows; ++i ) {
1654 0 : if ( covers[cols*i+c].u.md_addr!=NULL ) {
1655 0 : if ( first==-1 )
1656 0 : first = i;
1657 0 : last = i;
1658 : }
1659 : }
1660 0 : if ( first!=-1 ) {
1661 : /* there may not be a section break between first and last */
1662 0 : for ( i=first; i<=last; ++i )
1663 0 : covers[cols*i+2].u.md_ival = false;
1664 0 : for ( i=0; i<first; ++i )
1665 0 : if ( covers[cols*i+2].u.md_ival )
1666 0 : break;
1667 0 : if ( i==first )
1668 0 : covers[cols*first+2].u.md_ival = true;
1669 0 : for ( i=rows-1; i>last; --i )
1670 0 : if ( covers[cols*i+2].u.md_ival )
1671 0 : break;
1672 0 : if ( i<=last && last+1<rows )
1673 0 : covers[cols*(last+1)+2].u.md_ival = true;
1674 : }
1675 0 : GGadgetRedraw(g);
1676 0 : } else if ( c==2 ) {
1677 0 : first = last = -1;
1678 0 : for ( i=0; i<rows; ++i ) {
1679 0 : if ( covers[cols*i+1].u.md_addr!=NULL ) {
1680 0 : if ( first==-1 )
1681 0 : first = i;
1682 0 : last = i;
1683 : }
1684 : }
1685 0 : if ( covers[cols*i+2].u.md_ival ) {
1686 0 : if ( r<=first ) {
1687 0 : for ( i=0; i<=first; ++i ) if ( i!=r )
1688 0 : covers[cols*i+2].u.md_ival = false;
1689 0 : } else if ( r<=last ) {
1690 0 : covers[cols*i+2].u.md_ival = false;
1691 0 : GDrawBeep(NULL);
1692 : } else {
1693 0 : for ( i=last+1; i<=rows; ++i ) if ( i!=r )
1694 0 : covers[cols*i+2].u.md_ival = false;
1695 : }
1696 : } else {
1697 0 : for ( i=first; i>=0; --i )
1698 0 : if ( covers[cols*i+2].u.md_ival )
1699 0 : break;
1700 0 : if ( i==0 )
1701 0 : covers[cols*0+2].u.md_ival = true;
1702 : }
1703 0 : GGadgetRedraw(g);
1704 : }
1705 0 : }
1706 :
1707 0 : static int WhichSections(struct contextchaindlg *ccd, GGadget *g) {
1708 0 : int off = GGadgetGetCid(g)-CID_MatchClasses;
1709 0 : int sections = 0;
1710 :
1711 0 : if ( ccd->fpst->type==pst_contextpos || ccd->fpst->type==pst_contextsub )
1712 0 : sections = 0x7; /* All sections */
1713 0 : else if ( off==0 ) {
1714 0 : sections = 0x2; /* Match */
1715 0 : if ( GGadgetIsChecked(GWidgetGetControl(ccd->classes_simple,CID_SameAsClasses_S+20)))
1716 0 : sections |= 0x1;
1717 0 : if ( GGadgetIsChecked(GWidgetGetControl(ccd->classes_simple,CID_SameAsClasses_S+40)))
1718 0 : sections |= 0x4;
1719 0 : } else if ( off==20 )
1720 0 : sections = 0x1; /* Backtracking */
1721 : else
1722 0 : sections = 0x4; /* Foreward */
1723 0 : return( sections );
1724 : }
1725 :
1726 0 : static void RenameClass(struct contextchaindlg *ccd,char *old,char *new,int sections) {
1727 : /* A class has been renamed. We should fix up all class rules that use */
1728 : /* the old name to use the new one. The name may only be valid in one */
1729 : /* section of the rule (backtrack, match, or forward), or in all, or */
1730 : /* in match and one of the other two */
1731 : int rows, i;
1732 0 : GGadget *gclassrules = GWidgetGetControl(ccd->classes_simple,CID_CList_Simple);
1733 0 : struct matrix_data *classrules = GMatrixEditGet(gclassrules,&rows);
1734 0 : int cols = GMatrixEditGetColCnt(gclassrules);
1735 0 : char *end_back=NULL, *end_match=NULL, *pt, *last_name, *temp;
1736 : int ch;
1737 :
1738 0 : if ( sections==0x7 ) {
1739 : /* name change applies through out rule, no need to search for sections */
1740 0 : for ( i=0; i<rows; ++i ) {
1741 0 : char *oldrule = classrules[cols*i+0].u.md_str;
1742 0 : char *newrule = rpl(oldrule,old,new);
1743 0 : free(oldrule);
1744 0 : classrules[cols*i+0].u.md_str = newrule;
1745 : }
1746 : } else {
1747 0 : for ( i=0; i<rows; ++i ) {
1748 0 : char *oldrule = classrules[cols*i+0].u.md_str;
1749 : char *newrule;
1750 0 : for ( pt=last_name=oldrule; *pt; ) {
1751 0 : while ( isspace(*pt)) ++pt;
1752 0 : if ( *pt=='|' ) {
1753 0 : if ( end_back == NULL )
1754 0 : end_back = pt;
1755 0 : else if ( end_match==NULL )
1756 0 : end_match = pt;
1757 0 : } else if ( end_back==NULL && ( *pt=='<' || *pt=='@' )) {
1758 0 : end_back = last_name;
1759 : } else
1760 0 : last_name = pt;
1761 0 : if ( *pt=='<' || *pt=='@' ) {
1762 0 : while ( *pt!='>' && *pt!='\0' ) ++pt;
1763 0 : if ( *pt=='>' ) ++pt;
1764 : } else {
1765 0 : while ( !isspace( *pt ) && *pt!='\0' )
1766 0 : ++pt;
1767 : }
1768 : }
1769 0 : if ( (sections==0x3 && end_match==NULL) ||
1770 0 : (sections==0x6 && end_back==NULL) ||
1771 0 : (sections==0x2 && end_match==NULL && end_back==NULL)) {
1772 0 : newrule = rpl(oldrule,old,new);
1773 0 : } else if ( sections==0x3 ) {
1774 0 : ch = *end_match; *end_match='\0';
1775 0 : temp = rpl(oldrule,old,new);
1776 0 : *end_match = ch;
1777 0 : newrule = strconcat(temp,end_match);
1778 0 : free(temp);
1779 0 : } else if ( sections==0x6 ) {
1780 0 : temp = rpl(end_back,old,new);
1781 0 : ch = *end_back; *end_back = '\0';
1782 0 : newrule = strconcat(oldrule,temp);
1783 0 : *end_back = ch;
1784 0 : free(temp);
1785 0 : } else if ( sections==0x1 ) {
1786 0 : if ( end_back==NULL )
1787 0 : newrule=NULL;
1788 : else {
1789 0 : ch = *end_back; *end_back = '\0';
1790 0 : temp = rpl(oldrule,old,new);
1791 0 : *end_back = ch;
1792 0 : newrule = strconcat(temp,end_back);
1793 0 : free(temp);
1794 : }
1795 0 : } else if ( sections==0x2 ) {
1796 0 : if ( end_match==NULL ) {
1797 0 : temp = rpl(end_back,old,new); /* end_back is not NULL, checked above */
1798 0 : ch = *end_back; *end_back = '\0';
1799 0 : newrule = strconcat(oldrule,temp);
1800 0 : *end_back = ch;
1801 0 : free(temp);
1802 0 : } else if ( end_back==NULL ) {
1803 0 : ch = *end_match; *end_match = '\0';
1804 0 : temp = rpl(oldrule,old,new);
1805 0 : *end_match = ch;
1806 0 : newrule = strconcat(temp,end_match);
1807 0 : free(temp);
1808 : } else {
1809 0 : ch = *end_match; *end_match = '\0';
1810 0 : temp = rpl(end_back,old,new);
1811 0 : *end_match = ch;
1812 0 : ch = *end_back; *end_back = '\0';
1813 0 : newrule = strconcat3(oldrule,temp,end_match);
1814 0 : *end_back = ch;
1815 0 : free(temp);
1816 : }
1817 0 : } else if ( sections==0x4 ) {
1818 0 : if ( end_match==NULL )
1819 0 : newrule=NULL;
1820 : else {
1821 0 : temp = rpl(end_match,old,new);
1822 0 : ch = *end_match; *end_match = '\0';
1823 0 : newrule = strconcat(oldrule,temp);
1824 0 : *end_match = ch;
1825 0 : free(temp);
1826 : }
1827 : } else
1828 0 : newrule = NULL;
1829 0 : if ( newrule!=NULL ) {
1830 0 : free(oldrule);
1831 0 : classrules[cols*i+0].u.md_str = newrule;
1832 : }
1833 : }
1834 : }
1835 0 : GGadgetRedraw(gclassrules);
1836 0 : }
1837 :
1838 0 : static void CCD_FinishClassEdit(GGadget *g,int r, int c, int wasnew) {
1839 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1840 :
1841 0 : if ( c==1 )
1842 0 : ME_ClassCheckUnique(g, r, c, ccd->sf);
1843 0 : else if ( c==0 ) {
1844 : int rows, i;
1845 0 : struct matrix_data *classes_simple = _GMatrixEditGet(g,&rows);
1846 : char buffer[40], *end, *pt;
1847 :
1848 0 : if ( strchr(classes_simple[3*r+0].u.md_str,' ')!=NULL ) {
1849 0 : for ( pt=classes_simple[3*r+0].u.md_str; *pt; ++pt) {
1850 0 : if ( isspace(*pt))
1851 0 : *pt = '_';
1852 : }
1853 0 : GGadgetRedraw(g);
1854 0 : ff_post_error(_("Bad class name"),_("No spaces allowed in class names."));
1855 : }
1856 0 : i = strtol(classes_simple[3*r+0].u.md_str,&end,10);
1857 0 : if ( *end=='\0' && i!=r ) {
1858 0 : sprintf( buffer,"%d",r );
1859 0 : free( classes_simple[3*r+0].u.md_str );
1860 0 : classes_simple[3*r+0].u.md_str = copy(buffer);
1861 0 : GGadgetRedraw(g);
1862 0 : ff_post_error(_("Bad class name"),_("If a class name is a number, it must be the index of the class in the array of classes_simple."));
1863 : }
1864 0 : for ( i=0; i<rows; ++i ) if ( i!=r ) {
1865 0 : if ( strcmp(classes_simple[3*i+0].u.md_str,classes_simple[3*r+0].u.md_str) == 0 ) {
1866 0 : sprintf( buffer,"%d",r );
1867 0 : free( classes_simple[3*r+0].u.md_str );
1868 0 : classes_simple[3*r+0].u.md_str = copy(buffer);
1869 0 : GGadgetRedraw(g);
1870 0 : ff_post_error(_("Bad class name"),_("The class name, %s, is already in use."), classes_simple[3*i+0].u.md_str);
1871 : }
1872 : }
1873 0 : if ( strcmp(classes_simple[3*r+0].u.md_str,classes_simple[3*r+2].u.md_str)!=0 ) {
1874 0 : RenameClass(ccd,classes_simple[3*r+2].u.md_str,classes_simple[3*r+0].u.md_str,WhichSections(ccd,g));
1875 0 : free(classes_simple[3*r+2].u.md_str);
1876 0 : classes_simple[3*r+2].u.md_str = copy(classes_simple[3*r+0].u.md_str);
1877 : }
1878 : }
1879 0 : }
1880 :
1881 0 : static void CCD_ClassGoing(GGadget *g,int r) {
1882 : /* We are about to delete this row in the class dlg, so fix up all numeric */
1883 : /* classes_simple after it */
1884 0 : struct contextchaindlg *ccd = GDrawGetUserData(GGadgetGetWindow(g));
1885 0 : int sections = WhichSections(ccd,g);
1886 : int rows, i;
1887 0 : struct matrix_data *classes_simple = _GMatrixEditGet(g,&rows);
1888 : char buffer[20], *end;
1889 :
1890 0 : for ( i=r+1; i<rows; ++i ) {
1891 0 : strtol(classes_simple[3*i+0].u.md_str,&end,10);
1892 0 : if ( *end=='\0' ) {
1893 0 : sprintf(buffer,"%d",i-1);
1894 0 : free(classes_simple[3*i+0].u.md_str);
1895 0 : classes_simple[3*i+0].u.md_str = copy(buffer);
1896 0 : RenameClass(ccd,classes_simple[3*i+2].u.md_str,buffer,sections);
1897 0 : free(classes_simple[3*i+2].u.md_str);
1898 0 : classes_simple[3*i+2].u.md_str = copy(buffer);
1899 : }
1900 : }
1901 0 : }
1902 :
1903 0 : static void CCD_InitClassRow(GGadget *g,int r) {
1904 : char buffer[20];
1905 : int rows;
1906 0 : struct matrix_data *classes_simple = _GMatrixEditGet(g,&rows);
1907 :
1908 0 : sprintf( buffer, "%d", r );
1909 0 : classes_simple[3*r+0].u.md_str = copy(buffer);
1910 0 : }
1911 :
1912 0 : static int CCD_EnableDeleteClass(GGadget *g,int whichclass) {
1913 0 : return( whichclass>0 );
1914 : }
1915 :
1916 0 : static enum gme_updown CCD_EnableUpDown(GGadget *g,int r) {
1917 : int rows;
1918 0 : enum gme_updown ret = 0;
1919 :
1920 0 : (void) GMatrixEditGet(g,&rows);
1921 0 : if ( r>=2 )
1922 0 : ret = ud_up_enabled;
1923 0 : if ( r>=1 && r<rows-1 )
1924 0 : ret |= ud_down_enabled;
1925 0 : return( ret );
1926 : }
1927 :
1928 : static GTextInfo section[] = {
1929 : { (unichar_t *) N_("Section|Continue"), NULL, 0, 0, (void *) 0, NULL, 0, 0, 0, 0, 1, 0, 1, 0, 0, '\0'},
1930 : { (unichar_t *) N_("Section|Start"), NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
1931 : GTEXTINFO_EMPTY
1932 : };
1933 : static struct col_init class_ci[] = {
1934 : { me_string, NULL, NULL, NULL, N_("Class|Name") },
1935 : { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the class") },
1936 : { me_string, NULL, NULL, NULL, "Old Name (hidden)" },
1937 : };
1938 : static struct col_init classlist_ci[] = {
1939 : { me_string, NULL, NULL, NULL, N_("Class|Name") },
1940 : { me_string, NULL, NULL, NULL, N_("Glyphs in the class") },
1941 : };
1942 : static struct col_init coverage_ci[] = {
1943 : { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the coverage tables") },
1944 : };
1945 : static struct col_init seqlookup_ci[] = {
1946 : { me_enum, NULL, NULL, NULL, N_("Apply lookup") },
1947 : { me_int, NULL, NULL, NULL, N_("at position") },
1948 : };
1949 : static struct col_init glyphrules_ci[] = {
1950 : { me_onlyfuncedit, _CCD_NewGlyphRule, NULL, NULL, N_("Matching rules based on a list of glyphs") },
1951 : };
1952 : static struct col_init classrules_ci[] = {
1953 : { me_onlyfuncedit, _CCD_NewClassRule, NULL, NULL, N_("Matching rules based on a list of classes") },
1954 : };
1955 : static struct col_init coveragesimple_ci[] = {
1956 : { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the coverage tables") },
1957 : { me_enum, NULL, NULL, NULL, N_("Apply lookup") },
1958 : { me_enum, NULL, section, NULL, N_("Section")},
1959 : { me_addr, NULL, section, NULL, "Old lookup, internal use only"},
1960 : };
1961 : static struct col_init rcoveragesimple_ci[] = {
1962 : { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Glyphs in the coverage tables") },
1963 : { me_funcedit, CCD_PickGlyphsForClass, NULL, NULL, N_("Replacement glyphs") },
1964 : };
1965 : static struct col_init glyph_ci[] = {
1966 : { me_string, NULL, NULL, NULL, N_("Matching rules based on a list of glyphs") },
1967 : };
1968 : static struct col_init classsimple_ci[] = {
1969 : { me_string, NULL, NULL, NULL, N_("Matching rules based on a list of classes") },
1970 : };
1971 :
1972 : /* The "simple" dialog has several problems:
1973 : 1. The order in which lookups are to be applied is lost, they will be
1974 : applied in sequence order
1975 : 2. In coverage_simple classes_simple only one lookup may be applied for any given
1976 : coverage_simple set.
1977 : Adobe's feature files have these restrictions and more, so my hope is that
1978 : they will not matter.
1979 : If they do matter, then we fall back on the old, more complex (I think more
1980 : complex anyway) format.
1981 : */
1982 0 : static int CanBeSimple(FPST *fpst) {
1983 : int i, s, last_seq;
1984 0 : for ( i=0; i<fpst->rule_cnt; ++i ) {
1985 0 : struct fpst_rule *r = &fpst->rules[i];
1986 :
1987 0 : last_seq = -1;
1988 0 : for ( s=0; s<r->lookup_cnt; ++s ) {
1989 0 : if ( last_seq>r->lookups[s].seq )
1990 0 : return( false );
1991 0 : else if ( last_seq==r->lookups[s].seq &&
1992 0 : (fpst->format==pst_coverage || fpst->format==pst_reversecoverage))
1993 0 : return( false );
1994 0 : last_seq = r->lookups[s].seq;
1995 : }
1996 : }
1997 0 : return( true );
1998 : }
1999 :
2000 0 : void ContextChainEdit(SplineFont *sf,FPST *fpst,
2001 : struct gfi_data *gfi, unichar_t *newname,int layer) {
2002 : struct contextchaindlg *ccd;
2003 : int i,j,k;
2004 : static char *titles[2][5] = {
2005 : { N_("Edit Contextual Position"), N_("Edit Contextual Substitution"),
2006 : N_("Edit Chaining Position"), N_("Edit Chaining Substitution"),
2007 : N_("Edit Reverse Chaining Substitution"),
2008 : },
2009 : { N_("New Contextual Position"), N_("New Contextual Substitution"),
2010 : N_("New Chaining Position"), N_("New Chaining Substitution"),
2011 : N_("New Reverse Chaining Substitution")
2012 : }};
2013 : GRect pos, subpos;
2014 : GWindow gw;
2015 : GWindowAttrs wattrs;
2016 : GTabInfo faspects[5];
2017 : GGadgetCreateData glgcd[8], fgcd[3], ggcd[3][14], cgcd[3][18],
2018 : clgcd[10], subboxes[3][5], topbox[3], classbox[2], extrabuttonsgcd[3];
2019 : GTextInfo gllabel[8], flabel[3], glabel[3][14], clabel[3][18],
2020 : cllabel[10], extrabuttonslab[3];
2021 : GGadgetCreateData bgcd[6], rgcd[15], boxes[4], *barray[10], *hvarray[7][2];
2022 : GGadgetCreateData *subvarray[3][10], *subvarray2[4], *subvarray3[4], *topvarray[8],
2023 : *classv[4], *subvarray4[4], *barray2[6];
2024 : GTextInfo blabel[5], rlabel[15];
2025 0 : struct fpst_rule *r=NULL;
2026 : FPST *tempfpst;
2027 : struct matrixinit coverage_mi[3], class_mi[3], classlist_mi[3],
2028 : gl_seqlookup_mi, cl_seqlookup_mi,
2029 : co_seqlookup_mi, classrules_mi, glyphrules_mi,
2030 : coveragesimple_mi, classsimple_mi, glyphs_mi;
2031 : static int inited=false;
2032 0 : int isgpos = ( fpst->type==pst_contextpos || fpst->type==pst_chainpos );
2033 : struct matrix_data *md;
2034 : GTextInfo *lookup_list, *addlookup_list, *addrmlookup_list;
2035 0 : int use_simple = CanBeSimple(fpst);
2036 : struct matrix_data *_classes[3]; int clen[3];
2037 :
2038 0 : lookup_list = SFLookupArrayFromType(sf,isgpos?gpos_start:gsub_start);
2039 0 : for ( i=0; lookup_list[i].text!=NULL; ++i ) {
2040 0 : if (fpst!=NULL && lookup_list[i].userdata == fpst->subtable->lookup )
2041 0 : lookup_list[i].disabled = true;
2042 0 : lookup_list[i].selected = false;
2043 : }
2044 0 : addlookup_list = calloc(i+3,sizeof(GTextInfo));
2045 0 : memcpy(addlookup_list+1,lookup_list,(i+1)*sizeof(GTextInfo));
2046 0 : addrmlookup_list = calloc(i+3,sizeof(GTextInfo));
2047 0 : memcpy(addrmlookup_list+2,lookup_list,(i+1)*sizeof(GTextInfo));
2048 0 : addlookup_list[0].text = (unichar_t *) S_("Add Lookup");
2049 0 : addlookup_list[0].text_is_1byte = true;
2050 0 : addlookup_list[0].selected = true;
2051 0 : addrmlookup_list[0].text = (unichar_t *) S_("Add Lookup");
2052 0 : addrmlookup_list[0].text_is_1byte = true;
2053 0 : addrmlookup_list[0].selected = true;
2054 0 : addrmlookup_list[1].text = (unichar_t *) S_("Remove Lookup");
2055 0 : addrmlookup_list[1].text_is_1byte = true;
2056 0 : addrmlookup_list[1].selected = false;
2057 0 : addrmlookup_list[1].userdata = (void *) (intpt) -1;
2058 0 : coveragesimple_ci[1].enum_vals = addrmlookup_list;
2059 0 : seqlookup_ci[0].enum_vals = lookup_list;
2060 :
2061 0 : if ( !inited ) {
2062 0 : inited = true;
2063 0 : section[0].text = (unichar_t *) S_( (char *) section[0].text);
2064 0 : section[1].text = (unichar_t *) S_( (char *) section[1].text);
2065 0 : classlist_ci[0].title = class_ci[0].title = S_(class_ci[0].title);
2066 0 : classlist_ci[1].title = class_ci[1].title = S_(class_ci[1].title);
2067 0 : coverage_ci[0].title = S_(coverage_ci[0].title);
2068 0 : seqlookup_ci[0].title = S_(seqlookup_ci[0].title);
2069 0 : seqlookup_ci[1].title = S_(seqlookup_ci[1].title);
2070 0 : glyphrules_ci[0].title = S_(glyphrules_ci[0].title);
2071 0 : classrules_ci[0].title = S_(classrules_ci[0].title);
2072 0 : coveragesimple_ci[0].title = S_(coveragesimple_ci[0].title);
2073 0 : coveragesimple_ci[1].title = S_(coveragesimple_ci[1].title);
2074 0 : coveragesimple_ci[2].title = S_(coveragesimple_ci[2].title);
2075 0 : rcoveragesimple_ci[0].title = S_(rcoveragesimple_ci[0].title);
2076 0 : rcoveragesimple_ci[1].title = S_(rcoveragesimple_ci[1].title);
2077 0 : glyph_ci[0].title = S_(glyph_ci[0].title);
2078 : }
2079 :
2080 0 : ccd = chunkalloc(sizeof(struct contextchaindlg));
2081 0 : ccd->gfi = gfi;
2082 0 : ccd->sf = sf;
2083 0 : ccd->fpst = fpst;
2084 0 : ccd->newname = newname;
2085 0 : ccd->isnew = newname!=NULL;
2086 0 : ccd->layer = layer;
2087 :
2088 0 : memset(&wattrs,0,sizeof(wattrs));
2089 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2090 0 : wattrs.event_masks = ~(1<<et_charup);
2091 0 : wattrs.is_dlg = true;
2092 0 : wattrs.restrict_input_to_me = false;
2093 0 : wattrs.undercursor = 1;
2094 0 : wattrs.cursor = ct_pointer;
2095 0 : wattrs.utf8_window_title = _(titles[ccd->isnew][fpst->type-pst_contextpos]);
2096 0 : pos.x = pos.y = 0;
2097 0 : pos.width =GDrawPointsToPixels(NULL,GGadgetScale(CCD_WIDTH));
2098 0 : pos.height = GDrawPointsToPixels(NULL,CCD_HEIGHT);
2099 0 : ccd->gw = gw = GDrawCreateTopWindow(NULL,&pos,ccd_e_h,ccd,&wattrs);
2100 :
2101 0 : subpos = pos;
2102 0 : subpos.y = subpos.x = 4;
2103 0 : subpos.width -= 8;
2104 0 : ccd->subheightdiff = GDrawPointsToPixels(NULL,44)-8;
2105 0 : subpos.height -= ccd->subheightdiff;
2106 :
2107 :
2108 0 : memset(&blabel,0,sizeof(blabel));
2109 0 : memset(&bgcd,0,sizeof(bgcd));
2110 0 : memset(&boxes,0,sizeof(boxes));
2111 :
2112 0 : ccd->canceldrop = GDrawPointsToPixels(NULL,30);
2113 0 : bgcd[0].gd.pos = subpos;
2114 0 : bgcd[0].gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
2115 0 : bgcd[0].gd.cid = CID_SubSize;
2116 0 : bgcd[0].creator = GSpacerCreate;
2117 0 : hvarray[0][0] = &bgcd[0]; hvarray[0][1] = NULL;
2118 :
2119 0 : bgcd[1].gd.flags = gg_visible | gg_enabled;
2120 0 : blabel[1].text = (unichar_t *) _("_OK");
2121 0 : blabel[1].text_is_1byte = true;
2122 0 : blabel[1].text_in_resource = true;
2123 0 : bgcd[1].gd.label = &blabel[1];
2124 0 : bgcd[1].gd.cid = CID_OK;
2125 0 : bgcd[1].gd.handle_controlevent = CCD_OK;
2126 0 : bgcd[1].creator = GButtonCreate;
2127 0 : barray[0] = GCD_Glue; barray[1] = &bgcd[1];
2128 :
2129 0 : bgcd[2].gd.flags = gg_visible;
2130 0 : blabel[2].text = (unichar_t *) _("< _Prev");
2131 0 : blabel[2].text_is_1byte = true;
2132 0 : blabel[2].text_in_resource = true;
2133 0 : bgcd[2].gd.label = &blabel[2];
2134 0 : bgcd[2].gd.handle_controlevent = CCD_Prev;
2135 0 : bgcd[2].gd.cid = CID_Prev;
2136 0 : bgcd[2].creator = GButtonCreate;
2137 0 : barray[2] = GCD_Glue; barray[3] = &bgcd[2];
2138 :
2139 0 : bgcd[3].gd.flags = gg_visible;
2140 0 : blabel[3].text = (unichar_t *) _("_Next >");
2141 0 : blabel[3].text_is_1byte = true;
2142 0 : blabel[3].text_in_resource = true;
2143 0 : bgcd[3].gd.label = &blabel[3];
2144 0 : bgcd[3].gd.handle_controlevent = CCD_Next;
2145 0 : bgcd[3].gd.cid = CID_Next;
2146 0 : bgcd[3].creator = GButtonCreate;
2147 0 : barray[4] = GCD_Glue; barray[5] = &bgcd[3];
2148 :
2149 0 : bgcd[4].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
2150 0 : blabel[4].text = (unichar_t *) _("_Cancel");
2151 0 : blabel[4].text_is_1byte = true;
2152 0 : blabel[4].text_in_resource = true;
2153 0 : bgcd[4].gd.label = &blabel[4];
2154 0 : bgcd[4].gd.handle_controlevent = CCD_Cancel;
2155 0 : bgcd[4].gd.cid = CID_Cancel;
2156 0 : bgcd[4].creator = GButtonCreate;
2157 0 : barray[6] = GCD_Glue; barray[7] = &bgcd[4]; barray[8] = GCD_Glue; barray[9] = NULL;
2158 :
2159 0 : boxes[2].gd.flags = gg_enabled | gg_visible;
2160 0 : boxes[2].gd.u.boxelements = barray;
2161 0 : boxes[2].creator = GHBoxCreate;
2162 0 : hvarray[1][0] = &boxes[2]; hvarray[1][1] = hvarray[2][0] = NULL;
2163 :
2164 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
2165 0 : boxes[0].gd.flags = gg_enabled | gg_visible;
2166 0 : boxes[0].gd.u.boxelements = hvarray[0];
2167 0 : boxes[0].creator = GHVGroupCreate;
2168 :
2169 0 : if ( fpst->type == pst_reversesub ) {
2170 0 : bgcd[2].gd.flags = bgcd[3].gd.flags = gg_visible;
2171 0 : ccd->aw = use_simple ? aw_coverage_simple : aw_coverage;
2172 0 : } else if ( ccd->isnew || fpst->rule_cnt==0) {
2173 0 : fpst->format = pst_class;
2174 0 : bgcd[1].gd.flags = gg_visible;
2175 0 : bgcd[3].gd.flags = gg_visible | gg_enabled;
2176 0 : ccd->aw = aw_formats;
2177 0 : } else if ( fpst->format==pst_coverage ) {
2178 0 : bgcd[2].gd.flags = gg_visible | gg_enabled;
2179 0 : bgcd[3].gd.flags = gg_visible;
2180 0 : ccd->aw = use_simple ? aw_coverage_simple : aw_coverage;
2181 : /* different buttens are enabled from those of reversesub above */
2182 0 : } else if ( fpst->format==pst_class ) {
2183 0 : bgcd[2].gd.flags = gg_visible | gg_enabled;
2184 0 : bgcd[3].gd.flags = gg_visible;
2185 0 : ccd->aw = use_simple ? aw_classes_simple : aw_classrules;
2186 : } else {
2187 0 : bgcd[2].gd.flags = gg_visible | gg_enabled;
2188 0 : bgcd[3].gd.flags = gg_visible;
2189 0 : ccd->aw = use_simple ? aw_glyphs_simple : aw_grules;
2190 : }
2191 :
2192 0 : GGadgetsCreate(gw,boxes);
2193 0 : GHVBoxSetExpandableRow(boxes[0].ret,0);
2194 0 : GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
2195 : /*GHVBoxFitWindow(boxes[0].ret);*/
2196 :
2197 0 : wattrs.mask = wam_events;
2198 0 : ccd->formats = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2199 0 : memset(&rlabel,0,sizeof(rlabel));
2200 0 : memset(&rgcd,0,sizeof(rgcd));
2201 0 : memset(boxes,0,sizeof(boxes));
2202 :
2203 0 : i = 0;
2204 0 : rgcd[i].gd.pos.x = 5; rgcd[i].gd.pos.y = 5+i*13;
2205 0 : rgcd[i].gd.flags = gg_visible | gg_enabled;
2206 0 : rlabel[i].text = (unichar_t *) _(
2207 : "OpenType Contextual or Chaining subtables may be in one\n"
2208 : " of three formats. The context may be specified either\n"
2209 : " as a string of specific glyphs, a string of glyph classes\n"
2210 : " or a string of coverage tables\n"
2211 : "In the first format you must specify a string of glyph-names\n"
2212 : " In the second format you must specify a string of class names\n"
2213 : " In the third format you must specify a string each element\n"
2214 : " of which may contain several glyph-names\n"
2215 : "For chaining subtables you may also specify backtrack and\n"
2216 : " lookahead lists.");
2217 0 : rlabel[i].text_is_1byte = true;
2218 0 : rgcd[i].gd.label = &rlabel[i];
2219 0 : rgcd[i++].creator = GLabelCreate;
2220 0 : hvarray[0][0] = &rgcd[i-1]; hvarray[0][1] = NULL;
2221 :
2222 0 : rgcd[i].gd.flags = gg_visible | gg_enabled | (fpst->format==pst_glyphs ? gg_cb_on : 0 );
2223 0 : rlabel[i].text = (unichar_t *) _("By Glyphs");
2224 0 : rlabel[i].text_is_1byte = true;
2225 0 : rgcd[i].gd.label = &rlabel[i];
2226 0 : rgcd[i].gd.cid = CID_ByGlyph;
2227 0 : rgcd[i++].creator = GRadioCreate;
2228 0 : barray[0] = GCD_HPad10; barray[1] = &rgcd[i-1];
2229 :
2230 0 : rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
2231 0 : rgcd[i].gd.flags = gg_visible | gg_enabled | (fpst->format==pst_class ? gg_cb_on : 0 );
2232 0 : rlabel[i].text = (unichar_t *) _("By Classes");
2233 0 : rlabel[i].text_is_1byte = true;
2234 0 : rgcd[i].gd.label = &rlabel[i];
2235 0 : rgcd[i].gd.cid = CID_ByClass;
2236 0 : rgcd[i++].creator = GRadioCreate;
2237 0 : barray[2] = &rgcd[i-1];
2238 :
2239 0 : rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
2240 0 : rgcd[i].gd.flags = gg_visible | gg_enabled | (fpst->format!=pst_glyphs && fpst->format!=pst_class ? gg_cb_on : 0 );
2241 0 : rlabel[i].text = (unichar_t *) _("By Coverage");
2242 0 : rlabel[i].text_is_1byte = true;
2243 0 : rgcd[i].gd.label = &rlabel[i];
2244 0 : rgcd[i].gd.cid = CID_ByCoverage;
2245 0 : rgcd[i++].creator = GRadioCreate;
2246 0 : barray[3] = &rgcd[i-1]; barray[4] = GCD_Glue; barray[5] = NULL;
2247 :
2248 0 : boxes[2].gd.flags = gg_enabled|gg_visible;
2249 0 : boxes[2].gd.u.boxelements = barray;
2250 0 : boxes[2].creator = GHBoxCreate;
2251 0 : hvarray[1][0] = &boxes[2]; hvarray[1][1] = NULL;
2252 :
2253 0 : rgcd[i].gd.flags = gg_visible | gg_enabled;
2254 0 : rlabel[i].text = (unichar_t *) _(
2255 : "This dialog has two formats. A simpler one which\n"
2256 : " hides some of the complexities of these rules,\n"
2257 : " or a more complex form which gives you full control.");
2258 0 : rlabel[i].text_is_1byte = true;
2259 0 : rgcd[i].gd.label = &rlabel[i];
2260 0 : rgcd[i++].creator = GLabelCreate;
2261 0 : hvarray[2][0] = GCD_HPad10; hvarray[2][1] = NULL;
2262 0 : hvarray[3][0] = &rgcd[i-1]; hvarray[3][1] = NULL;
2263 :
2264 0 : rgcd[i].gd.pos.x = 5; rgcd[i].gd.pos.y = 5+i*13;
2265 0 : rgcd[i].gd.flags = gg_visible | gg_enabled;
2266 0 : rlabel[i].text = (unichar_t *) _( "Dialog Type:");
2267 0 : rlabel[i].text_is_1byte = true;
2268 0 : rgcd[i].gd.label = &rlabel[i];
2269 0 : rgcd[i++].creator = GLabelCreate;
2270 0 : barray2[0] = GCD_HPad10; barray2[1] = &rgcd[i-1];
2271 :
2272 0 : rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
2273 0 : rgcd[i].gd.flags = gg_visible | gg_enabled | (use_simple ? gg_cb_on : 0 );
2274 0 : rlabel[i].text = (unichar_t *) _("Simple");
2275 0 : rlabel[i].text_is_1byte = true;
2276 0 : rgcd[i].gd.label = &rlabel[i];
2277 0 : rgcd[i].gd.cid = CID_Simple;
2278 0 : rgcd[i++].creator = GRadioCreate;
2279 0 : barray2[2] = &rgcd[i-1];
2280 :
2281 0 : rgcd[i].gd.pos.x = rgcd[i-1].gd.pos.x; rgcd[i].gd.pos.y = rgcd[i-1].gd.pos.y+16;
2282 0 : rgcd[i].gd.flags = gg_visible | gg_enabled | (!use_simple ? gg_cb_on : 0 );
2283 0 : rlabel[i].text = (unichar_t *) _("Complex");
2284 0 : rlabel[i].text_is_1byte = true;
2285 0 : rgcd[i].gd.label = &rlabel[i];
2286 0 : rgcd[i].gd.cid = CID_Complex;
2287 0 : rgcd[i++].creator = GRadioCreate;
2288 0 : barray2[3] = &rgcd[i-1]; barray2[4] = GCD_Glue; barray2[5] = NULL;
2289 :
2290 0 : boxes[3].gd.flags = gg_enabled|gg_visible;
2291 0 : boxes[3].gd.u.boxelements = barray2;
2292 0 : boxes[3].creator = GHBoxCreate;
2293 0 : hvarray[4][0] = &boxes[3]; hvarray[4][1] = NULL;
2294 0 : hvarray[5][0] = GCD_Glue; hvarray[5][1] = NULL; hvarray[6][0] = NULL;
2295 :
2296 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
2297 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
2298 0 : boxes[0].gd.u.boxelements = hvarray[0];
2299 0 : boxes[0].creator = GHVGroupCreate;
2300 :
2301 0 : GGadgetsCreate(ccd->formats,boxes);
2302 0 : GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
2303 0 : GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
2304 0 : GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
2305 :
2306 : /* Pane showing all rules from a glyph format, simple format */
2307 0 : ccd->grules = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2308 0 : memset(&gllabel,0,sizeof(gllabel));
2309 0 : memset(&glgcd,0,sizeof(glgcd));
2310 :
2311 0 : k = 0;
2312 0 : memset(&glyphrules_mi,0,sizeof(glyphrules_mi));
2313 0 : glyphrules_mi.col_cnt = 1;
2314 0 : glyphrules_mi.col_init = glyphrules_ci;
2315 0 : if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 ) {
2316 0 : glyphrules_mi.initial_row_cnt = fpst->rule_cnt;
2317 0 : md = calloc(fpst->rule_cnt,sizeof(struct matrix_data));
2318 0 : for ( j=0; j<fpst->rule_cnt; ++j ) {
2319 0 : md[j+0].u.md_str = gruleitem(&fpst->rules[j]);
2320 : }
2321 0 : glyphrules_mi.matrix_data = md;
2322 : } else {
2323 0 : glyphrules_mi.initial_row_cnt = 0;
2324 0 : glyphrules_mi.matrix_data = NULL;
2325 : }
2326 0 : glgcd[k].gd.flags = gg_visible | gg_enabled;
2327 0 : glgcd[k].gd.cid = CID_GList+0;
2328 0 : glgcd[k].gd.u.matrix = &glyphrules_mi;
2329 0 : glgcd[k++].creator = GMatrixEditCreate;
2330 : /* No need for a box, this widget fills the pane */
2331 :
2332 0 : GGadgetsCreate(ccd->grules,glgcd);
2333 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->grules,CID_GList+0),
2334 : true);
2335 0 : GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->grules,CID_GList+0),CCD_NewGlyphRule);
2336 :
2337 0 : ccd->glyphs_simple = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2338 0 : memset(&gllabel,0,sizeof(gllabel));
2339 0 : memset(&glgcd,0,sizeof(glgcd));
2340 :
2341 0 : k = 0;
2342 0 : memset(&glyphs_mi,0,sizeof(glyphs_mi));
2343 0 : glyphs_mi.col_cnt = 1;
2344 0 : glyphs_mi.col_init = glyph_ci;
2345 0 : if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 ) {
2346 0 : glyphs_mi.initial_row_cnt = fpst->rule_cnt;
2347 0 : md = calloc(fpst->rule_cnt,sizeof(struct matrix_data));
2348 0 : for ( j=0; j<fpst->rule_cnt; ++j ) {
2349 0 : md[j+0].u.md_str = FPSTRule_To_Str(sf,fpst,&fpst->rules[j]);;
2350 : }
2351 0 : glyphs_mi.matrix_data = md;
2352 : } else {
2353 0 : glyphs_mi.initial_row_cnt = 0;
2354 0 : glyphs_mi.matrix_data = NULL;
2355 : }
2356 0 : glgcd[k].gd.flags = gg_visible | gg_enabled;
2357 0 : glgcd[k].gd.cid = CID_GList_Simple;
2358 0 : glgcd[k].gd.u.matrix = &glyphs_mi;
2359 0 : glgcd[k++].creator = GMatrixEditCreate;
2360 : /* No need for a box, this widget fills the pane */
2361 :
2362 0 : GGadgetsCreate(ccd->glyphs_simple,glgcd);
2363 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->glyphs_simple,CID_GList_Simple),
2364 : true);
2365 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->glyphs_simple,CID_GList_Simple),0,
2366 : CCD_GlyphListCompletion);
2367 :
2368 0 : memset(&extrabuttonslab,0,sizeof(extrabuttonslab));
2369 0 : memset(&extrabuttonsgcd,0,sizeof(extrabuttonsgcd));
2370 :
2371 0 : i=0;
2372 0 : if ( fpst->type==pst_chainpos || fpst->type==pst_chainsub ) {
2373 0 : extrabuttonsgcd[i].gd.flags = gg_visible | gg_enabled;
2374 0 : extrabuttonslab[i].text = (unichar_t *) _("New Section");
2375 0 : extrabuttonslab[i].text_is_1byte = true;
2376 0 : extrabuttonsgcd[i].gd.label = &extrabuttonslab[i];
2377 0 : extrabuttonsgcd[i].gd.cid = CID_GNewSection;
2378 0 : extrabuttonsgcd[i].gd.handle_controlevent = CCD_NewSection;
2379 0 : extrabuttonsgcd[i++].creator = GButtonCreate;
2380 : }
2381 0 : extrabuttonsgcd[i].gd.flags = gg_visible | gg_enabled;
2382 0 : extrabuttonslab[i].text = (unichar_t *) _("Add Lookup");
2383 0 : extrabuttonslab[i].text_is_1byte = true;
2384 0 : extrabuttonsgcd[i].gd.u.list = addlookup_list;
2385 0 : extrabuttonsgcd[i].gd.label = &extrabuttonslab[i];
2386 : {
2387 : extern FontInstance *_ggadget_default_font;
2388 0 : GDrawSetFont(ccd->glyphs_simple,_ggadget_default_font);
2389 : }
2390 0 : extrabuttonsgcd[i].gd.pos.width = GDrawPixelsToPoints(ccd->glyphs_simple,
2391 0 : GDrawGetText8Width(ccd->glyphs_simple,(char *)extrabuttonslab[i].text,-1))+50;
2392 0 : extrabuttonsgcd[i].gd.cid = CID_GAddLookup;
2393 0 : extrabuttonsgcd[i].gd.handle_controlevent = CCD_AddLookup;
2394 0 : extrabuttonsgcd[i++].creator = GListButtonCreate;
2395 0 : GMatrixEditAddButtons(GWidgetGetControl(ccd->glyphs_simple,CID_GList_Simple),extrabuttonsgcd);
2396 :
2397 : /* Pane showing a single rule from a glyph format (not classes or coverage tables) */
2398 0 : ccd->glyphs = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2399 0 : memset(&ggcd,0,sizeof(ggcd));
2400 0 : memset(&fgcd,0,sizeof(fgcd));
2401 0 : memset(&glabel,0,sizeof(glabel));
2402 0 : memset(&flabel,0,sizeof(flabel));
2403 0 : memset(&faspects,0,sizeof(faspects));
2404 0 : memset(&subboxes,0,sizeof(subboxes));
2405 0 : memset(&topbox,0,sizeof(topbox));
2406 0 : for ( i=0; i<3; ++i ) { /* Match, background foreground tabs */
2407 0 : k=0;
2408 0 : glabel[i][k].text = (unichar_t *) _("Set From Selection");
2409 0 : glabel[i][k].text_is_1byte = true;
2410 0 : ggcd[i][k].gd.label = &glabel[i][k];
2411 0 : ggcd[i][k].gd.popup_msg = (unichar_t *) _("Set this glyph list from a selection.");
2412 0 : ggcd[i][k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
2413 0 : ggcd[i][k].gd.handle_controlevent = CCD_FromSelection;
2414 0 : ggcd[i][k].data=(void *)((intpt)CID_GlyphList+(0*100+i*20));
2415 0 : ggcd[i][k++].creator = GButtonCreate;
2416 0 : subvarray[i][0] = &ggcd[i][k-1];
2417 :
2418 0 : ggcd[i][k].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap;
2419 0 : ggcd[i][k].gd.cid = CID_GlyphList+(0*100+i*20);
2420 0 : ggcd[i][k].gd.u.completion = CCD_GlyphListCompletion;
2421 0 : ggcd[i][k++].creator = GTextCompletionCreate;
2422 0 : subvarray[i][1] = &ggcd[i][k-1];
2423 :
2424 0 : if ( i==0 ) {
2425 0 : glabel[i][k].text = (unichar_t *) _("An ordered list of lookups and positions");
2426 0 : glabel[i][k].text_is_1byte = true;
2427 0 : ggcd[i][k].gd.label = &glabel[i][k];
2428 0 : ggcd[i][k].gd.flags = gg_visible | gg_enabled;
2429 0 : ggcd[i][k++].creator = GLabelCreate;
2430 0 : subvarray[i][2] = &ggcd[i][k-1];
2431 :
2432 0 : memset(&gl_seqlookup_mi,0,sizeof(gl_seqlookup_mi));
2433 0 : gl_seqlookup_mi.col_cnt = 2;
2434 0 : gl_seqlookup_mi.col_init = seqlookup_ci;
2435 0 : gl_seqlookup_mi.matrix_data = NULL;
2436 0 : gl_seqlookup_mi.initial_row_cnt = 0;
2437 :
2438 0 : ggcd[i][k].gd.flags = gg_visible | gg_enabled;
2439 0 : ggcd[i][k].gd.cid = CID_LookupList+0;
2440 0 : ggcd[i][k].gd.u.matrix = &gl_seqlookup_mi;
2441 0 : ggcd[i][k++].creator = GMatrixEditCreate;
2442 0 : subvarray[i][3] = &ggcd[i][k-1];
2443 : } else
2444 0 : subvarray[i][2] = subvarray[i][3] = GCD_Glue;
2445 0 : subvarray[i][4] = NULL;
2446 :
2447 0 : subboxes[i][0].gd.flags = gg_enabled|gg_visible;
2448 0 : subboxes[i][0].gd.u.boxelements = subvarray[i];
2449 0 : subboxes[i][0].creator = GVBoxCreate;
2450 : }
2451 :
2452 0 : j = 0;
2453 :
2454 0 : faspects[j].text = (unichar_t *) _("Match");
2455 0 : faspects[j].text_is_1byte = true;
2456 0 : faspects[j].selected = true;
2457 0 : faspects[j].gcd = subboxes[j]; ++j;
2458 :
2459 0 : faspects[j].text = (unichar_t *) _("Backtrack");
2460 0 : faspects[j].text_is_1byte = true;
2461 0 : faspects[j].disabled = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2462 0 : faspects[j].gcd = subboxes[j]; ++j;
2463 :
2464 0 : faspects[j].text = (unichar_t *) _("Lookahead");
2465 0 : faspects[j].text_is_1byte = true;
2466 0 : faspects[j].disabled = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2467 0 : faspects[j].gcd = subboxes[j]; ++j;
2468 :
2469 0 : flabel[0].text = (unichar_t *) _("A list of glyphs:");
2470 0 : flabel[0].text_is_1byte = true;
2471 0 : fgcd[0].gd.label = &flabel[0];
2472 0 : fgcd[0].gd.flags = gg_visible | gg_enabled;
2473 0 : fgcd[0].creator = GLabelCreate;
2474 0 : topvarray[0] = &fgcd[0];
2475 :
2476 0 : fgcd[1].gd.u.tabs = faspects;
2477 0 : fgcd[1].gd.flags = gg_visible | gg_enabled;
2478 0 : fgcd[1].gd.cid = CID_MatchType;
2479 0 : fgcd[1].creator = GTabSetCreate;
2480 0 : topvarray[1] = &fgcd[1];
2481 0 : topvarray[2] = NULL;
2482 0 : topbox[0].gd.flags = gg_enabled|gg_visible;
2483 0 : topbox[0].gd.u.boxelements = topvarray;
2484 0 : topbox[0].creator = GVBoxCreate;
2485 0 : GGadgetsCreate(ccd->glyphs,topbox);
2486 :
2487 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->glyphs,CID_LookupList+0),
2488 : true);
2489 0 : GHVBoxSetExpandableRow(topbox[0].ret,1);
2490 0 : GHVBoxSetExpandableRow(subboxes[0][0].ret,3);
2491 0 : GHVBoxSetExpandableRow(subboxes[1][0].ret,gb_expandglue);
2492 0 : GHVBoxSetExpandableRow(subboxes[2][0].ret,gb_expandglue);
2493 :
2494 : /* Pane showing the single rule in a coverage table (complex) */
2495 0 : ccd->coverage = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2496 0 : memset(&clabel,0,sizeof(clabel));
2497 0 : memset(&cgcd,0,sizeof(cgcd));
2498 0 : memset(&subboxes,0,sizeof(subboxes));
2499 0 : memset(&topbox,0,sizeof(topbox));
2500 :
2501 0 : for ( i=0; i<3; ++i ) {
2502 0 : k = 0;
2503 0 : memset(&coverage_mi[i],0,sizeof(coverage_mi[i]));
2504 0 : coverage_mi[i].col_cnt = 1;
2505 0 : coverage_mi[i].col_init = coverage_ci;
2506 0 : if (( fpst->format==pst_coverage || fpst->format==pst_reversecoverage )
2507 0 : && fpst->rules!=NULL ) {
2508 0 : int cnt = (&fpst->rules[0].u.coverage.ncnt)[i];
2509 0 : char **names = (&fpst->rules[0].u.coverage.ncovers)[i];
2510 0 : coverage_mi[i].initial_row_cnt = cnt;
2511 0 : md = calloc(cnt,sizeof(struct matrix_data));
2512 0 : for ( j=0; j<cnt; ++j ) {
2513 0 : md[j].u.md_str = SFNameList2NameUni(sf,names[j]);
2514 : }
2515 0 : coverage_mi[i].matrix_data = md;
2516 : } else {
2517 0 : coverage_mi[i].initial_row_cnt = 0;
2518 0 : coverage_mi[i].matrix_data = NULL;
2519 : }
2520 0 : coverage_mi[i].finishedit = CCD_FinishCoverageEdit;
2521 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
2522 0 : cgcd[i][k].gd.cid = CID_GList+100+i*20;
2523 0 : cgcd[i][k].gd.u.matrix = &coverage_mi[i];
2524 0 : cgcd[i][k++].creator = GMatrixEditCreate;
2525 :
2526 0 : faspects[i].gcd = &cgcd[i][k-1];
2527 :
2528 0 : if ( i==0 ) {
2529 0 : if ( ccd->fpst->type!=pst_reversesub ) {
2530 0 : clabel[i][k].text = (unichar_t *) _("An ordered list of lookups and positions");
2531 0 : clabel[i][k].text_is_1byte = true;
2532 0 : cgcd[i][k].gd.label = &clabel[i][k];
2533 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
2534 0 : cgcd[i][k++].creator = GLabelCreate;
2535 0 : subvarray2[0] = &cgcd[i][k-1];
2536 :
2537 0 : memset(&co_seqlookup_mi,0,sizeof(co_seqlookup_mi));
2538 0 : co_seqlookup_mi.col_cnt = 2;
2539 0 : co_seqlookup_mi.col_init = seqlookup_ci;
2540 0 : if ( fpst->format==pst_coverage ) {
2541 0 : r = &fpst->rules[0];
2542 0 : co_seqlookup_mi.initial_row_cnt = r->lookup_cnt;
2543 0 : md = calloc(2*r->lookup_cnt,sizeof(struct matrix_data));
2544 0 : for ( j=0; j<r->lookup_cnt; ++j ) {
2545 0 : md[2*j+0].u.md_ival = (intpt) (void *) r->lookups[j].lookup;
2546 0 : md[2*j+1].u.md_ival = (intpt) r->lookups[j].seq;
2547 : }
2548 0 : co_seqlookup_mi.matrix_data = md;
2549 : } else {
2550 0 : co_seqlookup_mi.initial_row_cnt = 0;
2551 0 : co_seqlookup_mi.matrix_data = NULL;
2552 : }
2553 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
2554 0 : cgcd[i][k].gd.cid = CID_LookupList+100+(i*20);
2555 0 : cgcd[i][k].gd.u.matrix = &co_seqlookup_mi;
2556 0 : cgcd[i][k++].creator = GMatrixEditCreate;
2557 0 : subvarray2[1] = &cgcd[i][k-1];
2558 0 : subvarray2[2] = NULL;
2559 :
2560 0 : subboxes[i][1].gd.flags = gg_enabled|gg_visible;
2561 0 : subboxes[i][1].gd.u.boxelements = subvarray2;
2562 0 : subboxes[i][1].creator = GVBoxCreate;
2563 :
2564 0 : subvarray3[0] = &cgcd[i][0];
2565 0 : subvarray3[1] = &subboxes[i][1];
2566 0 : subvarray3[2] = NULL;
2567 :
2568 0 : subboxes[i][2].gd.flags = gg_enabled|gg_visible;
2569 0 : subboxes[i][2].gd.u.boxelements = subvarray3;
2570 0 : subboxes[i][2].creator = GVBoxCreate;
2571 0 : faspects[i].gcd = subboxes[i]+2;
2572 : } else {
2573 0 : r = NULL;
2574 0 : if ( fpst->rule_cnt==1 ) r = &fpst->rules[0];
2575 :
2576 0 : clabel[i][k].text = (unichar_t *) _("Replacements");
2577 0 : clabel[i][k].text_is_1byte = true;
2578 0 : cgcd[i][k].gd.label = &clabel[i][k];
2579 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
2580 0 : cgcd[i][k++].creator = GLabelCreate;
2581 0 : subvarray2[0] = &cgcd[i][k-1];
2582 :
2583 0 : clabel[i][k].text = (unichar_t *) _("Set From Selection");
2584 0 : clabel[i][k].text_is_1byte = true;
2585 0 : cgcd[i][k].gd.label = &clabel[i][k];
2586 0 : cgcd[i][k].gd.popup_msg = (unichar_t *) _("Set this glyph list from a selection.");
2587 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled | gg_utf8_popup;
2588 0 : cgcd[i][k].gd.handle_controlevent = CCD_FromSelection;
2589 0 : cgcd[i][k].data = (void *) (intpt) (CID_RplList+100);
2590 0 : cgcd[i][k++].creator = GButtonCreate;
2591 0 : subvarray2[1] = &cgcd[i][k-1];
2592 0 : subvarray2[2] = GCD_Glue;
2593 0 : subvarray2[3] = NULL;
2594 :
2595 0 : subboxes[i][1].gd.flags = gg_enabled|gg_visible;
2596 0 : subboxes[i][1].gd.u.boxelements = subvarray2;
2597 0 : subboxes[i][1].creator = GHBoxCreate;
2598 0 : subvarray3[0] = &subboxes[i][1];
2599 :
2600 0 : if ( r!=NULL && r->u.rcoverage.replacements!=NULL ) {
2601 0 : clabel[i][k].text = (unichar_t *) SFNameList2NameUni(sf,r->u.rcoverage.replacements);
2602 0 : clabel[i][k].text_is_1byte = true;
2603 0 : cgcd[i][k].gd.label = &clabel[i][k];
2604 : }
2605 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
2606 0 : cgcd[i][k].gd.cid = CID_RplList+100;
2607 0 : cgcd[i][k].gd.u.completion = CCD_GlyphListCompletion;
2608 0 : cgcd[i][k++].creator = GTextCompletionCreate;
2609 0 : subvarray3[1] = &cgcd[i][k-1];
2610 0 : subvarray3[2] = GCD_Glue;
2611 0 : subvarray3[3] = NULL;
2612 :
2613 0 : subboxes[i][2].gd.flags = gg_enabled|gg_visible;
2614 0 : subboxes[i][2].gd.u.boxelements = subvarray3;
2615 0 : subboxes[i][2].creator = GVBoxCreate;
2616 :
2617 0 : subvarray4[0] = &cgcd[i][0];
2618 0 : subvarray4[1] = &subboxes[i][2];
2619 0 : subvarray4[2] = NULL;
2620 :
2621 0 : subboxes[i][3].gd.flags = gg_enabled|gg_visible;
2622 0 : subboxes[i][3].gd.u.boxelements = subvarray4;
2623 0 : subboxes[i][3].creator = GVBoxCreate;
2624 0 : faspects[i].gcd = subboxes[i]+3;
2625 : }
2626 : }
2627 : }
2628 :
2629 0 : flabel[0].text = (unichar_t *) _("A coverage table:");
2630 0 : flabel[0].text_is_1byte = true;
2631 0 : fgcd[0].gd.label = &flabel[0];
2632 0 : fgcd[0].gd.flags = gg_visible | gg_enabled;
2633 0 : fgcd[0].creator = GLabelCreate;
2634 0 : topvarray[0] = &fgcd[0];
2635 :
2636 0 : fgcd[1].gd.u.tabs = faspects;
2637 0 : fgcd[1].gd.flags = gg_visible | gg_enabled;
2638 0 : fgcd[1].gd.cid = CID_MatchType+100;
2639 0 : fgcd[1].creator = GTabSetCreate;
2640 0 : topvarray[1] = &fgcd[1];
2641 0 : topvarray[2] = NULL;
2642 0 : topbox[0].gd.flags = gg_enabled|gg_visible;
2643 0 : topbox[0].gd.u.boxelements = topvarray;
2644 0 : topbox[0].creator = GVBoxCreate;
2645 0 : GGadgetsCreate(ccd->coverage,topbox);
2646 0 : for ( i=0; i<3; ++i ) {
2647 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->coverage,CID_GList+100+i*20),
2648 : true);
2649 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->coverage,CID_GList+100+i*20),0,
2650 : CCD_GlyphListCompletion);
2651 : }
2652 0 : if ( ccd->fpst->type!=pst_reversesub ) {
2653 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->coverage,CID_LookupList+100+0),
2654 : true);
2655 0 : GHVBoxSetExpandableRow(subboxes[0][1].ret,1);
2656 : } else {
2657 0 : GHVBoxSetExpandableCol(subboxes[0][1].ret,gb_expandglue);
2658 0 : GHVBoxSetExpandableRow(subboxes[0][2].ret,gb_expandglue);
2659 : }
2660 0 : GHVBoxSetExpandableRow(topbox[0].ret,1);
2661 :
2662 : /* Pane showing the single rule in a coverage table (simple) */
2663 0 : ccd->coverage_simple = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2664 0 : memset(&clabel,0,sizeof(clabel));
2665 0 : memset(&cgcd,0,sizeof(cgcd));
2666 0 : memset(&subboxes,0,sizeof(subboxes));
2667 0 : memset(&flabel,0,sizeof(flabel));
2668 0 : memset(&fgcd,0,sizeof(fgcd));
2669 0 : memset(&topbox,0,sizeof(topbox));
2670 :
2671 0 : memset(&coveragesimple_mi,0,sizeof(coveragesimple_mi));
2672 0 : coveragesimple_mi.col_cnt = 4;
2673 0 : coveragesimple_mi.col_init = coveragesimple_ci;
2674 0 : if ( fpst->format==pst_reversecoverage ) {
2675 0 : coveragesimple_mi.col_cnt = 2;
2676 0 : coveragesimple_mi.col_init = rcoveragesimple_ci;
2677 : }
2678 0 : if (( fpst->format==pst_coverage || fpst->format==pst_reversecoverage )
2679 0 : && fpst->rules!=NULL ) {
2680 0 : int cnt = fpst->rules[0].u.coverage.ncnt+fpst->rules[0].u.coverage.bcnt+fpst->rules[0].u.coverage.fcnt;
2681 0 : coveragesimple_mi.initial_row_cnt = cnt;
2682 0 : md = calloc(cnt*coveragesimple_mi.col_cnt,sizeof(struct matrix_data));
2683 0 : for ( i=0,j=fpst->rules[0].u.coverage.bcnt-1; j>=0; --j, ++i )
2684 0 : md[i*coveragesimple_mi.col_cnt].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.coverage.bcovers[j]);
2685 0 : for ( j=0; j<fpst->rules[0].u.coverage.ncnt; ++j, ++i ) {
2686 0 : md[coveragesimple_mi.col_cnt*i+0].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.coverage.ncovers[j]);
2687 0 : if ( fpst->format==pst_reversecoverage )
2688 0 : md[i*2+1].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.rcoverage.replacements);
2689 : else {
2690 0 : md[4*i+2].u.md_ival = j==0;
2691 0 : for ( k=0; k<fpst->rules[0].lookup_cnt; ++k ) {
2692 0 : if ( fpst->rules[0].lookups[k].seq==j ) {
2693 0 : md[4*i+1].u.md_addr = md[4*i+3].u.md_addr = fpst->rules[0].lookups[k].lookup;
2694 0 : break;
2695 : }
2696 : }
2697 : }
2698 : }
2699 0 : for ( j=0; j<fpst->rules[0].u.coverage.fcnt; ++j, ++i ) {
2700 0 : md[coveragesimple_mi.col_cnt*i].u.md_str = SFNameList2NameUni(sf,fpst->rules[0].u.coverage.fcovers[j]);
2701 0 : if ( fpst->format==pst_coverage )
2702 0 : md[4*i+2].u.md_ival = j==0;
2703 : }
2704 0 : coveragesimple_mi.matrix_data = md;
2705 : } else {
2706 0 : coveragesimple_mi.initial_row_cnt = 0;
2707 0 : coveragesimple_mi.matrix_data = NULL;
2708 : }
2709 0 : coveragesimple_mi.finishedit = CCD_FinishCoverageSimpleEdit;
2710 :
2711 0 : flabel[0].text = (unichar_t *) _("A list of coverage tables:");
2712 0 : flabel[0].text_is_1byte = true;
2713 0 : fgcd[0].gd.label = &flabel[0];
2714 0 : fgcd[0].gd.flags = gg_visible | gg_enabled;
2715 0 : fgcd[0].creator = GLabelCreate;
2716 0 : topvarray[0] = &fgcd[0];
2717 :
2718 0 : fgcd[1].gd.flags = gg_visible | gg_enabled;
2719 0 : fgcd[1].gd.cid = CID_Covers;
2720 0 : fgcd[1].gd.u.matrix = &coveragesimple_mi;
2721 0 : fgcd[1].creator = GMatrixEditCreate;
2722 0 : topvarray[1] = &fgcd[1];
2723 0 : topvarray[2] = NULL;
2724 0 : topbox[0].gd.flags = gg_enabled|gg_visible;
2725 0 : topbox[0].gd.u.boxelements = topvarray;
2726 0 : topbox[0].creator = GVBoxCreate;
2727 0 : GGadgetsCreate(ccd->coverage_simple,topbox);
2728 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->coverage_simple,CID_Covers),
2729 : true);
2730 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->coverage_simple,CID_Covers),0,
2731 : CCD_GlyphListCompletion);
2732 0 : if ( fpst->type==pst_reversesub ) {
2733 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->coverage_simple,CID_Covers),1,
2734 : CCD_GlyphListCompletion);
2735 : }
2736 0 : GHVBoxSetExpandableRow(topbox[0].ret,1);
2737 0 : if ( fpst->type == pst_contextpos || fpst->type == pst_contextsub )
2738 0 : GMatrixEditShowColumn(GWidgetGetControl(ccd->coverage_simple,CID_Covers),2,false);
2739 0 : if ( fpst->format!=pst_reversecoverage )
2740 0 : GMatrixEditShowColumn(GWidgetGetControl(ccd->coverage_simple,CID_Covers),3,false);
2741 :
2742 :
2743 : /* This pane displays a set of class rules, and below the three sets of classes for those rules */
2744 0 : ccd->classrules = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2745 0 : memset(&cllabel,0,sizeof(cllabel));
2746 0 : memset(&clgcd,0,sizeof(clgcd));
2747 0 : memset(&clabel,0,sizeof(clabel));
2748 0 : memset(&cgcd,0,sizeof(cgcd));
2749 0 : memset(&subboxes,0,sizeof(subboxes));
2750 0 : memset(&topbox,0,sizeof(topbox));
2751 0 : memset(&classbox,0,sizeof(classbox));
2752 :
2753 0 : tempfpst = fpst;
2754 0 : if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 )
2755 0 : tempfpst = FPSTGlyphToClass(fpst);
2756 :
2757 0 : k=0;
2758 :
2759 0 : memset(&classrules_mi,0,sizeof(classrules_mi));
2760 0 : classrules_mi.col_cnt = 1;
2761 0 : classrules_mi.col_init = classrules_ci;
2762 : /* Further inits happen after we've set up the classnames */
2763 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
2764 0 : clgcd[k].gd.cid = CID_GList+200;
2765 0 : clgcd[k].gd.u.matrix = &classrules_mi;
2766 0 : clgcd[k++].creator = GMatrixEditCreate;
2767 0 : classv[k-1] = &clgcd[k-1];
2768 :
2769 0 : clgcd[k].gd.pos.width = CCD_WIDTH-23;
2770 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
2771 0 : clgcd[k++].creator = GLineCreate;
2772 0 : classv[k-1] = &clgcd[k-1];
2773 0 : classv[k] = NULL;
2774 :
2775 0 : classbox[0].gd.flags = gg_enabled|gg_visible;
2776 0 : classbox[0].gd.u.boxelements = classv;
2777 0 : classbox[0].creator = GVBoxCreate;
2778 0 : topvarray[0] = &classbox[0];
2779 :
2780 0 : for ( i=0; i<3; ++i ) {
2781 0 : int l=0, cc, j, sameas=0;
2782 :
2783 0 : if ( i!=0 ) {
2784 0 : if ( (&tempfpst->nccnt)[i] == tempfpst->nccnt ) {
2785 0 : sameas = gg_cb_on;
2786 0 : for ( j=1; j<(&tempfpst->nccnt)[i]; ++j ) {
2787 0 : if ( strcmp((&tempfpst->nclass)[i][j],tempfpst->nclass[j])!=0 ) {
2788 0 : sameas = 0;
2789 0 : break;
2790 : }
2791 : }
2792 : }
2793 0 : clabel[i][l].text = (unichar_t *) _("Same as Match Classes");
2794 0 : clabel[i][l].text_is_1byte = true;
2795 0 : cgcd[i][l].gd.label = &clabel[i][l];
2796 0 : cgcd[i][l].gd.handle_controlevent = CCD_SameAsClasses;
2797 0 : cgcd[i][l].gd.flags = gg_visible | gg_enabled | sameas;
2798 0 : cgcd[i][l].gd.cid = CID_SameAsClasses + i*20;
2799 0 : cgcd[i][l++].creator = GCheckBoxCreate;
2800 0 : subvarray[i][l-1] = &cgcd[i][l-1];
2801 : }
2802 :
2803 0 : memset(&class_mi[i],0,sizeof(class_mi[0]));
2804 0 : class_mi[i].col_cnt = 3;
2805 0 : class_mi[i].col_init = class_ci;
2806 : {
2807 : char **classes, **classnames;
2808 0 : if ( tempfpst->format==pst_class ) {
2809 0 : classes = (&tempfpst->nclass)[i];
2810 0 : classnames = (&tempfpst->nclassnames)[i];
2811 : } else {
2812 0 : classes = NULL;
2813 0 : classnames = NULL;
2814 : }
2815 0 : if ( classes==NULL )
2816 : /* Make sure the class 0 is always present */
2817 0 : cc=1;
2818 : else
2819 0 : cc = (&tempfpst->nccnt)[i];
2820 0 : class_mi[i].initial_row_cnt = cc;
2821 0 : md = calloc(3*cc+3,sizeof(struct matrix_data));
2822 0 : md[0+0].u.md_str = copy(classnames==NULL || cc==0 || classnames[0]==NULL?S_("Glyphs|All_Others"):classnames[0]);
2823 0 : md[3*0+1].u.md_str = copy(_("{Everything Else}"));
2824 0 : md[3*0+1].frozen = true;
2825 0 : md[0+2].u.md_str = copy(md[0+0].u.md_str);
2826 0 : for ( j=1; j<cc; ++j ) {
2827 0 : if ( classnames==NULL || classnames[j]==NULL ) {
2828 : char buffer[12];
2829 0 : sprintf( buffer,"%d",j );
2830 0 : md[3*j+0].u.md_str = copy(buffer);
2831 : } else
2832 0 : md[3*j+0].u.md_str = copy(classnames[j]);
2833 0 : md[3*j+1].u.md_str = SFNameList2NameUni(sf,classes[j]);
2834 0 : md[3*j+2].u.md_str = copy(md[3*j+0].u.md_str);
2835 : }
2836 0 : class_mi[i].matrix_data = md;
2837 :
2838 0 : clen[i] = cc;
2839 0 : _classes[i] = md;
2840 : }
2841 0 : class_mi[i].initrow = CCD_InitClassRow;
2842 0 : class_mi[i].finishedit = CCD_FinishClassEdit;
2843 0 : class_mi[i].candelete = CCD_EnableDeleteClass;
2844 :
2845 0 : if ( sameas )
2846 0 : cgcd[i][l].gd.flags = gg_visible;
2847 : else
2848 0 : cgcd[i][l].gd.flags = gg_visible | gg_enabled;
2849 0 : cgcd[i][l].gd.cid = CID_GList+300+i*20;
2850 0 : cgcd[i][l].gd.u.matrix = &class_mi[i];
2851 0 : cgcd[i][l++].creator = GMatrixEditCreate;
2852 0 : subvarray[i][l-1] = &cgcd[i][l-1];
2853 0 : subvarray[i][l] = NULL;
2854 :
2855 0 : subboxes[i][0].gd.flags = gg_enabled|gg_visible;
2856 0 : subboxes[i][0].gd.u.boxelements = subvarray[i];
2857 0 : subboxes[i][0].creator = GVBoxCreate;
2858 :
2859 0 : faspects[i].gcd = subboxes[i];
2860 : }
2861 0 : j=0;
2862 0 : faspects[j++].text = (unichar_t *) _("Match Classes");
2863 0 : faspects[j++].text = (unichar_t *) _("Back Classes");
2864 0 : faspects[j++].text = (unichar_t *) _("Ahead Classes");
2865 :
2866 : /* Finish initializing the list of class rules */
2867 0 : if ( tempfpst->format==pst_class && tempfpst->rule_cnt>0 ) {
2868 0 : classrules_mi.initial_row_cnt = tempfpst->rule_cnt;
2869 0 : md = calloc(tempfpst->rule_cnt,sizeof(struct matrix_data));
2870 0 : for ( j=0; j<tempfpst->rule_cnt; ++j ) {
2871 0 : md[j+0].u.md_str = classruleitem(&tempfpst->rules[j],_classes,clen,3);
2872 : }
2873 0 : classrules_mi.matrix_data = md;
2874 : } else {
2875 0 : classrules_mi.initial_row_cnt = 0;
2876 0 : classrules_mi.matrix_data = NULL;
2877 : }
2878 :
2879 0 : clgcd[k].gd.u.tabs = faspects;
2880 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
2881 0 : clgcd[k].gd.cid = CID_MatchType+300;
2882 0 : clgcd[k].creator = GTabSetCreate;
2883 0 : topvarray[1] = &clgcd[k]; topvarray[2] = NULL;
2884 0 : topbox[0].gd.flags = gg_enabled|gg_visible;
2885 0 : topbox[0].gd.u.boxelements = topvarray;
2886 0 : topbox[0].creator = GVBoxCreate;
2887 0 : GGadgetsCreate(ccd->classrules,topbox);
2888 :
2889 : /* Top box should give it's size equally to its two components */
2890 0 : GHVBoxSetExpandableRow(classbox[0].ret,0);
2891 0 : GHVBoxSetExpandableRow(subboxes[0][0].ret,0);
2892 0 : GHVBoxSetExpandableRow(subboxes[1][0].ret,1);
2893 0 : GHVBoxSetExpandableRow(subboxes[2][0].ret,1);
2894 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classrules,CID_GList+300+0*20),0,CCD_GlyphListCompletion);
2895 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classrules,CID_GList+300+1*20),0,CCD_GlyphListCompletion);
2896 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classrules,CID_GList+300+2*20),0,CCD_GlyphListCompletion);
2897 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->classrules,CID_GList+200), true);
2898 0 : GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classrules,CID_GList+200),CCD_NewClassRule);
2899 0 : for ( i=0; i<3; ++i ) {
2900 0 : GGadget *list = GWidgetGetControl(ccd->classrules,CID_GList+300+i*20);
2901 0 : GMatrixEditShowColumn(list,2,false);
2902 0 : GMatrixEditSetUpDownVisible(list, true);
2903 0 : GMatrixEditSetCanUpDown(list, CCD_EnableUpDown);
2904 : }
2905 :
2906 : /* This pane displays a set of class rules, and below the three sets of classes_simple for those rules */
2907 0 : ccd->classes_simple = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
2908 0 : memset(&cllabel,0,sizeof(cllabel));
2909 0 : memset(&clgcd,0,sizeof(clgcd));
2910 0 : memset(&clabel,0,sizeof(clabel));
2911 0 : memset(&cgcd,0,sizeof(cgcd));
2912 0 : memset(&subboxes,0,sizeof(subboxes));
2913 0 : memset(&topbox,0,sizeof(topbox));
2914 0 : memset(&classbox,0,sizeof(classbox));
2915 0 : memset(&faspects,0,sizeof(faspects));
2916 :
2917 0 : tempfpst = fpst;
2918 0 : if ( fpst->format==pst_glyphs && fpst->rule_cnt>0 )
2919 0 : tempfpst = FPSTGlyphToClass(fpst);
2920 :
2921 0 : k=0;
2922 :
2923 0 : memset(&classsimple_mi,0,sizeof(classsimple_mi));
2924 0 : classsimple_mi.col_cnt = 1;
2925 0 : classsimple_mi.col_init = classsimple_ci;
2926 0 : if ( tempfpst->format==pst_class && tempfpst->rule_cnt>0 ) {
2927 0 : classsimple_mi.initial_row_cnt = tempfpst->rule_cnt;
2928 0 : md = calloc(tempfpst->rule_cnt,sizeof(struct matrix_data));
2929 0 : for ( j=0; j<tempfpst->rule_cnt; ++j ) {
2930 0 : md[j+0].u.md_str = FPSTRule_To_Str(sf,tempfpst,&tempfpst->rules[j]);;
2931 : }
2932 0 : classsimple_mi.matrix_data = md;
2933 : } else {
2934 0 : classsimple_mi.initial_row_cnt = 0;
2935 0 : classsimple_mi.matrix_data = NULL;
2936 : }
2937 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
2938 0 : clgcd[k].gd.cid = CID_CList_Simple;
2939 0 : clgcd[k].gd.u.matrix = &classsimple_mi;
2940 0 : clgcd[k++].creator = GMatrixEditCreate;
2941 0 : classv[k-1] = &clgcd[k-1];
2942 :
2943 0 : clgcd[k].gd.pos.width = CCD_WIDTH-23;
2944 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
2945 0 : clgcd[k++].creator = GLineCreate;
2946 0 : classv[k-1] = &clgcd[k-1];
2947 0 : classv[k] = NULL;
2948 :
2949 0 : classbox[0].gd.flags = gg_enabled|gg_visible;
2950 0 : classbox[0].gd.u.boxelements = classv;
2951 0 : classbox[0].creator = GVBoxCreate;
2952 0 : topvarray[0] = &classbox[0];
2953 :
2954 0 : for ( i=0; i<3; ++i ) {
2955 0 : int l=0, cc, j, sameas=0;
2956 :
2957 0 : if ( i!=0 ) {
2958 0 : if ( (&tempfpst->nccnt)[i] == tempfpst->nccnt ) {
2959 0 : sameas = gg_cb_on;
2960 0 : for ( j=1; j<(&tempfpst->nccnt)[i]; ++j ) {
2961 0 : if ( strcmp((&tempfpst->nclass)[i][j],tempfpst->nclass[j])!=0 ) {
2962 0 : sameas = 0;
2963 0 : break;
2964 : }
2965 : }
2966 : }
2967 0 : clabel[i][l].text = (unichar_t *) _("Same as Match Classes");
2968 0 : clabel[i][l].text_is_1byte = true;
2969 0 : cgcd[i][l].gd.label = &clabel[i][l];
2970 0 : cgcd[i][l].gd.handle_controlevent = CCD_SameAsClasses;
2971 0 : cgcd[i][l].gd.flags = gg_visible | gg_enabled | sameas;
2972 0 : cgcd[i][l].gd.cid = CID_SameAsClasses_S + i*20;
2973 0 : cgcd[i][l++].creator = GCheckBoxCreate;
2974 0 : subvarray[i][l-1] = &cgcd[i][l-1];
2975 : }
2976 :
2977 0 : memset(&class_mi[i],0,sizeof(class_mi[0]));
2978 0 : class_mi[i].col_cnt = 3;
2979 0 : class_mi[i].col_init = class_ci;
2980 : {
2981 : char **classes, **classnames;
2982 0 : if ( tempfpst->format==pst_class ) {
2983 0 : classes = (&tempfpst->nclass)[i];
2984 0 : classnames = (&tempfpst->nclassnames)[i];
2985 : } else {
2986 0 : classes = NULL;
2987 0 : classnames = NULL;
2988 : }
2989 0 : if ( classes==NULL )
2990 : /* Make sure the class 0 is always present */
2991 0 : cc=1;
2992 : else
2993 0 : cc = (&tempfpst->nccnt)[i];
2994 0 : class_mi[i].initial_row_cnt = cc;
2995 0 : md = calloc(3*cc+3,sizeof(struct matrix_data));
2996 : /* GT: This is the default class name for the class containing any glyphs_simple */
2997 : /* GT: which aren't specified in other classes_simple. The class name may NOT */
2998 : /* GT: contain spaces. Use an underscore or something similar instead */
2999 0 : md[0+0].u.md_str = copy(classnames==NULL || cc==0 || classnames[0]==NULL?S_("Glyphs|All_Others"):classnames[0]);
3000 0 : md[0+1].u.md_str = copy(_("{Everything Else}"));
3001 0 : md[0+1].frozen = true;
3002 0 : md[0+2].u.md_str = copy(md[0+0].u.md_str);
3003 0 : for ( j=1; j<cc; ++j ) {
3004 0 : if ( classnames==NULL || classnames[j]==NULL ) {
3005 : char buffer[12];
3006 0 : sprintf( buffer,"%d",j );
3007 0 : md[3*j+0].u.md_str = copy(buffer);
3008 : } else
3009 0 : md[3*j+0].u.md_str = copy(classnames[j]);
3010 0 : md[3*j+1].u.md_str = SFNameList2NameUni(sf,classes[j]);
3011 0 : md[3*j+2].u.md_str = copy(md[3*j+0].u.md_str);
3012 : }
3013 0 : class_mi[i].matrix_data = md;
3014 : }
3015 0 : class_mi[i].initrow = CCD_InitClassRow;
3016 0 : class_mi[i].finishedit = CCD_FinishClassEdit;
3017 0 : class_mi[i].candelete = CCD_EnableDeleteClass;
3018 :
3019 0 : if ( sameas )
3020 0 : cgcd[i][l].gd.flags = gg_visible;
3021 : else
3022 0 : cgcd[i][l].gd.flags = gg_visible | gg_enabled;
3023 0 : cgcd[i][l].gd.cid = CID_MatchClasses+i*20;
3024 0 : cgcd[i][l].gd.u.matrix = &class_mi[i];
3025 0 : cgcd[i][l++].creator = GMatrixEditCreate;
3026 0 : subvarray[i][l-1] = &cgcd[i][l-1];
3027 0 : subvarray[i][l] = NULL;
3028 :
3029 0 : subboxes[i][0].gd.flags = gg_enabled|gg_visible;
3030 0 : subboxes[i][0].gd.u.boxelements = subvarray[i];
3031 0 : subboxes[i][0].creator = GVBoxCreate;
3032 :
3033 0 : faspects[i].gcd = subboxes[i];
3034 0 : faspects[i].text_is_1byte = true;
3035 : }
3036 0 : j=0;
3037 0 : faspects[j++].text = (unichar_t *) _("Match Classes");
3038 0 : faspects[j++].text = (unichar_t *) _("Back Classes");
3039 0 : faspects[j++].text = (unichar_t *) _("Ahead Classes");
3040 0 : if ( fpst->type == pst_contextpos || fpst->type == pst_contextsub )
3041 0 : faspects[1].disabled = faspects[2].disabled = true;
3042 :
3043 0 : clgcd[k].gd.u.tabs = faspects;
3044 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
3045 0 : clgcd[k].gd.cid = CID_ClassMatchType;
3046 0 : clgcd[k].creator = GTabSetCreate;
3047 0 : topvarray[1] = &clgcd[k]; topvarray[2] = NULL;
3048 0 : topbox[0].gd.flags = gg_enabled|gg_visible;
3049 0 : topbox[0].gd.u.boxelements = topvarray;
3050 0 : topbox[0].creator = GVBoxCreate;
3051 0 : GGadgetsCreate(ccd->classes_simple,topbox);
3052 :
3053 : /* Top box should give it's size equally to its two components */
3054 0 : GHVBoxSetExpandableRow(classbox[0].ret,0);
3055 0 : GHVBoxSetExpandableRow(subboxes[0][0].ret,0);
3056 0 : GHVBoxSetExpandableRow(subboxes[1][0].ret,1);
3057 0 : GHVBoxSetExpandableRow(subboxes[2][0].ret,1);
3058 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_MatchClasses),1,CCD_GlyphListCompletion);
3059 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_BackClasses),1,CCD_GlyphListCompletion);
3060 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_ForeClasses),1,CCD_GlyphListCompletion);
3061 0 : GMatrixEditSetColumnCompletion(GWidgetGetControl(ccd->classes_simple,CID_CList_Simple),0,
3062 : CCD_ClassListCompletion);
3063 0 : if ( fpst->type==pst_chainpos || fpst->type==pst_chainsub ) {
3064 0 : extrabuttonsgcd[0].gd.cid = CID_CNewSection;
3065 0 : extrabuttonsgcd[1].gd.cid = CID_CAddLookup;
3066 : } else
3067 0 : extrabuttonsgcd[0].gd.cid = CID_CAddLookup;
3068 0 : GMatrixEditSetUpDownVisible(GWidgetGetControl(ccd->classes_simple,CID_CList_Simple), true);
3069 0 : GMatrixEditAddButtons(GWidgetGetControl(ccd->classes_simple,CID_CList_Simple),extrabuttonsgcd);
3070 0 : for ( i=0; i<3; ++i ) {
3071 0 : GGadget *list = GWidgetGetControl(ccd->classes_simple,CID_MatchClasses+i*20);
3072 0 : GMatrixEditShowColumn(list,2,false);
3073 0 : GMatrixEditSetUpDownVisible(list, true);
3074 0 : GMatrixEditSetCanUpDown(list, CCD_EnableUpDown);
3075 0 : GMatrixEditSetBeforeDelete(list,CCD_ClassGoing);
3076 : }
3077 0 : if ( tempfpst!=fpst )
3078 0 : FPSTFree(tempfpst);
3079 :
3080 : /* This pane displays a tabbed set describing one rule in class format */
3081 0 : ccd->classnumber = GWidgetCreateSubWindow(ccd->gw,&subpos,subccd_e_h,ccd,&wattrs);
3082 0 : memset(&clabel,0,sizeof(clabel));
3083 0 : memset(&cgcd,0,sizeof(cgcd));
3084 0 : memset(&cllabel,0,sizeof(cllabel));
3085 0 : memset(&clgcd,0,sizeof(clgcd));
3086 :
3087 0 : for ( i=0; i<3; ++i ) {
3088 0 : k=0;
3089 :
3090 0 : clabel[i][k].text = (unichar_t *) _("List of class names");
3091 0 : clabel[i][k].text_is_1byte = true;
3092 0 : cgcd[i][k].gd.label = &clabel[i][k];
3093 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
3094 0 : cgcd[i][k++].creator = GLabelCreate;
3095 0 : subvarray[i][k-1] = &cgcd[i][k-1];
3096 :
3097 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap;
3098 0 : cgcd[i][k].gd.cid = CID_ClassNumbers+i*20;
3099 0 : cgcd[i][k++].creator = GTextAreaCreate;
3100 0 : subvarray[i][k-1] = &cgcd[i][k-1];
3101 :
3102 0 : clabel[i][k].text = (unichar_t *) _("Classes");
3103 0 : clabel[i][k].text_is_1byte = true;
3104 0 : cgcd[i][k].gd.label = &clabel[i][k];
3105 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled;
3106 0 : cgcd[i][k++].creator = GLabelCreate;
3107 0 : subvarray[i][k-1] = &cgcd[i][k-1];
3108 :
3109 0 : memset(&classlist_mi[i],0,sizeof(classlist_mi[0]));
3110 0 : classlist_mi[i].col_cnt = 2;
3111 0 : classlist_mi[i].col_init = classlist_ci;
3112 :
3113 0 : cgcd[i][k].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap;
3114 0 : cgcd[i][k].gd.cid = CID_ClassList+i*20;
3115 0 : cgcd[i][k].gd.u.matrix = &classlist_mi[i];
3116 0 : cgcd[i][k++].creator = GMatrixEditCreate;
3117 0 : subvarray[i][k-1] = &cgcd[i][k-1];
3118 0 : subvarray[i][k] = NULL;
3119 :
3120 0 : subboxes[i][0].gd.flags = gg_enabled|gg_visible;
3121 0 : subboxes[i][0].gd.u.boxelements = subvarray[i];
3122 0 : subboxes[i][0].creator = GVBoxCreate;
3123 :
3124 0 : faspects[i].gcd = subboxes[i];
3125 :
3126 0 : if ( i==0 ) {
3127 0 : clabel[i][k].text = (unichar_t *) _("An ordered list of lookups and positions");
3128 0 : clabel[i][k].text_is_1byte = true;
3129 0 : ggcd[i][k].gd.label = &clabel[i][k];
3130 0 : ggcd[i][k].gd.flags = gg_visible | gg_enabled;
3131 0 : ggcd[i][k++].creator = GLabelCreate;
3132 0 : subvarray2[0] = &ggcd[i][k-1];
3133 :
3134 0 : memset(&cl_seqlookup_mi,0,sizeof(cl_seqlookup_mi));
3135 0 : cl_seqlookup_mi.col_cnt = 2;
3136 0 : cl_seqlookup_mi.col_init = seqlookup_ci;
3137 0 : cl_seqlookup_mi.matrix_data = NULL;
3138 0 : cl_seqlookup_mi.initial_row_cnt = 0;
3139 :
3140 0 : ggcd[i][k].gd.flags = gg_visible | gg_enabled;
3141 0 : ggcd[i][k].gd.cid = CID_LookupList+500;
3142 0 : ggcd[i][k].gd.u.matrix = &cl_seqlookup_mi;
3143 0 : ggcd[i][k++].creator = GMatrixEditCreate;
3144 0 : subvarray2[1] = &ggcd[i][k-1];
3145 0 : subvarray2[2] = NULL;
3146 :
3147 0 : subboxes[i][1].gd.flags = gg_enabled|gg_visible;
3148 0 : subboxes[i][1].gd.u.boxelements = subvarray2;
3149 0 : subboxes[i][1].creator = GVBoxCreate;
3150 :
3151 0 : subvarray3[0] = &subboxes[i][0];
3152 0 : subvarray3[1] = &subboxes[i][1];
3153 0 : subvarray3[2] = NULL;
3154 :
3155 0 : subboxes[i][2].gd.flags = gg_enabled|gg_visible;
3156 0 : subboxes[i][2].gd.u.boxelements = subvarray3;
3157 0 : subboxes[i][2].creator = GVBoxCreate;
3158 0 : faspects[i].gcd = subboxes[i]+2;
3159 : }
3160 : }
3161 :
3162 0 : j=0;
3163 0 : faspects[j++].text = (unichar_t *) _("Match");
3164 0 : faspects[j++].text = (unichar_t *) _("Backtrack");
3165 0 : faspects[j++].text = (unichar_t *) _("Lookahead");
3166 :
3167 0 : k=0;
3168 0 : clgcd[k].gd.u.tabs = faspects;
3169 0 : clgcd[k].gd.flags = gg_visible | gg_enabled;
3170 0 : clgcd[k].gd.cid = CID_ClassType;
3171 0 : clgcd[k].creator = GTabSetCreate;
3172 0 : GGadgetsCreate(ccd->classnumber,clgcd);
3173 0 : GHVBoxSetExpandableRow(subboxes[0][0].ret,3);
3174 0 : GHVBoxSetExpandableRow(subboxes[1][0].ret,3);
3175 0 : GHVBoxSetExpandableRow(subboxes[2][0].ret,3);
3176 0 : GHVBoxSetExpandableRow(subboxes[0][1].ret,1);
3177 :
3178 0 : GMatrixEditSetEditable(GWidgetGetControl(ccd->classnumber,CID_ClassList+0*20),false);
3179 0 : GMatrixEditSetEditable(GWidgetGetControl(ccd->classnumber,CID_ClassList+1*20),false);
3180 0 : GMatrixEditSetEditable(GWidgetGetControl(ccd->classnumber,CID_ClassList+2*20),false);
3181 0 : GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classnumber,CID_ClassList+0*20),CCD_ClassSelected);
3182 0 : GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classnumber,CID_ClassList+1*20),CCD_ClassSelected);
3183 0 : GMatrixEditSetOtherButtonEnable(GWidgetGetControl(ccd->classnumber,CID_ClassList+2*20),CCD_ClassSelected);
3184 :
3185 :
3186 0 : if ( ccd->aw == aw_formats )
3187 0 : GDrawSetVisible(ccd->formats,true);
3188 0 : else if ( use_simple ) {
3189 0 : if ( ccd->aw == aw_glyphs_simple )
3190 0 : GDrawSetVisible(ccd->glyphs_simple,true);
3191 0 : else if ( ccd->aw == aw_classes_simple )
3192 0 : GDrawSetVisible(ccd->classes_simple,true);
3193 : else {
3194 0 : GDrawSetVisible(ccd->coverage_simple,true);
3195 0 : GDrawResize(ccd->gw,
3196 0 : fpst->format==pst_reversecoverage?3*pos.width/2:2*pos.width,
3197 : pos.height);
3198 : }
3199 : } else {
3200 0 : if ( ccd->aw == aw_grules )
3201 0 : GDrawSetVisible(ccd->grules,true);
3202 0 : else if ( ccd->aw == aw_classrules )
3203 0 : GDrawSetVisible(ccd->classrules,true);
3204 : else
3205 0 : GDrawSetVisible(ccd->coverage,true);
3206 : }
3207 :
3208 0 : GDrawSetVisible(gw,true);
3209 0 : while ( !ccd->done )
3210 0 : GDrawProcessOneEvent(NULL);
3211 0 : GDrawDestroyWindow(ccd->gw);
3212 :
3213 0 : GTextInfoListFree(lookup_list);
3214 0 : seqlookup_ci[1].enum_vals = NULL;
3215 :
3216 : /* ccd is freed by the event handler when we get a et_destroy event */
3217 :
3218 0 : return;
3219 : }
|