1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13
14 * The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <fontforge-config.h>
30
31 #include "autowidth2.h"
32 #include "chardata.h"
33 #include "cvundoes.h"
34 #include "fontforgeui.h"
35 #include "fvcomposite.h"
36 #include "fvfonts.h"
37 #include "gkeysym.h"
38 #include "lookups.h"
39 #include "namelist.h"
40 #include "splinefill.h"
41 #include "splineutil.h"
42 #include "tottfgpos.h"
43 #include "ttf.h" /* For MAC_DELETED_GLYPH_NAME */
44 #include "unicodelibinfo.h"
45 #include "ustring.h"
46 #include "utype.h"
47
48 #include <math.h>
49
50 extern int lookup_hideunused;
51
52 static int last_gi_aspect = 0;
53
54 typedef struct charinfo {
55 CharView *cv;
56 EncMap *map;
57 SplineChar *sc, *cachedsc;
58 int def_layer;
59 SplineChar *oldsc; /* oldsc->charinfo will point to us. Used to keep track of that pointer */
60 int enc;
61 GWindow gw;
62 int done, first, changed;
63 struct lookup_subtable *old_sub;
64 int r,c;
65 int lc_seen, lc_aspect, vert_aspect;
66 Color last, real_last;
67 struct splinecharlist *changes;
68 int name_change, uni_change;
69 } CharInfo;
70
71 #define CI_Width 218
72 #define CI_Height 292
73
74 #define CID_UName 1001
75 #define CID_UValue 1002
76 #define CID_UChar 1003
77 #define CID_Cancel 1005
78 #define CID_ComponentMsg 1006
79 #define CID_Components 1007
80 #define CID_ComponentTextField 1008
81 #define CID_ComponentChangeMsg 1009
82 #define CID_ComponentDefaultCB 1010
83 #define CID_ComponentInterpMsg 1011
84 #define CID_Comment 1012
85 #define CID_Color 1013
86 #define CID_GClass 1014
87 #define CID_Tabs 1015
88
89 #define CID_TeX_Height 1016
90 #define CID_TeX_Depth 1017
91 #define CID_TeX_Italic 1018
92 #define CID_HorAccent 1019
93 /* Room for one more here, if we need it */
94 #define CID_TeX_HeightD 1020
95 #define CID_TeX_DepthD 1021
96 #define CID_TeX_ItalicD 1022
97 #define CID_HorAccentD 1023
98
99 #define CID_ItalicDevTab 1024
100 #define CID_AccentDevTab 1025
101
102 #define CID_IsExtended 1026
103 #define CID_DefLCCount 1040
104 #define CID_LCCount 1041
105 #define CID_LCCountLab 1042
106
107 #define CID_UnlinkRmOverlap 1045
108 #define CID_AltUni 1046
109
110 /* Offsets for repeated fields. add 100*index (index<=6) */
111 #define CID_List 1220
112 #define CID_New 1221
113 #define CID_Delete 1222
114 #define CID_Edit 1223
115
116 #define CID_PST 1111
117 #define CID_Tag 1112
118 #define CID_Contents 1113
119 #define CID_SelectResults 1114
120 #define CID_MergeResults 1115
121 #define CID_RestrictSelection 1116
122
123 /* Offsets for repeated fields. add 100*index (index<2) */ /* 0=>Vert, 1=>Hor */
124 #define CID_VariantList 2000
125 #define CID_ExtItalicCor 2001
126 #define CID_ExtItalicDev 2002
127 #define CID_ExtensionList 2003
128
129 #define CID_IsTileMargin 3001
130 #define CID_TileMargin 3002
131 #define CID_IsTileBBox 3003
132 #define CID_TileBBoxMinX 3004
133 #define CID_TileBBoxMinY 3005
134 #define CID_TileBBoxMaxX 3006
135 #define CID_TileBBoxMaxY 3007
136
137 #define SIM_DX 1
138 #define SIM_DY 3
139 #define SIM_DX_ADV 5
140 #define SIM_DY_ADV 7
141 #define PAIR_DX1 2
142 #define PAIR_DY1 4
143 #define PAIR_DX_ADV1 6
144 #define PAIR_DY_ADV1 8
145 #define PAIR_DX2 10
146 #define PAIR_DY2 12
147 #define PAIR_DX_ADV2 14
148 #define PAIR_DY_ADV2 16
149
150 static GTextInfo glyphclasses[] = {
151 { (unichar_t *) N_("Automatic"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
152 { (unichar_t *) N_("No Class"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
153 { (unichar_t *) N_("Base Glyph"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
154 { (unichar_t *) N_("Base Lig"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
155 { (unichar_t *) N_("Mark"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
156 { (unichar_t *) N_("Component"), NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
157 GTEXTINFO_EMPTY
158 };
159
160 #define CUSTOM_COLOR 9
161 #define COLOR_CHOOSE (-10)
162 static GTextInfo std_colors[] = {
163 { (unichar_t *) N_("Color|Choose..."), NULL, 0, 0, (void *) COLOR_CHOOSE, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' },
164 { (unichar_t *) N_("Color|Default"), &def_image, 0, 0, (void *) COLOR_DEFAULT, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' },
165 { NULL, &white_image, 0, 0, (void *) 0xffffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
166 { NULL, &red_image, 0, 0, (void *) 0xff0000, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
167 { NULL, &green_image, 0, 0, (void *) 0x00ff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
168 { NULL, &blue_image, 0, 0, (void *) 0x0000ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
169 { NULL, &yellow_image, 0, 0, (void *) 0xffff00, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
170 { NULL, &cyan_image, 0, 0, (void *) 0x00ffff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
171 { NULL, &magenta_image, 0, 0, (void *) 0xff00ff, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
172 { NULL, NULL, 0, 0, (void *) 0x000000, NULL, 0, 1, 0, 0, 0, 0, 0, 0, 0, '\0' },
173 GTEXTINFO_EMPTY
174 };
175
176 static char *newstrings[] = { N_("New Positioning"), N_("New Pair Position"),
177 N_("New Substitution Variant"),
178 N_("New Alternate List"), N_("New Multiple List"), N_("New Ligature"), NULL };
179
CounterMaskLine(SplineChar * sc,HintMask * hm)180 static unichar_t *CounterMaskLine(SplineChar *sc, HintMask *hm) {
181 unichar_t *textmask = NULL;
182 int j,k,len;
183 StemInfo *h;
184 char buffer[100];
185
186 for ( j=0; j<2; ++j ) {
187 len = 0;
188 for ( h=sc->hstem, k=0; h!=NULL && k<HntMax; h=h->next, ++k ) {
189 if ( (*hm)[k>>3]& (0x80>>(k&7)) ) {
190 sprintf( buffer, "H<%g,%g>, ",
191 rint(h->start*100)/100, rint(h->width*100)/100 );
192 if ( textmask!=NULL )
193 uc_strcpy(textmask+len,buffer);
194 len += strlen(buffer);
195 }
196 }
197 for ( h=sc->vstem; h!=NULL && k<HntMax; h=h->next, ++k ) {
198 if ( (*hm)[k>>3]& (0x80>>(k&7)) ) {
199 sprintf( buffer, "V<%g,%g>, ",
200 rint(h->start*100)/100, rint(h->width*100)/100 );
201 if ( textmask!=NULL )
202 uc_strcpy(textmask+len,buffer);
203 len += strlen(buffer);
204 }
205 }
206 if ( textmask==NULL ) {
207 textmask = malloc((len+1)*sizeof(unichar_t));
208 *textmask = '\0';
209 }
210 }
211 if ( len>1 && textmask[len-2]==',' )
212 textmask[len-2] = '\0';
213 return( textmask );
214 }
215
216 #define CID_HintMask 2020
217 #define HI_Width 200
218 #define HI_Height 260
219
220 struct hi_data {
221 int done, ok, empty;
222 GWindow gw;
223 HintMask *cur;
224 SplineChar *sc;
225 };
226
HI_Ok(GGadget * g,GEvent * e)227 static int HI_Ok(GGadget *g, GEvent *e) {
228 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
229 struct hi_data *hi = GDrawGetUserData(GGadgetGetWindow(g));
230 int32 i, len;
231 GTextInfo **ti = GGadgetGetList(GWidgetGetControl(hi->gw,CID_HintMask),&len);
232
233 for ( i=0; i<len; ++i )
234 if ( ti[i]->selected )
235 break;
236
237 memset(hi->cur,0,sizeof(HintMask));
238 if ( i==len ) {
239 hi->empty = true;
240 } else {
241 for ( i=0; i<len; ++i )
242 if ( ti[i]->selected )
243 (*hi->cur)[i>>3] |= (0x80>>(i&7));
244 }
245 PI_ShowHints(hi->sc,GWidgetGetControl(hi->gw,CID_HintMask),false);
246
247 hi->done = true;
248 hi->ok = true;
249 }
250 return( true );
251 }
252
HI_DoCancel(struct hi_data * hi)253 static void HI_DoCancel(struct hi_data *hi) {
254 hi->done = true;
255 PI_ShowHints(hi->sc,GWidgetGetControl(hi->gw,CID_HintMask),false);
256 }
257
HI_HintSel(GGadget * g,GEvent * e)258 static int HI_HintSel(GGadget *g, GEvent *e) {
259 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
260 struct hi_data *hi = GDrawGetUserData(GGadgetGetWindow(g));
261
262 PI_ShowHints(hi->sc,g,true);
263 /* Do I need to check for overlap here? */
264 }
265 return( true );
266 }
267
HI_Cancel(GGadget * g,GEvent * e)268 static int HI_Cancel(GGadget *g, GEvent *e) {
269 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
270 HI_DoCancel( GDrawGetUserData(GGadgetGetWindow(g)));
271 }
272 return( true );
273 }
274
hi_e_h(GWindow gw,GEvent * event)275 static int hi_e_h(GWindow gw, GEvent *event) {
276 if ( event->type==et_close ) {
277 HI_DoCancel( GDrawGetUserData(gw));
278 } else if ( event->type==et_char ) {
279 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
280 help("ui/dialogs/charinfo.html", "#charinfo-counters");
281 return( true );
282 }
283 return( false );
284 }
285 return( true );
286 }
287
CI_AskCounters(CharInfo * ci,HintMask * old)288 static void CI_AskCounters(CharInfo *ci,HintMask *old) {
289 HintMask *cur = old != NULL ? old : chunkalloc(sizeof(HintMask));
290 struct hi_data hi;
291 GWindowAttrs wattrs;
292 GGadgetCreateData hgcd[5], *varray[11], *harray[8], boxes[3];
293 GTextInfo hlabel[5];
294 GGadget *list = GWidgetGetControl(ci->gw,CID_List+600);
295 int j,k;
296 GRect pos;
297
298 memset(&hi,0,sizeof(hi));
299 hi.cur = cur;
300 hi.sc = ci->sc;
301
302 memset(&wattrs,0,sizeof(wattrs));
303 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
304 wattrs.event_masks = ~(1<<et_charup);
305 wattrs.restrict_input_to_me = 1;
306 wattrs.undercursor = 1;
307 wattrs.cursor = ct_pointer;
308 wattrs.utf8_window_title = old==NULL?_("New Counter Mask"):_("Edit Counter Mask");
309 wattrs.is_dlg = true;
310 pos.width = GGadgetScale(GDrawPointsToPixels(NULL,HI_Width));
311 pos.height = GDrawPointsToPixels(NULL,HI_Height);
312 hi.gw = GDrawCreateTopWindow(NULL,&pos,hi_e_h,&hi,&wattrs);
313
314
315 memset(hgcd,0,sizeof(hgcd));
316 memset(boxes,0,sizeof(boxes));
317 memset(hlabel,0,sizeof(hlabel));
318
319 j=k=0;
320
321 hgcd[j].gd.pos.x = 20-3; hgcd[j].gd.pos.y = HI_Height-31-3;
322 hgcd[j].gd.pos.width = -1; hgcd[j].gd.pos.height = 0;
323 hgcd[j].gd.flags = gg_visible | gg_enabled;
324 hlabel[j].text = (unichar_t *) _("Select hints between which counters are formed");
325 hlabel[j].text_is_1byte = true;
326 hlabel[j].text_in_resource = true;
327 hgcd[j].gd.label = &hlabel[j];
328 varray[k++] = &hgcd[j]; varray[k++] = NULL;
329 hgcd[j++].creator = GLabelCreate;
330
331 hgcd[j].gd.pos.x = 5; hgcd[j].gd.pos.y = 5;
332 hgcd[j].gd.pos.width = HI_Width-10; hgcd[j].gd.pos.height = HI_Height-45;
333 hgcd[j].gd.flags = gg_visible | gg_enabled | gg_list_multiplesel;
334 hgcd[j].gd.cid = CID_HintMask;
335 hgcd[j].gd.u.list = SCHintList(ci->sc,old);
336 hgcd[j].gd.handle_controlevent = HI_HintSel;
337 varray[k++] = &hgcd[j]; varray[k++] = NULL;
338 varray[k++] = GCD_Glue; varray[k++] = NULL;
339 hgcd[j++].creator = GListCreate;
340
341 hgcd[j].gd.pos.x = 20-3; hgcd[j].gd.pos.y = HI_Height-31-3;
342 hgcd[j].gd.pos.width = -1; hgcd[j].gd.pos.height = 0;
343 hgcd[j].gd.flags = gg_visible | gg_enabled | gg_but_default;
344 hlabel[j].text = (unichar_t *) _("_OK");
345 hlabel[j].text_is_1byte = true;
346 hlabel[j].text_in_resource = true;
347 hgcd[j].gd.label = &hlabel[j];
348 hgcd[j].gd.handle_controlevent = HI_Ok;
349 harray[0] = GCD_Glue; harray[1] = &hgcd[j]; harray[2] = GCD_Glue; harray[3] = GCD_Glue;
350 hgcd[j++].creator = GButtonCreate;
351
352 hgcd[j].gd.pos.x = -20; hgcd[j].gd.pos.y = HI_Height-31;
353 hgcd[j].gd.pos.width = -1; hgcd[j].gd.pos.height = 0;
354 hgcd[j].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
355 hlabel[j].text = (unichar_t *) _("_Cancel");
356 hlabel[j].text_is_1byte = true;
357 hlabel[j].text_in_resource = true;
358 hgcd[j].gd.label = &hlabel[j];
359 hgcd[j].gd.handle_controlevent = HI_Cancel;
360 harray[4] = GCD_Glue; harray[5] = &hgcd[j]; harray[6] = GCD_Glue; harray[7] = NULL;
361 hgcd[j++].creator = GButtonCreate;
362
363 boxes[2].gd.flags = gg_enabled|gg_visible;
364 boxes[2].gd.u.boxelements = harray;
365 boxes[2].creator = GHBoxCreate;
366 varray[k++] = &boxes[2]; varray[k++] = NULL;
367 varray[k++] = GCD_Glue; varray[k++] = NULL;
368 varray[k] = NULL;
369
370 boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
371 boxes[0].gd.flags = gg_enabled|gg_visible;
372 boxes[0].gd.u.boxelements = varray;
373 boxes[0].creator = GHVGroupCreate;
374
375 GGadgetsCreate(hi.gw,boxes);
376 GHVBoxSetExpandableRow(boxes[0].ret,1);
377 GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
378 GHVBoxFitWindow(boxes[0].ret);
379 GTextInfoListFree(hgcd[0].gd.u.list);
380
381 PI_ShowHints(hi.sc,hgcd[0].ret,true);
382
383 GDrawSetVisible(hi.gw,true);
384 while ( !hi.done )
385 GDrawProcessOneEvent(NULL);
386 GDrawDestroyWindow(hi.gw);
387
388 if ( !hi.ok ) {
389 if ( old==NULL ) chunkfree(cur,sizeof(HintMask));
390 return; /* Cancelled */
391 } else if ( old==NULL && hi.empty ) {
392 if ( old==NULL ) chunkfree(cur,sizeof(HintMask));
393 return; /* Didn't add anything new */
394 } else if ( old==NULL ) {
395 GListAddStr(list,CounterMaskLine(hi.sc,cur),cur);
396 return;
397 } else if ( !hi.empty ) {
398 GListReplaceStr(list,GGadgetGetFirstListSelectedItem(list),
399 CounterMaskLine(hi.sc,cur),cur);
400 return;
401 } else {
402 GListDelSelected(list);
403 chunkfree(cur,sizeof(HintMask));
404 }
405 }
406
CI_NewCounter(GGadget * g,GEvent * e)407 static int CI_NewCounter(GGadget *g, GEvent *e) {
408 CharInfo *ci;
409
410 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
411 ci = GDrawGetUserData(GGadgetGetWindow(g));
412 CI_AskCounters(ci,NULL);
413 }
414 return( true );
415 }
416
CI_EditCounter(GGadget * g,GEvent * e)417 static int CI_EditCounter(GGadget *g, GEvent *e) {
418 GTextInfo *ti;
419 GGadget *list;
420 CharInfo *ci;
421
422 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
423 ci = GDrawGetUserData(GGadgetGetWindow(g));
424 list = GWidgetGetControl(GGadgetGetWindow(g),CID_List+6*100);
425 if ( (ti = GGadgetGetListItemSelected(list))==NULL )
426 return( true );
427 CI_AskCounters(ci,ti->userdata);
428 }
429 return( true );
430 }
431
CI_DeleteCounter(GGadget * g,GEvent * e)432 static int CI_DeleteCounter(GGadget *g, GEvent *e) {
433 int32 len; int i,j, offset;
434 GTextInfo **old, **new_;
435 GGadget *list;
436 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
437 offset = GGadgetGetCid(g)-CID_Delete;
438 list = GWidgetGetControl(GGadgetGetWindow(g),CID_List+offset);
439 old = GGadgetGetList(list,&len);
440 new_ = calloc(len+1,sizeof(GTextInfo *));
441 for ( i=j=0; i<len; ++i )
442 if ( !old[i]->selected ) {
443 new_[j] = (GTextInfo *) malloc(sizeof(GTextInfo));
444 *new_[j] = *old[i];
445 new_[j]->text = u_copy(new_[j]->text);
446 ++j;
447 }
448 new_[j] = (GTextInfo *) calloc(1,sizeof(GTextInfo));
449 if ( offset==600 ) {
450 for ( i=0; i<len; ++i ) if ( old[i]->selected )
451 chunkfree(old[i]->userdata,sizeof(HintMask));
452 }
453 GGadgetSetList(list,new_,false);
454 GGadgetSetEnabled(GWidgetGetControl(GGadgetGetWindow(g),CID_Delete+offset),false);
455 GGadgetSetEnabled(GWidgetGetControl(GGadgetGetWindow(g),CID_Edit+offset),false);
456 }
457 return( true );
458 }
459
CI_CounterSelChanged(GGadget * g,GEvent * e)460 static int CI_CounterSelChanged(GGadget *g, GEvent *e) {
461 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
462 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
463 int sel = GGadgetGetFirstListSelectedItem(g);
464 int offset = GGadgetGetCid(g)-CID_List;
465 GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Delete+offset),sel!=-1);
466 GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_Edit+offset),sel!=-1);
467 } else if ( e->type==et_controlevent && e->u.control.subtype == et_listdoubleclick ) {
468 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
469 int offset = GGadgetGetCid(g)-CID_List;
470 e->u.control.subtype = et_buttonactivate;
471 e->u.control.g = GWidgetGetControl(ci->gw,CID_Edit+offset);
472 CI_EditCounter(e->u.control.g,e);
473 }
474 return( true );
475 }
476
ParseUValue(GWindow gw,int cid,int minusoneok)477 static int ParseUValue(GWindow gw, int cid, int minusoneok) {
478 const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(gw,cid));
479 unichar_t *end;
480 int val;
481
482 if (( *ret=='U' || *ret=='u' ) && ret[1]=='+' )
483 val = u_strtoul(ret+2,&end,16);
484 else if ( *ret=='#' )
485 val = u_strtoul(ret+1,&end,16);
486 else
487 val = u_strtoul(ret,&end,16);
488 if ( val==-1 && minusoneok )
489 return( -1 );
490 if ( *end || val<0 || val>0x10ffff ) {
491 GGadgetProtest8( _("Unicode _Value:") );
492 return( -2 );
493 }
494 return( val );
495 }
496
SetNameFromUnicode(GWindow gw,int cid,int val)497 static void SetNameFromUnicode(GWindow gw,int cid,int val) {
498 unichar_t *temp;
499 char buf[100];
500 CharInfo *ci = GDrawGetUserData(gw);
501
502 temp = utf82u_copy(StdGlyphName(buf,val,ci->sc->parent->uni_interp,ci->sc->parent->for_new_glyphs));
503 GGadgetSetTitle(GWidgetGetControl(gw,cid),temp);
504 free(temp);
505 }
506
SCInsertPST(SplineChar * sc,PST * new_)507 void SCInsertPST(SplineChar *sc,PST *new_) {
508 new_->next = sc->possub;
509 sc->possub = new_;
510 }
511
CI_NameCheck(const unichar_t * name)512 static int CI_NameCheck(const unichar_t *name) {
513 int bad, questionable;
514 extern int allow_utf8_glyphnames;
515 char *buts[3];
516 buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
517
518 if ( uc_strcmp(name,".notdef")==0 ) /* This name is a special case and doesn't follow conventions */
519 return( true );
520 if ( u_strlen(name)>31 ) {
521 ff_post_error(_("Bad Name"),_("Glyph names are limited to 31 characters"));
522 return( false );
523 } else if ( *name=='\0' ) {
524 ff_post_error(_("Bad Name"),_("Bad Name"));
525 return( false );
526 } else if ( isdigit(*name) || *name=='.' ) {
527 ff_post_error(_("Bad Name"),_("A glyph name may not start with a digit nor a full stop (period)"));
528 return( false );
529 }
530 bad = questionable = false;
531 while ( *name ) {
532 if ( *name<=' ' || (!allow_utf8_glyphnames && *name>=0x7f) ||
533 *name=='(' || *name=='[' || *name=='{' || *name=='<' ||
534 *name==')' || *name==']' || *name=='}' || *name=='>' ||
535 *name=='%' || *name=='/' )
536 bad=true;
537 else if ( !isalnum(*name) && *name!='.' && *name!='_' )
538 questionable = true;
539 ++name;
540 }
541 if ( bad ) {
542 ff_post_error(_("Bad Name"),_("A glyph name must be ASCII, without spaces and may not contain the characters \"([{<>}])/%%\", and should contain only alphanumerics, periods and underscores"));
543 return( false );
544 } else if ( questionable ) {
545 if ( gwwv_ask(_("Bad Name"),(const char **) buts,0,1,_("A glyph name should contain only alphanumerics, periods and underscores\nDo you want to use this name in spite of that?"))==1 )
546 return(false);
547 }
548 return( true );
549 }
550
CI_ParseCounters(CharInfo * ci)551 static void CI_ParseCounters(CharInfo *ci) {
552 int32 i,len;
553 GTextInfo **ti = GGadgetGetList(GWidgetGetControl(ci->gw,CID_List+600),&len);
554 SplineChar *sc = ci->cachedsc;
555
556 free(sc->countermasks);
557
558 sc->countermask_cnt = len;
559 if ( len==0 )
560 sc->countermasks = NULL;
561 else {
562 sc->countermasks = malloc(len*sizeof(HintMask));
563 for ( i=0; i<len; ++i ) {
564 memcpy(sc->countermasks[i],ti[i]->userdata,sizeof(HintMask));
565 chunkfree(ti[i]->userdata,sizeof(HintMask));
566 ti[i]->userdata = NULL;
567 }
568 }
569 }
570
DeviceTableOK(char * dvstr,int * _low,int * _high)571 int DeviceTableOK(char *dvstr, int *_low, int *_high) {
572 char *pt, *end;
573 int low, high, pixel, cor;
574
575 low = high = -1;
576 if ( dvstr!=NULL ) {
577 while ( *dvstr==' ' ) ++dvstr;
578 for ( pt=dvstr; *pt; ) {
579 pixel = strtol(pt,&end,10);
580 if ( pixel<=0 || pt==end)
581 break;
582 pt = end;
583 if ( *pt==':' ) ++pt;
584 cor = strtol(pt,&end,10);
585 if ( pt==end || cor<-128 || cor>127 )
586 break;
587 pt = end;
588 while ( *pt==' ' ) ++pt;
589 if ( *pt==',' ) ++pt;
590 while ( *pt==' ' ) ++pt;
591 if ( low==-1 ) low = high = pixel;
592 else if ( pixel<low ) low = pixel;
593 else if ( pixel>high ) high = pixel;
594 }
595 if ( *pt != '\0' )
596 return( false );
597 }
598 *_low = low; *_high = high;
599 return( true );
600 }
601
DeviceTableParse(DeviceTable * dv,char * dvstr)602 DeviceTable *DeviceTableParse(DeviceTable *dv,char *dvstr) {
603 char *pt, *end;
604 int low, high, pixel, cor;
605
606 DeviceTableOK(dvstr,&low,&high);
607 if ( low==-1 ) {
608 if ( dv!=NULL ) {
609 free(dv->corrections);
610 memset(dv,0,sizeof(*dv));
611 }
612 return( dv );
613 }
614 if ( dv==NULL )
615 dv = chunkalloc(sizeof(DeviceTable));
616 else
617 free(dv->corrections);
618 dv->first_pixel_size = low;
619 dv->last_pixel_size = high;
620 dv->corrections = calloc(high-low+1,1);
621
622 for ( pt=dvstr; *pt; ) {
623 pixel = strtol(pt,&end,10);
624 if ( pixel<=0 || pt==end)
625 break;
626 pt = end;
627 if ( *pt==':' ) ++pt;
628 cor = strtol(pt,&end,10);
629 if ( pt==end || cor<-128 || cor>127 )
630 break;
631 pt = end;
632 while ( *pt==' ' ) ++pt;
633 if ( *pt==',' ) ++pt;
634 while ( *pt==' ' ) ++pt;
635 dv->corrections[pixel-low] = cor;
636 }
637 return( dv );
638 }
639
VRDevTabParse(struct vr * vr,struct matrix_data * md)640 void VRDevTabParse(struct vr *vr,struct matrix_data *md) {
641 ValDevTab temp, *adjust;
642 int any = false;
643
644 if ( (adjust = vr->adjust)==NULL ) {
645 adjust = &temp;
646 memset(&temp,0,sizeof(temp));
647 }
648 any |= (DeviceTableParse(&adjust->xadjust,md[0].u.md_str)!=NULL);
649 any |= (DeviceTableParse(&adjust->yadjust,md[2].u.md_str)!=NULL);
650 any |= (DeviceTableParse(&adjust->xadv,md[4].u.md_str)!=NULL);
651 any |= (DeviceTableParse(&adjust->yadv,md[6].u.md_str)!=NULL);
652 if ( any && adjust==&temp ) {
653 vr->adjust = chunkalloc(sizeof(ValDevTab));
654 *vr->adjust = temp;
655 } else if ( !any && vr->adjust!=NULL ) {
656 ValDevFree(vr->adjust);
657 vr->adjust = NULL;
658 }
659 }
660
DevTabToString(char ** str,DeviceTable * adjust)661 void DevTabToString(char **str,DeviceTable *adjust) {
662 char *pt;
663 int i;
664
665 if ( adjust==NULL || adjust->corrections==NULL ) {
666 *str = NULL;
667 return;
668 }
669 *str = pt = malloc(11*(adjust->last_pixel_size-adjust->first_pixel_size+1)+1);
670 for ( i=adjust->first_pixel_size; i<=adjust->last_pixel_size; ++i ) {
671 if ( adjust->corrections[i-adjust->first_pixel_size]!=0 )
672 sprintf( pt, "%d:%d, ", i, adjust->corrections[i-adjust->first_pixel_size]);
673 pt += strlen(pt);
674 }
675 if ( pt>*str && pt[-2] == ',' )
676 pt[-2] = '\0';
677 }
678
ValDevTabToStrings(struct matrix_data * mds,int first_offset,ValDevTab * adjust)679 void ValDevTabToStrings(struct matrix_data *mds,int first_offset,ValDevTab *adjust) {
680 if ( adjust==NULL )
681 return;
682 DevTabToString(&mds[first_offset].u.md_str,&adjust->xadjust);
683 DevTabToString(&mds[first_offset+2].u.md_str,&adjust->yadjust);
684 DevTabToString(&mds[first_offset+4].u.md_str,&adjust->xadv);
685 DevTabToString(&mds[first_offset+6].u.md_str,&adjust->yadv);
686 }
687
KpMDParse(SplineChar * sc,struct lookup_subtable * sub,struct matrix_data * possub,int rows,int cols,int i)688 void KpMDParse(SplineChar *sc,struct lookup_subtable *sub,
689 struct matrix_data *possub,int rows,int cols,int i) {
690 SplineChar *other;
691 PST *pst;
692 KernPair *kp;
693 int isv, iskpable, offset, newv;
694 char *dvstr;
695 char *pt, *start;
696 int ch;
697
698 for ( start=possub[cols*i+1].u.md_str; ; ) {
699 while ( *start==' ' ) ++start;
700 if ( *start=='\0' )
701 break;
702 for ( pt=start; *pt!='\0' && *pt!=' ' && *pt!='('; ++pt );
703 ch = *pt; *pt = '\0';
704 other = SFGetChar(sc->parent,-1,start);
705 for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
706 if ( pst->subtable == sub &&
707 strcmp(start,pst->u.pair.paired)==0 )
708 break;
709 }
710 kp = NULL;
711 if ( pst==NULL && other!=NULL ) {
712 for ( isv=0; isv<2; ++isv ) {
713 for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
714 if ( kp->subtable==(void *) possub[cols*i+0].u.md_ival &&
715 kp->sc == other )
716 break;
717 if ( kp!=NULL )
718 break;
719 }
720 }
721 newv = false;
722 if ( other==NULL )
723 iskpable = false;
724 else if ( sub->vertical_kerning ) {
725 newv = true;
726 iskpable = possub[cols*i+PAIR_DX1].u.md_ival==0 &&
727 possub[cols*i+PAIR_DY1].u.md_ival==0 &&
728 possub[cols*i+PAIR_DX_ADV1].u.md_ival==0 &&
729 possub[cols*i+PAIR_DX2].u.md_ival==0 &&
730 possub[cols*i+PAIR_DY2].u.md_ival==0 &&
731 possub[cols*i+PAIR_DX_ADV2].u.md_ival==0 &&
732 possub[cols*i+PAIR_DY_ADV2].u.md_ival==0;
733 offset = possub[cols*i+PAIR_DY1].u.md_ival;
734 iskpable &= (possub[cols*i+PAIR_DX1+1].u.md_str==NULL || *possub[cols*i+PAIR_DX1+1].u.md_str==0 ) &&
735 (possub[cols*i+PAIR_DY1+1].u.md_str==0 || *possub[cols*i+PAIR_DY1+1].u.md_str==0 ) &&
736 (possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 ) &&
737 (possub[cols*i+PAIR_DX2+1].u.md_str==0 || *possub[cols*i+PAIR_DX2+1].u.md_str==0 ) &&
738 (possub[cols*i+PAIR_DY2+1].u.md_str==0 || *possub[cols*i+PAIR_DY2+1].u.md_str==0 ) &&
739 (possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 ) &&
740 (possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 );
741 dvstr = possub[cols*i+PAIR_DY1+1].u.md_str;
742 } else if ( sub->lookup->lookup_flags & pst_r2l ) {
743 iskpable = possub[cols*i+PAIR_DX1].u.md_ival==0 &&
744 possub[cols*i+PAIR_DY1].u.md_ival==0 &&
745 possub[cols*i+PAIR_DX_ADV1].u.md_ival==0 &&
746 possub[cols*i+PAIR_DY_ADV1].u.md_ival==0 &&
747 possub[cols*i+PAIR_DX2].u.md_ival==0 &&
748 possub[cols*i+PAIR_DY2].u.md_ival==0 &&
749 possub[cols*i+PAIR_DY_ADV2].u.md_ival==0;
750 offset = possub[cols*i+PAIR_DX_ADV2].u.md_ival;
751 iskpable &= (possub[cols*i+PAIR_DX1+1].u.md_str==NULL || *possub[cols*i+PAIR_DX1+1].u.md_str==0 ) &&
752 (possub[cols*i+PAIR_DY1+1].u.md_str==0 || *possub[cols*i+PAIR_DY1+1].u.md_str==0 ) &&
753 (possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV1+1].u.md_str==0 ) &&
754 (possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 ) &&
755 (possub[cols*i+PAIR_DX2+1].u.md_str==0 || *possub[cols*i+PAIR_DX2+1].u.md_str==0 ) &&
756 (possub[cols*i+PAIR_DY2+1].u.md_str==0 || *possub[cols*i+PAIR_DY2+1].u.md_str==0 ) &&
757 (possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 );
758 dvstr = possub[cols*i+PAIR_DX_ADV2+1].u.md_str;
759 } else {
760 iskpable = possub[cols*i+PAIR_DX1].u.md_ival==0 &&
761 possub[cols*i+PAIR_DY1].u.md_ival==0 &&
762 possub[cols*i+PAIR_DY_ADV1].u.md_ival==0 &&
763 possub[cols*i+PAIR_DX2].u.md_ival==0 &&
764 possub[cols*i+PAIR_DY2].u.md_ival==0 &&
765 possub[cols*i+PAIR_DX_ADV2].u.md_ival==0 &&
766 possub[cols*i+PAIR_DY_ADV2].u.md_ival==0;
767 offset = possub[cols*i+PAIR_DX_ADV1].u.md_ival;
768 iskpable &= (possub[cols*i+PAIR_DX1+1].u.md_str==NULL || *possub[cols*i+PAIR_DX1+1].u.md_str==0 ) &&
769 (possub[cols*i+PAIR_DY1+1].u.md_str==0 || *possub[cols*i+PAIR_DY1+1].u.md_str==0 ) &&
770 (possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV1+1].u.md_str==0 ) &&
771 (possub[cols*i+PAIR_DX2+1].u.md_str==0 || *possub[cols*i+PAIR_DX2+1].u.md_str==0 ) &&
772 (possub[cols*i+PAIR_DY2+1].u.md_str==0 || *possub[cols*i+PAIR_DY2+1].u.md_str==0 ) &&
773 (possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DX_ADV2+1].u.md_str==0 ) &&
774 (possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 || *possub[cols*i+PAIR_DY_ADV2+1].u.md_str==0 );
775 dvstr = possub[cols*i+PAIR_DX_ADV1+1].u.md_str;
776 }
777 if ( iskpable ) {
778 if ( kp==NULL ) {
779 /* If there's a pst, ignore it, it will not get ticked and will*/
780 /* be freed later */
781 kp = chunkalloc(sizeof(KernPair));
782 kp->subtable = sub;
783 kp->sc = other;
784 if ( newv ) {
785 kp->next = sc->vkerns;
786 sc->vkerns = kp;
787 } else {
788 kp->next = sc->kerns;
789 sc->kerns = kp;
790 }
791 }
792 DeviceTableFree(kp->adjust);
793 kp->adjust = DeviceTableParse(NULL,dvstr);
794 kp->off = offset;
795 kp->kcid = true;
796 } else {
797 if ( pst == NULL ) {
798 /* If there's a kp, ignore it, it will not get ticked and will*/
799 /* be freed later */
800 pst = chunkalloc(sizeof(PST));
801 pst->type = pst_pair;
802 pst->subtable = sub;
803 pst->next = sc->possub;
804 sc->possub = pst;
805 pst->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
806 pst->u.pair.paired = copy(start);
807 }
808 VRDevTabParse(&pst->u.pair.vr[0],&possub[cols*i+PAIR_DX1+1]);
809 VRDevTabParse(&pst->u.pair.vr[1],&possub[cols*i+PAIR_DX2]+1);
810 pst->u.pair.vr[0].xoff = possub[cols*i+PAIR_DX1].u.md_ival;
811 pst->u.pair.vr[0].yoff = possub[cols*i+PAIR_DY1].u.md_ival;
812 pst->u.pair.vr[0].h_adv_off = possub[cols*i+PAIR_DX_ADV1].u.md_ival;
813 pst->u.pair.vr[0].v_adv_off = possub[cols*i+PAIR_DY_ADV1].u.md_ival;
814 pst->u.pair.vr[1].xoff = possub[cols*i+PAIR_DX2].u.md_ival;
815 pst->u.pair.vr[1].yoff = possub[cols*i+PAIR_DY2].u.md_ival;
816 pst->u.pair.vr[1].h_adv_off = possub[cols*i+PAIR_DX_ADV2].u.md_ival;
817 pst->u.pair.vr[1].v_adv_off = possub[cols*i+PAIR_DY_ADV2].u.md_ival;
818 pst->ticked = true;
819 }
820 *pt = ch;
821 if ( ch=='(' ) {
822 while ( *pt!=')' && *pt!='\0' ) ++pt;
823 if ( *pt==')' ) ++pt;
824 }
825 start = pt;
826 }
827 }
828
CI_ProcessPosSubs(CharInfo * ci)829 static int CI_ProcessPosSubs(CharInfo *ci) {
830 /* Check for duplicate entries in kerning and ligatures. If we find any */
831 /* complain and return failure */
832 /* Check for various other errors */
833 /* Otherwise process */
834 SplineChar *sc = ci->cachedsc, *found;
835 int i,j, rows, cols, isv, pstt, ch;
836 char *pt;
837 struct matrix_data *possub;
838 char *buts[3];
839 KernPair *kp, *kpprev, *kpnext;
840 PST *pst, *pstprev, *pstnext, *lcpst=NULL;
841
842 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100), &rows );
843 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100) );
844 for ( i=0; i<rows; ++i ) {
845 for ( j=i+1; j<rows; ++j ) {
846 if ( possub[cols*i+0].u.md_ival == possub[cols*j+0].u.md_ival &&
847 strcmp(possub[cols*i+1].u.md_str,possub[cols*j+1].u.md_str)==0 ) {
848 ff_post_error( _("Duplicate Ligature"),_("There are two ligature entries with the same components (%.80s) in the same lookup subtable (%.30s)"),
849 possub[cols*j+1].u.md_str,
850 ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name );
851 return( false );
852 }
853 }
854 }
855 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100), &rows );
856 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100));
857 for ( i=0; i<rows; ++i ) {
858 for ( j=i+1; j<rows; ++j ) {
859 if ( possub[cols*i+0].u.md_ival == possub[cols*j+0].u.md_ival &&
860 strcmp(possub[cols*i+1].u.md_str,possub[cols*j+1].u.md_str)==0 ) {
861 ff_post_error( _("Duplicate Kern data"),_("There are two kerning entries for the same glyph (%.80s) in the same lookup subtable (%.30s)"),
862 possub[cols*j+1].u.md_str,
863 ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name );
864 return( false );
865 }
866 }
867 }
868
869 /* Check for badly specified device tables */
870 for ( pstt = pst_position; pstt<=pst_pair; ++pstt ) {
871 int startc = pstt==pst_position ? SIM_DX+1 : PAIR_DX1+1;
872 int low, high, c, r;
873 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100), &rows );
874 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100));
875 for ( r=0; r<rows; ++r ) {
876 for ( c=startc; c<cols; c+=2 ) {
877 if ( !DeviceTableOK(possub[r*cols+c].u.md_str,&low,&high) ) {
878 ff_post_error( _("Bad Device Table Adjustment"),_("A device table adjustment specified for %.80s is invalid"),
879 possub[cols*r+0].u.md_str );
880 return( true );
881 }
882 }
883 }
884 }
885
886 for ( pstt = pst_pair; pstt<=pst_ligature; ++pstt ) {
887 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100), &rows );
888 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100));
889 for ( i=0; i<rows; ++i ) {
890 char *start = possub[cols*i+1].u.md_str;
891 while ( *start== ' ' ) ++start;
892 if ( *start=='\0' ) {
893 ff_post_error( _("Missing glyph name"),_("You must specify a glyph name for subtable %s"),
894 ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name );
895 return( false );
896 }
897 while ( *start ) {
898 for ( pt=start; *pt!='\0' && *pt!=' ' && *pt!='(' ; ++pt );
899 ch = *pt; *pt='\0';
900 found = SFGetChar(sc->parent,-1,start);
901 if ( found==NULL ) {
902 buts[0] = _("_Yes");
903 buts[1] = _("_Cancel");
904 buts[2] = NULL;
905 if ( gwwv_ask(_("Missing glyph"),(const char **) buts,0,1,_("In lookup subtable %.30s you refer to a glyph named %.80s, which is not in the font yet. Was this intentional?"),
906 ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name,
907 start)==1 ) {
908 *pt = ch;
909 return( false );
910 }
911 } else if ( found==ci->sc && pstt!=pst_pair ) {
912 buts[0] = _("_Yes");
913 buts[1] = _("_Cancel");
914 buts[2] = NULL;
915 if ( gwwv_ask(_("Substitution generates itself"),(const char **) buts,0,1,_("In lookup subtable %.30s you replace a glyph with itself. Was this intentional?"),
916 ((struct lookup_subtable *) possub[cols*i+0].u.md_ival)->subtable_name)==1 ) {
917 *pt = ch;
918 return( false );
919 }
920 }
921 *pt = ch;
922 if ( ch=='(' ) {
923 while ( *pt!=')' && *pt!='\0' ) ++pt;
924 if ( *pt==')' ) ++pt;
925 }
926 while ( *pt== ' ' ) ++pt;
927 start = pt;
928 }
929 }
930 }
931
932 /* If we get this far, then we didn't find any errors */
933 for ( pst = sc->possub; pst!=NULL; pst=pst->next ) {
934 pst->ticked = false;
935 if ( pst->type==pst_lcaret )
936 lcpst = pst;
937 }
938
939 // There is no dialog datastructure for the ligature carets, so copy them here
940 // The entry will be modified in _CI_OK when needed
941 for ( pst = ci->sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next )
942 ;
943 if ( pst!=NULL ) {
944 if ( lcpst==NULL ) {
945 lcpst = chunkalloc(sizeof(PST));
946 lcpst->type = pst_lcaret;
947 lcpst->next = sc->possub;
948 sc->possub = lcpst;
949 }
950 if ( lcpst->u.lcaret.carets!=NULL )
951 free(lcpst->u.lcaret.carets);
952 lcpst->u.lcaret.cnt = pst->u.lcaret.cnt;
953 lcpst->u.lcaret.carets = malloc(pst->u.lcaret.cnt*sizeof(int16));
954 memcpy(lcpst->u.lcaret.carets,pst->u.lcaret.carets,pst->u.lcaret.cnt*sizeof(int16));
955 lcpst->ticked = true;
956 }
957
958 for ( isv=0; isv<2; ++isv )
959 for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
960 kp->kcid = 0;
961
962 for ( pstt=pst_substitution; pstt<=pst_ligature; ++pstt ) {
963 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100), &rows );
964 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pstt-1)*100) );
965 for ( i=0; i<rows; ++i ) {
966 for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
967 if ( pst->subtable == (void *) possub[cols*i+0].u.md_ival &&
968 !pst->ticked )
969 break;
970 }
971 if ( pst==NULL ) {
972 pst = chunkalloc(sizeof(PST));
973 pst->type = pstt;
974 pst->subtable = (void *) possub[cols*i+0].u.md_ival;
975 pst->next = sc->possub;
976 sc->possub = pst;
977 } else
978 free( pst->u.subs.variant );
979 pst->ticked = true;
980 pst->u.subs.variant = GlyphNameListDeUnicode( possub[cols*i+1].u.md_str );
981 if ( pstt==pst_ligature )
982 pst->u.lig.lig = sc;
983 }
984 }
985
986 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100), &rows );
987 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100));
988 for ( i=0; i<rows; ++i ) {
989 for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
990 if ( pst->subtable == (void *) possub[cols*i+0].u.md_ival &&
991 !pst->ticked )
992 break;
993 }
994 if ( pst==NULL ) {
995 pst = chunkalloc(sizeof(PST));
996 pst->type = pst_position;
997 pst->subtable = (void *) possub[cols*i+0].u.md_ival;
998 pst->next = sc->possub;
999 sc->possub = pst;
1000 }
1001 VRDevTabParse(&pst->u.pos,&possub[cols*i+SIM_DX+1]);
1002 pst->u.pos.xoff = possub[cols*i+SIM_DX].u.md_ival;
1003 pst->u.pos.yoff = possub[cols*i+SIM_DY].u.md_ival;
1004 pst->u.pos.h_adv_off = possub[cols*i+SIM_DX_ADV].u.md_ival;
1005 pst->u.pos.v_adv_off = possub[cols*i+SIM_DY_ADV].u.md_ival;
1006 pst->ticked = true;
1007 }
1008
1009 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100), &rows );
1010 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100));
1011 for ( i=0; i<rows; ++i ) {
1012 struct lookup_subtable *sub = ((struct lookup_subtable *) possub[cols*i+0].u.md_ival);
1013 KpMDParse(sc,sub,possub,rows,cols,i);
1014 }
1015
1016 /* Now, free anything that did not get ticked */
1017 for ( pstprev=NULL, pst = sc->possub; pst!=NULL; pst=pstnext ) {
1018 pstnext = pst->next;
1019 if ( pst->ticked )
1020 pstprev = pst;
1021 else {
1022 if ( pstprev==NULL )
1023 sc->possub = pstnext;
1024 else
1025 pstprev->next = pstnext;
1026 pst->next = NULL;
1027 PSTFree(pst);
1028 }
1029 }
1030 for ( isv=0; isv<2; ++isv ) {
1031 for ( kpprev=NULL, kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kpnext ) {
1032 kpnext = kp->next;
1033 if ( kp->kcid!=0 )
1034 kpprev = kp;
1035 else {
1036 if ( kpprev!=NULL )
1037 kpprev->next = kpnext;
1038 else if ( isv )
1039 sc->vkerns = kpnext;
1040 else
1041 sc->kerns = kpnext;
1042 kp->next = NULL;
1043 KernPairsFree(kp);
1044 }
1045 }
1046 }
1047 for ( isv=0; isv<2; ++isv )
1048 for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
1049 kp->kcid = 0;
1050 return( true );
1051 }
1052
gettex(GWindow gw,int cid,char * msg,int * err)1053 static int gettex(GWindow gw,int cid,char *msg,int *err) {
1054 const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(gw,cid));
1055
1056 if ( *ret=='\0' )
1057 return( TEX_UNDEF );
1058 return( GetInt8(gw,cid,msg,err));
1059 }
1060
GV_ParseConstruction(struct glyphvariants * gv,struct matrix_data * stuff,int rows,int cols)1061 struct glyphvariants *GV_ParseConstruction(struct glyphvariants *gv,
1062 struct matrix_data *stuff, int rows, int cols) {
1063 int i;
1064
1065 if ( gv==NULL )
1066 gv = chunkalloc(sizeof(struct glyphvariants));
1067
1068 gv->part_cnt = rows;
1069 gv->parts = calloc(rows,sizeof(struct gv_part));
1070 for ( i=0; i<rows; ++i ) {
1071 gv->parts[i].component = copy(stuff[i*cols+0].u.md_str);
1072 gv->parts[i].is_extender = stuff[i*cols+1].u.md_ival;
1073 gv->parts[i].startConnectorLength = stuff[i*cols+2].u.md_ival;
1074 gv->parts[i].endConnectorLength = stuff[i*cols+3].u.md_ival;
1075 gv->parts[i].fullAdvance = stuff[i*cols+4].u.md_ival;
1076 }
1077 return( gv );
1078 }
1079
CI_ParseVariants(struct glyphvariants * gv,CharInfo * ci,int is_horiz,char * italic_correction_devtab,int italic_correction,int only_parts)1080 static struct glyphvariants *CI_ParseVariants(struct glyphvariants *gv,
1081 CharInfo *ci, int is_horiz,
1082 char *italic_correction_devtab, int italic_correction,
1083 int only_parts) {
1084 char *variants = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_VariantList+is_horiz*100));
1085 GGadget *construct = GWidgetGetControl(ci->gw,CID_ExtensionList+is_horiz*100);
1086 int rows, cols = GMatrixEditGetColCnt(construct);
1087 struct matrix_data *stuff = GMatrixEditGet(construct,&rows);
1088
1089 if ( (variants==NULL || variants[0]=='\0' || only_parts) && rows==0 ) {
1090 free(variants);
1091 GlyphVariantsFree(gv);
1092 return( NULL );
1093 }
1094 if ( gv==NULL )
1095 gv = chunkalloc(sizeof(struct glyphvariants));
1096 free(gv->variants); gv->variants = NULL;
1097 if ( only_parts ) {
1098 free(variants); variants = NULL;
1099 } else if ( variants!=NULL && *variants!='\0' )
1100 gv->variants = variants;
1101 else {
1102 gv->variants = NULL;
1103 free( variants);
1104 }
1105 if ( !only_parts ) {
1106 gv->italic_correction = italic_correction;
1107 gv->italic_adjusts = DeviceTableParse(gv->italic_adjusts,italic_correction_devtab);
1108 }
1109 gv = GV_ParseConstruction(gv,stuff,rows,cols);
1110 return( gv );
1111 }
1112
CI_ValidateAltUnis(CharInfo * ci)1113 static int CI_ValidateAltUnis(CharInfo *ci) {
1114 GGadget *au = GWidgetGetControl(ci->gw,CID_AltUni);
1115 int rows, cols = GMatrixEditGetColCnt(au);
1116 struct matrix_data *stuff = GMatrixEditGet(au,&rows);
1117 int i, asked = false;
1118
1119 for ( i=0; i<rows; ++i ) {
1120 int uni = stuff[i*cols+0].u.md_ival, vs = stuff[i*cols+1].u.md_ival;
1121 if ( uni<0 || uni>=unicode4_size ||
1122 vs<-1 || vs>=unicode4_size ) {
1123 ff_post_error(_("Unicode out of range"), _("Bad unicode value for an alternate unicode / variation selector"));
1124 return( false );
1125 }
1126 if ( (vs>=0x180B && vs<=0x180D) || /* Mongolian VS */
1127 (vs>=0xfe00 && vs<=0xfe0f) || /* First VS block */
1128 (vs>=0xE0100 && vs<=0xE01EF) ) { /* Second VS block */
1129 /* ok, that's a reasonable value */;
1130 } else if ( vs==0 || vs==-1 ) {
1131 /* That's ok too (means no selector, just an alternate encoding) */;
1132 } else if ( !asked ) {
1133 char *buts[3];
1134 buts[0] = _("_OK"); buts[1] = _("_Cancel"); buts[2]=NULL;
1135 if ( gwwv_ask(_("Unexpected Variation Selector"),(const char **) buts,0,1,
1136 _("Variation selectors are normally between\n"
1137 " U+180B and U+180D\n"
1138 " U+FE00 and U+FE0F\n"
1139 " U+E0100 and U+E01EF\n"
1140 "did you really intend to use U+%04X?"), vs)==1 )
1141 return( false );
1142 asked = true;
1143 }
1144 }
1145 return( true );
1146 }
1147
CI_ParseAltUnis(CharInfo * ci)1148 static void CI_ParseAltUnis(CharInfo *ci) {
1149 GGadget *au = GWidgetGetControl(ci->gw,CID_AltUni);
1150 int rows, cols = GMatrixEditGetColCnt(au);
1151 struct matrix_data *stuff = GMatrixEditGet(au,&rows);
1152 int i;
1153 struct altuni *altuni, *last = NULL;
1154 SplineChar *sc = ci->cachedsc;
1155 int deenc = false;
1156 FontView *fvs;
1157 int oldcnt, newcnt;
1158
1159 oldcnt = 0;
1160 for ( altuni=sc->altuni ; altuni!=NULL; altuni = altuni->next )
1161 if ( altuni->vs==-1 && altuni->fid==0 )
1162 ++oldcnt;
1163
1164 newcnt = 0;
1165 for ( i=0; i<rows; ++i ) {
1166 int uni = stuff[i*cols+0].u.md_ival, vs = stuff[i*cols+1].u.md_ival;
1167 if ( vs!=0 )
1168 continue;
1169 ++newcnt;
1170 if ( uni==sc->unicodeenc )
1171 continue;
1172 for ( altuni=sc->altuni ; altuni!=NULL; altuni = altuni->next )
1173 if ( uni==altuni->unienc && altuni->vs==-1 && altuni->fid==0 )
1174 break;
1175 if ( altuni==NULL ) {
1176 deenc = true;
1177 break;
1178 }
1179 }
1180 if ( oldcnt!=newcnt || deenc ) {
1181 for ( fvs=(FontView *) sc->parent->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
1182 fvs->b.map->enc = &custom;
1183 FVSetTitle((FontViewBase *) fvs);
1184 }
1185 }
1186 AltUniFree(sc->altuni); sc->altuni = NULL;
1187 for ( i=0; i<rows; ++i ) {
1188 int uni = stuff[i*cols+0].u.md_ival, vs = stuff[i*cols+1].u.md_ival;
1189 altuni = chunkalloc(sizeof(struct altuni));
1190 altuni->unienc = uni;
1191 altuni->vs = vs==0 ? -1 : vs;
1192 altuni->fid = 0;
1193 if ( last == NULL )
1194 sc->altuni = altuni;
1195 else
1196 last->next = altuni;
1197 last = altuni;
1198 }
1199 }
1200
CI_KPCopy(KernPair * kp)1201 static KernPair *CI_KPCopy(KernPair *kp) {
1202 KernPair *head=NULL, *last=NULL, *newkp;
1203
1204 while ( kp!=NULL ) {
1205 newkp = chunkalloc(sizeof(KernPair));
1206 *newkp = *kp;
1207 newkp->adjust = DeviceTableCopy(kp->adjust);
1208 newkp->next = NULL;
1209 if ( head==NULL )
1210 head = newkp;
1211 else
1212 last->next = newkp;
1213 last = newkp;
1214 kp = kp->next;
1215 }
1216 return( head );
1217 }
1218
CI_PSTCopy(PST * pst)1219 static PST *CI_PSTCopy(PST *pst) {
1220 PST *head=NULL, *last=NULL, *newpst;
1221
1222 while ( pst!=NULL ) {
1223 newpst = chunkalloc(sizeof(KernPair));
1224 *newpst = *pst;
1225 if ( newpst->type==pst_ligature ) {
1226 newpst->u.lig.components = copy(pst->u.lig.components);
1227 } else if ( newpst->type==pst_pair ) {
1228 newpst->u.pair.paired = copy(pst->u.pair.paired);
1229 newpst->u.pair.vr = chunkalloc(sizeof( struct vr [2]));
1230 memcpy(newpst->u.pair.vr,pst->u.pair.vr,sizeof(struct vr [2]));
1231 newpst->u.pair.vr[0].adjust = ValDevTabCopy(pst->u.pair.vr[0].adjust);
1232 newpst->u.pair.vr[1].adjust = ValDevTabCopy(pst->u.pair.vr[1].adjust);
1233 } else if ( newpst->type==pst_lcaret ) {
1234 newpst->u.lcaret.carets = malloc(pst->u.lcaret.cnt*sizeof(int16));
1235 memcpy(newpst->u.lcaret.carets,pst->u.lcaret.carets,pst->u.lcaret.cnt*sizeof(int16));
1236 } else if ( newpst->type==pst_substitution || newpst->type==pst_multiple || newpst->type==pst_alternate )
1237 newpst->u.subs.variant = copy(pst->u.subs.variant);
1238 newpst->next = NULL;
1239 if ( head==NULL )
1240 head = newpst;
1241 else
1242 last->next = newpst;
1243 last = newpst;
1244 pst = pst->next;
1245 }
1246 return( head );
1247 }
1248
CI_SCDuplicate(SplineChar * sc)1249 static SplineChar *CI_SCDuplicate(SplineChar *sc) {
1250 SplineChar *newsc; /* copy everything we care about in this dlg */
1251
1252 newsc = chunkalloc(sizeof(SplineChar));
1253 newsc->name = copy(sc->name);
1254 newsc->parent = sc->parent;
1255 newsc->unicodeenc = sc->unicodeenc;
1256 newsc->orig_pos = sc->orig_pos;
1257 newsc->comment = copy(sc->comment);
1258 newsc->user_decomp = u_copy(sc->user_decomp);
1259 newsc->unlink_rm_ovrlp_save_undo = sc->unlink_rm_ovrlp_save_undo;
1260 newsc->glyph_class = sc->glyph_class;
1261 newsc->color = sc->color;
1262 if ( sc->countermask_cnt!=0 ) {
1263 newsc->countermask_cnt = sc->countermask_cnt;
1264 newsc->countermasks = malloc(sc->countermask_cnt*sizeof(HintMask));
1265 memcpy(newsc->countermasks,sc->countermasks,sc->countermask_cnt*sizeof(HintMask));
1266 }
1267 newsc->tex_height = sc->tex_height;
1268 newsc->tex_depth = sc->tex_depth;
1269 newsc->italic_correction = sc->italic_correction;
1270 newsc->top_accent_horiz = sc->top_accent_horiz;
1271 newsc->is_extended_shape = sc->is_extended_shape;
1272 newsc->italic_adjusts = DeviceTableCopy(sc->italic_adjusts);
1273 newsc->top_accent_adjusts = DeviceTableCopy(sc->top_accent_adjusts);
1274 newsc->horiz_variants = GlyphVariantsCopy(sc->horiz_variants);
1275 newsc->vert_variants = GlyphVariantsCopy(sc->vert_variants);
1276 newsc->altuni = AltUniCopy(sc->altuni,NULL);
1277 newsc->lig_caret_cnt_fixed = sc->lig_caret_cnt_fixed;
1278 newsc->possub = CI_PSTCopy(sc->possub);
1279 newsc->kerns = CI_KPCopy(sc->kerns);
1280 newsc->vkerns = CI_KPCopy(sc->vkerns);
1281 newsc->tile_margin = sc->tile_margin;
1282 newsc->tile_bounds = sc->tile_bounds;
1283 return( newsc );
1284 }
1285
CI_CheckMetaData(CharInfo * ci,SplineChar * oldsc,char * name,int unienc,char * comment)1286 static int CI_CheckMetaData(CharInfo *ci,SplineChar *oldsc,char *name,int unienc, char *comment) {
1287 SplineFont *sf = oldsc->parent;
1288 int i;
1289 int isnotdef, samename=false, sameuni=false;
1290 struct altuni *alt;
1291 SplineChar *newsc = ci->cachedsc;
1292 struct splinecharlist *scl, *baduniscl, *badnamescl;
1293 SplineChar *baduni, *badname;
1294
1295 for ( alt=oldsc->altuni; alt!=NULL && (alt->unienc!=unienc || alt->vs!=-1 || alt->fid!=0); alt=alt->next );
1296 if ( unienc==oldsc->unicodeenc || alt!=NULL )
1297 sameuni=true;
1298 samename = ( oldsc->name!=NULL && strcmp(name,oldsc->name)==0 );
1299
1300 isnotdef = strcmp(name,".notdef")==0;
1301 if (( !sameuni && unienc!=-1) || (!samename && !isnotdef) ) {
1302 baduniscl = badnamescl = NULL;
1303 baduni = badname = NULL;
1304 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]!=ci->sc ) {
1305 if ( unienc!=-1 && sf->glyphs[i]->unicodeenc==unienc ) {
1306 for ( scl=ci->changes; scl!=NULL && scl->sc->orig_pos!=i; scl = scl->next );
1307 if ( scl==NULL ) {
1308 baduni = sf->glyphs[i];
1309 baduniscl = NULL;
1310 } else if ( scl->sc->unicodeenc==unienc ) {
1311 baduni = scl->sc;
1312 baduniscl = scl;
1313 }
1314 }
1315 if ( !isnotdef && strcmp(name,sf->glyphs[i]->name )==0 ) {
1316 for ( scl=ci->changes; scl!=NULL && scl->sc->orig_pos!=i; scl = scl->next );
1317 if ( scl==NULL ) {
1318 badname = sf->glyphs[i];
1319 badnamescl = NULL;
1320 } else if ( strcmp(scl->sc->name,name)==0 ) {
1321 badname = scl->sc;
1322 badnamescl = scl;
1323 }
1324 }
1325 }
1326 for ( scl=ci->changes; scl!=NULL ; scl = scl->next ) if ( scl->sc!=newsc ) {
1327 if ( unienc!=-1 && scl->sc->unicodeenc==unienc ) {
1328 baduni = scl->sc;
1329 baduniscl = scl;
1330 }
1331 if ( !isnotdef && strcmp(scl->sc->name,name)==0 ) {
1332 badname = scl->sc;
1333 badnamescl = scl;
1334 }
1335 }
1336 if ( baduni!=NULL || badname!=NULL ) {
1337 char *buts[3];
1338 buts[0] = _("_Yes"); buts[1]=_("_Cancel"); buts[2] = NULL;
1339 if ( badname==baduni ) {
1340 if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this name and encoding,\nboth must be unique within a font,\ndo you want to swap them?"))==1 )
1341 return( false );
1342 /* If we're going to swap, then add the swapee to the list of */
1343 /* things that need changing */
1344 if ( baduniscl==NULL ) {
1345 baduni = CI_SCDuplicate(baduni);
1346 baduniscl = chunkalloc(sizeof(struct splinecharlist));
1347 baduniscl->sc = baduni;
1348 baduniscl->next = ci->changes;
1349 ci->changes = baduniscl;
1350 }
1351 baduni->unicodeenc = oldsc->unicodeenc;
1352 free(baduni->name); baduni->name = copy(oldsc->name);
1353 } else {
1354 if ( baduni!=NULL ) {
1355 if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this encoding,\nwhich must be unique within a font,\ndo you want to swap the encodings of the two?"))==1 )
1356 return( false );
1357 if ( baduniscl==NULL ) {
1358 baduni = CI_SCDuplicate(baduni);
1359 baduniscl = chunkalloc(sizeof(struct splinecharlist));
1360 baduniscl->sc = baduni;
1361 baduniscl->next = ci->changes;
1362 ci->changes = baduniscl;
1363 }
1364 baduni->unicodeenc = oldsc->unicodeenc;
1365 }
1366 if ( badname!=NULL ) {
1367 if ( ff_ask(_("Multiple"),(const char **) buts,0,1,_("There is already a glyph with this name,\nwhich must be unique within a font,\ndo you want to swap the names of the two?"))==1 )
1368 return( false );
1369 if ( badnamescl==NULL ) {
1370 badname = CI_SCDuplicate(badname);
1371 badnamescl = chunkalloc(sizeof(struct splinecharlist));
1372 badnamescl->sc = badname;
1373 badnamescl->next = ci->changes;
1374 ci->changes = badnamescl;
1375 }
1376 free(badname->name); badname->name = copy(oldsc->name);
1377 }
1378 }
1379 }
1380 }
1381 if ( !samename )
1382 ci->name_change = true;
1383 if ( !sameuni )
1384 ci->uni_change = true;
1385 free( newsc->name ); free( newsc->comment );
1386 newsc->name = copy( name );
1387 newsc->unicodeenc = unienc;
1388 newsc->comment = copy( comment );
1389 return( true );
1390 }
1391
_CI_OK(CharInfo * ci)1392 static int _CI_OK(CharInfo *ci) {
1393 int val;
1394 int ret;
1395 char *name, *comment;
1396 const unichar_t *nm;
1397 int err = false;
1398 int tex_height, tex_depth, italic, topaccent;
1399 int hic, vic;
1400 int lc_cnt=-1;
1401 char *italicdevtab=NULL, *accentdevtab=NULL, *hicdt=NULL, *vicdt=NULL;
1402 int lig_caret_cnt_fixed=0;
1403 int low,high;
1404 real tile_margin=0;
1405 DBounds tileb;
1406 SplineChar *oldsc = ci->cachedsc==NULL ? ci->sc : ci->cachedsc;
1407
1408 if ( !CI_ValidateAltUnis(ci))
1409 return( false );
1410
1411 val = ParseUValue(ci->gw,CID_UValue,true);
1412 if ( val==-2 )
1413 return( false );
1414 tex_height = gettex(ci->gw,CID_TeX_Height,_("Height"),&err);
1415 tex_depth = gettex(ci->gw,CID_TeX_Depth ,_("Depth") ,&err);
1416 italic = gettex(ci->gw,CID_TeX_Italic,_("Italic Correction"),&err);
1417 topaccent = gettex(ci->gw,CID_HorAccent,_("Top Accent Horizontal Pos"),&err);
1418 if ( err )
1419 return( false );
1420 hic = GetInt8(ci->gw,CID_ExtItalicCor+1*100,_("Horizontal Extension Italic Correction"),&err);
1421 vic = GetInt8(ci->gw,CID_ExtItalicCor+0*100,_("Vertical Extension Italic Correction"),&err);
1422 if ( err )
1423 return( false );
1424
1425 memset(&tileb,0,sizeof(tileb));
1426 if ( ci->sc->parent->multilayer ) {
1427 if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_IsTileMargin)))
1428 tile_margin = GetReal8(ci->gw,CID_TileMargin,_("Tile Margin"),&err);
1429 else {
1430 tileb.minx = GetReal8(ci->gw,CID_TileBBoxMinX,_("Tile Min X"),&err);
1431 tileb.miny = GetReal8(ci->gw,CID_TileBBoxMinY,_("Tile Min Y"),&err);
1432 tileb.maxx = GetReal8(ci->gw,CID_TileBBoxMaxX,_("Tile Max X"),&err);
1433 tileb.maxy = GetReal8(ci->gw,CID_TileBBoxMaxY,_("Tile Max Y"),&err);
1434 }
1435 if ( err )
1436 return( false );
1437 }
1438
1439 lig_caret_cnt_fixed = !GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_DefLCCount));
1440 if ( ci->lc_seen ) {
1441 lc_cnt = GetInt8(ci->gw,CID_LCCount,_("Ligature Caret Count"),&err);
1442 if ( err )
1443 return( false );
1444 if ( lc_cnt<0 || lc_cnt>100 ) {
1445 ff_post_error(_("Bad Lig. Caret Count"),_("Unreasonable ligature caret count"));
1446 return( false );
1447 }
1448 }
1449 nm = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UName));
1450 if ( !CI_NameCheck(nm) )
1451 return( false );
1452
1453 italicdevtab = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_ItalicDevTab));
1454 accentdevtab = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_AccentDevTab));
1455 hicdt = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+1*100));
1456 vicdt = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+0*100));
1457 if ( !DeviceTableOK(italicdevtab,&low,&high) || !DeviceTableOK(accentdevtab,&low,&high) ||
1458 !DeviceTableOK(hicdt,&low,&high) || !DeviceTableOK(vicdt,&low,&high)) {
1459 ff_post_error( _("Bad Device Table Adjustment"),_("A device table adjustment specified for the MATH table is invalid") );
1460 free( accentdevtab );
1461 free( italicdevtab );
1462 free(hicdt); free(vicdt);
1463 return( false );
1464 }
1465 if ( ci->cachedsc==NULL ) {
1466 struct splinecharlist *scl;
1467 ci->cachedsc = chunkalloc(sizeof(SplineChar));
1468 ci->cachedsc->orig_pos = ci->sc->orig_pos;
1469 ci->cachedsc->parent = ci->sc->parent;
1470 ci->cachedsc->user_decomp = u_copy(ci->sc->user_decomp);
1471 scl = chunkalloc(sizeof(struct splinecharlist));
1472 scl->sc = ci->cachedsc;
1473 scl->next = ci->changes;
1474 ci->changes = scl;
1475 }
1476 /* CI_ProcessPosSubs is the first thing which might change anything real */
1477 if ( !CI_ProcessPosSubs(ci)) {
1478 free( accentdevtab );
1479 free( italicdevtab );
1480 free(hicdt); free(vicdt);
1481 return( false );
1482 }
1483 name = u2utf8_copy( nm );
1484 comment = GGadgetGetTitle8(GWidgetGetControl(ci->gw,CID_Comment));
1485 if ( comment!=NULL && *comment=='\0' ) {
1486 free(comment);
1487 comment=NULL;
1488 }
1489 ret = CI_CheckMetaData(ci,oldsc,name,val,comment);
1490 free(name); free(comment);
1491 if ( !ret ) {
1492 free( accentdevtab );
1493 free( italicdevtab );
1494 free(hicdt); free(vicdt);
1495 return( false );
1496 }
1497 ci->cachedsc->unlink_rm_ovrlp_save_undo = GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_UnlinkRmOverlap));
1498 ci->cachedsc->glyph_class = GGadgetGetFirstListSelectedItem(GWidgetGetControl(ci->gw,CID_GClass));
1499 val = GGadgetGetFirstListSelectedItem(GWidgetGetControl(ci->gw,CID_Color));
1500 if ( val!=-1 )
1501 ci->cachedsc->color = (intpt) (std_colors[val].userdata);
1502 CI_ParseCounters(ci);
1503 ci->cachedsc->tex_height = tex_height;
1504 ci->cachedsc->tex_depth = tex_depth;
1505 ci->cachedsc->italic_correction = italic;
1506 ci->cachedsc->top_accent_horiz = topaccent;
1507 ci->cachedsc->is_extended_shape = GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_IsExtended));
1508 ci->cachedsc->italic_adjusts = DeviceTableParse(ci->cachedsc->italic_adjusts,italicdevtab);
1509 ci->cachedsc->top_accent_adjusts = DeviceTableParse(ci->cachedsc->top_accent_adjusts,accentdevtab);
1510 ci->cachedsc->horiz_variants = CI_ParseVariants(ci->cachedsc->horiz_variants,ci,1,hicdt,hic,false);
1511 ci->cachedsc->vert_variants = CI_ParseVariants(ci->cachedsc->vert_variants ,ci,0,vicdt,vic,false);
1512
1513 free( accentdevtab );
1514 free( italicdevtab );
1515 free(hicdt); free(vicdt);
1516
1517 CI_ParseAltUnis(ci);
1518
1519 if ( ci->lc_seen ) {
1520 PST *pst, *prev=NULL;
1521 int i;
1522 ci->cachedsc->lig_caret_cnt_fixed = lig_caret_cnt_fixed;
1523 for ( pst = ci->cachedsc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next )
1524 prev = pst;
1525 if ( pst==NULL && lc_cnt==0 )
1526 /* Nothing to do */;
1527 else if ( pst!=NULL && lc_cnt==0 ) {
1528 if ( prev==NULL )
1529 ci->cachedsc->possub = pst->next;
1530 else
1531 prev->next = pst->next;
1532 pst->next = NULL;
1533 PSTFree(pst);
1534 } else {
1535 if ( pst==NULL ) {
1536 pst = chunkalloc(sizeof(PST));
1537 pst->type = pst_lcaret;
1538 pst->next = ci->sc->possub;
1539 ci->cachedsc->possub = pst;
1540 }
1541 if ( lc_cnt>pst->u.lcaret.cnt )
1542 pst->u.lcaret.carets = realloc(pst->u.lcaret.carets,lc_cnt*sizeof(int16));
1543 for ( i=pst->u.lcaret.cnt; i<lc_cnt; ++i )
1544 pst->u.lcaret.carets[i] = 0;
1545 pst->u.lcaret.cnt = lc_cnt;
1546 }
1547 }
1548
1549 ci->cachedsc->tile_margin = tile_margin;
1550 ci->cachedsc->tile_bounds = tileb;
1551
1552 return( ret );
1553 }
1554
CI_ApplyAll(CharInfo * ci)1555 static void CI_ApplyAll(CharInfo *ci) {
1556 int refresh_fvdi = false;
1557 struct splinecharlist *scl;
1558 SplineChar *cached, *sc;
1559 SplineFont *sf = ci->sc->parent;
1560 FontView *fvs;
1561
1562 for ( scl = ci->changes; scl!=NULL; scl=scl->next ) {
1563 cached = scl->sc;
1564 sc = sf->glyphs[cached->orig_pos];
1565 SCPreserveState(sc,2);
1566 if ( strcmp(cached->name,sc->name)!=0 || cached->unicodeenc!=sc->unicodeenc )
1567 refresh_fvdi = 1;
1568 if ( sc->name==NULL || strcmp( sc->name,cached->name )!=0 ) {
1569 if ( sc->name!=NULL )
1570 SFGlyphRenameFixup(sf,sc->name,cached->name,false);
1571 free(sc->name); sc->name = copy(cached->name);
1572 sc->namechanged = true;
1573 GlyphHashFree(sf);
1574 }
1575 if ( sc->unicodeenc != cached->unicodeenc ) {
1576 struct splinecharlist *scl;
1577 int layer;
1578 RefChar *ref;
1579 struct altuni *alt;
1580
1581 /* All references need the new unicode value */
1582 for ( scl=sc->dependents; scl!=NULL; scl=scl->next ) {
1583 for ( layer=ly_back; layer<scl->sc->layer_cnt; ++layer )
1584 for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1585 if ( ref->sc==sc )
1586 ref->unicode_enc = cached->unicodeenc;
1587 }
1588 /* If the current unicode enc were in the list of alt unis */
1589 /* the user might have forgotten to remove it. So if s/he did */
1590 /* forget, swap the altuni value with the old value */
1591 for ( alt=cached->altuni; alt!=NULL && (alt->unienc!=cached->unicodeenc || alt->vs!=-1 || alt->fid!=0); alt=alt->next );
1592 if ( alt!=NULL ) /* alt->unienc==new value */
1593 alt->unienc = sc->unicodeenc;
1594 sc->unicodeenc = cached->unicodeenc;
1595 }
1596 free(sc->comment); sc->comment = copy(cached->comment);
1597 sc->unlink_rm_ovrlp_save_undo = cached->unlink_rm_ovrlp_save_undo;
1598 sc->glyph_class = cached->glyph_class;
1599 if ( sc->color != cached->color )
1600 refresh_fvdi = true;
1601 sc->color = cached->color;
1602 free(sc->countermasks);
1603 sc->countermask_cnt = cached->countermask_cnt;
1604 sc->countermasks = cached->countermasks;
1605 cached->countermasks = NULL; cached->countermask_cnt = 0;
1606 sc->tex_height = cached->tex_height;
1607 sc->tex_depth = cached->tex_depth;
1608 sc->italic_correction = cached->italic_correction;
1609 sc->top_accent_horiz = cached->top_accent_horiz;
1610 sc->is_extended_shape = cached->is_extended_shape;
1611 DeviceTableFree(sc->italic_adjusts);
1612 DeviceTableFree(sc->top_accent_adjusts);
1613 sc->italic_adjusts = cached->italic_adjusts;
1614 sc->top_accent_adjusts = cached->top_accent_adjusts;
1615 cached->italic_adjusts = cached->top_accent_adjusts = NULL;
1616 GlyphVariantsFree(sc->horiz_variants);
1617 GlyphVariantsFree(sc->vert_variants);
1618 sc->horiz_variants = cached->horiz_variants;
1619 sc->vert_variants = cached->vert_variants;
1620 cached->horiz_variants = cached->vert_variants = NULL;
1621 AltUniFree(sc->altuni);
1622 sc->altuni = cached->altuni;
1623 cached->altuni = NULL;
1624 sc->lig_caret_cnt_fixed = cached->lig_caret_cnt_fixed;
1625 PSTFree(sc->possub);
1626 sc->possub = cached->possub;
1627 cached->possub = NULL;
1628 KernPairsFree(sc->kerns); KernPairsFree(sc->vkerns);
1629 sc->kerns = cached->kerns; sc->vkerns = cached->vkerns;
1630 cached->kerns = cached->vkerns = NULL;
1631 sc->tile_margin = cached->tile_margin;
1632 sc->tile_bounds = cached->tile_bounds;
1633 if ( !sc->changed ) {
1634 sc->changed = true;
1635 refresh_fvdi = true;
1636 }
1637 SCRefreshTitles(sc);
1638 }
1639 if ( ci->name_change || ci->uni_change ) {
1640 for ( fvs=(FontView *) sf->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
1641 /* Postscript encodings are by name, others are by unicode */
1642 /* Hence slight differences in when we update the encoding */
1643 if ( (ci->name_change && fvs->b.map->enc->psnames!=NULL ) ||
1644 (ci->uni_change && fvs->b.map->enc->psnames==NULL )) {
1645 fvs->b.map->enc = &custom;
1646 FVSetTitle((FontViewBase *) fvs);
1647 refresh_fvdi = true;
1648 }
1649 }
1650 }
1651 if ( refresh_fvdi ) {
1652 for ( fvs=(FontView *) sf->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
1653 GDrawRequestExpose(fvs->gw,NULL,false); /* Redraw info area just in case this char is selected */
1654 GDrawRequestExpose(fvs->v,NULL,false); /* Redraw character area in case this char is on screen */
1655 }
1656 }
1657 if ( ci->changes )
1658 sf->changed = true;
1659 }
1660
CI_Finish(CharInfo * ci)1661 static void CI_Finish(CharInfo *ci) {
1662 struct splinecharlist *scl, *next;
1663
1664 for ( scl=ci->changes; scl!=NULL; scl=next ) {
1665 next = scl->next;
1666 SplineCharFree(scl->sc);
1667 chunkfree(scl,sizeof(*scl));
1668 }
1669 GDrawDestroyWindow(ci->gw);
1670 }
1671
CI_OK(GGadget * g,GEvent * e)1672 static int CI_OK(GGadget *g, GEvent *e) {
1673 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1674 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
1675 if ( _CI_OK(ci) ) {
1676 CI_ApplyAll(ci);
1677 CI_Finish(ci);
1678 }
1679 }
1680 return( true );
1681 }
1682
CI_BoundsToMargin(CharInfo * ci)1683 static void CI_BoundsToMargin(CharInfo *ci) {
1684 int err=false;
1685 real margin = GetCalmReal8(ci->gw,CID_TileMargin,NULL,&err);
1686 DBounds b;
1687 char buffer[40];
1688
1689 if ( err )
1690 return;
1691 SplineCharFindBounds(ci->sc,&b);
1692 sprintf( buffer, "%g", (double)(b.minx-margin) );
1693 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinX),buffer);
1694 sprintf( buffer, "%g", (double)(b.miny-margin) );
1695 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinY),buffer);
1696 sprintf( buffer, "%g", (double)(b.maxx+margin) );
1697 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxX),buffer);
1698 sprintf( buffer, "%g", (double)(b.maxy+margin) );
1699 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxY),buffer);
1700 }
1701
CI_TileMarginChange(GGadget * g,GEvent * e)1702 static int CI_TileMarginChange(GGadget *g, GEvent *e) {
1703 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
1704
1705 if ( e->type==et_controlevent && e->u.control.subtype == et_textfocuschanged &&
1706 e->u.control.u.tf_focus.gained_focus )
1707 GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_IsTileMargin),true);
1708 else if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged )
1709 CI_BoundsToMargin(ci);
1710 return( true );
1711 }
1712
1713 /* Generate default settings for the entries in ligature lookup
1714 * TODO: expand beyond (bmp) */
LigDefaultStr(int uni,char * name,int alt_lig)1715 static char *LigDefaultStr(int uni, char *name, int alt_lig ) {
1716 const unichar_t *alt=NULL, *pt;
1717 char *components = NULL, *tmp;
1718 int len;
1719 unichar_t hack[30], *upt;
1720 char buffer[80];
1721
1722 /* If it's not (bmp) unicode we have no info on it */
1723 /* Unless it looks like one of adobe's special ligature names */
1724 if ( uni==-1 || uni>=0x10000 )
1725 /* Nope */;
1726 else if ( isdecompositionnormative(uni) &&
1727 unicode_alternates[uni>>8]!=NULL &&
1728 (alt = unicode_alternates[uni>>8][uni&0xff])!=NULL ) {
1729 if ( alt[1]=='\0' ||
1730 Ligature_alt_getC(Ligature_find_N(uni))<=1 ||
1731 Fraction_alt_getC(Fraction_find_N(uni))<=1 )
1732 alt = NULL; /* Single replacements aren't ligatures */
1733 else if ( iscombining(alt[1]) && ( alt[2]=='\0' || iscombining(alt[2]))) {
1734 if ( alt_lig != -10 ) /* alt_lig = 10 => mac unicode decomp */
1735 alt = NULL; /* Otherwise, don't treat accented letters as ligatures */
1736 } else if (! is_LIGATURE_or_VULGAR_FRACTION((uint32)(uni)) &&
1737 uni!=0x152 && uni!=0x153 && /* oe ligature should not be standard */
1738 uni!=0x132 && uni!=0x133 && /* nor ij */
1739 (uni<0xfb2a || uni>0xfb4f) && /* Allow hebrew precomposed chars */
1740 uni!=0x215f && /* exclude 1/ */
1741 !((uni>=0x0958 && uni<=0x095f) || uni==0x929 || uni==0x931 || uni==0x934)) {
1742 alt = NULL;
1743 } else if ( (tmp=unicode_name(65))==NULL ) { /* test for 'A' to see if library exists */
1744 if ( (uni>=0xbc && uni<=0xbe ) || /* Latin1 vulgar fractions */
1745 (uni>=0x2150 && uni<=0x215e ) || /* other vulgar fractions */
1746 (uni>=0x2189) || /* other vulgar fraction */
1747 (uni>=0xfb00 && uni<=0xfb06 ) || /* latin ligatures */
1748 (uni>=0xfb13 && uni<=0xfb17 ) || /* armenian ligatures */
1749 uni==0xfb1f || /* hebrew ligature */
1750 (uni>=0xfb2a && uni<=0xfb4f ) || /* hebrew precomposed chars */
1751 (uni>=0xfbea && uni<=0xfd3d ) || /* arabic ligatures */
1752 (uni>=0xfd50 && uni<=0xfdcf ) || /* arabic ligatures */
1753 (uni>=0xfdf0 && uni<=0xfdfb ) || /* arabic ligatures */
1754 (uni>=0xfef5 && uni<=0xfefc )) /* arabic ligatures */
1755 ; /* These are good */
1756 else
1757 alt = NULL;
1758 } else
1759 free(tmp); /* found 'A' means there is a library, now cleanup */
1760 }
1761 if ( alt==NULL ) {
1762 if ( name==NULL || alt_lig )
1763 return( NULL );
1764 else
1765 return( AdobeLigatureFormat(name));
1766 }
1767
1768 if ( uni==0xfb03 && alt_lig==1 )
1769 components = copy("ff i");
1770 else if ( uni==0xfb04 && alt_lig==1 )
1771 components = copy("ff l");
1772 else if ( alt!=NULL ) {
1773 if ( alt[1]==0x2044 && (alt[2]==0 || alt[3]==0) && alt_lig==1 ) {
1774 u_strcpy(hack,alt);
1775 hack[1] = '/';
1776 alt = hack;
1777 } else if ( alt_lig>0 )
1778 return( NULL );
1779
1780 if ( isarabisolated(uni) || isarabinitial(uni) || isarabmedial(uni) || isarabfinal(uni) ) {
1781 /* If it is arabic, then convert from the unformed version to the formed */
1782 if ( u_strlen(alt)<sizeof(hack)/sizeof(hack[0])-1 ) {
1783 u_strcpy(hack,alt);
1784 for ( upt=hack ; *upt ; ++upt ) {
1785 /* Make everything medial */
1786 if ( *upt>=0x600 && *upt<=0x6ff )
1787 *upt = ArabicForms[*upt-0x600].medial;
1788 }
1789 if ( isarabisolated(uni) || isarabfinal(uni) ) {
1790 int len = upt-hack-1;
1791 if ( alt[len]>=0x600 && alt[len]<=0x6ff )
1792 hack[len] = ArabicForms[alt[len]-0x600].final;
1793 }
1794 if ( isarabisolated(uni) || isarabinitial(uni) ) {
1795 if ( alt[0]>=0x600 && alt[0]<=0x6ff )
1796 hack[0] = ArabicForms[alt[0]-0x600].initial;
1797 }
1798 alt = hack;
1799 }
1800 }
1801
1802 components=NULL;
1803 while ( 1 ) {
1804 len = 0;
1805 for ( pt=alt; *pt; ++pt ) {
1806 if ( components==NULL ) {
1807 len += strlen(StdGlyphName(buffer,*pt,ui_none,(NameList *)-1))+1;
1808 } else {
1809 const char *temp = StdGlyphName(buffer,*pt,ui_none,(NameList *)-1);
1810 strcpy(components+len,temp);
1811 len += strlen( temp );
1812 components[len++] = ' ';
1813 }
1814 }
1815 if ( components!=NULL )
1816 break;
1817 components = malloc(len+1);
1818 }
1819 components[len-1] = '\0';
1820 }
1821 return( components );
1822 }
1823
AdobeLigatureFormat(char * name)1824 char *AdobeLigatureFormat(char *name) {
1825 /* There are two formats for ligs: <glyph-name>_<glyph-name>{...} or */
1826 /* uni<code><code>{...} (only works for BMP) */
1827 /* I'm not checking to see if all the components are valid */
1828 char *components, *pt, buffer[12];
1829 const char *next;
1830 int len = strlen(name), uni;
1831
1832 if ( strncmp(name,"uni",3)==0 && (len-3)%4==0 && len>7 ) {
1833 pt = name+3;
1834 components = malloc(1); *components = '\0';
1835 while ( *pt ) {
1836 if ( sscanf(pt,"%4x", (unsigned *) &uni )==0 ) {
1837 free(components); components = NULL;
1838 break;
1839 }
1840 next = StdGlyphName(buffer,uni,ui_none,(NameList *)-1);
1841 components = realloc(components,strlen(components) + strlen(next) + 2);
1842 if ( *components!='\0' )
1843 strcat(components," ");
1844 strcat(components,next);
1845 pt += 4;
1846 }
1847 if ( components!=NULL )
1848 return( components );
1849 }
1850
1851 if ( strchr(name,'_')==NULL )
1852 return( NULL );
1853 pt = components = copy(name);
1854 while ( (pt = strchr(pt,'_'))!=NULL )
1855 *pt = ' ';
1856 return( components );
1857 }
1858
1859 /* TODO: see what can be brought-in from is_Ligature_data.h tables, but this */
1860 /* also appears to run various features beyond ligatures and fractions too. */
LigTagFromUnicode(int uni)1861 uint32 LigTagFromUnicode(int uni) {
1862 int tag = CHR('l','i','g','a'); /* standard */
1863
1864 if ( (uni>=0xbc && uni<=0xbe) || /* latin1 vulgar fractions */
1865 (uni>=0x2150 && uni<=0x215f) ||/* other vulgar fractions */
1866 (uni==0x2189) )
1867 tag = CHR('f','r','a','c'); /* Fraction */
1868 /* hebrew precomposed characters */
1869 else if ( uni>=0xfb2a && uni<=0xfb4e )
1870 tag = CHR('c','c','m','p');
1871 else if ( uni==0xfb4f )
1872 tag = CHR('h','l','i','g');
1873 /* armenian */
1874 else if ( uni>=0xfb13 && uni<=0xfb17 )
1875 tag = CHR('l','i','g','a');
1876 /* devanagari ligatures */
1877 else if ( (uni>=0x0958 && uni<=0x095f) || uni==0x931 || uni==0x934 || uni==0x929 )
1878 tag = CHR('n','u','k','t');
1879 else switch ( uni ) {
1880 case 0xfb05: /* long-s t */
1881 /* This should be 'liga' for long-s+t and 'hlig' for s+t */
1882 tag = CHR('l','i','g','a');
1883 break;
1884 case 0x00c6: case 0x00e6: /* ae, AE */
1885 case 0x0152: case 0x0153: /* oe, OE */
1886 case 0x0132: case 0x0133: /* ij, IJ */
1887 case 0xfb06: /* s t */
1888 tag = CHR('d','l','i','g');
1889 break;
1890 case 0xfefb: case 0xfefc: /* Lam & Alef, required ligs */
1891 tag = CHR('r','l','i','g');
1892 break;
1893 }
1894 return( tag );
1895 }
1896
SuffixCheck(SplineChar * sc,char * suffix)1897 SplineChar *SuffixCheck(SplineChar *sc,char *suffix) {
1898 SplineChar *alt = NULL;
1899 SplineFont *sf = sc->parent;
1900 char namebuf[200];
1901
1902 if ( *suffix=='.' ) ++suffix;
1903 if ( sf->cidmaster!=NULL ) {
1904 sprintf( namebuf, "%.20s.%d.%.80s", sf->cidmaster->ordering, sc->orig_pos, suffix );
1905 alt = SFGetChar(sf,-1,namebuf);
1906 if ( alt==NULL ) {
1907 sprintf( namebuf, "cid-%d.%.80s", sc->orig_pos, suffix );
1908 alt = SFGetChar(sf,-1,namebuf);
1909 }
1910 }
1911 if ( alt==NULL && sc->unicodeenc!=-1 ) {
1912 sprintf( namebuf, "uni%04X.%.80s", sc->unicodeenc, suffix );
1913 alt = SFGetChar(sf,-1,namebuf);
1914 }
1915 if ( alt==NULL ) {
1916 sprintf( namebuf, "glyph%d.%.80s", sc->orig_pos, suffix );
1917 alt = SFGetChar(sf,-1,namebuf);
1918 }
1919 if ( alt==NULL ) {
1920 sprintf( namebuf, "%.80s.%.80s", sc->name, suffix );
1921 alt = SFGetChar(sf,-1,namebuf);
1922 }
1923 return( alt );
1924 }
1925
SuffixCheckCase(SplineChar * sc,char * suffix,int cvt2lc)1926 static SplineChar *SuffixCheckCase(SplineChar *sc,char *suffix, int cvt2lc ) {
1927 SplineChar *alt = NULL;
1928 SplineFont *sf = sc->parent;
1929 char namebuf[100];
1930
1931 if ( *suffix=='.' ) ++suffix;
1932 if ( sf->cidmaster!=NULL )
1933 return( NULL );
1934
1935 /* Small cap characters are sometimes named "a.sc" */
1936 /* and sometimes "A.small" */
1937 /* So if I want a 'smcp' feature I must convert "a" to "A.small" */
1938 /* And if I want a 'c2sc' feature I must convert "A" to "a.sc" */
1939 if ( cvt2lc ) {
1940 if ( alt==NULL && sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
1941 isupper(sc->unicodeenc)) {
1942 sprintf( namebuf, "uni%04X.%s", tolower(sc->unicodeenc), suffix );
1943 alt = SFGetChar(sf,-1,namebuf);
1944 }
1945 if ( alt==NULL && isupper(*sc->name)) {
1946 sprintf( namebuf, "%c%s.%s", tolower(*sc->name), sc->name+1, suffix );
1947 alt = SFGetChar(sf,-1,namebuf);
1948 }
1949 } else {
1950 if ( alt==NULL && sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
1951 islower(sc->unicodeenc)) {
1952 sprintf( namebuf, "uni%04X.%s", toupper(sc->unicodeenc), suffix );
1953 alt = SFGetChar(sf,-1,namebuf);
1954 }
1955 if ( alt==NULL && islower(*sc->name)) {
1956 sprintf( namebuf, "%c%s.%s", toupper(*sc->name), sc->name+1, suffix );
1957 alt = SFGetChar(sf,-1,namebuf);
1958 }
1959 }
1960 return( alt );
1961 }
1962
SCLigCaretCheck(SplineChar * sc,int clean)1963 void SCLigCaretCheck(SplineChar *sc,int clean) {
1964 PST *pst, *carets=NULL, *prev_carets=NULL, *prev;
1965 int lig_comp_max=0, lc, i;
1966 char *pt;
1967 /* Check to see if this is a ligature character, and if so, does it have */
1968 /* a ligature caret structure. If a lig but no lig caret structure then */
1969 /* create a lig caret struct */
1970 /* This is not entirely sufficient. If we have an old type1 font with afm */
1971 /* file then there was no way of saying "ffi = f + f + i" instead you */
1972 /* said "ffi = ff + i" (only two component ligatures allowed). This means*/
1973 /* we'd get the wrong number of lcaret positions */
1974
1975 if ( sc->lig_caret_cnt_fixed )
1976 return;
1977
1978 for ( pst=sc->possub, prev=NULL; pst!=NULL; prev = pst, pst=pst->next ) {
1979 if ( pst->type == pst_lcaret ) {
1980 if ( carets!=NULL )
1981 IError("Too many ligature caret structures" );
1982 else {
1983 carets = pst;
1984 prev_carets = prev;
1985 }
1986 } else if ( pst->type==pst_ligature ) {
1987 for ( lc=0, pt=pst->u.lig.components; *pt; ++pt )
1988 if ( *pt==' ' ) ++lc;
1989 if ( lc>lig_comp_max )
1990 lig_comp_max = lc;
1991 }
1992 }
1993 if ( lig_comp_max == 0 ) {
1994 if ( clean && carets!=NULL ) {
1995 if ( prev_carets==NULL )
1996 sc->possub = carets->next;
1997 else
1998 prev_carets->next = carets->next;
1999 carets->next = NULL;
2000 PSTFree(carets);
2001 }
2002 return;
2003 }
2004 if ( carets==NULL ) {
2005 carets = chunkalloc(sizeof(PST));
2006 carets->type = pst_lcaret;
2007 carets->subtable = NULL; /* Not relevant here */
2008 carets->next = sc->possub;
2009 sc->possub = carets;
2010 }
2011 if ( carets->u.lcaret.cnt>=lig_comp_max ) {
2012 carets->u.lcaret.cnt = lig_comp_max;
2013 return;
2014 }
2015 if ( carets->u.lcaret.carets==NULL )
2016 carets->u.lcaret.carets = (int16 *) calloc(lig_comp_max,sizeof(int16));
2017 else {
2018 carets->u.lcaret.carets = (int16 *) realloc(carets->u.lcaret.carets,lig_comp_max*sizeof(int16));
2019 for ( i=carets->u.lcaret.cnt; i<lig_comp_max; ++i )
2020 carets->u.lcaret.carets[i] = 0;
2021 }
2022 carets->u.lcaret.cnt = lig_comp_max;
2023 }
2024
CI_SName(GGadget * g,GEvent * e)2025 static int CI_SName(GGadget *g, GEvent *e) { /* Set From Name */
2026 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2027 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2028 const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UName));
2029 int i;
2030 char buf[40], *ctemp; unichar_t ubuf[2], *temp;
2031 ctemp = u2utf8_copy(ret);
2032 i = UniFromName(ctemp,ui_none,&custom);
2033 free(ctemp);
2034 if ( i==-1 ) {
2035 /* Adobe says names like uni00410042 represent a ligature (A&B) */
2036 /* (that is "uni" followed by two (or more) 4-digit codes). */
2037 /* But that names outside of BMP should be uXXXX or uXXXXX or uXXXXXX */
2038 if ( ret[0]=='u' && ret[1]!='n' && u_strlen(ret)<=1+6 ) {
2039 unichar_t *end;
2040 i = u_strtol(ret+1,&end,16);
2041 if ( *end )
2042 i = -1;
2043 else /* Make sure it is properly capitalized */
2044 SetNameFromUnicode(ci->gw,CID_UName,i);
2045 }
2046 }
2047
2048 sprintf(buf,"U+%04x", i);
2049 temp = uc_copy(i==-1?"-1":buf);
2050 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UValue),temp);
2051 free(temp);
2052
2053 ubuf[0] = i;
2054 if ( i==-1 || i>0xffff )
2055 ubuf[0] = '\0';
2056 ubuf[1] = '\0';
2057 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
2058 }
2059 return( true );
2060 }
2061
CI_SValue(GGadget * g,GEvent * e)2062 static int CI_SValue(GGadget *g, GEvent *e) { /* Set From Value */
2063 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2064 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2065 unichar_t ubuf[2];
2066 int val;
2067
2068 val = ParseUValue(ci->gw,CID_UValue,false);
2069 if ( val<0 )
2070 return( true );
2071
2072 SetNameFromUnicode(ci->gw,CID_UName,val);
2073
2074 ubuf[0] = val;
2075 if ( val==-1 )
2076 ubuf[0] = '\0';
2077 ubuf[1] = '\0';
2078 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
2079 }
2080 return( true );
2081 }
2082
TIFromName(const char * name)2083 GTextInfo *TIFromName(const char *name) {
2084 GTextInfo *ti = calloc(1,sizeof(GTextInfo));
2085 ti->text = utf82u_copy(name);
2086 ti->fg = COLOR_DEFAULT;
2087 ti->bg = COLOR_DEFAULT;
2088 return( ti );
2089 }
2090
CI_SetNameList(CharInfo * ci,int val)2091 static void CI_SetNameList(CharInfo *ci,int val) {
2092 GGadget *g = GWidgetGetControl(ci->gw,CID_UName);
2093 int cnt;
2094
2095 if ( GGadgetGetUserData(g)==(void *) (intpt) val )
2096 return; /* Didn't change */
2097 {
2098 GTextInfo **list = NULL;
2099 char **names = AllGlyphNames(val,ci->sc->parent->for_new_glyphs,ci->sc);
2100
2101 for ( cnt=0; names[cnt]!=NULL; ++cnt );
2102 list = malloc((cnt+1)*sizeof(GTextInfo*));
2103 for ( cnt=0; names[cnt]!=NULL; ++cnt ) {
2104 list[cnt] = TIFromName(names[cnt]);
2105 free(names[cnt]);
2106 }
2107 free(names);
2108 list[cnt] = TIFromName(NULL);
2109 GGadgetSetList(g,list,true);
2110 }
2111 GGadgetSetUserData(g,(void *) (intpt) val);
2112 }
2113
CI_UValChanged(GGadget * g,GEvent * e)2114 static int CI_UValChanged(GGadget *g, GEvent *e) {
2115 if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2116 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2117 const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UValue));
2118 unichar_t *end;
2119 int val;
2120
2121 if (( *ret=='U' || *ret=='u' ) && ret[1]=='+' )
2122 ret += 2;
2123 val = u_strtol(ret,&end,16);
2124 if ( *end=='\0' )
2125 CI_SetNameList(ci,val);
2126 }
2127 return( true );
2128 }
2129
CI_CharChanged(GGadget * g,GEvent * e)2130 static int CI_CharChanged(GGadget *g, GEvent *e) {
2131 if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2132 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2133 const unichar_t *ret = _GGadgetGetTitle(GWidgetGetControl(ci->gw,CID_UChar));
2134 int val = *ret;
2135 unichar_t *temp, ubuf[2]; char buf[10];
2136
2137 if ( ret[0]=='\0' )
2138 return( true );
2139 else if ( ret[1]!='\0' ) {
2140 ff_post_notice(_("Only a single character allowed"),_("Only a single character allowed"));
2141 ubuf[0] = ret[0];
2142 ubuf[1] = '\0';
2143 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
2144 return( true );
2145 }
2146
2147 SetNameFromUnicode(ci->gw,CID_UName,val);
2148 CI_SetNameList(ci,val);
2149
2150 sprintf(buf,"U+%04x", val);
2151 temp = uc_copy(buf);
2152 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UValue),temp);
2153 free(temp);
2154 }
2155 return( true );
2156 }
2157
CI_CommentChanged(GGadget * g,GEvent * e)2158 static int CI_CommentChanged(GGadget *g, GEvent *e) {
2159 if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2160 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2161 /* Let's give things with comments a white color. This may not be a good idea */
2162 if ( ci->first && ci->sc->color==COLOR_DEFAULT &&
2163 0==GGadgetGetFirstListSelectedItem(GWidgetGetControl(ci->gw,CID_Color)) )
2164 GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_Color),1);
2165 ci->first = false;
2166 }
2167 return( true );
2168 }
2169
2170 struct devtab_dlg {
2171 int done;
2172 GWindow gw;
2173 GGadget *gme;
2174 DeviceTable devtab;
2175 };
2176
2177 static struct col_init devtabci[] = {
2178 { me_int, NULL, NULL, NULL, N_("Pixel Size") },
2179 { me_int, NULL, NULL, NULL, N_("Correction") },
2180 COL_INIT_EMPTY
2181 };
2182
DevTabMatrixInit(struct matrixinit * mi,char * dvstr)2183 static void DevTabMatrixInit(struct matrixinit *mi,char *dvstr) {
2184 struct matrix_data *md;
2185 int k, p, cnt;
2186 DeviceTable devtab;
2187
2188 memset(&devtab,0,sizeof(devtab));
2189 DeviceTableParse(&devtab,dvstr);
2190 cnt = 0;
2191 if ( devtab.corrections!=NULL ) {
2192 for ( k=devtab.first_pixel_size; k<=devtab.last_pixel_size; ++k )
2193 if ( devtab.corrections[k-devtab.first_pixel_size]!=0 )
2194 ++cnt;
2195 }
2196
2197 memset(mi,0,sizeof(*mi));
2198 mi->col_cnt = 2;
2199 mi->col_init = devtabci;
2200
2201 md = NULL;
2202 for ( k=0; k<2; ++k ) {
2203 cnt = 0;
2204 if ( devtab.corrections==NULL )
2205 /* Do Nothing */;
2206 else for ( p=devtab.first_pixel_size; p<=devtab.last_pixel_size; ++p ) {
2207 if ( devtab.corrections[p-devtab.first_pixel_size]!=0 ) {
2208 if ( k ) {
2209 md[2*cnt+0].u.md_ival = p;
2210 md[2*cnt+1].u.md_ival = devtab.corrections[p-devtab.first_pixel_size];
2211 }
2212 ++cnt;
2213 }
2214 }
2215 if ( md==NULL )
2216 md = calloc(2*(cnt+10),sizeof(struct matrix_data));
2217 }
2218 mi->matrix_data = md;
2219 mi->initial_row_cnt = cnt;
2220
2221 mi->initrow = NULL;
2222 mi->finishedit = NULL;
2223 mi->candelete = NULL;
2224 mi->popupmenu = NULL;
2225 mi->handle_key = NULL;
2226 mi->bigedittitle = NULL;
2227
2228 free( devtab.corrections );
2229 }
2230
DevTabDlg_OK(GGadget * g,GEvent * e)2231 static int DevTabDlg_OK(GGadget *g, GEvent *e) {
2232
2233 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2234 struct devtab_dlg *dvd = GDrawGetUserData(GGadgetGetWindow(g));
2235 int rows, i, low, high;
2236 struct matrix_data *corrections = GMatrixEditGet(dvd->gme, &rows);
2237
2238 low = high = -1;
2239 for ( i=0; i<rows; ++i ) {
2240 if ( corrections[2*i+1].u.md_ival<-128 || corrections[2*i+1].u.md_ival>127 ) {
2241 ff_post_error(_("Bad correction"),_("The correction on line %d is too big. It must be between -128 and 127"),
2242 i+1 );
2243 return(true);
2244 } else if ( corrections[2*i+0].u.md_ival<0 || corrections[2*i+0].u.md_ival>32767 ) {
2245 gwwv_post_error(_("Bad pixel size"),_("The pixel size on line %d is out of bounds."),
2246 i+1 );
2247 return(true);
2248 }
2249 if ( corrections[2*i+1].u.md_ival!=0 ) {
2250 if ( low==-1 )
2251 low = high = corrections[2*i+0].u.md_ival;
2252 else if ( corrections[2*i+0].u.md_ival<low )
2253 low = corrections[2*i+0].u.md_ival;
2254 else if ( corrections[2*i+0].u.md_ival>high )
2255 high = corrections[2*i+0].u.md_ival;
2256 }
2257 }
2258 memset(&dvd->devtab,0,sizeof(DeviceTable));
2259 if ( low!=-1 ) {
2260 dvd->devtab.first_pixel_size = low;
2261 dvd->devtab.last_pixel_size = high;
2262 dvd->devtab.corrections = calloc(high-low+1,1);
2263 for ( i=0; i<rows; ++i ) {
2264 if ( corrections[2*i+1].u.md_ival!=0 ) {
2265 dvd->devtab.corrections[ corrections[2*i+0].u.md_ival-low ] =
2266 corrections[2*i+1].u.md_ival;
2267 }
2268 }
2269 }
2270 dvd->done = 2;
2271 }
2272 return( true );
2273 }
2274
DevTabDlg_Cancel(GGadget * g,GEvent * e)2275 static int DevTabDlg_Cancel(GGadget *g, GEvent *e) {
2276
2277 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
2278 struct devtab_dlg *dvd = GDrawGetUserData(GGadgetGetWindow(g));
2279 dvd->done = true;
2280 }
2281 return( true );
2282 }
2283
devtabdlg_e_h(GWindow gw,GEvent * event)2284 static int devtabdlg_e_h(GWindow gw, GEvent *event) {
2285
2286 if ( event->type==et_close ) {
2287 struct devtab_dlg *dvd = GDrawGetUserData(gw);
2288 dvd->done = true;
2289 } else if ( event->type == et_char ) {
2290 return( false );
2291 }
2292
2293 return( true );
2294 }
2295
DevTab_Dlg(GGadget * g,int r,int c)2296 char *DevTab_Dlg(GGadget *g, int r, int c) {
2297 int rows, k, j, cols = GMatrixEditGetColCnt(g);
2298 struct matrix_data *strings = GMatrixEditGet(g, &rows);
2299 char *dvstr = strings[cols*r+c].u.md_str;
2300 struct devtab_dlg dvd;
2301 GRect pos;
2302 GWindow gw;
2303 GWindowAttrs wattrs;
2304 GGadgetCreateData gcd[4], boxes[3];
2305 GGadgetCreateData *varray[6], *harray3[8];
2306 GTextInfo label[4];
2307 struct matrixinit mi;
2308
2309 memset(&dvd,0,sizeof(dvd));
2310
2311 memset(&wattrs,0,sizeof(wattrs));
2312 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
2313 wattrs.event_masks = ~(1<<et_charup);
2314 wattrs.is_dlg = true;
2315 wattrs.restrict_input_to_me = 1;
2316 wattrs.undercursor = 1;
2317 wattrs.cursor = ct_pointer;
2318 wattrs.utf8_window_title = _("Device Table Adjustments");
2319 pos.x = pos.y = 0;
2320 pos.width =GDrawPointsToPixels(NULL,GGadgetScale(268));
2321 pos.height = GDrawPointsToPixels(NULL,375);
2322 dvd.gw = gw = GDrawCreateTopWindow(NULL,&pos,devtabdlg_e_h,&dvd,&wattrs);
2323
2324 DevTabMatrixInit(&mi,dvstr);
2325
2326 memset(&gcd,0,sizeof(gcd));
2327 memset(&boxes,0,sizeof(boxes));
2328 memset(&label,0,sizeof(label));
2329 k=j=0;
2330 gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = gcd[1].gd.pos.y+14;
2331 gcd[k].gd.flags = gg_enabled | gg_visible;
2332 gcd[k].gd.u.matrix = &mi;
2333 gcd[k].gd.popup_msg = _(
2334 "At small pixel sizes (screen font sizes)\n"
2335 "the rounding errors that occur may be\n"
2336 "extremely ugly. A device table allows\n"
2337 "you to specify adjustments to the rounded\n"
2338 "Every pixel size my have its own adjustment.");
2339 gcd[k].creator = GMatrixEditCreate;
2340 varray[j++] = &gcd[k++]; varray[j++] = NULL;
2341
2342 gcd[k].gd.pos.x = 30-3;
2343 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
2344 label[k].text = (unichar_t *) _("_OK");
2345 label[k].text_is_1byte = true;
2346 label[k].text_in_resource = true;
2347 gcd[k].gd.label = &label[k];
2348 gcd[k].gd.handle_controlevent = DevTabDlg_OK;
2349 gcd[k++].creator = GButtonCreate;
2350
2351 gcd[k].gd.pos.x = -30;
2352 gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
2353 label[k].text = (unichar_t *) _("_Cancel");
2354 label[k].text_is_1byte = true;
2355 label[k].text_in_resource = true;
2356 gcd[k].gd.label = &label[k];
2357 gcd[k].gd.handle_controlevent = DevTabDlg_Cancel;
2358 gcd[k].gd.cid = CID_Cancel;
2359 gcd[k++].creator = GButtonCreate;
2360
2361 harray3[0] = harray3[2] = harray3[3] = harray3[4] = harray3[6] = GCD_Glue;
2362 harray3[7] = NULL;
2363 harray3[1] = &gcd[k-2]; harray3[5] = &gcd[k-1];
2364
2365 boxes[0].gd.flags = gg_enabled|gg_visible;
2366 boxes[0].gd.u.boxelements = harray3;
2367 boxes[0].creator = GHBoxCreate;
2368 varray[j++] = &boxes[0]; varray[j++] = NULL; varray[j] = NULL;
2369
2370 boxes[1].gd.pos.x = boxes[1].gd.pos.y = 2;
2371 boxes[1].gd.flags = gg_enabled|gg_visible;
2372 boxes[1].gd.u.boxelements = varray;
2373 boxes[1].creator = GHVGroupCreate;
2374
2375 GGadgetsCreate(gw,boxes+1);
2376
2377 free( mi.matrix_data );
2378
2379 dvd.gme = gcd[0].ret;
2380 GMatrixEditSetNewText(gcd[0].ret,S_("PixelSize|New"));
2381 GHVBoxSetExpandableRow(boxes[1].ret,1);
2382 GHVBoxSetExpandableCol(boxes[0].ret,gb_expandgluesame);
2383
2384 GHVBoxFitWindow(boxes[1].ret);
2385
2386 GDrawSetVisible(gw,true);
2387 while ( !dvd.done )
2388 GDrawProcessOneEvent(NULL);
2389 GDrawDestroyWindow(gw);
2390 if ( dvd.done==2 ) {
2391 char *ret;
2392 DevTabToString(&ret,&dvd.devtab);
2393 free(dvd.devtab.corrections);
2394 return( ret );
2395 } else
2396 return( copy(dvstr));
2397 }
2398
2399 static void finishedit(GGadget *g, int r, int c, int wasnew);
2400 static void kernfinishedit(GGadget *g, int r, int c, int wasnew);
2401 static void kerninit(GGadget *g, int r);
2402 static void enable_enum(GGadget *g, GMenuItem *mi, int r, int c);
2403
2404 static struct col_init simplesubsci[] = {
2405 { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
2406 { me_string, NULL, NULL, NULL, N_("Replacement Glyph Name") },
2407 COL_INIT_EMPTY
2408 };
2409 static struct col_init ligatureci[] = {
2410 { me_enum , NULL, NULL, NULL, N_("Subtable") }, /* There can be multiple ligatures for a glyph */
2411 { me_string, NULL, NULL, NULL, N_("Source Glyph Names") },
2412 COL_INIT_EMPTY
2413 };
2414 static struct col_init altsubsci[] = {
2415 { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
2416 { me_string, NULL, NULL, NULL, N_("Replacement Glyph Names") },
2417 COL_INIT_EMPTY
2418 };
2419 static struct col_init multsubsci[] = {
2420 { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
2421 { me_string, NULL, NULL, NULL, N_("Replacement Glyph Names") },
2422 COL_INIT_EMPTY
2423 };
2424 static struct col_init simpleposci[] = {
2425 { me_enum , NULL, NULL, enable_enum, N_("Subtable") },
2426 { me_int, NULL, NULL, NULL, NU_("∆x") }, /* delta-x */
2427 /* GT: "Adjust" here means Device Table based pixel adjustments, an OpenType */
2428 /* GT: concept which allows small corrections for small pixel sizes where */
2429 /* GT: rounding errors (in kerning for example) may smush too glyphs together */
2430 /* GT: or space them too far apart. Generally not a problem for big pixelsizes*/
2431 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2432 { me_int, NULL, NULL, NULL, NU_("∆y") }, /* delta-y */
2433 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2434 { me_int, NULL, NULL, NULL, NU_("∆x_adv") }, /* delta-x-adv */
2435 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2436 { me_int, NULL, NULL, NULL, NU_("∆y_adv") }, /* delta-y-adv */
2437 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2438 COL_INIT_EMPTY
2439 };
2440 static struct col_init pairposci[] = {
2441 { me_enum , NULL, NULL, NULL, N_("Subtable") }, /* There can be multiple kern-pairs for a glyph */
2442 { me_string , DevTab_Dlg, NULL, NULL, N_("Second Glyph Name") },
2443 { me_int, NULL, NULL, NULL, NU_("∆x #1") }, /* delta-x */
2444 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2445 { me_int, NULL, NULL, NULL, NU_("∆y #1") }, /* delta-y */
2446 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2447 { me_int, NULL, NULL, NULL, NU_("∆x_adv #1") }, /* delta-x-adv */
2448 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2449 { me_int, NULL, NULL, NULL, NU_("∆y_adv #1") }, /* delta-y-adv */
2450 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2451 { me_int, NULL, NULL, NULL, NU_("∆x #2") }, /* delta-x */
2452 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2453 { me_int, NULL, NULL, NULL, NU_("∆y #2") }, /* delta-y */
2454 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2455 { me_int, NULL, NULL, NULL, NU_("∆x_adv #2") }, /* delta-x-adv */
2456 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2457 { me_int, NULL, NULL, NULL, NU_("∆y_adv #2") }, /* delta-y-adv */
2458 { me_funcedit, DevTab_Dlg, NULL, NULL, N_("Adjust") },
2459 COL_INIT_EMPTY
2460 };
2461 static int pst2lookuptype[] = { ot_undef, gpos_single, gpos_pair, gsub_single,
2462 gsub_alternate, gsub_multiple, gsub_ligature, 0 };
2463 struct matrixinit mi[] = {
2464 { sizeof(simpleposci)/sizeof(struct col_init)-1, simpleposci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
2465 { sizeof(pairposci)/sizeof(struct col_init)-1, pairposci, 0, NULL, kerninit, NULL, kernfinishedit, NULL, NULL, NULL },
2466 { sizeof(simplesubsci)/sizeof(struct col_init)-1, simplesubsci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
2467 { sizeof(altsubsci)/sizeof(struct col_init)-1, altsubsci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
2468 { sizeof(multsubsci)/sizeof(struct col_init)-1, multsubsci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
2469 { sizeof(ligatureci)/sizeof(struct col_init)-1, ligatureci, 0, NULL, NULL, NULL, finishedit, NULL, NULL, NULL },
2470 MATRIXINIT_EMPTY
2471 };
2472
enable_enum(GGadget * g,GMenuItem * mi,int r,int c)2473 static void enable_enum(GGadget *g, GMenuItem *mi, int r, int c) {
2474 int i,rows,j;
2475 struct matrix_data *possub;
2476 CharInfo *ci;
2477 int sel,cols;
2478
2479 if ( c!=0 )
2480 return;
2481 ci = GDrawGetUserData(GGadgetGetWindow(g));
2482 sel = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-2;
2483 possub = GMatrixEditGet(g, &rows);
2484 cols = GMatrixEditGetColCnt(g);
2485
2486 ci->old_sub = (void *) possub[r*cols+0].u.md_ival;
2487
2488 for ( i=0; mi[i].ti.text!=NULL || mi[i].ti.line; ++i ) {
2489 if ( mi[i].ti.line ) /* Lines, and the new entry always enabled */
2490 mi[i].ti.disabled = false;
2491 else if ( mi[i].ti.userdata == NULL )
2492 /* One of the lookup (rather than subtable) entries. leave disabled */;
2493 else if ( mi[i].ti.userdata == (void *) possub[r*cols+0].u.md_ival ) {
2494 mi[i].ti.selected = true; /* Current thing, they can keep on using it */
2495 mi[i].ti.disabled = false;
2496 } else {
2497 for ( j=0; j<rows; ++j )
2498 if ( mi[i].ti.userdata == (void *) possub[j*cols+0].u.md_ival ) {
2499 mi[i].ti.selected = false;
2500 mi[i].ti.disabled = true;
2501 break;
2502 }
2503 if ( j==rows ) { /* This subtable hasn't been used yet */
2504 mi[i].ti.disabled = false;
2505 }
2506 }
2507 }
2508 }
2509
SCSubtableDefaultSubsCheck(SplineChar * sc,struct lookup_subtable * sub,struct matrix_data * possub,int col_cnt,int r,int layer)2510 void SCSubtableDefaultSubsCheck(SplineChar *sc, struct lookup_subtable *sub,
2511 struct matrix_data *possub, int col_cnt, int r, int layer) {
2512 FeatureScriptLangList *fl;
2513 int lookup_type = sub->lookup->lookup_type;
2514 SplineChar *alt;
2515 char buffer[8];
2516 int i;
2517 static uint32 form_tags[] = { CHR('i','n','i','t'), CHR('m','e','d','i'), CHR('f','i','n','a'), CHR('i','s','o','l'), 0 };
2518 real loff, roff;
2519
2520 if ( lookup_type == gsub_single && sub->suffix != NULL ) {
2521 alt = SuffixCheck(sc,sub->suffix);
2522 if ( alt!=NULL ) {
2523 possub[r*col_cnt+1].u.md_str = copy( alt->name );
2524 return;
2525 }
2526 }
2527
2528 for ( fl = sub->lookup->features; fl!=NULL; fl=fl->next ) {
2529 if ( lookup_type == gpos_single ) {
2530 /* These too features are designed to crop off the left and right */
2531 /* side bearings respectively */
2532 if ( fl->featuretag == CHR('l','f','b','d') ) {
2533 GuessOpticalOffset(sc,layer,&loff,&roff,0);
2534 /* Adjust horixontal positioning and horizontal advance by */
2535 /* the left side bearing */
2536 possub[r*col_cnt+SIM_DX].u.md_ival = -loff;
2537 possub[r*col_cnt+SIM_DX_ADV].u.md_ival = -loff;
2538 return;
2539 } else if ( fl->featuretag == CHR('r','t','b','d') ) {
2540 GuessOpticalOffset(sc,layer,&loff,&roff,0);
2541 /* Adjust horizontal advance by right side bearing */
2542 possub[r*col_cnt+SIM_DX_ADV].u.md_ival = -roff;
2543 return;
2544 }
2545 } else if ( lookup_type == gsub_single ) {
2546 alt = NULL;
2547 if ( fl->featuretag == CHR('s','m','c','p') ) {
2548 alt = SuffixCheck(sc,"sc");
2549 if ( alt==NULL )
2550 alt = SuffixCheckCase(sc,"small",false);
2551 } else if ( fl->featuretag == CHR('c','2','s','c') ) {
2552 alt = SuffixCheck(sc,"small");
2553 if ( alt==NULL )
2554 alt = SuffixCheckCase(sc,"sc",true);
2555 } else if ( fl->featuretag == CHR('r','t','l','a') ) {
2556 if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && tomirror(sc->unicodeenc)!=0 )
2557 alt = SFGetChar(sc->parent,tomirror(sc->unicodeenc),NULL);
2558 } else if ( sc->unicodeenc==0x3c3 && fl->featuretag==CHR('f','i','n','a') ) {
2559 /* Greek final sigma */
2560 alt = SFGetChar(sc->parent,0x3c2,NULL);
2561 }
2562 if ( alt==NULL ) {
2563 buffer[0] = fl->featuretag>>24;
2564 buffer[1] = fl->featuretag>>16;
2565 buffer[2] = fl->featuretag>>8;
2566 buffer[3] = fl->featuretag&0xff;
2567 buffer[4] = 0;
2568 alt = SuffixCheck(sc,buffer);
2569 }
2570 if ( alt==NULL && sc->unicodeenc>=0x600 && sc->unicodeenc<0x700 ) {
2571 /* Arabic forms */
2572 for ( i=0; form_tags[i]!=0; ++i ) if ( form_tags[i]==fl->featuretag ) {
2573 if ( (&(ArabicForms[sc->unicodeenc-0x600].initial))[i]!=0 &&
2574 (&(ArabicForms[sc->unicodeenc-0x600].initial))[i]!=sc->unicodeenc &&
2575 (alt = SFGetChar(sc->parent,(&(ArabicForms[sc->unicodeenc-0x600].initial))[i],NULL))!=NULL )
2576 break;
2577 }
2578 }
2579 if ( alt!=NULL ) {
2580 possub[r*col_cnt+1].u.md_str = copy( alt->name );
2581 return;
2582 }
2583 } else if ( lookup_type == gsub_ligature ) {
2584 if ( fl->featuretag == LigTagFromUnicode(sc->unicodeenc) ) {
2585 int alt_index;
2586 for ( alt_index = 0; ; ++alt_index ) {
2587 char *components = LigDefaultStr(sc->unicodeenc,sc->name,alt_index);
2588 if ( components==NULL )
2589 break;
2590 for ( i=0; i<r; ++i ) {
2591 if ( possub[i*col_cnt+0].u.md_ival == (intpt) sub &&
2592 strcmp(possub[i*col_cnt+1].u.md_str,components)==0 )
2593 break;
2594 }
2595 if ( i==r ) {
2596 possub[r*col_cnt+1].u.md_str = components;
2597 return;
2598 }
2599 free( components );
2600 }
2601 }
2602 }
2603 }
2604 }
2605
finishedit(GGadget * g,int r,int c,int wasnew)2606 static void finishedit(GGadget *g, int r, int c, int wasnew) {
2607 int rows;
2608 struct matrix_data *possub;
2609 CharInfo *ci;
2610 int sel,cols;
2611 struct lookup_subtable *sub;
2612 struct subtable_data sd;
2613 GTextInfo *ti;
2614
2615 if ( c!=0 )
2616 return;
2617 ci = GDrawGetUserData(GGadgetGetWindow(g));
2618 sel = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-2;
2619 possub = GMatrixEditGet(g, &rows);
2620 cols = GMatrixEditGetColCnt(g);
2621 if ( possub[r*cols+0].u.md_ival!=0 ) {
2622 if ( wasnew )
2623 SCSubtableDefaultSubsCheck(ci->sc,(struct lookup_subtable *) possub[r*cols+0].u.md_ival, possub,
2624 cols, r, ci->def_layer );
2625 return;
2626 }
2627 /* They asked to create a new subtable */
2628
2629 memset(&sd,0,sizeof(sd));
2630 sd.flags = sdf_dontedit;
2631 sub = SFNewLookupSubtableOfType(ci->sc->parent,pst2lookuptype[sel+1],&sd,ci->def_layer);
2632 if ( sub!=NULL ) {
2633 possub[r*cols+0].u.md_ival = (intpt) sub;
2634 ti = SFSubtableListOfType(ci->sc->parent, pst2lookuptype[sel+1], false, false);
2635 GMatrixEditSetColumnChoices(g,0,ti);
2636 GTextInfoListFree(ti);
2637 if ( wasnew && ci->cv!=NULL )
2638 SCSubtableDefaultSubsCheck(ci->sc,sub, possub, cols, r, CVLayer((CharViewBase *) (ci->cv)));
2639 } else if ( ci->old_sub!=NULL ) {
2640 /* Restore old value */
2641 possub[r*cols+0].u.md_ival = (intpt) ci->old_sub;
2642 } else {
2643 GMatrixEditDeleteRow(g,r);
2644 }
2645 ci->old_sub = NULL;
2646 GGadgetRedraw(g);
2647 }
2648
kern_AddKP(void * data,SplineChar * left,SplineChar * right,int off)2649 static void kern_AddKP(void *data,SplineChar *left, SplineChar *right, int off) {
2650 int *kp_offset = data;
2651 *kp_offset = off;
2652 }
2653
kernfinishedit(GGadget * g,int r,int c,int wasnew)2654 static void kernfinishedit(GGadget *g, int r, int c, int wasnew) {
2655 int rows;
2656 struct matrix_data *possub;
2657 CharInfo *ci;
2658 int cols;
2659 struct lookup_subtable *sub;
2660 SplineChar *lefts[2], *rights[2];
2661 int touch, separation, kp_offset=0;
2662 SplineChar *osc;
2663
2664 if ( c==1 ) {
2665 ci = GDrawGetUserData(GGadgetGetWindow(g));
2666 possub = GMatrixEditGet(g, &rows);
2667 cols = GMatrixEditGetColCnt(g);
2668 sub = (struct lookup_subtable *) possub[r*cols+0].u.md_ival;
2669 if ( possub[r*cols+PAIR_DX_ADV1].u.md_ival==0 &&
2670 possub[r*cols+1].u.md_str!=NULL &&
2671 (osc = SFGetChar(ci->sc->parent,-1,possub[r*cols+1].u.md_str))!=NULL ) {
2672 lefts[1] = rights[1] = NULL;
2673 if ( sub->lookup->lookup_flags & pst_r2l ) {
2674 lefts[0] = osc;
2675 rights[0] = ci->sc;
2676 } else {
2677 lefts[0] = ci->sc;
2678 rights[0] = osc;
2679 }
2680 touch = sub->kerning_by_touch;
2681 separation = sub->separation;
2682 if ( separation==0 && !touch )
2683 separation = 15*(osc->parent->ascent+osc->parent->descent)/100;
2684 AutoKern2(osc->parent,ci->def_layer,lefts,rights,sub,
2685 separation,0,touch,0,0, /* Don't bother with minkern or onlyCloser, they asked for this, they get it, whatever it may be */
2686 kern_AddKP,&kp_offset);
2687 possub[r*cols+PAIR_DX_ADV1].u.md_ival=kp_offset;
2688 }
2689 } else
2690 finishedit(g,r,c,wasnew);
2691 }
2692
SubHasScript(uint32 script,struct lookup_subtable * sub)2693 static int SubHasScript(uint32 script,struct lookup_subtable *sub) {
2694 FeatureScriptLangList *f;
2695 struct scriptlanglist *s;
2696
2697 if ( sub==NULL )
2698 return(false);
2699 for ( f = sub->lookup->features; f!=NULL; f=f->next ) {
2700 for ( s=f->scripts; s!=NULL; s=s->next ) {
2701 if ( s->script == script )
2702 return( true );
2703 }
2704 }
2705 return( false );
2706 }
2707
kerninit(GGadget * g,int r)2708 static void kerninit(GGadget *g, int r) {
2709 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2710 GMenuItem *mi = GMatrixEditGetColumnChoices(g,0);
2711 int i,cols,rows;
2712 struct matrix_data *possub;
2713 uint32 script;
2714
2715 possub = GMatrixEditGet(g, &rows);
2716 cols = GMatrixEditGetColCnt(g);
2717
2718 if ( r!=0 )
2719 possub[r*cols+0].u.md_ival = possub[(r-1)*cols+0].u.md_ival;
2720 else {
2721 script = SCScriptFromUnicode(ci->sc);
2722 for ( i=0; mi[i].ti.line || mi[i].ti.text!=NULL; ++i ) {
2723 if ( SubHasScript(script,(struct lookup_subtable *) mi[i].ti.userdata ) )
2724 break;
2725 }
2726 if ( mi[i].ti.line || mi[i].ti.text!=NULL )
2727 possub[r*cols+0].u.md_ival = (intpt) mi[i].ti.userdata;
2728 }
2729 }
2730
CI_DoHideUnusedSingle(CharInfo * ci)2731 static void CI_DoHideUnusedSingle(CharInfo *ci) {
2732 GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100);
2733 int rows, cols = GMatrixEditGetColCnt(pstk);
2734 struct matrix_data *old = GMatrixEditGet(pstk,&rows);
2735 uint8 cols_used[20];
2736 int r, col, tot;
2737
2738 if ( lookup_hideunused ) {
2739 memset(cols_used,0,sizeof(cols_used));
2740 for ( r=0; r<rows; ++r ) {
2741 for ( col=1; col<cols; col+=2 ) {
2742 if ( old[cols*r+col].u.md_ival!=0 )
2743 cols_used[col] = true;
2744 if ( old[cols*r+col+1].u.md_str!=NULL && *old[cols*r+col+1].u.md_str!='\0' )
2745 cols_used[col+1] = true;
2746 }
2747 }
2748 for ( col=1, tot=0; col<cols; ++col )
2749 tot += cols_used[col];
2750 /* If no columns used (no info yet, all info is to preempt a kernclass and sets to 0) */
2751 /* then show what we expect to be the default column for this kerning mode*/
2752 if ( tot==0 ) {
2753 if ( strstr(ci->sc->name,".vert")!=NULL || strstr(ci->sc->name,".vrt2")!=NULL )
2754 cols_used[SIM_DY] = true;
2755 else
2756 cols_used[SIM_DX] = true;
2757 }
2758 for ( col=1; col<cols; ++col )
2759 GMatrixEditShowColumn(pstk,col,cols_used[col]);
2760 } else {
2761 for ( col=1; col<cols; ++col )
2762 GMatrixEditShowColumn(pstk,col,true);
2763 }
2764 GWidgetToDesiredSize(ci->gw);
2765
2766 GGadgetRedraw(pstk);
2767 }
2768
CI_DoHideUnusedPair(CharInfo * ci)2769 static void CI_DoHideUnusedPair(CharInfo *ci) {
2770 GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100);
2771 int rows, cols = GMatrixEditGetColCnt(pstk);
2772 struct matrix_data *old = GMatrixEditGet(pstk,&rows);
2773 uint8 cols_used[20];
2774 int r, col, tot;
2775
2776 if ( lookup_hideunused ) {
2777 memset(cols_used,0,sizeof(cols_used));
2778 for ( r=0; r<rows; ++r ) {
2779 for ( col=2; col<cols; col+=2 ) {
2780 if ( old[cols*r+col].u.md_ival!=0 )
2781 cols_used[col] = true;
2782 if ( old[cols*r+col+1].u.md_str!=NULL && *old[cols*r+col+1].u.md_str!='\0' )
2783 cols_used[col+1] = true;
2784 }
2785 }
2786 for ( col=2, tot=0; col<cols; ++col )
2787 tot += cols_used[col];
2788 /* If no columns used (no info yet, all info is to preempt a kernclass and sets to 0) */
2789 /* then show what we expect to be the default column for this kerning mode*/
2790 if ( tot==0 ) {
2791 if ( strstr(ci->sc->name,".vert")!=NULL || strstr(ci->sc->name,".vrt2")!=NULL )
2792 cols_used[PAIR_DY_ADV1] = true;
2793 else if ( SCRightToLeft(ci->sc))
2794 cols_used[PAIR_DX_ADV2] = true;
2795 else
2796 cols_used[PAIR_DX_ADV1] = true;
2797 }
2798 for ( col=2; col<cols; ++col )
2799 GMatrixEditShowColumn(pstk,col,cols_used[col]);
2800 } else {
2801 for ( col=2; col<cols; ++col )
2802 GMatrixEditShowColumn(pstk,col,true);
2803 }
2804 GWidgetToDesiredSize(ci->gw);
2805
2806 GGadgetRedraw(pstk);
2807 }
2808
CI_HideUnusedPair(GGadget * g,GEvent * e)2809 static int CI_HideUnusedPair(GGadget *g, GEvent *e) {
2810 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2811 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2812 lookup_hideunused = GGadgetIsChecked(g);
2813 CI_DoHideUnusedPair(ci);
2814 GGadgetRedraw(GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100));
2815 }
2816 return( true );
2817 }
2818
CI_HideUnusedSingle(GGadget * g,GEvent * e)2819 static int CI_HideUnusedSingle(GGadget *g, GEvent *e) {
2820 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
2821 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
2822 lookup_hideunused = GGadgetIsChecked(g);
2823 CI_DoHideUnusedSingle(ci);
2824 GGadgetRedraw(GWidgetGetControl(ci->gw,CID_List+(pst_position-1)*100));
2825 }
2826 return( true );
2827 }
2828
CI_FreeKernedImage(const void * _ci,GImage * img)2829 static void CI_FreeKernedImage(const void *_ci, GImage *img) {
2830 GImageDestroy(img);
2831 }
2832
2833 static const int kern_popup_size = 100;
2834
Rasterize(SplineChar * sc,int def_layer)2835 static BDFChar *Rasterize(SplineChar *sc,int def_layer) {
2836 void *freetypecontext=NULL;
2837 BDFChar *ret;
2838
2839 freetypecontext = FreeTypeFontContext(sc->parent,sc,sc->parent->fv,def_layer);
2840 if ( freetypecontext!=NULL ) {
2841 ret = SplineCharFreeTypeRasterize(freetypecontext,sc->orig_pos,kern_popup_size,72,8);
2842 FreeTypeFreeContext(freetypecontext);
2843 } else
2844 ret = SplineCharAntiAlias(sc,def_layer,kern_popup_size,4);
2845 return( ret );
2846 }
2847
CI_GetKernedImage(const void * _ci)2848 static GImage *CI_GetKernedImage(const void *_ci) {
2849 CharInfo *ci = (CharInfo *) _ci;
2850 GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+(pst_pair-1)*100);
2851 int rows, cols = GMatrixEditGetColCnt(pstk);
2852 struct matrix_data *old = GMatrixEditGet(pstk,&rows);
2853 SplineChar *othersc = SFGetChar(ci->sc->parent,-1, old[cols*ci->r+1].u.md_str);
2854 BDFChar *me, *other;
2855 double scale = kern_popup_size/(double) (ci->sc->parent->ascent+ci->sc->parent->descent);
2856 int kern;
2857 int width, height, miny, maxy, minx, maxx;
2858 GImage *img;
2859 struct _GImage *base;
2860 Color fg, bg;
2861 int l,clut_scale;
2862 int x,y, xoffset, yoffset, coff1, coff2;
2863 struct lookup_subtable *sub = (struct lookup_subtable *) (old[cols*ci->r+0].u.md_ival);
2864
2865 if ( othersc==NULL )
2866 return( NULL );
2867 me = Rasterize(ci->sc,ci->def_layer);
2868 other = Rasterize(othersc,ci->def_layer);
2869 if ( sub->vertical_kerning ) {
2870 int vwidth = rint(ci->sc->vwidth*scale);
2871 kern = rint( old[cols*ci->r+PAIR_DY_ADV1].u.md_ival*scale );
2872 miny = me->ymin + rint(old[cols*ci->r+PAIR_DY1].u.md_ival*scale);
2873 maxy = me->ymax + rint(old[cols*ci->r+PAIR_DY1].u.md_ival*scale);
2874 if ( miny > vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymin )
2875 miny = vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymin;
2876 if ( maxy < vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymax )
2877 maxy = vwidth + kern + rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale) + other->ymax;
2878 height = maxy - miny + 2;
2879 minx = me->xmin + rint(old[cols*ci->r+PAIR_DX1].u.md_ival*scale); maxx = me->xmax + rint(old[cols*ci->r+PAIR_DX1].u.md_ival*scale);
2880 if ( minx>other->xmin + rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ) minx = other->xmin+ rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ;
2881 if ( maxx<other->xmax + rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ) maxx = other->xmax+ rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale) ;
2882
2883 img = GImageCreate(it_index,maxx-minx+2,height);
2884 base = img->u.image;
2885 memset(base->data,'\0',base->bytes_per_line*base->height);
2886
2887 yoffset = 1 + maxy - vwidth - kern - rint(old[cols*ci->r+PAIR_DY1].u.md_ival*scale);
2888 xoffset = 1 - minx + rint(old[cols*ci->r+PAIR_DX1].u.md_ival*scale);
2889 for ( y=me->ymin; y<=me->ymax; ++y ) {
2890 for ( x=me->xmin; x<=me->xmax; ++x ) {
2891 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] =
2892 me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
2893 }
2894 }
2895 yoffset = 1 + maxy - rint(old[cols*ci->r+PAIR_DY2].u.md_ival*scale);
2896 xoffset = 1 - minx + rint(old[cols*ci->r+PAIR_DX2].u.md_ival*scale);
2897 for ( y=other->ymin; y<=other->ymax; ++y ) {
2898 for ( x=other->xmin; x<=other->xmax; ++x ) {
2899 int n = other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)];
2900 if ( n>base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] )
2901 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] = n;
2902 }
2903 }
2904 } else {
2905 coff1 = coff2 = 0;
2906 if ( sub->lookup->lookup_flags & pst_r2l ) {
2907 BDFChar *temp = me;
2908 me = other;
2909 other = temp;
2910 coff1 = 8; coff2 = -8;
2911 }
2912 kern = rint( old[cols*ci->r+PAIR_DX_ADV1+coff1].u.md_ival*scale );
2913 minx = me->xmin + rint(old[cols*ci->r+PAIR_DX1+coff1].u.md_ival*scale);
2914 maxx = me->xmax + rint(old[cols*ci->r+PAIR_DX1+coff1].u.md_ival*scale);
2915 if ( minx > me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmin )
2916 minx = me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmin;
2917 if ( maxx < me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmax )
2918 maxx = me->width + kern + rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale) + other->xmax;
2919 width = maxx - minx + 2;
2920 miny = me->ymin + rint(old[cols*ci->r+PAIR_DY1+coff1].u.md_ival*scale); maxy = me->ymax + rint(old[cols*ci->r+PAIR_DY1+coff1].u.md_ival*scale);
2921 if ( miny>other->ymin + rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ) miny = other->ymin+ rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ;
2922 if ( maxy<other->ymax + rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ) maxy = other->ymax+ rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale) ;
2923
2924 img = GImageCreate(it_index,width,maxy-miny+2);
2925 base = img->u.image;
2926 memset(base->data,'\0',base->bytes_per_line*base->height);
2927
2928 xoffset = rint(old[cols*ci->r+PAIR_DX1+coff1].u.md_ival*scale) + 1 - minx;
2929 yoffset = 1 + maxy - rint(old[cols*ci->r+PAIR_DY1+coff1].u.md_ival*scale);
2930 for ( y=me->ymin; y<=me->ymax; ++y ) {
2931 for ( x=me->xmin; x<=me->xmax; ++x ) {
2932 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] =
2933 me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
2934 }
2935 }
2936 xoffset = 1 - minx + me->width + kern - rint(old[cols*ci->r+PAIR_DX2+coff2].u.md_ival*scale);
2937 yoffset = 1 + maxy - rint(old[cols*ci->r+PAIR_DY2+coff2].u.md_ival*scale);
2938 for ( y=other->ymin; y<=other->ymax; ++y ) {
2939 for ( x=other->xmin; x<=other->xmax; ++x ) {
2940 int n = other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)];
2941 if ( n>base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] )
2942 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] = n;
2943 }
2944 }
2945 }
2946 memset(base->clut,'\0',sizeof(*base->clut));
2947 bg = GDrawGetDefaultBackground(NULL);
2948 fg = GDrawGetDefaultForeground(NULL);
2949 clut_scale = me->depth == 8 ? 8 : 4;
2950 base->clut->clut_len = 1<<clut_scale;
2951 for ( l=0; l<(1<<clut_scale); ++l )
2952 base->clut->clut[l] =
2953 COLOR_CREATE(
2954 COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
2955 COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
2956 COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
2957 BDFCharFree(me);
2958 BDFCharFree(other);
2959 return( img );
2960 }
2961
2962 /* Draws an image of a glyph with a vertical bar down the middle. */
2963 /* used to show italic correction position (we also dot in the width line) */
2964 /* and top accent horizontal position for the MATH table */
SC_GetLinedImage(SplineChar * sc,int def_layer,int pos,int is_italic_cor)2965 GImage *SC_GetLinedImage(SplineChar *sc, int def_layer, int pos, int is_italic_cor) {
2966 BDFChar *me;
2967 double scale = kern_popup_size/(double) (sc->parent->ascent+sc->parent->descent);
2968 int miny, maxy, minx, maxx;
2969 GImage *img;
2970 struct _GImage *base;
2971 Color fg, bg;
2972 int l,clut_scale;
2973 int x,y, xoffset, yoffset;
2974 int pixel;
2975
2976 if ( is_italic_cor )
2977 pos += sc->width;
2978 pos = rint( pos*scale );
2979 if ( pos<-100 || pos>100 )
2980 return( NULL );
2981 me = Rasterize(sc,def_layer);
2982 if ( pos<me->xmin-10 || pos>me->xmax+30 ) {
2983 BDFCharFree(me);
2984 return( NULL );
2985 }
2986 if ( (minx=me->xmin)>0 ) minx = 0;
2987 if ( (maxx=me->xmax)<me->width ) maxx = me->width;
2988 if ( pos<minx ) minx = pos-2;
2989 if ( pos>maxx ) maxx = pos+2;
2990 miny = me->ymin - 4;
2991 maxy = me->ymax + 4;
2992
2993 pixel = me->depth == 8 ? 0xff : 0xf;
2994
2995 img = GImageCreate(it_index,maxx-minx+2,maxy-miny+2);
2996 base = img->u.image;
2997 memset(base->data,'\0',base->bytes_per_line*base->height);
2998
2999 xoffset = 1 - minx;
3000 yoffset = 1 + maxy;
3001 for ( y=me->ymin; y<=me->ymax; ++y ) {
3002 for ( x=me->xmin; x<=me->xmax; ++x ) {
3003 base->data[(yoffset-y)*base->bytes_per_line + (x+xoffset)] =
3004 me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
3005 }
3006 }
3007 for ( y=miny; y<=maxy; ++y ) {
3008 base->data[(yoffset-y)*base->bytes_per_line + (pos+xoffset)] = pixel;
3009 if ( is_italic_cor && (y&1 ))
3010 base->data[(yoffset-y)*base->bytes_per_line + (me->width+xoffset)] = pixel;
3011 }
3012
3013 memset(base->clut,'\0',sizeof(*base->clut));
3014 bg = GDrawGetDefaultBackground(NULL);
3015 fg = GDrawGetDefaultForeground(NULL);
3016 clut_scale = me->depth == 8 ? 8 : 4;
3017 base->clut->clut_len = 1<<clut_scale;
3018 for ( l=0; l<(1<<clut_scale); ++l )
3019 base->clut->clut[l] =
3020 COLOR_CREATE(
3021 COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
3022 COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
3023 COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
3024 BDFCharFree(me);
3025 return( img );
3026 }
3027
3028 // This defines the width of the arrow that gets drawn
3029 #define ICON_WIDTH 15
3030
GV_GetConstructedImage(SplineChar * sc,int def_layer,struct glyphvariants * gv,int is_horiz)3031 GImage *GV_GetConstructedImage(SplineChar *sc,int def_layer,struct glyphvariants *gv, int is_horiz) {
3032 SplineFont *sf = sc->parent;
3033 BDFChar *me, **others;
3034 double scale = kern_popup_size/(double) (sf->ascent+sf->descent);
3035 GImage *img;
3036 struct _GImage *base;
3037 Color fg, bg;
3038 int l,clut_scale;
3039 int x,y;
3040 int i,j;
3041
3042 if ( gv==NULL || gv->part_cnt==0 )
3043 return( NULL );
3044 me = Rasterize(sc,def_layer);
3045 others = malloc(gv->part_cnt*sizeof(BDFChar *));
3046 for ( i=0; i<gv->part_cnt; ++i ) {
3047 SplineChar *othersc = SFGetChar(sf,-1,gv->parts[i].component);
3048 if ( othersc==NULL ) {
3049 for ( j=0; j<i; ++j )
3050 BDFCharFree(others[j]);
3051 free(others);
3052 return( NULL );
3053 }
3054 others[i] = Rasterize(othersc,def_layer);
3055 }
3056 if ( is_horiz ) {
3057 int ymin, ymax;
3058 int width, xoff;
3059
3060 for ( i=1; i<gv->part_cnt; ++i ) { /* Normalize all but first. Makes construction easier */
3061 others[i]->xmax -= others[i]->xmin;
3062 others[i]->xmin = 0;
3063 }
3064 xoff = me->xmin<0 ? -me->xmin : 0;
3065 width = xoff + me->width + ICON_WIDTH;
3066 ymin = me->ymin; ymax = me->ymax;
3067 for ( i=0; i<gv->part_cnt; ++i ) {
3068 int overlap;
3069 if ( i==gv->part_cnt-1 )
3070 overlap=0;
3071 else {
3072 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
3073 gv->parts[i+1].startConnectorLength :
3074 gv->parts[i].endConnectorLength;
3075 overlap = rint( scale*overlap );
3076 }
3077 width += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->xmin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
3078 if ( others[i]->ymin<ymin ) ymin = others[i]->ymin;
3079 if ( others[i]->ymax>ymax ) ymax = others[i]->ymax;
3080 }
3081 if ( ymax<=ICON_WIDTH ) ymax = ICON_WIDTH;
3082 if ( ymin>0 ) ymin = 0;
3083 img = GImageCreate(it_index,width+10,ymax-ymin+2);
3084 base = img->u.image;
3085 memset(base->data,'\0',base->bytes_per_line*base->height);
3086
3087 ++xoff; /* One pixel margin */
3088
3089 for ( y=me->ymin; y<=me->ymax; ++y ) {
3090 for ( x=me->xmin; x<=me->xmax; ++x ) {
3091 base->data[(1+ymax-y)*base->bytes_per_line + (x+xoff)] =
3092 me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
3093 }
3094 }
3095 xoff += me->width;
3096 {
3097 int pixel = me->depth == 8 ? 0xff : 0xf;
3098 for ( j = -1; j<2; j+=2 ) {
3099 if ( me->ymax<-me->ymin )
3100 y = (me->ymax+me->ymin)/2;
3101 else
3102 y = 1+me->ymax/2;
3103 y = ymax-y + j*2;
3104 for ( x=1; x<ICON_WIDTH-5; ++x )
3105 base->data[y*base->bytes_per_line + (x+xoff)] = pixel;
3106 for ( x=ICON_WIDTH-8; x<ICON_WIDTH-1; ++x )
3107 base->data[(y+j*(ICON_WIDTH-4-x))*base->bytes_per_line + (x+xoff)] = pixel;
3108 }
3109 xoff += ICON_WIDTH;
3110 }
3111 for ( i=0; i<gv->part_cnt; ++i ) {
3112 int overlap;
3113 if ( i==gv->part_cnt-1 )
3114 overlap=0;
3115 else {
3116 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
3117 gv->parts[i+1].startConnectorLength :
3118 gv->parts[i].endConnectorLength;
3119 overlap = rint( scale*overlap );
3120 }
3121 for ( y=others[i]->ymin; y<=others[i]->ymax; ++y ) {
3122 for ( x=others[i]->xmin; x<=others[i]->xmax; ++x ) {
3123 int n = others[i]->bitmap[(others[i]->ymax-y)*others[i]->bytes_per_line + (x-others[i]->xmin)];
3124 if ( n>base->data[(ymax-y)*base->bytes_per_line + (x+xoff)] )
3125 base->data[(ymax-y)*base->bytes_per_line + (x+xoff)] = n;
3126 }
3127 }
3128 xoff += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->xmin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
3129 }
3130 } else {
3131 int xmin, xmax, ymin, ymax;
3132 int yoff, xoff, width;
3133
3134 for ( i=1; i<gv->part_cnt; ++i ) { /* Normalize all but first. Makes construction easier */
3135 others[i]->ymax -= others[i]->ymin;
3136 others[i]->ymin = 0;
3137 }
3138
3139 xoff = me->xmin<0 ? -me->xmin : 0;
3140 width = xoff + me->width + ICON_WIDTH;
3141 ymin = me->ymin; ymax = me->ymax;
3142 xmin = xmax = 0;
3143 yoff = 0;
3144 for ( i=0; i<gv->part_cnt; ++i ) {
3145 int overlap;
3146 if ( i==gv->part_cnt-1 )
3147 overlap=0;
3148 else {
3149 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
3150 gv->parts[i+1].startConnectorLength :
3151 gv->parts[i].endConnectorLength;
3152 overlap = rint( scale*overlap );
3153 }
3154 if ( ymin>others[i]->ymin+yoff ) ymin = others[i]->ymin+yoff;
3155 if ( ymax<others[i]->ymax+yoff ) ymax = others[i]->ymax+yoff;
3156 yoff += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->ymin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
3157 if ( others[i]->xmin<xmin ) xmin = others[i]->xmin;
3158 if ( others[i]->xmax>xmax ) xmax = others[i]->xmax;
3159 }
3160 if ( xmin<-width ) {
3161 xoff = -xmin-width;
3162 width = -xmin;
3163 }
3164 if ( xmax>0 )
3165 width += xmax;
3166 if ( ymax<=ICON_WIDTH ) ymax = ICON_WIDTH;
3167 if ( ymin>0 ) ymin = 0;
3168 img = GImageCreate(it_index,width+2,ymax-ymin+2);
3169 base = img->u.image;
3170 memset(base->data,'\0',base->bytes_per_line*base->height);
3171
3172 ++xoff; /* One pixel margin */
3173
3174 for ( y=me->ymin; y<=me->ymax; ++y ) {
3175 for ( x=me->xmin; x<=me->xmax; ++x ) {
3176 base->data[(1+ymax-y)*base->bytes_per_line + (x+xoff)] =
3177 me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
3178 }
3179 }
3180 xoff += me->width;
3181 {
3182 int pixel = me->depth == 8 ? 0xff : 0xf;
3183 for ( j = -1; j<2; j+=2 ) {
3184 if ( me->ymax<-me->ymin )
3185 y = (me->ymax+me->ymin)/2;
3186 else
3187 y = 1+me->ymax/2;
3188 // Figure out the centerpoint of the arrow
3189 y = ymax - y;
3190 if (y > (ymax - ymin - ICON_WIDTH/2)) {
3191 // Too far down; shift up to make it fit
3192 y = ymax - ymin - ICON_WIDTH/2;
3193 }
3194 y += j*2;
3195 for ( x=1; x<ICON_WIDTH-5; ++x )
3196 base->data[y*base->bytes_per_line + (x+xoff)] = pixel;
3197 for ( x=ICON_WIDTH-8; x<ICON_WIDTH-1; ++x )
3198 base->data[(y+j*(ICON_WIDTH-4-x))*base->bytes_per_line + (x+xoff)] = pixel;
3199 }
3200 xoff += ICON_WIDTH;
3201 }
3202 yoff=0;
3203 for ( i=0; i<gv->part_cnt; ++i ) {
3204 int overlap;
3205 if ( i==gv->part_cnt-1 )
3206 overlap=0;
3207 else {
3208 overlap = gv->parts[i].endConnectorLength>gv->parts[i+1].startConnectorLength ?
3209 gv->parts[i+1].startConnectorLength :
3210 gv->parts[i].endConnectorLength;
3211 overlap = rint( scale*overlap );
3212 }
3213 for ( y=others[i]->ymin; y<=others[i]->ymax; ++y ) {
3214 for ( x=others[i]->xmin; x<=others[i]->xmax; ++x ) {
3215 int n = others[i]->bitmap[(others[i]->ymax-y)*others[i]->bytes_per_line + (x-others[i]->xmin)];
3216 if ( n>base->data[(ymax-y-yoff)*base->bytes_per_line + (x+xoff)] )
3217 base->data[(ymax-y-yoff)*base->bytes_per_line + (x+xoff)] = n;
3218 }
3219 }
3220 yoff += rint(gv->parts[i].fullAdvance*scale) - overlap + others[i]->ymin/* Only does anything if i==0, then it normalizes the rest to the same baseline */;
3221 }
3222 }
3223 for ( i=0; i<gv->part_cnt; ++i )
3224 BDFCharFree(others[i]);
3225 free(others);
3226
3227 memset(base->clut,'\0',sizeof(*base->clut));
3228 bg = GDrawGetDefaultBackground(NULL);
3229 fg = GDrawGetDefaultForeground(NULL);
3230 clut_scale = me->depth == 8 ? 8 : 4;
3231 BDFCharFree(me);
3232 base->clut->clut_len = 1<<clut_scale;
3233 for ( l=0; l<(1<<clut_scale); ++l )
3234 base->clut->clut[l] =
3235 COLOR_CREATE(
3236 COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
3237 COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
3238 COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
3239 return( img );
3240 }
3241
CI_GetConstructedImage(const void * _ci)3242 static GImage *CI_GetConstructedImage(const void *_ci) {
3243 CharInfo *ci = (CharInfo *) _ci;
3244 GImage *ret;
3245 int is_horiz = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-ci->vert_aspect;
3246 struct glyphvariants *gv;
3247
3248 gv = CI_ParseVariants(NULL,ci,is_horiz,NULL,0,true);
3249
3250 ret = GV_GetConstructedImage(ci->sc,ci->def_layer,gv,is_horiz);
3251 GlyphVariantsFree(gv);
3252 return( ret );
3253 }
3254
NameList_GetImage(SplineFont * sf,SplineChar * sc,int def_layer,char * namelist,int isliga)3255 GImage *NameList_GetImage(SplineFont *sf,SplineChar *sc,int def_layer,
3256 char *namelist, int isliga ) {
3257 BDFChar *me, **extras;
3258 int width, xmin, xmax, ymin, ymax;
3259 GImage *img;
3260 struct _GImage *base;
3261 Color fg, bg;
3262 int l,clut_scale;
3263 int x,y;
3264 SplineChar *other;
3265 int extracnt;
3266 int i,j;
3267 char *subs = namelist, *pt, *start;
3268 int ch;
3269
3270 if ( sc==NULL || sf==NULL || namelist==NULL )
3271 return( NULL );
3272 me = Rasterize(sc,def_layer);
3273 ymin = me->ymin; ymax = me->ymax;
3274 xmin = me->xmin; xmax = me->xmax; width = me->width;
3275 extracnt = 0; extras = NULL;
3276
3277 for ( pt=subs; *pt ; ++extracnt ) {
3278 while ( *pt!=' ' && *pt!='\0' ) ++pt;
3279 if ( *pt==' ' )
3280 while ( *pt==' ' ) ++pt;
3281 }
3282 extras = malloc(extracnt*sizeof(BDFChar *));
3283 extracnt = 0;
3284 for ( pt=subs; *pt ; ) {
3285 start = pt;
3286 while ( *pt!=' ' && *pt!='\0' && *pt!='(' ) ++pt;
3287 ch = *pt; *pt = '\0';
3288 other = SFGetChar(sf,-1, start);
3289 *pt = ch;
3290 if ( ch=='(' ) {
3291 while ( *pt!=')' && *pt!='\0' ) ++pt;
3292 if ( *pt==')' ) ++pt;
3293 }
3294 if ( other!=NULL ) {
3295 if ( extracnt==0 ) width += ICON_WIDTH;
3296 extras[extracnt] = Rasterize(other,def_layer);
3297 if ( width+extras[extracnt]->xmin < xmin ) xmin = width+extras[extracnt]->xmin;
3298 if ( width+extras[extracnt]->xmax > xmax ) xmax = width+extras[extracnt]->xmax;
3299 if ( extras[extracnt]->ymin < ymin ) ymin = extras[extracnt]->ymin;
3300 if ( extras[extracnt]->ymax > ymax ) ymax = extras[extracnt]->ymax;
3301 width += extras[extracnt++]->width;
3302 }
3303 if ( *pt==' ' )
3304 while ( *pt==' ' ) ++pt;
3305 }
3306
3307 if ( ymax<=ICON_WIDTH ) ymax = ICON_WIDTH;
3308 if ( ymin>0 ) ymin = 0;
3309 if ( xmax<xmin ) {
3310 for ( i=0; i<extracnt; ++i )
3311 BDFCharFree(extras[i]);
3312 free(extras);
3313 return( NULL );
3314 }
3315
3316 if ( xmin>0 ) xmin = 0;
3317
3318 img = GImageCreate(it_index,xmax - xmin + 2,ymax-ymin+2);
3319 base = img->u.image;
3320 memset(base->data,'\0',base->bytes_per_line*base->height);
3321
3322 width = -xmin;
3323 ++width;
3324
3325 for ( y=me->ymin; y<=me->ymax; ++y ) {
3326 for ( x=me->xmin; x<=me->xmax; ++x ) {
3327 base->data[(1+ymax-y)*base->bytes_per_line + (x+width)] =
3328 me->bitmap[(me->ymax-y)*me->bytes_per_line + (x-me->xmin)];
3329 }
3330 }
3331 width += me->width;
3332 if ( extracnt!=0 ) {
3333 int pixel = me->depth == 8 ? 0xff : 0xf;
3334 if ( !isliga ) {
3335 for ( j = -1; j<2; j+=2 ) {
3336 if ( me->ymax<-me->ymin )
3337 y = (me->ymax+me->ymin)/2;
3338 else
3339 y = 1+me->ymax/2;
3340 // Figure out the centerpoint of the arrow
3341 y = ymax - y;
3342 if (y > (ymax - ymin - ICON_WIDTH/2)) {
3343 // Too far down; shift up to make it fit
3344 y = ymax - ymin - ICON_WIDTH/2;
3345 }
3346 // Draw the == part of the arrow
3347 y += j*2;
3348 for ( x=1; x<ICON_WIDTH-5; ++x )
3349 base->data[y*base->bytes_per_line + (x+width)] = pixel;
3350 // Draw the > part of the arrow
3351 for ( x=ICON_WIDTH-8; x<ICON_WIDTH-1; ++x )
3352 base->data[(y+j*(ICON_WIDTH-4-x))*base->bytes_per_line + (x+width)] = pixel;
3353 }
3354 } else if ( isliga>0 ) {
3355 for ( j = -1; j<2; j+=2 ) {
3356 y = 1+ymax/2 + j*2;
3357 // Draw the == part of the arrow
3358 for ( x=5; x<ICON_WIDTH-1; ++x )
3359 base->data[y*base->bytes_per_line + (x+width)] = pixel;
3360 // Draw the < part of the arrow
3361 for ( x=8; x>1 ; --x )
3362 base->data[(y+j*(x-3))*base->bytes_per_line + (x+width)] = pixel;
3363 }
3364 }
3365 width += ICON_WIDTH;
3366 for ( i=0; i<extracnt; ++i ) {
3367 BDFChar *other = extras[i];
3368 for ( y=other->ymin; y<=other->ymax; ++y ) {
3369 for ( x=other->xmin; x<=other->xmax; ++x ) {
3370 if ( other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)] != 0 )
3371 base->data[(1+ymax-y)*base->bytes_per_line + (x+width)] =
3372 other->bitmap[(other->ymax-y)*other->bytes_per_line + (x-other->xmin)];
3373 }
3374 }
3375 width += other->width;
3376 }
3377 }
3378 memset(base->clut,'\0',sizeof(*base->clut));
3379 bg = GDrawGetDefaultBackground(NULL);
3380 fg = GDrawGetDefaultForeground(NULL);
3381 clut_scale = me->depth == 8 ? 8 : 4;
3382 base->clut->clut_len = 1<<clut_scale;
3383 for ( l=0; l<(1<<clut_scale); ++l )
3384 base->clut->clut[l] =
3385 COLOR_CREATE(
3386 COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<clut_scale)-1),
3387 COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<clut_scale)-1),
3388 COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<clut_scale)-1) );
3389 BDFCharFree(me);
3390 for ( i=0; i<extracnt; ++i )
3391 BDFCharFree(extras[i]);
3392 free(extras);
3393 return( img );
3394 }
3395
PST_GetImage(GGadget * pstk,SplineFont * sf,int def_layer,struct lookup_subtable * sub,int popup_r,SplineChar * sc)3396 GImage *PST_GetImage(GGadget *pstk,SplineFont *sf,int def_layer,
3397 struct lookup_subtable *sub,int popup_r, SplineChar *sc ) {
3398 int rows, cols = GMatrixEditGetColCnt(pstk);
3399 struct matrix_data *old = GMatrixEditGet(pstk,&rows);
3400
3401 if ( sc==NULL || sub==NULL )
3402 return( NULL );
3403 if ( sub->lookup->lookup_type<gsub_single || sub->lookup->lookup_type>gsub_ligature )
3404 return( NULL );
3405
3406 return( NameList_GetImage(sf,sc,def_layer,old[cols*popup_r+1].u.md_str,
3407 sub->lookup->lookup_type==gsub_ligature));
3408 }
3409
_CI_GetImage(const void * _ci)3410 static GImage *_CI_GetImage(const void *_ci) {
3411 CharInfo *ci = (CharInfo *) _ci;
3412 int offset = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-2;
3413 GGadget *pstk = GWidgetGetControl(ci->gw,CID_List+offset*100);
3414 int rows, cols = GMatrixEditGetColCnt(pstk);
3415 struct matrix_data *old = GMatrixEditGet(pstk,&rows);
3416 struct lookup_subtable *sub = (struct lookup_subtable *) (old[cols*ci->r+0].u.md_ival);
3417
3418 if ( ci->r>=rows )
3419 return( NULL );
3420
3421 return( PST_GetImage(pstk,ci->sc->parent,ci->def_layer,sub,ci->r,ci->sc) );
3422 }
3423
CI_KerningPopupPrepare(GGadget * g,int r,int c)3424 static void CI_KerningPopupPrepare(GGadget *g, int r, int c) {
3425 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3426 int rows, cols = GMatrixEditGetColCnt(g);
3427 struct matrix_data *old = GMatrixEditGet(g,&rows);
3428
3429 if ( c<0 || c>=cols || r<0 || r>=rows || old[cols*r+1].u.md_str==NULL ||
3430 SFGetChar(ci->sc->parent,-1, old[cols*r+1].u.md_str)==NULL )
3431 return;
3432 ci->r = r; ci->c = c;
3433 GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,ci,CI_GetKernedImage,CI_FreeKernedImage);
3434 }
3435
CI_SubsPopupPrepare(GGadget * g,int r,int c)3436 static void CI_SubsPopupPrepare(GGadget *g, int r, int c) {
3437 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3438 int rows, cols = GMatrixEditGetColCnt(g);
3439
3440 (void) GMatrixEditGet(g,&rows);
3441 if ( c<0 || c>=cols || r<0 || r>=rows )
3442 return;
3443 ci->r = r; ci->c = c;
3444 GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,ci,_CI_GetImage,CI_FreeKernedImage);
3445 }
3446
CI_ConstructionPopupPrepare(GGadget * g,int r,int c)3447 static void CI_ConstructionPopupPrepare(GGadget *g, int r, int c) {
3448 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3449 int rows/*, cols = GMatrixEditGetColCnt(g)*/;
3450
3451 (void) GMatrixEditGet(g,&rows);
3452 if ( rows==0 )
3453 return;
3454 GGadgetPreparePopupImage(GGadgetGetWindow(g),NULL,ci,CI_GetConstructedImage,CI_FreeKernedImage);
3455 }
3456
CI_GlyphNameCompletion(GGadget * t,int from_tab)3457 static unichar_t **CI_GlyphNameCompletion(GGadget *t,int from_tab) {
3458 CharInfo *ci = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
3459 SplineFont *sf = ci->sc->parent;
3460
3461 return( SFGlyphNameCompletion(sf,t,from_tab,false));
3462 }
3463
CI_GlyphListCompletion(GGadget * t,int from_tab)3464 static unichar_t **CI_GlyphListCompletion(GGadget *t,int from_tab) {
3465 CharInfo *ci = GDrawGetUserData(GDrawGetParentWindow(GGadgetGetWindow(t)));
3466 SplineFont *sf = ci->sc->parent;
3467
3468 return( SFGlyphNameCompletion(sf,t,from_tab,true));
3469 }
3470
3471
extpart_finishedit(GGadget * g,int r,int c,int wasnew)3472 static void extpart_finishedit(GGadget *g, int r, int c, int wasnew) {
3473 int rows;
3474 struct matrix_data *possub;
3475 CharInfo *ci;
3476 int is_horiz,cols;
3477 DBounds b;
3478 double full_advance;
3479 SplineChar *sc;
3480
3481 if ( c!=0 )
3482 return;
3483 if ( !wasnew )
3484 return;
3485 /* If they added a new glyph to the sequence then set some defaults for it. */
3486 /* only the full advance has any likelyhood of being correct */
3487 ci = GDrawGetUserData(GGadgetGetWindow(g));
3488 is_horiz = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs))-ci->vert_aspect;
3489 possub = GMatrixEditGet(g, &rows);
3490 cols = GMatrixEditGetColCnt(g);
3491 if ( possub[r*cols+0].u.md_str==NULL )
3492 return;
3493 sc = SFGetChar(ci->sc->parent,-1,possub[r*cols+0].u.md_str);
3494 if ( sc==NULL )
3495 return;
3496 SplineCharFindBounds(sc,&b);
3497 if ( is_horiz )
3498 full_advance = b.maxx - b.minx;
3499 else
3500 full_advance = b.maxy - b.miny;
3501 possub[r*cols+2].u.md_ival = possub[r*cols+3].u.md_ival = rint(full_advance/3);
3502 possub[r*cols+4].u.md_ival = rint(full_advance);
3503 GGadgetRedraw(g);
3504 }
3505
3506 static GTextInfo truefalse[] = {
3507 { (unichar_t *) N_("false"), NULL, 0, 0, (void *) 0, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
3508 { (unichar_t *) N_("true"), NULL, 0, 0, (void *) 1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
3509 GTEXTINFO_EMPTY
3510 };
3511
3512 static struct col_init extensionpart[] = {
3513 { me_string , NULL, NULL, NULL, N_("Glyph") },
3514 { me_enum, NULL, truefalse, NULL, N_("Extender") },
3515 /* GT: "Len" is an abreviation for "Length" */
3516 { me_int, NULL, NULL, NULL, N_("StartLen") },
3517 { me_int, NULL, NULL, NULL, N_("EndLen") },
3518 { me_int, NULL, NULL, NULL, N_("FullLen") },
3519 COL_INIT_EMPTY
3520 };
3521 static struct matrixinit mi_extensionpart =
3522 { sizeof(extensionpart)/sizeof(struct col_init)-1, extensionpart, 0, NULL, NULL, NULL, extpart_finishedit, NULL, NULL, NULL };
3523
isxheight(int uni)3524 static int isxheight(int uni) {
3525 if ( uni>=0x10000 || !islower(uni))
3526 return( false );
3527
3528 if ( uni=='a' || uni=='c' || uni=='e' || uni=='i' || uni=='j' ||
3529 (uni>='m' && uni<='z') ||
3530 uni==0x131 || uni==0x237 || /* Ignore accented letters except the dotlessi/j */
3531 (uni>=0x250 && uni<0x253) || uni==0x254 || uni==0x255 ||
3532 (uni>=0x258 && uni<0x265) || uni==0x269 || uni==0x26A ||
3533 (uni>=0x26f && uni<=0x277) || uni==0x279 ||
3534 uni==0x3b1 || uni==0x3b3 || uni==0x3b5 || uni==0x3b7 ||
3535 uni==0x3b9 || uni==0x3ba || uni==0x3bc || uni==0x3bd ||
3536 (uni>=0x3bf && uni<=0x3c7) || uni==0x3c9 ||
3537 (uni>=0x400 && uni<=0x45f))
3538 return( true );
3539
3540 return( false );
3541 }
3542
isbaseline(int uni)3543 static int isbaseline(int uni) {
3544 /* Treat rounded letters as being on the base line */
3545 /* But don't bother including guys that normally are on the baseline */
3546
3547 if ( (uni>='a' && uni<'g') || uni=='h' || uni=='i' ||
3548 (uni>='k' && uni<='o') || (uni>='r' && uni<'y') || uni=='z' ||
3549 (uni>='A' && uni<='Z' ) ||
3550 uni==0x3b0 || uni==0x3b4 || uni==0x3b5 || (uni>=0x3b8 && uni<0x3bb) ||
3551 uni==0x3bd || uni==0x3bf || uni==0x3c0 || (uni>=0x3c2 && uni<0x3c6) ||
3552 uni==0x3c8 || uni==0x3c7 || uni==0x3c9 ||
3553 (uni>=0x391 && uni<0x3aa) ||
3554 (uni>=0x400 && uni<0x40f) || (uni>=0x410 && uni<=0x413) ||
3555 (uni>=0x415 && uni<0x425) || uni==0x427 || uni==0x428 ||
3556 (uni>=0x42a && uni<0x433) || (uni>=0x435 && uni<0x45e) )
3557 return( true );
3558
3559 return( false );
3560 }
3561
TeX_Default(GGadget * g,GEvent * e)3562 static int TeX_Default(GGadget *g, GEvent *e) {
3563 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3564 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3565 int cid = GGadgetGetCid(g), mcid = 0;
3566 DBounds b;
3567 int value;
3568 SplineChar *basesc = NULL;
3569 SplineFont *sf = ci->sc->parent;
3570 int style;
3571 char buf[12];
3572
3573 basesc = ci->sc;
3574 /* Try to align the top of lowercase (xheight) letters all at the */
3575 /* same height. Ditto for uppercase & ascender letters */
3576 if ( cid==CID_TeX_HeightD && ci->sc->unicodeenc<0x10000 &&
3577 isxheight(ci->sc->unicodeenc) &&
3578 (basesc = SFGetChar(sf,'x',NULL))!=NULL )
3579 /* Done */;
3580 else if ( cid==CID_TeX_HeightD && ci->sc->unicodeenc<0x10000 &&
3581 islower(ci->sc->unicodeenc) &&
3582 (basesc = SFGetChar(sf,'l',NULL))!=NULL )
3583 /* Done */;
3584 else if ( cid==CID_TeX_HeightD && ci->sc->unicodeenc<0x10000 &&
3585 isupper(ci->sc->unicodeenc) &&
3586 (basesc = SFGetChar(sf,'I',NULL))!=NULL )
3587 /* Done */;
3588 else if ( cid==CID_TeX_DepthD && ci->sc->unicodeenc<0x10000 &&
3589 isbaseline(ci->sc->unicodeenc) &&
3590 (basesc = SFGetChar(sf,'I',NULL))!=NULL )
3591 /* Done */;
3592 else
3593 basesc = ci->sc;
3594
3595 SplineCharFindBounds(basesc,&b);
3596 style = MacStyleCode(sf,NULL);
3597
3598 if ( cid == CID_TeX_HeightD ) {
3599 mcid = CID_TeX_Height;
3600 if ( basesc!=ci->sc && basesc->tex_height!=TEX_UNDEF )
3601 value = basesc->tex_height;
3602 else
3603 value = rint(b.maxy);
3604 if ( value<0 ) value = 0;
3605 } else if ( cid == CID_TeX_DepthD ) {
3606 mcid = CID_TeX_Depth;
3607 if ( basesc!=ci->sc && basesc->tex_depth!=TEX_UNDEF )
3608 value = basesc->tex_depth;
3609 else {
3610 value = -rint(b.miny);
3611 if ( value<5 ) value = 0;
3612 }
3613 } else if ( cid == CID_HorAccentD ) {
3614 mcid = CID_HorAccent;
3615 double italic_off = (b.maxy-b.miny)*tan(-sf->italicangle);
3616 if ( b.maxx-b.minx-italic_off < 0 )
3617 value = rint(b.minx + (b.maxx-b.minx)/2);
3618 else
3619 value = rint(b.minx + italic_off + (b.maxx - b.minx - italic_off)/2);
3620 } else if ( cid == CID_TeX_ItalicD ) {
3621 mcid = CID_TeX_Italic;
3622 if ( (style&sf_italic) || sf->italicangle!=0 )
3623 value = rint((b.maxx-ci->sc->width) +
3624 (sf->ascent+sf->descent)/16.0);
3625 else
3626 value = 0;
3627 }
3628 if (mcid!=0) {
3629 sprintf( buf, "%d", value );
3630 GGadgetSetTitle8(GWidgetGetControl(ci->gw,mcid),buf);
3631 }
3632 }
3633 return( true );
3634 }
3635
CI_SubSuperPositionings(GGadget * g,GEvent * e)3636 static int CI_SubSuperPositionings(GGadget *g, GEvent *e) {
3637 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3638 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3639 MathKernDialog(ci->sc,ci->def_layer);
3640 }
3641 return( true );
3642 }
3643
3644 static struct col_init altuniinfo[] = {
3645 { me_uhex , NULL, NULL, NULL, N_("Unicode") },
3646 { me_uhex, NULL, truefalse, NULL, N_("Variation Selector (or 0)") },
3647 COL_INIT_EMPTY
3648 };
3649 static struct matrixinit mi_altuniinfo =
3650 { sizeof(altuniinfo)/sizeof(struct col_init)-1, altuniinfo, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3651
CI_NoteAspect(CharInfo * ci)3652 static void CI_NoteAspect(CharInfo *ci) {
3653 int new_aspect = GTabSetGetSel(GWidgetGetControl(ci->gw,CID_Tabs));
3654 PST *pst;
3655 int cnt;
3656 char buf[20];
3657
3658 last_gi_aspect = new_aspect;
3659 if ( new_aspect == ci->lc_aspect && (!ci->lc_seen || GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_DefLCCount)))) {
3660 ci->lc_seen = true;
3661 for ( pst=ci->sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
3662 if ( GGadgetIsChecked(GWidgetGetControl(ci->gw,CID_DefLCCount)) &&
3663 pst==NULL ) {
3664 int rows, cols, i;
3665 struct matrix_data *possub;
3666 /* Normally we look for ligatures in the possub list, but here*/
3667 /* we will examine the ligature pane itself to get the most */
3668 /* up to date info */
3669 possub = GMatrixEditGet(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100), &rows );
3670 cols = GMatrixEditGetColCnt(GWidgetGetControl(ci->gw,CID_List+(pst_ligature-1)*100) );
3671 cnt = 0;
3672 for ( i=0; i<rows; ++i ) {
3673 char *pt = possub[cols*i+1].u.md_str;
3674 int comp = 0;
3675 while ( *pt!='\0' ) {
3676 while ( *pt==' ' ) ++pt;
3677 if ( *pt=='\0' )
3678 break;
3679 while ( *pt!=' ' && *pt!='\0' ) ++pt;
3680 ++comp;
3681 }
3682 if ( comp>cnt ) cnt = comp;
3683 }
3684 --cnt; /* We want one fewer caret than there are components -- carets go BETWEEN components */
3685 } else if ( pst!=NULL )
3686 cnt = pst->u.lcaret.cnt;
3687 else
3688 cnt = 0;
3689 if ( cnt<0 ) cnt = 0;
3690 sprintf( buf, "%d", cnt );
3691 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_LCCount),buf);
3692 }
3693 }
3694
CI_AspectChange(GGadget * g,GEvent * e)3695 static int CI_AspectChange(GGadget *g, GEvent *e) {
3696 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
3697 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3698 CI_NoteAspect(ci);
3699 }
3700 return( true );
3701 }
3702
CI_DefLCChange(GGadget * g,GEvent * e)3703 static int CI_DefLCChange(GGadget *g, GEvent *e) {
3704 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
3705 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3706 int show = !GGadgetIsChecked(g);
3707 GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCount),show);
3708 GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCountLab),show);
3709 }
3710 return( true );
3711 }
3712
3713 // Turn the user's entered decomposition into the format returned by SFGetAlternate
CI_ParseUserDecomposition(char * inp)3714 unichar_t* CI_ParseUserDecomposition(char* inp) {
3715 unsigned long len = strlen(inp);
3716 char* end;
3717 unichar_t* decomp = malloc((len+1)*sizeof(unichar_t));
3718
3719 int j = 0;
3720 for (unsigned long i = strtoul(inp, &end, 16); inp != end; i = strtoul(inp, &end, 16)) {
3721 inp = end;
3722 decomp[j] = i;
3723 j++;
3724 }
3725
3726 decomp[j] = '\0';
3727
3728 return decomp;
3729 }
3730
CI_CreateInterpretedAsLabel(unichar_t * inp)3731 char* CI_CreateInterpretedAsLabel(unichar_t* inp) {
3732 char* lblprefix = _("Interpreted as: ");
3733 char* lblerror = _("Error: wrong format");
3734 char* lblbuf;
3735
3736 // If I don't validate it, the string will become "(null)"
3737 bool valid = true;
3738 unichar_t* inp_ptr = inp;
3739 if (inp != NULL) {
3740 while (*inp_ptr != '\0') {
3741 if (*inp_ptr > 0x10FFFF) valid = false;
3742 inp_ptr++;
3743 }
3744 }
3745
3746 if (inp != NULL && inp[0] != 0 && valid) {
3747 char* inp_l = u2utf8_copy(inp);
3748 lblbuf = malloc(strlen(lblprefix)+strlen(inp_l)+1);
3749 sprintf(lblbuf, "%s%s", lblprefix, inp_l);
3750 free(inp_l);
3751 } else {
3752 lblbuf = copy(lblerror);
3753 }
3754
3755 return lblbuf;
3756 }
3757
CI_CmpUseNonDefault(GGadget * g,GEvent * e)3758 static int CI_CmpUseNonDefault(GGadget *g, GEvent *e) {
3759 int show = !GGadgetIsChecked(g);
3760 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3761 GGadget* cotf = GWidgetGetControl(ci->gw,CID_ComponentTextField);
3762 GGadget* coim = GWidgetGetControl(ci->gw,CID_ComponentInterpMsg);
3763 GGadgetSetEnabled(cotf, show);
3764 if (ci->sc->user_decomp != NULL) free(ci->sc->user_decomp);
3765 if (!show) {
3766 ci->sc->user_decomp = NULL;
3767 GGadgetSetTitle8(coim, "");
3768 } else {
3769 unichar_t* ud = CI_ParseUserDecomposition(GGadgetGetTitle8(cotf));
3770 ci->sc->user_decomp = ud;
3771 char* lbl = CI_CreateInterpretedAsLabel(ci->sc->user_decomp);
3772 GGadgetSetTitle8(coim, lbl);
3773 free(lbl);
3774 }
3775
3776 return true;
3777 }
3778
GV_ToMD(GGadget * g,struct glyphvariants * gv)3779 void GV_ToMD(GGadget *g, struct glyphvariants *gv) {
3780 int cols = GMatrixEditGetColCnt(g), j;
3781 struct matrix_data *mds;
3782 if ( gv==NULL ) {
3783 GMatrixEditSet(g, NULL,0,false);
3784 return;
3785 }
3786 mds = calloc(gv->part_cnt*cols,sizeof(struct matrix_data));
3787 for ( j=0; j<gv->part_cnt; ++j ) {
3788 mds[j*cols+0].u.md_str = copy(gv->parts[j].component);
3789 mds[j*cols+1].u.md_ival = gv->parts[j].is_extender;
3790 mds[j*cols+2].u.md_ival = gv->parts[j].startConnectorLength;
3791 mds[j*cols+3].u.md_ival = gv->parts[j].endConnectorLength;
3792 mds[j*cols+4].u.md_ival = gv->parts[j].fullAdvance;
3793 }
3794 GMatrixEditSet(g, mds,gv->part_cnt,false);
3795 }
3796
GA_ToMD(GGadget * g,SplineChar * sc)3797 static void GA_ToMD(GGadget *g, SplineChar *sc) {
3798 struct altuni *alt;
3799 int cols = GMatrixEditGetColCnt(g), cnt;
3800 struct matrix_data *mds;
3801 if ( sc->altuni==NULL ) {
3802 GMatrixEditSet(g, NULL,0,false);
3803 return;
3804 }
3805 for ( cnt=0, alt=sc->altuni; alt!=NULL; ++cnt, alt=alt->next );
3806 mds = calloc(cnt*cols,sizeof(struct matrix_data));
3807 for ( cnt=0, alt=sc->altuni; alt!=NULL; ++cnt, alt=alt->next ) {
3808 mds[cnt*cols+0].u.md_ival = alt->unienc;
3809 mds[cnt*cols+1].u.md_ival = alt->vs==-1? 0 : alt->vs;
3810 }
3811 GMatrixEditSet(g, mds,cnt,false);
3812 }
3813
CI_SetColorList(CharInfo * ci,Color color)3814 static void CI_SetColorList(CharInfo *ci,Color color) {
3815 int i;
3816 uint16 junk;
3817
3818 std_colors[CUSTOM_COLOR].image = NULL;
3819 for ( i=0; std_colors[i].image!=NULL; ++i ) {
3820 if ( std_colors[i].userdata == (void *) (intpt) color )
3821 break;
3822 }
3823 if ( std_colors[i].image==NULL ) {
3824 std_colors[i].image = &customcolor_image;
3825 customcolor_image.u.image->clut->clut[1] = color;
3826 std_colors[i].userdata = (void *) (intpt) color;
3827 }
3828 GGadgetSetList(GWidgetGetControl(ci->gw,CID_Color), GTextInfoArrayFromList(std_colors,&junk), false);
3829 GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_Color),i);
3830 if ( color!=COLOR_DEFAULT )
3831 ci->last = color;
3832 ci->real_last = color;
3833 }
3834
3835 struct colcount { Color color; int cnt; };
colcountorder(const void * op1,const void * op2)3836 static int colcountorder(const void *op1, const void *op2) {
3837 const struct colcount *c1 = op1, *c2 = op2;
3838
3839 return( c2->cnt - c1->cnt ); /* Biggest first */
3840 }
3841
SFFontCols(SplineFont * sf,struct hslrgb fontcols[6])3842 struct hslrgb *SFFontCols(SplineFont *sf,struct hslrgb fontcols[6]) {
3843 int i, gid, cnt;
3844 struct colcount *colcount, stds[7];
3845 SplineChar *sc;
3846
3847 memset(stds,0,sizeof(stds));
3848 stds[0].color = 0xffffff;
3849 stds[1].color = 0xff0000;
3850 stds[2].color = 0x00ff00;
3851 stds[3].color = 0x0000ff;
3852 stds[4].color = 0xffff00;
3853 stds[5].color = 0x00ffff;
3854 stds[6].color = 0xff00ff;
3855 colcount = calloc(sf->glyphcnt,sizeof(struct colcount));
3856
3857 cnt = 0;
3858 for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc= sf->glyphs[gid])!=NULL ) {
3859 if ( sc->color==COLOR_DEFAULT )
3860 continue;
3861 for ( i=0; i<7 && sc->color!=stds[i].color; ++i );
3862 if ( i<7 ) {
3863 ++stds[i].cnt;
3864 continue;
3865 }
3866 for ( i=0; i<cnt && sc->color!=colcount[i].color; ++i );
3867 if ( i==cnt )
3868 colcount[cnt++].color = sc->color;
3869 ++colcount[i].cnt;
3870 }
3871
3872 if ( cnt<6 ) {
3873 for ( i=0; i<cnt; ++i )
3874 ++colcount[i].cnt;
3875 for ( i=0; i<7; ++i ) if ( stds[i].cnt!=0 ) {
3876 colcount[cnt].color = stds[i].color;
3877 colcount[cnt++].cnt = 1;
3878 }
3879 }
3880 qsort(colcount,cnt,sizeof(struct colcount),colcountorder);
3881
3882 memset(fontcols,0,6*sizeof(struct hslrgb));
3883 for ( i=0; i<6 && i<cnt; ++i ) {
3884 fontcols[i].rgb = true;
3885 fontcols[i].r = ((colcount[i].color>>16)&0xff)/255.0;
3886 fontcols[i].g = ((colcount[i].color>>8 )&0xff)/255.0;
3887 fontcols[i].b = ((colcount[i].color )&0xff)/255.0;
3888 }
3889 free(colcount);
3890 if ( cnt==0 )
3891 return( NULL );
3892
3893 return(fontcols);
3894 }
3895
CI_PickColor(GGadget * g,GEvent * e)3896 static int CI_PickColor(GGadget *g, GEvent *e) {
3897 if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
3898 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
3899 GTextInfo *ti = GGadgetGetListItemSelected(g);
3900 if ( ti==NULL )
3901 /* Can't happen */;
3902 else if ( ti->userdata == (void *) COLOR_CHOOSE ) {
3903 struct hslrgb col, font_cols[6];
3904 memset(&col,0,sizeof(col));
3905 col.rgb = true;
3906 col.r = ((ci->last>>16)&0xff)/255.;
3907 col.g = ((ci->last>>8 )&0xff)/255.;
3908 col.b = ((ci->last )&0xff)/255.;
3909 col = GWidgetColor(_("Pick a color"),&col,SFFontCols(ci->sc->parent,font_cols));
3910 if ( col.rgb ) {
3911 ci->last = (((int) rint(255.*col.r))<<16 ) |
3912 (((int) rint(255.*col.g))<<8 ) |
3913 (((int) rint(255.*col.b)) );
3914 CI_SetColorList(ci,ci->last);
3915 } else /* Cancelled */
3916 CI_SetColorList(ci,ci->real_last);
3917 } else {
3918 if ( (intpt) ti->userdata!=COLOR_DEFAULT )
3919 ci->last = (intpt) ti->userdata;
3920 ci->real_last = (intpt) ti->userdata;
3921 }
3922 }
3923 return( true );
3924 }
3925
BytesNeeded(unichar_t in)3926 static int BytesNeeded(unichar_t in) {
3927 if (in <= 0xff) {
3928 return 1;
3929 } else if (in <= 0xffff) {
3930 return 2;
3931 } else if (in <= 0xffffff) {
3932 return 3;
3933 } else {
3934 return 4;
3935 }
3936 }
3937
CIFillup(CharInfo * ci)3938 static void CIFillup(CharInfo *ci) {
3939 SplineChar *sc = ci->cachedsc!=NULL ? ci->cachedsc : ci->sc;
3940 SplineFont *sf = sc->parent;
3941 unichar_t *temp;
3942 char buffer[400];
3943 char buf[200];
3944 const unichar_t *bits, *bits2;
3945 const unichar_t *d_ptr = sc->user_decomp;
3946 int i,j,gid, isv;
3947 struct matrix_data *mds[pst_max];
3948 int cnts[pst_max];
3949 PST *pst;
3950 KernPair *kp;
3951 unichar_t ubuf[4];
3952 GTextInfo **ti;
3953 char *devtabstr;
3954
3955 sprintf(buf,_("Glyph Info for %.40s"),sc->name);
3956 GDrawSetWindowTitles8(ci->gw, buf, _("Glyph Info..."));
3957
3958 if ( ci->oldsc!=NULL && ci->oldsc->charinfo==ci )
3959 ci->oldsc->charinfo = NULL;
3960 ci->sc->charinfo = ci;
3961 ci->oldsc = ci->sc;
3962
3963 GGadgetSetEnabled(GWidgetGetControl(ci->gw,-1), ci->enc>0 &&
3964 ((gid=ci->map->map[ci->enc-1])==-1 ||
3965 sf->glyphs[gid]==NULL || sf->glyphs[gid]->charinfo==NULL ||
3966 gid==sc->orig_pos));
3967 GGadgetSetEnabled(GWidgetGetControl(ci->gw,1), ci->enc<ci->map->enccount-1 &&
3968 ((gid=ci->map->map[ci->enc+1])==-1 ||
3969 sf->glyphs[gid]==NULL || sf->glyphs[gid]->charinfo==NULL ||
3970 gid==sc->orig_pos));
3971
3972 temp = utf82u_copy(sc->name);
3973 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UName),temp);
3974 free(temp);
3975 CI_SetNameList(ci,sc->unicodeenc);
3976
3977 sprintf(buffer,"U+%04x", sc->unicodeenc);
3978 temp = utf82u_copy(sc->unicodeenc==-1?"-1":buffer);
3979 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UValue),temp);
3980 free(temp);
3981
3982 ubuf[0] = sc->unicodeenc;
3983 if ( sc->unicodeenc==-1 )
3984 ubuf[0] = '\0';
3985 ubuf[1] = '\0';
3986 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_UChar),ubuf);
3987
3988 memset(cnts,0,sizeof(cnts));
3989 for ( pst = sc->possub; pst!=NULL; pst=pst->next ) if ( pst->type!=pst_lcaret )
3990 ++cnts[pst->type];
3991 for ( isv=0; isv<2; ++isv ) {
3992 for ( kp=isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
3993 ++cnts[pst_pair];
3994 }
3995 for ( i=pst_null+1; i<pst_max && i<pst_lcaret ; ++i )
3996 mds[i] = calloc((cnts[i]+1)*mi[i-1].col_cnt,sizeof(struct matrix_data));
3997 memset(cnts,0,sizeof(cnts));
3998 for ( pst = sc->possub; pst!=NULL; pst=pst->next ) if ( pst->type!=pst_lcaret ) {
3999 j = (cnts[pst->type]++ * mi[pst->type-1].col_cnt);
4000 mds[pst->type][j+0].u.md_ival = (intpt) pst->subtable;
4001 if ( pst->type==pst_position ) {
4002 mds[pst->type][j+SIM_DX].u.md_ival = pst->u.pos.xoff;
4003 mds[pst->type][j+SIM_DY].u.md_ival = pst->u.pos.yoff;
4004 mds[pst->type][j+SIM_DX_ADV].u.md_ival = pst->u.pos.h_adv_off;
4005 mds[pst->type][j+SIM_DY_ADV].u.md_ival = pst->u.pos.v_adv_off;
4006 ValDevTabToStrings(mds[pst_position],j+SIM_DX+1,pst->u.pos.adjust);
4007 } else if ( pst->type==pst_pair ) {
4008 mds[pst->type][j+1].u.md_str = copy(pst->u.pair.paired);
4009 mds[pst->type][j+PAIR_DX1].u.md_ival = pst->u.pair.vr[0].xoff;
4010 mds[pst->type][j+PAIR_DY1].u.md_ival = pst->u.pair.vr[0].yoff;
4011 mds[pst->type][j+PAIR_DX_ADV1].u.md_ival = pst->u.pair.vr[0].h_adv_off;
4012 mds[pst->type][j+PAIR_DY_ADV1].u.md_ival = pst->u.pair.vr[0].v_adv_off;
4013 mds[pst->type][j+PAIR_DX2].u.md_ival = pst->u.pair.vr[1].xoff;
4014 mds[pst->type][j+PAIR_DY2].u.md_ival = pst->u.pair.vr[1].yoff;
4015 mds[pst->type][j+PAIR_DX_ADV2].u.md_ival = pst->u.pair.vr[1].h_adv_off;
4016 mds[pst->type][j+PAIR_DY_ADV2].u.md_ival = pst->u.pair.vr[1].v_adv_off;
4017 ValDevTabToStrings(mds[pst_pair],j+PAIR_DX1+1,pst->u.pair.vr[0].adjust);
4018 ValDevTabToStrings(mds[pst_pair],j+PAIR_DX2+1,pst->u.pair.vr[1].adjust);
4019 } else {
4020 mds[pst->type][j+1].u.md_str = SFNameList2NameUni(sf,pst->u.subs.variant);
4021 }
4022 }
4023 for ( isv=0; isv<2; ++isv ) {
4024 for ( kp=isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next ) {
4025 j = (cnts[pst_pair]++ * mi[pst_pair-1].col_cnt);
4026 mds[pst_pair][j+0].u.md_ival = (intpt) kp->subtable;
4027 mds[pst_pair][j+1].u.md_str = SCNameUniStr(kp->sc);
4028 if ( isv ) {
4029 mds[pst_pair][j+PAIR_DY_ADV1].u.md_ival = kp->off;
4030 DevTabToString(&mds[pst_pair][j+PAIR_DY_ADV1+1].u.md_str,kp->adjust);
4031 } else if ( kp->subtable->lookup->lookup_flags&pst_r2l ) {
4032 mds[pst_pair][j+PAIR_DX_ADV2].u.md_ival = kp->off;
4033 DevTabToString(&mds[pst_pair][j+PAIR_DX_ADV2+1].u.md_str,kp->adjust);
4034 } else {
4035 mds[pst_pair][j+PAIR_DX_ADV1].u.md_ival = kp->off;
4036 DevTabToString(&mds[pst_pair][j+PAIR_DX_ADV1+1].u.md_str,kp->adjust);
4037 }
4038 }
4039 }
4040 for ( i=pst_null+1; i<pst_lcaret /* == pst_max-1 */; ++i ) {
4041 GMatrixEditSet(GWidgetGetControl(ci->gw,CID_List+(i-1)*100),
4042 mds[i],cnts[i],false);
4043 }
4044 /* There's always a pane showing kerning data */
4045 CI_DoHideUnusedPair(ci);
4046 CI_DoHideUnusedSingle(ci);
4047
4048 GGadget *cotf = GWidgetGetControl(ci->gw,CID_ComponentTextField);
4049 GGadget *codcb = GWidgetGetControl(ci->gw,CID_ComponentDefaultCB);
4050 GGadget *coim = GWidgetGetControl(ci->gw,CID_ComponentInterpMsg);
4051 GGadget *cola = GWidgetGetControl(ci->gw,CID_ComponentChangeMsg);
4052
4053 bits = bits2 = SFGetAlternate(sc->parent,sc->unicodeenc,NULL,true);
4054 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ComponentMsg),
4055 bits==NULL ? _("No components") :
4056 hascomposing(sc->parent,sc->unicodeenc,sc) ? _("Accented glyph composed of:") :
4057 _("Glyph composed of:"));
4058 if ( bits==NULL ) {
4059 ubuf[0] = '\0';
4060 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_Components),ubuf);
4061 GGadgetSetTitle(cotf,ubuf);
4062 } else {
4063 unichar_t *temp = malloc(18*u_strlen(bits)*sizeof(unichar_t));
4064 unichar_t *upt=temp;
4065 while ( *bits!='\0' ) {
4066 sprintf(buffer, "U+%04x (", *bits );
4067 uc_strcpy(upt,buffer);
4068 upt += u_strlen(upt);
4069 if (iscombining(*bits)) {
4070 *upt = 0x25CC; // DOTTED CIRCLE “◌”
4071 upt += 1;
4072 }
4073 *upt = *bits;
4074 upt += 1;
4075 sprintf(buffer, ") ");
4076 uc_strcpy(upt,buffer);
4077 upt += u_strlen(upt);
4078
4079 ++bits;
4080 }
4081 upt[-1] = '\0';
4082 GGadgetSetTitle(GWidgetGetControl(ci->gw,CID_Components),temp);
4083 free(temp);
4084 }
4085
4086 if (d_ptr == NULL) d_ptr = bits2;
4087
4088 int d_length = d_ptr ? u_strlen(d_ptr) : 0;
4089
4090 const int MAX_UNICHAR_T_BYTES = 4;
4091 char* codepoints_as_hex = malloc(((2 * MAX_UNICHAR_T_BYTES) * d_length) + d_length + 1);
4092 codepoints_as_hex[0] = '\0';
4093
4094 if (d_ptr == NULL) d_ptr = bits2;
4095
4096 while (d_ptr != NULL && *d_ptr != '\0') {
4097 switch (BytesNeeded(*d_ptr)) {
4098 case 1:
4099 sprintf(buffer, "%02x ", *d_ptr); break;
4100 case 2:
4101 sprintf(buffer, "%04x ", *d_ptr); break;
4102 case 3:
4103 sprintf(buffer, "%06x ", *d_ptr); break;
4104 default:
4105 sprintf(buffer, "%08x ", *d_ptr);
4106 }
4107 codepoints_as_hex = strcat(codepoints_as_hex, buffer);
4108 ++d_ptr;
4109 }
4110
4111 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ComponentTextField),codepoints_as_hex);
4112 free(codepoints_as_hex);
4113
4114 if (!GGadgetIsEnabled(codcb)) GGadgetSetEnabled(codcb, true);
4115 char* lbl = CI_CreateInterpretedAsLabel(sc->user_decomp);
4116 if (sc->user_decomp != NULL) {
4117 GGadgetSetChecked(codcb, false);
4118 GGadgetSetEnabled(cotf, true);
4119 GGadgetSetEnabled(cola, true);
4120 GGadgetSetTitle8(coim,lbl);
4121 } else {
4122 GGadgetSetChecked(codcb, true);
4123 GGadgetSetEnabled(cotf, false);
4124 GGadgetSetEnabled(cola, false);
4125 GGadgetSetTitle8(coim,"");
4126 }
4127 free(lbl);
4128
4129 GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_Color),0);
4130
4131 GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_UnlinkRmOverlap),sc->unlink_rm_ovrlp_save_undo);
4132
4133 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_Comment),
4134 sc->comment?sc->comment:"");
4135 GGadgetSelectOneListItem(GWidgetGetControl(ci->gw,CID_GClass),sc->glyph_class);
4136 CI_SetColorList(ci,sc->color);
4137 ci->first = sc->comment==NULL;
4138
4139 ti = malloc((sc->countermask_cnt+1)*sizeof(GTextInfo *));
4140 ti[sc->countermask_cnt] = calloc(1,sizeof(GTextInfo));
4141 for ( i=0; i<sc->countermask_cnt; ++i ) {
4142 ti[i] = calloc(1,sizeof(GTextInfo));
4143 ti[i]->text = CounterMaskLine(sc,&sc->countermasks[i]);
4144 ti[i]->fg = ti[i]->bg = COLOR_DEFAULT;
4145 ti[i]->userdata = chunkalloc(sizeof(HintMask));
4146 memcpy(ti[i]->userdata,sc->countermasks[i],sizeof(HintMask));
4147 }
4148 GGadgetSetList(GWidgetGetControl(ci->gw,CID_List+600),ti,false);
4149
4150 if ( sc->tex_height!=TEX_UNDEF )
4151 sprintf(buffer,"%d",sc->tex_height);
4152 else
4153 buffer[0] = '\0';
4154 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TeX_Height),buffer);
4155
4156 if ( sc->tex_depth!=TEX_UNDEF )
4157 sprintf(buffer,"%d",sc->tex_depth);
4158 else
4159 buffer[0] = '\0';
4160 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TeX_Depth),buffer);
4161
4162 if ( sc->italic_correction!=TEX_UNDEF )
4163 sprintf(buffer,"%d",sc->italic_correction);
4164 else
4165 buffer[0] = '\0';
4166 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TeX_Italic),buffer);
4167 DevTabToString(&devtabstr,sc->italic_adjusts);
4168 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ItalicDevTab),devtabstr==NULL?"":devtabstr);
4169 free(devtabstr);
4170
4171 if ( sc->top_accent_horiz!=TEX_UNDEF )
4172 sprintf(buffer,"%d",sc->top_accent_horiz);
4173 else
4174 buffer[0] = '\0';
4175 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_HorAccent),buffer);
4176 DevTabToString(&devtabstr,sc->top_accent_adjusts);
4177 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_AccentDevTab),devtabstr==NULL?"":devtabstr);
4178 free(devtabstr);
4179
4180 GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_IsExtended),sc->is_extended_shape);
4181
4182 {
4183 GGadget *g = GWidgetGetControl(ci->gw,CID_VariantList+0*100);
4184 if ( sc->vert_variants==NULL || sc->vert_variants->variants==NULL )
4185 GGadgetSetTitle8(g,"");
4186 else
4187 GGadgetSetTitle8(g,sc->vert_variants->variants);
4188 sprintf(buffer,"%d",sc->vert_variants!=NULL?sc->vert_variants->italic_correction:0);
4189 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicCor+0*100),buffer);
4190 DevTabToString(&devtabstr,sc->vert_variants!=NULL?
4191 sc->vert_variants->italic_adjusts:
4192 NULL);
4193 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+0*100),devtabstr==NULL?"":devtabstr);
4194 free(devtabstr);
4195
4196 g = GWidgetGetControl(ci->gw,CID_VariantList+1*100);
4197 if ( sc->horiz_variants==NULL || sc->horiz_variants->variants==NULL )
4198 GGadgetSetTitle8(g,"");
4199 else
4200 GGadgetSetTitle8(g,sc->horiz_variants->variants);
4201 sprintf(buffer,"%d",sc->horiz_variants!=NULL?sc->horiz_variants->italic_correction:0);
4202 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicCor+1*100),buffer);
4203 DevTabToString(&devtabstr,sc->horiz_variants!=NULL?
4204 sc->horiz_variants->italic_adjusts:
4205 NULL);
4206 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_ExtItalicDev+1*100),devtabstr==NULL?"":devtabstr);
4207 free(devtabstr);
4208 }
4209 for ( i=0; i<2; ++i ) {
4210 struct glyphvariants *gv = i ? sc->horiz_variants : sc->vert_variants ;
4211 GGadget *g = GWidgetGetControl(ci->gw,CID_ExtensionList+i*100);
4212 GV_ToMD(g, gv);
4213 }
4214 GA_ToMD(GWidgetGetControl(ci->gw,CID_AltUni), sc);
4215
4216 if ( ci->sc->parent->multilayer ) {
4217 int margined = sc->tile_margin!=0 || (sc->tile_bounds.minx==0 && sc->tile_bounds.maxx==0);
4218 char buffer[40];
4219
4220 GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_IsTileMargin),margined);
4221 if ( margined ) {
4222 sprintf( buffer, "%g", (double) sc->tile_margin );
4223 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileMargin),buffer);
4224 CI_BoundsToMargin(ci);
4225 } else {
4226 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileMargin),"0");
4227 sprintf( buffer, "%g", (double) sc->tile_bounds.minx );
4228 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinX),buffer);
4229 sprintf( buffer, "%g", (double) sc->tile_bounds.miny );
4230 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMinY),buffer);
4231 sprintf( buffer, "%g", (double) sc->tile_bounds.maxx );
4232 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxX),buffer);
4233 sprintf( buffer, "%g", (double) sc->tile_bounds.maxy );
4234 GGadgetSetTitle8(GWidgetGetControl(ci->gw,CID_TileBBoxMaxY),buffer);
4235 }
4236 }
4237
4238 GGadgetSetChecked(GWidgetGetControl(ci->gw,CID_DefLCCount), !sc->lig_caret_cnt_fixed );
4239 GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCountLab), sc->lig_caret_cnt_fixed );
4240 GGadgetSetEnabled(GWidgetGetControl(ci->gw,CID_LCCount), sc->lig_caret_cnt_fixed );
4241 ci->lc_seen = false;
4242 CI_NoteAspect(ci);
4243 }
4244
CI_NextPrev(GGadget * g,GEvent * e)4245 static int CI_NextPrev(GGadget *g, GEvent *e) {
4246 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
4247 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
4248 int enc = ci->enc + GGadgetGetCid(g); /* cid is 1 for next, -1 for prev */
4249 SplineChar *new_;
4250 struct splinecharlist *scl;
4251
4252 if ( enc<0 || enc>=ci->map->enccount ) {
4253 GGadgetSetEnabled(g,false);
4254 return( true );
4255 }
4256 if ( !_CI_OK(ci))
4257 return( true );
4258 new_ = SFMakeChar(ci->sc->parent,ci->map,enc);
4259 if ( new_->charinfo!=NULL && new_->charinfo!=ci ) {
4260 GGadgetSetEnabled(g,false);
4261 return( true );
4262 }
4263 ci->sc = new_;
4264 ci->enc = enc;
4265 for ( scl=ci->changes; scl!=NULL && scl->sc->orig_pos!=new_->orig_pos;
4266 scl = scl->next );
4267 ci->cachedsc = scl==NULL ? NULL : scl->sc;
4268 CIFillup(ci);
4269 }
4270 return( true );
4271 }
4272
CI_DoCancel(CharInfo * ci)4273 static void CI_DoCancel(CharInfo *ci) {
4274 int32 i,len;
4275 GTextInfo **ti = GGadgetGetList(GWidgetGetControl(ci->gw,CID_List+600),&len);
4276
4277 for ( i=0; i<len; ++i )
4278 chunkfree(ti[i]->userdata,sizeof(HintMask));
4279 CI_Finish(ci);
4280 }
4281
CI_Cancel(GGadget * g,GEvent * e)4282 static int CI_Cancel(GGadget *g, GEvent *e) {
4283 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
4284 CharInfo *ci = GDrawGetUserData(GGadgetGetWindow(g));
4285 CI_DoCancel(ci);
4286 }
4287 return( true );
4288 }
4289
ci_e_h(GWindow gw,GEvent * event)4290 static int ci_e_h(GWindow gw, GEvent *event) {
4291 if ( event->type==et_close ) {
4292 CharInfo *ci = GDrawGetUserData(gw);
4293 CI_DoCancel(ci);
4294 } else if ( event->type==et_char ) {
4295 CharInfo *ci = GDrawGetUserData(gw);
4296 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
4297 help("ui/dialogs/charinfo.html", NULL);
4298 return( true );
4299 } else if ( GMenuIsCommand(event,H_("Quit|Ctl+Q") )) {
4300 MenuExit(NULL,NULL,NULL);
4301 } else if ( GMenuIsCommand(event,H_("Close|Ctl+Shft+Q") )) {
4302 CI_DoCancel(ci);
4303 }
4304 return( false );
4305 } else if ( event->type == et_destroy ) {
4306 CharInfo *ci = GDrawGetUserData(gw);
4307 ci->sc->charinfo = NULL;
4308 free(ci);
4309 } else if ( event->type == et_map ) {
4310 /* Above palettes */
4311 GDrawRaise(gw);
4312 }
4313 return( true );
4314 }
4315
SCCharInfo(SplineChar * sc,int deflayer,EncMap * map,int enc)4316 void SCCharInfo(SplineChar *sc,int deflayer, EncMap *map,int enc) {
4317 CharInfo *ci;
4318 GRect pos;
4319 GWindowAttrs wattrs;
4320 GGadgetCreateData ugcd[14], cgcd[6], psgcd[7][7], cogcd[6], mgcd[9], tgcd[16];
4321 GGadgetCreateData lcgcd[4], vargcd[2][7];
4322 GTextInfo ulabel[14], clabel[6], pslabel[7][6], colabel[4], mlabel[9], tlabel[16];
4323 GTextInfo lclabel[4], varlabel[2][6];
4324 GGadgetCreateData mbox[4], *mvarray[7], *mharray1[7], *mharray2[8];
4325 GGadgetCreateData ubox[3], *uhvarray[29], *uharray[6];
4326 GGadgetCreateData cbox[3], *cvarray[5], *charray[4];
4327 GGadgetCreateData pstbox[7][4], *pstvarray[7][5], *pstharray1[7][8];
4328 GGadgetCreateData cobox[2], *covarray[8];
4329 GGadgetCreateData tbox[3], *thvarray[36], *tbarray[4];
4330 GGadgetCreateData lcbox[2], *lchvarray[4][4];
4331 GGadgetCreateData varbox[2][2], *varhvarray[2][5][4];
4332 GGadgetCreateData tilegcd[16], tilebox[4];
4333 GTextInfo tilelabel[16];
4334 GGadgetCreateData *tlvarray[6], *tlharray[4], *tlhvarray[4][5];
4335 int i;
4336 GTabInfo aspects[17];
4337 static GBox smallbox = { bt_raised, bs_rect, 2, 1, 0, 0, 0, 0, 0, 0, COLOR_DEFAULT, COLOR_DEFAULT, 0, 0, 0, 0, 0, 0, 0 };
4338 static int boxset=0;
4339 FontRequest rq;
4340 static GFont *font=NULL;
4341
4342 CharInfoInit();
4343
4344 if ( sc->charinfo!=NULL ) {
4345 GDrawSetVisible(sc->charinfo->gw,true);
4346 GDrawRaise(sc->charinfo->gw);
4347 return;
4348 }
4349
4350 ci = calloc(1,sizeof(CharInfo));
4351 ci->sc = sc;
4352 ci->def_layer = deflayer;
4353 ci->done = false;
4354 ci->map = map;
4355 ci->last = 0xffffff;
4356 if ( enc==-1 )
4357 enc = map->backmap[sc->orig_pos];
4358 ci->enc = enc;
4359
4360 if ( !boxset ) {
4361 extern GBox _ggadget_Default_Box;
4362 GGadgetInit();
4363 smallbox = _ggadget_Default_Box;
4364 smallbox.padding = 1;
4365 boxset = 1;
4366 }
4367
4368 memset(&wattrs,0,sizeof(wattrs));
4369 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
4370 wattrs.event_masks = ~(1<<et_charup);
4371 wattrs.restrict_input_to_me = false;
4372 wattrs.undercursor = 1;
4373 wattrs.cursor = ct_pointer;
4374 wattrs.utf8_window_title = _("Glyph Info");
4375 wattrs.is_dlg = false;
4376 pos.x = pos.y = 0;
4377 pos.width = GGadgetScale(GDrawPointsToPixels(NULL,CI_Width+65));
4378 pos.height = GDrawPointsToPixels(NULL,CI_Height);
4379 ci->gw = GDrawCreateTopWindow(NULL,&pos,ci_e_h,ci,&wattrs);
4380
4381 memset(&ugcd,0,sizeof(ugcd));
4382 memset(&ubox,0,sizeof(ubox));
4383 memset(&ulabel,0,sizeof(ulabel));
4384
4385 ulabel[0].text = (unichar_t *) _("Gl_yph Name:");
4386 ulabel[0].text_is_1byte = true;
4387 ulabel[0].text_in_resource = true;
4388 ugcd[0].gd.label = &ulabel[0];
4389 ugcd[0].gd.pos.x = 5; ugcd[0].gd.pos.y = 5+4;
4390 ugcd[0].gd.flags = gg_enabled|gg_visible;
4391 ugcd[0].gd.mnemonic = 'N';
4392 ugcd[0].creator = GLabelCreate;
4393 uhvarray[0] = &ugcd[0];
4394
4395 ugcd[1].gd.pos.x = 85; ugcd[1].gd.pos.y = 5;
4396 ugcd[1].gd.flags = gg_enabled|gg_visible;
4397 ugcd[1].gd.mnemonic = 'N';
4398 ugcd[1].gd.cid = CID_UName;
4399 ugcd[1].creator = GListFieldCreate;
4400 ugcd[1].data = (void *) (-2);
4401 uhvarray[1] = &ugcd[1]; uhvarray[2] = NULL;
4402
4403 ulabel[2].text = (unichar_t *) _("Unicode _Value:");
4404 ulabel[2].text_in_resource = true;
4405 ulabel[2].text_is_1byte = true;
4406 ugcd[2].gd.label = &ulabel[2];
4407 ugcd[2].gd.pos.x = 5; ugcd[2].gd.pos.y = 31+4;
4408 ugcd[2].gd.flags = gg_enabled|gg_visible;
4409 ugcd[2].gd.mnemonic = 'V';
4410 ugcd[2].creator = GLabelCreate;
4411 uhvarray[3] = &ugcd[2];
4412
4413 ugcd[3].gd.pos.x = 85; ugcd[3].gd.pos.y = 31;
4414 ugcd[3].gd.flags = gg_enabled|gg_visible;
4415 ugcd[3].gd.mnemonic = 'V';
4416 ugcd[3].gd.cid = CID_UValue;
4417 ugcd[3].gd.handle_controlevent = CI_UValChanged;
4418 ugcd[3].creator = GTextFieldCreate;
4419 uhvarray[4] = &ugcd[3]; uhvarray[5] = NULL;
4420
4421 ulabel[4].text = (unichar_t *) _("Unicode C_har:");
4422 ulabel[4].text_in_resource = true;
4423 ulabel[4].text_is_1byte = true;
4424 ugcd[4].gd.label = &ulabel[4];
4425 ugcd[4].gd.pos.x = 5; ugcd[4].gd.pos.y = 57+4;
4426 ugcd[4].gd.flags = gg_enabled|gg_visible;
4427 ugcd[4].gd.mnemonic = 'h';
4428 ugcd[4].creator = GLabelCreate;
4429 uhvarray[6] = &ugcd[4];
4430
4431 ugcd[5].gd.pos.x = 85; ugcd[5].gd.pos.y = 57;
4432 ugcd[5].gd.flags = gg_enabled|gg_visible|gg_text_xim;
4433 ugcd[5].gd.mnemonic = 'h';
4434 ugcd[5].gd.cid = CID_UChar;
4435 ugcd[5].gd.handle_controlevent = CI_CharChanged;
4436 ugcd[5].creator = GTextFieldCreate;
4437 uhvarray[7] = &ugcd[5]; uhvarray[8] = NULL;
4438
4439 ugcd[6].gd.pos.x = 12; ugcd[6].gd.pos.y = 117;
4440 ugcd[6].gd.flags = gg_visible | gg_enabled;
4441 ulabel[6].text = (unichar_t *) _("Set From N_ame");
4442 ulabel[6].text_is_1byte = true;
4443 ulabel[6].text_in_resource = true;
4444 ugcd[6].gd.mnemonic = 'a';
4445 ugcd[6].gd.label = &ulabel[6];
4446 ugcd[6].gd.handle_controlevent = CI_SName;
4447 ugcd[6].creator = GButtonCreate;
4448 uharray[0] = GCD_Glue; uharray[1] = &ugcd[6];
4449
4450 ugcd[7].gd.pos.x = 107; ugcd[7].gd.pos.y = 117;
4451 ugcd[7].gd.flags = gg_visible | gg_enabled;
4452 ulabel[7].text = (unichar_t *) _("Set From Val_ue");
4453 ulabel[7].text_is_1byte = true;
4454 ulabel[7].text_in_resource = true;
4455 ugcd[7].gd.mnemonic = 'l';
4456 ugcd[7].gd.label = &ulabel[7];
4457 ugcd[7].gd.handle_controlevent = CI_SValue;
4458 ugcd[7].creator = GButtonCreate;
4459 uharray[2] = GCD_Glue; uharray[3] = &ugcd[7]; uharray[4] = GCD_Glue; uharray[5] = NULL;
4460
4461 ubox[2].gd.flags = gg_enabled|gg_visible;
4462 ubox[2].gd.u.boxelements = uharray;
4463 ubox[2].creator = GHBoxCreate;
4464 uhvarray[9] = &ubox[2]; uhvarray[10] = GCD_ColSpan; uhvarray[11] = NULL;
4465
4466 ugcd[8].gd.flags = gg_visible | gg_enabled;
4467 ulabel[8].text = (unichar_t *) _("Alternate Unicode Encodings / Variation Selectors");
4468 ulabel[8].text_is_1byte = true;
4469 ugcd[8].gd.label = &ulabel[8];
4470 ugcd[8].gd.popup_msg = _(
4471 "Some glyphs may be used for more than one\n"
4472 "unicode code point -- I don't recommend\n"
4473 "doing this, better to use a reference --\n"
4474 "but it is possible.\n"
4475 "The latin \"A\", the greek \"Alpha\" and the\n"
4476 "cyrillic \"A\" look very much the same.\n\n"
4477 "On the other hand certain Mongolian and CJK\n"
4478 "characters have multiple glyphs depending\n"
4479 "on a unicode Variation Selector.\n\n"
4480 "In the first case use a variation selector\n"
4481 "of 0, in the second use the appropriate\n"
4482 "codepoint.");
4483 ugcd[8].creator = GLabelCreate;
4484 uhvarray[12] = &ugcd[8]; uhvarray[13] = GCD_ColSpan; uhvarray[14] = NULL;
4485
4486 ugcd[9].gd.flags = gg_enabled|gg_visible;
4487 ugcd[9].gd.u.matrix = &mi_altuniinfo;
4488 ugcd[9].gd.cid = CID_AltUni;
4489 ugcd[9].gd.popup_msg = ugcd[8].gd.popup_msg;
4490 ugcd[9].creator = GMatrixEditCreate;
4491 uhvarray[15] = &ugcd[9]; uhvarray[16] = GCD_ColSpan; uhvarray[17] = NULL;
4492
4493 ugcd[10].gd.pos.x = 5; ugcd[10].gd.pos.y = 83+4;
4494 ugcd[10].gd.flags = gg_visible | gg_enabled;
4495 ulabel[10].text = (unichar_t *) _("OT _Glyph Class:");
4496 ulabel[10].text_is_1byte = true;
4497 ulabel[10].text_in_resource = true;
4498 ugcd[10].gd.label = &ulabel[10];
4499 ugcd[10].creator = GLabelCreate;
4500 uhvarray[18] = &ugcd[10];
4501
4502 ugcd[11].gd.pos.x = 85; ugcd[11].gd.pos.y = 83;
4503 ugcd[11].gd.flags = gg_visible | gg_enabled;
4504 ugcd[11].gd.cid = CID_GClass;
4505 ugcd[11].gd.u.list = glyphclasses;
4506 ugcd[11].creator = GListButtonCreate;
4507 uhvarray[19] = &ugcd[11]; uhvarray[20] = NULL;
4508
4509 ugcd[12].gd.flags = gg_visible | gg_enabled;
4510 ulabel[12].text = (unichar_t *) _("Mark for Unlink, Remove Overlap before Generating");
4511 ulabel[12].text_is_1byte = true;
4512 ulabel[12].text_in_resource = true;
4513 ugcd[12].gd.label = &ulabel[12];
4514 ugcd[12].gd.cid = CID_UnlinkRmOverlap;
4515 ugcd[12].gd.popup_msg = _("A few glyphs, like Aring, Ccedilla, Eogonek\nare composed of two overlapping references.\nOften it is desirable to retain the references\n(so that changes made to the base glyph are\nreflected in the composed glyph), but that\nmeans you are stuck with overlapping contours.\nThis flag means that just before generating\nthe font, FontForge will unlink the references\nand run remove overlap on them, while\n retaining the references in the SFD.");
4516 ugcd[12].creator = GCheckBoxCreate;
4517 uhvarray[21] = &ugcd[12]; uhvarray[22] = GCD_ColSpan; uhvarray[23] = NULL;
4518 uhvarray[24] = GCD_Glue; uhvarray[25] = GCD_Glue; uhvarray[26] = NULL;
4519 uhvarray[27] = NULL;
4520
4521 ubox[0].gd.flags = gg_enabled|gg_visible;
4522 ubox[0].gd.u.boxelements = uhvarray;
4523 ubox[0].creator = GHVBoxCreate;
4524
4525
4526 memset(&cgcd,0,sizeof(cgcd));
4527 memset(&cbox,0,sizeof(cbox));
4528 memset(&clabel,0,sizeof(clabel));
4529
4530 clabel[0].text = (unichar_t *) _("Comment");
4531 clabel[0].text_is_1byte = true;
4532 cgcd[0].gd.label = &clabel[0];
4533 cgcd[0].gd.pos.x = 5; cgcd[0].gd.pos.y = 5;
4534 cgcd[0].gd.flags = gg_enabled|gg_visible;
4535 cgcd[0].creator = GLabelCreate;
4536 cvarray[0] = &cgcd[0];
4537
4538 cgcd[1].gd.pos.x = 5; cgcd[1].gd.pos.y = cgcd[0].gd.pos.y+13;
4539 cgcd[1].gd.pos.height = 7*12+6;
4540 cgcd[1].gd.flags = gg_enabled|gg_visible|gg_textarea_wrap|gg_text_xim;
4541 cgcd[1].gd.cid = CID_Comment;
4542 cgcd[1].gd.handle_controlevent = CI_CommentChanged;
4543 cgcd[1].creator = GTextAreaCreate;
4544 cvarray[1] = &cgcd[1]; cvarray[2] = GCD_Glue;
4545
4546 clabel[2].text = (unichar_t *) _("Color:");
4547 clabel[2].text_is_1byte = true;
4548 cgcd[2].gd.label = &clabel[2];
4549 cgcd[2].gd.pos.x = 5; cgcd[2].gd.pos.y = cgcd[1].gd.pos.y+cgcd[1].gd.pos.height+5+6;
4550 cgcd[2].gd.flags = gg_enabled|gg_visible;
4551 cgcd[2].creator = GLabelCreate;
4552 charray[0] = &cgcd[2];
4553
4554 cgcd[3].gd.pos.x = cgcd[3].gd.pos.x; cgcd[3].gd.pos.y = cgcd[2].gd.pos.y-6;
4555 cgcd[3].gd.flags = gg_enabled|gg_visible;
4556 cgcd[3].gd.cid = CID_Color;
4557 cgcd[3].gd.handle_controlevent = CI_PickColor;
4558 std_colors[0].image = GGadgetImageCache("colorwheel.png");
4559 cgcd[3].gd.u.list = std_colors;
4560 cgcd[3].creator = GListButtonCreate;
4561 charray[1] = &cgcd[3]; charray[2] = GCD_Glue; charray[3] = NULL;
4562
4563 cbox[2].gd.flags = gg_enabled|gg_visible;
4564 cbox[2].gd.u.boxelements = charray;
4565 cbox[2].creator = GHBoxCreate;
4566 cvarray[3] = &cbox[2]; cvarray[4] = NULL;
4567
4568 cbox[0].gd.flags = gg_enabled|gg_visible;
4569 cbox[0].gd.u.boxelements = cvarray;
4570 cbox[0].creator = GVBoxCreate;
4571
4572 memset(&psgcd,0,sizeof(psgcd));
4573 memset(&pstbox,0,sizeof(pstbox));
4574 memset(&pslabel,0,sizeof(pslabel));
4575
4576 for ( i=0; i<6; ++i ) {
4577 psgcd[i][0].gd.pos.x = 5; psgcd[i][0].gd.pos.y = 5;
4578 psgcd[i][0].gd.flags = gg_visible | gg_enabled;
4579 psgcd[i][0].gd.cid = CID_List+i*100;
4580 psgcd[i][0].gd.u.matrix = &mi[i];
4581 mi[i].col_init[0].enum_vals = SFSubtableListOfType(sc->parent, pst2lookuptype[i+1], false, false);
4582 psgcd[i][0].creator = GMatrixEditCreate;
4583 }
4584 for ( i=pst_position; i<=pst_pair; ++i ) {
4585 pslabel[i-1][1].text = (unichar_t *) _("_Hide Unused Columns");
4586 pslabel[i-1][1].text_is_1byte = true;
4587 pslabel[i-1][1].text_in_resource = true;
4588 psgcd[i-1][1].gd.label = &pslabel[i-1][1];
4589 psgcd[i-1][1].gd.pos.x = 5; psgcd[i-1][1].gd.pos.y = 5+4;
4590 psgcd[i-1][1].gd.flags = lookup_hideunused ? (gg_enabled|gg_visible|gg_cb_on) : (gg_enabled|gg_visible);
4591 psgcd[i-1][1].gd.popup_msg = _("Don't display columns of 0s.\nThe OpenType lookup allows for up to 8 kinds\nof data, but almost all kerning lookups will use just one.\nOmitting the others makes the behavior clearer.");
4592 psgcd[i-1][1].gd.handle_controlevent = i==pst_position ? CI_HideUnusedSingle : CI_HideUnusedPair;
4593 psgcd[i-1][1].creator = GCheckBoxCreate;
4594 pstvarray[i-1][0] = &psgcd[i-1][0];
4595 pstvarray[i-1][1] = &psgcd[i-1][1];
4596 pstvarray[i-1][2] = NULL;
4597
4598 pstbox[i-1][0].gd.flags = gg_enabled|gg_visible;
4599 pstbox[i-1][0].gd.u.boxelements = pstvarray[i-1];
4600 pstbox[i-1][0].creator = GVBoxCreate;
4601 }
4602
4603 psgcd[6][0].gd.pos.x = 5; psgcd[6][0].gd.pos.y = 5;
4604 psgcd[6][0].gd.flags = gg_visible | gg_enabled;
4605 psgcd[6][0].gd.cid = CID_List+6*100;
4606 psgcd[6][0].gd.handle_controlevent = CI_CounterSelChanged;
4607 psgcd[6][0].gd.box = &smallbox;
4608 psgcd[6][0].creator = GListCreate;
4609 pstvarray[6][0] = &psgcd[6][0];
4610
4611 psgcd[6][1].gd.pos.x = 10; psgcd[6][1].gd.pos.y = psgcd[6][0].gd.pos.y+psgcd[6][0].gd.pos.height+4;
4612 psgcd[6][1].gd.flags = gg_visible | gg_enabled;
4613 pslabel[6][1].text = (unichar_t *) S_("CounterHint|_New...");
4614 pslabel[6][1].text_is_1byte = true;
4615 pslabel[6][1].text_in_resource = true;
4616 psgcd[6][1].gd.label = &pslabel[6][1];
4617 psgcd[6][1].gd.cid = CID_New+6*100;
4618 psgcd[6][1].gd.handle_controlevent = CI_NewCounter;
4619 psgcd[6][1].gd.box = &smallbox;
4620 psgcd[6][1].creator = GButtonCreate;
4621 pstharray1[6][0] = GCD_Glue; pstharray1[6][1] = &psgcd[6][1];
4622
4623 psgcd[6][2].gd.pos.x = 20+GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor); psgcd[6][2].gd.pos.y = psgcd[6][1].gd.pos.y;
4624 psgcd[6][2].gd.flags = gg_visible;
4625 pslabel[6][2].text = (unichar_t *) _("_Delete");
4626 pslabel[6][2].text_is_1byte = true;
4627 pslabel[6][2].text_in_resource = true;
4628 psgcd[6][2].gd.label = &pslabel[6][2];
4629 psgcd[6][2].gd.cid = CID_Delete+6*100;
4630 psgcd[6][2].gd.handle_controlevent = CI_DeleteCounter;
4631 psgcd[6][2].gd.box = &smallbox;
4632 psgcd[6][2].creator = GButtonCreate;
4633 pstharray1[6][2] = GCD_Glue; pstharray1[6][3] = &psgcd[6][2];
4634
4635 psgcd[6][3].gd.pos.x = -10; psgcd[6][3].gd.pos.y = psgcd[6][1].gd.pos.y;
4636 psgcd[6][3].gd.flags = gg_visible;
4637 pslabel[6][3].text = (unichar_t *) _("_Edit...");
4638 pslabel[6][3].text_is_1byte = true;
4639 pslabel[6][3].text_in_resource = true;
4640 psgcd[6][3].gd.label = &pslabel[6][3];
4641 psgcd[6][3].gd.cid = CID_Edit+6*100;
4642 psgcd[6][3].gd.handle_controlevent = CI_EditCounter;
4643 psgcd[6][3].gd.box = &smallbox;
4644 psgcd[6][3].creator = GButtonCreate;
4645 pstharray1[6][4] = GCD_Glue; pstharray1[6][5] = &psgcd[6][3]; pstharray1[6][6] = GCD_Glue; pstharray1[6][7] = NULL;
4646
4647 pstbox[6][2].gd.flags = gg_enabled|gg_visible;
4648 pstbox[6][2].gd.u.boxelements = pstharray1[6];
4649 pstbox[6][2].creator = GHBoxCreate;
4650 pstvarray[6][1] = &pstbox[6][2]; pstvarray[6][2] = NULL;
4651
4652 pstbox[6][0].gd.flags = gg_enabled|gg_visible;
4653 pstbox[6][0].gd.u.boxelements = pstvarray[6];
4654 pstbox[6][0].creator = GVBoxCreate;
4655 psgcd[6][4].gd.flags = psgcd[6][5].gd.flags = 0; /* No copy, paste for hint masks */
4656
4657 memset(&cogcd,0,sizeof(cogcd));
4658 memset(&cobox,0,sizeof(cobox));
4659 memset(&colabel,0,sizeof(colabel));
4660
4661 colabel[0].text = (unichar_t *) _("Accented glyph composed of:");
4662 colabel[0].text_is_1byte = true;
4663 cogcd[0].gd.label = &colabel[0];
4664 cogcd[0].gd.flags = gg_enabled|gg_visible;
4665 cogcd[0].gd.cid = CID_ComponentMsg;
4666 cogcd[0].creator = GLabelCreate;
4667
4668 cogcd[1].gd.flags = gg_enabled|gg_visible;
4669 cogcd[1].gd.cid = CID_Components;
4670 cogcd[1].creator = GLabelCreate;
4671
4672 colabel[1].text = (unichar_t *) _("\n\nIf the default decomposition is inappropriate for this font, you may choose your own.");
4673 colabel[1].text_is_1byte = true;
4674 cogcd[2].gd.label = &colabel[1];
4675 cogcd[2].gd.flags = gg_enabled|gg_visible;
4676 cogcd[2].gd.cid = CID_ComponentChangeMsg;
4677 cogcd[2].creator = GLabelCreate;
4678
4679 colabel[2].text = (unichar_t *) _("Use default?");
4680 colabel[2].text_is_1byte = true;
4681 cogcd[3].gd.flags = gg_enabled | gg_visible | gg_cb_on;
4682 cogcd[3].gd.cid = CID_ComponentDefaultCB;
4683 cogcd[3].gd.handle_controlevent = CI_CmpUseNonDefault;
4684 cogcd[3].gd.label = &colabel[2];
4685 cogcd[3].creator = GCheckBoxCreate;
4686
4687 cogcd[4].gd.flags = gg_visible;
4688 cogcd[4].gd.popup_msg = _("For example, to build this character from U+0061 (lowercase a) as the base and U+030C (combining caron), write:\n0061 030C");
4689 cogcd[4].gd.cid = CID_ComponentTextField;
4690 cogcd[4].gd.handle_controlevent = CI_CmpUseNonDefault;
4691 cogcd[4].gd.pos.x = 500; cogcd[4].gd.pos.y = 20;
4692 cogcd[4].creator = GTextFieldCreate;
4693
4694 cogcd[5].gd.flags = gg_enabled|gg_visible;
4695 cogcd[5].gd.cid = CID_ComponentInterpMsg;
4696 cogcd[5].creator = GLabelCreate;
4697
4698 covarray[0] = &cogcd[0]; covarray[1] = &cogcd[1]; covarray[2] = &cogcd[2]; covarray[3] = &cogcd[3]; covarray[4] = &cogcd[4]; covarray[5] = &cogcd[5]; covarray[6] = GCD_Glue; covarray[7] = NULL;
4699 cobox[0].gd.flags = gg_enabled|gg_visible;
4700 cobox[0].gd.u.boxelements = covarray;
4701 cobox[0].creator = GVBoxCreate;
4702
4703 memset(&tgcd,0,sizeof(tgcd));
4704 memset(&tbox,0,sizeof(tbox));
4705 memset(&tlabel,0,sizeof(tlabel));
4706
4707 tlabel[0].text = (unichar_t *) _("Height:");
4708 tlabel[0].text_is_1byte = true;
4709 tgcd[0].gd.label = &tlabel[0];
4710 tgcd[0].gd.pos.x = 5; tgcd[0].gd.pos.y = 5+4;
4711 tgcd[0].gd.flags = gg_enabled|gg_visible;
4712 tgcd[0].gd.popup_msg = _("The height and depth fields are the metrics fields used\nby TeX, they are corrected for optical distortion.\nSo 'x' and 'o' probably have the same height.");
4713 tgcd[0].creator = GLabelCreate;
4714 thvarray[0] = &tgcd[0];
4715
4716 tgcd[1].gd.pos.x = 85; tgcd[1].gd.pos.y = 5;
4717 tgcd[1].gd.pos.width = 60;
4718 tgcd[1].gd.flags = gg_enabled|gg_visible;
4719 tgcd[1].gd.cid = CID_TeX_Height;
4720 tgcd[1].creator = GTextFieldCreate;
4721 tgcd[1].gd.popup_msg = tgcd[0].gd.popup_msg;
4722 thvarray[1] = &tgcd[1];
4723
4724 tlabel[2].text = (unichar_t *) _("Guess");
4725 tlabel[2].text_is_1byte = true;
4726 tgcd[2].gd.label = &tlabel[2];
4727 tgcd[2].gd.flags = gg_enabled|gg_visible;
4728 tgcd[2].gd.cid = CID_TeX_HeightD;
4729 tgcd[2].gd.handle_controlevent = TeX_Default;
4730 tgcd[2].creator = GButtonCreate;
4731 tgcd[2].gd.popup_msg = tgcd[0].gd.popup_msg;
4732 thvarray[2] = &tgcd[2]; thvarray[3] = GCD_Glue; thvarray[4] = NULL;
4733
4734 tlabel[3].text = (unichar_t *) _("Depth:");
4735 tlabel[3].text_is_1byte = true;
4736 tgcd[3].gd.label = &tlabel[3];
4737 tgcd[3].gd.pos.x = 5; tgcd[3].gd.pos.y = 31+4;
4738 tgcd[3].gd.flags = gg_enabled|gg_visible;
4739 tgcd[3].gd.popup_msg = tgcd[0].gd.popup_msg;
4740 tgcd[3].creator = GLabelCreate;
4741 thvarray[5] = &tgcd[3];
4742
4743 tgcd[4].gd.pos.x = 85; tgcd[4].gd.pos.y = 31;
4744 tgcd[4].gd.pos.width = 60;
4745 tgcd[4].gd.flags = gg_enabled|gg_visible;
4746 tgcd[4].gd.cid = CID_TeX_Depth;
4747 tgcd[4].creator = GTextFieldCreate;
4748 tgcd[4].gd.popup_msg = tgcd[0].gd.popup_msg;
4749 thvarray[6] = &tgcd[4];
4750
4751 tlabel[5].text = (unichar_t *) _("Guess");
4752 tlabel[5].text_is_1byte = true;
4753 tgcd[5].gd.label = &tlabel[5];
4754 tgcd[5].gd.flags = gg_enabled|gg_visible;
4755 tgcd[5].gd.cid = CID_TeX_DepthD;
4756 tgcd[5].gd.handle_controlevent = TeX_Default;
4757 tgcd[5].creator = GButtonCreate;
4758 tgcd[5].gd.popup_msg = tgcd[0].gd.popup_msg;
4759 thvarray[7] = &tgcd[5]; thvarray[8] = GCD_Glue; thvarray[9] = NULL;
4760
4761 tlabel[6].text = (unichar_t *) _("Italic Correction:");
4762 tlabel[6].text_is_1byte = true;
4763 tgcd[6].gd.label = &tlabel[6];
4764 tgcd[6].gd.pos.x = 5; tgcd[6].gd.pos.y = 57+4;
4765 tgcd[6].gd.flags = gg_enabled|gg_visible;
4766 tgcd[6].creator = GLabelCreate;
4767 tgcd[6].gd.popup_msg = _("The Italic correction field is used by both TeX and the MS 'MATH'\ntable. It is used when joining slanted text (italic) to upright.\nIt is the amount of extra white space needed so the slanted text\nwill not run into the upright text.");
4768 thvarray[10] = &tgcd[6];
4769
4770 tgcd[7].gd.pos.x = 85; tgcd[7].gd.pos.y = 57;
4771 tgcd[7].gd.pos.width = 60;
4772 tgcd[7].gd.flags = gg_enabled|gg_visible;
4773 tgcd[7].gd.cid = CID_TeX_Italic;
4774 tgcd[7].creator = GTextFieldCreate;
4775 tgcd[7].gd.popup_msg = tgcd[6].gd.popup_msg;
4776 thvarray[11] = &tgcd[7];
4777
4778 tlabel[8].text = (unichar_t *) _("Guess");
4779 tlabel[8].text_is_1byte = true;
4780 tgcd[8].gd.label = &tlabel[8];
4781 tgcd[8].gd.flags = gg_enabled|gg_visible;
4782 tgcd[8].gd.cid = CID_TeX_ItalicD;
4783 tgcd[8].gd.handle_controlevent = TeX_Default;
4784 tgcd[8].creator = GButtonCreate;
4785 tgcd[8].gd.popup_msg = tgcd[6].gd.popup_msg;
4786 thvarray[12] = &tgcd[8];
4787
4788 tgcd[9].gd.flags = gg_enabled|gg_visible;
4789 tgcd[9].gd.cid = CID_ItalicDevTab;
4790 tgcd[9].creator = GTextFieldCreate;
4791 tgcd[9].gd.popup_msg = _("A device table for italic correction.\nExpects a comma separated list of <pixelsize>\":\"<adjustment>\nAs \"9:-1,12:1,13:1\"");
4792 thvarray[13] = &tgcd[9]; thvarray[14] = NULL;
4793
4794 tlabel[10].text = (unichar_t *) _("Top Accent Pos:");
4795 tlabel[10].text_is_1byte = true;
4796 tgcd[10].gd.label = &tlabel[10];
4797 tgcd[10].gd.pos.x = 5; tgcd[10].gd.pos.y = 57+4;
4798 tgcd[10].gd.flags = gg_enabled|gg_visible;
4799 tgcd[10].gd.popup_msg = tgcd[9].gd.popup_msg;
4800 tgcd[10].creator = GLabelCreate;
4801 tgcd[10].gd.popup_msg = _("In the MS 'MATH' table this value specifies where (horizontally)\nan accent should be placed above the glyph. Vertical placement\nis handled by other means");
4802 thvarray[15] = &tgcd[10];
4803
4804 tgcd[11].gd.pos.x = 85; tgcd[11].gd.pos.y = 57;
4805 tgcd[11].gd.pos.width = 60;
4806 tgcd[11].gd.flags = gg_enabled|gg_visible;
4807 tgcd[11].gd.cid = CID_HorAccent;
4808 tgcd[11].creator = GTextFieldCreate;
4809 tgcd[11].gd.popup_msg = tgcd[10].gd.popup_msg;
4810 thvarray[16] = &tgcd[11];
4811
4812 tlabel[12].text = (unichar_t *) _("Guess");
4813 tlabel[12].text_is_1byte = true;
4814 tgcd[12].gd.label = &tlabel[12];
4815 tgcd[12].gd.flags = gg_enabled|gg_visible;
4816 tgcd[12].gd.cid = CID_HorAccentD;
4817 tgcd[12].gd.handle_controlevent = TeX_Default;
4818 tgcd[12].creator = GButtonCreate;
4819 tgcd[12].gd.popup_msg = tgcd[10].gd.popup_msg;
4820 thvarray[17] = &tgcd[12];
4821
4822 tgcd[13].gd.flags = gg_enabled|gg_visible;
4823 tgcd[13].gd.cid = CID_AccentDevTab;
4824 tgcd[13].creator = GTextFieldCreate;
4825 tgcd[13].gd.popup_msg = _("A device table for horizontal accent positioning.\nExpects a comma separated list of <pixelsize>\":\"<adjustment>\nAs \"9:-1,12:1,13:1\"");
4826 thvarray[18] = &tgcd[13]; thvarray[19] = NULL;
4827
4828 tlabel[14].text = (unichar_t *) _("Is Extended Shape");
4829 tlabel[14].text_is_1byte = true;
4830 tgcd[14].gd.label = &tlabel[14];
4831 tgcd[14].gd.pos.x = 5; tgcd[14].gd.pos.y = 57+4;
4832 tgcd[14].gd.flags = gg_enabled|gg_visible;
4833 tgcd[14].gd.cid = CID_IsExtended;
4834 tgcd[14].creator = GCheckBoxCreate;
4835 tgcd[14].gd.popup_msg = _("Is this an extended shape (like a tall parenthesis)?\nExtended shapes need special attention for vertical\nsuperscript placement.");
4836 thvarray[20] = &tgcd[14];
4837 thvarray[21] = thvarray[22] = GCD_ColSpan; thvarray[23] = GCD_Glue; thvarray[24] = NULL;
4838
4839 tlabel[15].text = (unichar_t *) _("Math Kerning"); /* Graphical */
4840 tlabel[15].text_is_1byte = true;
4841 tgcd[15].gd.label = &tlabel[15];
4842 tgcd[15].gd.flags = gg_enabled|gg_visible;
4843 tgcd[15].gd.handle_controlevent = CI_SubSuperPositionings;
4844 tgcd[15].creator = GButtonCreate;
4845 tgcd[15].gd.popup_msg = _("Brings up a dialog which gives fine control over\nhorizontal positioning of subscripts and superscripts\ndepending on their vertical positioning.");
4846 tbarray[0] = GCD_Glue; tbarray[1] = &tgcd[15]; tbarray[2] = GCD_Glue; tbarray[3] = NULL;
4847
4848 tbox[2].gd.flags = gg_enabled|gg_visible;
4849 tbox[2].gd.u.boxelements = tbarray;
4850 tbox[2].creator = GHBoxCreate;
4851
4852 thvarray[25] = &tbox[2];
4853 thvarray[26] = thvarray[27] = thvarray[28] = GCD_ColSpan; thvarray[29] = NULL;
4854
4855 thvarray[30] = thvarray[31] = thvarray[32] = thvarray[33] = GCD_Glue; thvarray[34] = NULL;
4856 thvarray[35] = NULL;
4857
4858 tbox[0].gd.flags = gg_enabled|gg_visible;
4859 tbox[0].gd.u.boxelements = thvarray;
4860 tbox[0].creator = GHVBoxCreate;
4861
4862 memset(&lcgcd,0,sizeof(lcgcd));
4863 memset(&lcbox,0,sizeof(lcbox));
4864 memset(&lclabel,0,sizeof(lclabel));
4865
4866 lclabel[0].text = (unichar_t *) _("Default Ligature Caret Count");
4867 lclabel[0].text_is_1byte = true;
4868 lclabel[0].text_in_resource = true;
4869 lcgcd[0].gd.cid = CID_DefLCCount;
4870 lcgcd[0].gd.label = &lclabel[0];
4871 lcgcd[0].gd.flags = gg_enabled|gg_visible;
4872 lcgcd[0].gd.popup_msg = _("Ligature caret locations are used by a text editor\nwhen it needs to draw a text edit caret inside a\nligature. This means there should be a caret between\neach ligature component so if there are n components\nthere should be n-1 caret locations.\n You may adjust the caret locations themselves in the\noutline glyph view (drag them from to origin to the\nappropriate place)." );
4873 lcgcd[0].gd.handle_controlevent = CI_DefLCChange;
4874 lcgcd[0].creator = GCheckBoxCreate;
4875 lchvarray[0][0] = &lcgcd[0];
4876 lchvarray[0][1] = lchvarray[0][2] = GCD_Glue; lchvarray[0][3] = NULL;
4877
4878 lclabel[1].text = (unichar_t *) _("Ligature Caret Count:");
4879 lclabel[1].text_is_1byte = true;
4880 lclabel[1].text_in_resource = true;
4881 lcgcd[1].gd.label = &lclabel[1];
4882 lcgcd[1].gd.flags = gg_enabled|gg_visible;
4883 lcgcd[1].gd.cid = CID_LCCountLab;
4884 lcgcd[1].gd.popup_msg = _("Ligature caret locations are used by a text editor\nwhen it needs to draw a text edit caret inside a\nligature. This means there should be a caret between\neach ligature component so if there are n components\nthere should be n-1 caret locations.\n You may adjust the caret locations themselves in the\noutline glyph view (drag them from to origin to the\nappropriate place)." );
4885 lcgcd[1].creator = GLabelCreate;
4886 lchvarray[1][0] = &lcgcd[1];
4887
4888 lcgcd[2].gd.pos.width = 50;
4889 lcgcd[2].gd.flags = gg_enabled|gg_visible;
4890 lcgcd[2].gd.cid = CID_LCCount;
4891 lcgcd[2].gd.popup_msg = _("Ligature caret locations are used by a text editor\nwhen it needs to draw a text edit caret inside a\nligature. This means there should be a caret between\neach ligature component so if there are n components\nthere should be n-1 caret locations.\n You may adjust the caret locations themselves in the\noutline glyph view (drag them from to origin to the\nappropriate place)." );
4892 lcgcd[2].creator = GNumericFieldCreate;
4893 lchvarray[1][1] = &lcgcd[2]; lchvarray[1][2] = GCD_Glue; lchvarray[1][3] = NULL;
4894
4895 lchvarray[2][0] = lchvarray[2][1] = lchvarray[2][2] = GCD_Glue;
4896 lchvarray[2][3] = lchvarray[3][0] = NULL;
4897
4898 lcbox[0].gd.flags = gg_enabled|gg_visible;
4899 lcbox[0].gd.u.boxelements = lchvarray[0];
4900 lcbox[0].creator = GHVBoxCreate;
4901
4902 memset(&vargcd,0,sizeof(vargcd));
4903 memset(&varbox,0,sizeof(varbox));
4904 memset(&varlabel,0,sizeof(varlabel));
4905
4906 for ( i=0; i<2; ++i ) {
4907 varlabel[i][0].text = (unichar_t *) _("Variant Glyphs:");
4908 varlabel[i][0].text_is_1byte = true;
4909 vargcd[i][0].gd.label = &varlabel[i][0];
4910 vargcd[i][0].gd.pos.x = 5; vargcd[i][0].gd.pos.y = 57+4;
4911 vargcd[i][0].gd.flags = gg_enabled|gg_visible;
4912 vargcd[i][0].creator = GLabelCreate;
4913 vargcd[i][0].gd.popup_msg = _("A list of the names of pre defined glyphs which represent\nbigger versions of the current glyph.");
4914 varhvarray[i][0][0] = &vargcd[i][0];
4915
4916 vargcd[i][1].gd.flags = gg_enabled|gg_visible;
4917 vargcd[i][1].gd.cid = CID_VariantList+i*100;
4918 vargcd[i][1].creator = GTextCompletionCreate;
4919 vargcd[i][1].gd.popup_msg = vargcd[i][0].gd.popup_msg;
4920 varhvarray[i][0][1] = &vargcd[i][1]; varhvarray[i][0][2] = GCD_ColSpan; varhvarray[i][0][3] = NULL;
4921
4922 varlabel[i][2].text = (unichar_t *) _("Glyph Extension Components");
4923 varlabel[i][2].text_is_1byte = true;
4924 vargcd[i][2].gd.label = &varlabel[i][2];
4925 vargcd[i][2].gd.flags = gg_enabled|gg_visible;
4926 vargcd[i][2].creator = GLabelCreate;
4927 vargcd[i][2].gd.popup_msg = _("A really big version of this glyph may be made up of the\nfollowing component glyphs. They will be stacked either\nhorizontally or vertically. Glyphs marked as Extenders may\nbe removed or repeated (to make shorter or longer versions).\nThe StartLength is the length of the flat section at the\nstart of the glyph which may be overlapped with the previous\nglyph, while the EndLength is the similar region at the end\nof the glyph. The FullLength is the full length of the glyph." );
4928 varhvarray[i][1][0] = &vargcd[i][2];
4929 varhvarray[i][1][1] = varhvarray[i][1][2] = GCD_ColSpan; varhvarray[i][1][3] = NULL;
4930
4931 /* GT: "Cor" is an abbreviation for correction */
4932 varlabel[i][3].text = (unichar_t *) _("Italic Cor:");
4933 varlabel[i][3].text_is_1byte = true;
4934 vargcd[i][3].gd.label = &varlabel[i][3];
4935 vargcd[i][3].gd.flags = gg_enabled|gg_visible;
4936 vargcd[i][3].creator = GLabelCreate;
4937 vargcd[i][3].gd.popup_msg = _("The italic correction of the composed glyph. Should be independent of glyph size");
4938 varhvarray[i][2][0] = &vargcd[i][3];
4939
4940 vargcd[i][4].gd.flags = gg_enabled|gg_visible;
4941 vargcd[i][4].gd.pos.width = 60;
4942 vargcd[i][4].gd.cid = CID_ExtItalicCor+i*100;
4943 vargcd[i][4].creator = GTextFieldCreate;
4944 vargcd[i][4].gd.popup_msg = vargcd[i][3].gd.popup_msg;
4945 varhvarray[i][2][1] = &vargcd[i][4];
4946
4947 vargcd[i][5].gd.flags = gg_enabled|gg_visible;
4948 vargcd[i][5].gd.pos.width = 60;
4949 vargcd[i][5].gd.cid = CID_ExtItalicDev+i*100;
4950 vargcd[i][5].creator = GTextFieldCreate;
4951 vargcd[i][5].gd.popup_msg = vargcd[i][3].gd.popup_msg;
4952 varhvarray[i][2][2] = &vargcd[i][5];
4953 varhvarray[i][2][3] = NULL;
4954
4955 vargcd[i][6].gd.flags = gg_enabled|gg_visible;
4956 vargcd[i][6].gd.u.matrix = &mi_extensionpart;
4957 vargcd[i][6].gd.cid = CID_ExtensionList+i*100;
4958 vargcd[i][6].creator = GMatrixEditCreate;
4959 varhvarray[i][3][0] = &vargcd[i][6];
4960 varhvarray[i][3][1] = varhvarray[i][3][2] = GCD_ColSpan; varhvarray[i][3][3] = NULL;
4961
4962 varhvarray[i][4][0] = NULL;
4963
4964 varbox[i][0].gd.flags = gg_enabled|gg_visible;
4965 varbox[i][0].gd.u.boxelements = varhvarray[i][0];
4966 varbox[i][0].creator = GHVBoxCreate;
4967 }
4968
4969 memset(&tilegcd,0,sizeof(tilegcd));
4970 memset(&tilebox,0,sizeof(tilebox));
4971 memset(&tilelabel,0,sizeof(tilelabel));
4972
4973 i=0;
4974 tilelabel[i].text = (unichar_t *) _(
4975 "If this glyph is used as a pattern to tile\n"
4976 "some other glyph then it is useful to specify\n"
4977 "the amount of whitespace surrounding the tile.\n"
4978 "Either specify a margin to extend the bounding\n"
4979 "box of the contents, or specify the bounds\n"
4980 "explicitly.");
4981 tilelabel[i].text_is_1byte = true;
4982 tilelabel[i].text_in_resource = true;
4983 tilegcd[i].gd.label = &tilelabel[i];
4984 tilegcd[i].gd.flags = gg_enabled|gg_visible;
4985 tilegcd[i++].creator = GLabelCreate;
4986 tlvarray[0] = &tilegcd[i-1];
4987
4988 tilelabel[i].text = (unichar_t *) _("Tile Margin:");
4989 tilelabel[i].text_is_1byte = true;
4990 tilelabel[i].text_in_resource = true;
4991 tilegcd[i].gd.label = &tilelabel[i];
4992 tilegcd[i].gd.flags = gg_enabled|gg_visible;
4993 tilegcd[i].gd.cid = CID_IsTileMargin;
4994 tilegcd[i++].creator = GRadioCreate;
4995 tlharray[0] = &tilegcd[i-1];
4996
4997 tilegcd[i].gd.pos.width = 60;
4998 tilegcd[i].gd.flags = gg_enabled|gg_visible;
4999 tilegcd[i].gd.cid = CID_TileMargin;
5000 tilegcd[i].gd.handle_controlevent = CI_TileMarginChange;
5001 tilegcd[i++].creator = GTextFieldCreate;
5002 tlharray[1] = &tilegcd[i-1]; tlharray[2] = GCD_Glue; tlharray[3] = NULL;
5003
5004 tilebox[2].gd.flags = gg_enabled|gg_visible;
5005 tilebox[2].gd.u.boxelements = tlharray;
5006 tilebox[2].creator = GHBoxCreate;
5007 tlvarray[1] = &tilebox[2];
5008
5009 tilelabel[i].text = (unichar_t *) _("Tile Bounding Box:");
5010 tilelabel[i].text_is_1byte = true;
5011 tilelabel[i].text_in_resource = true;
5012 tilegcd[i].gd.label = &tilelabel[i];
5013 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5014 tilegcd[i].gd.cid = CID_IsTileBBox;
5015 tilegcd[i++].creator = GRadioCreate;
5016 tlvarray[2] = &tilegcd[i-1];
5017
5018 tlhvarray[0][0] = GCD_Glue;
5019
5020 tilelabel[i].text = (unichar_t *) _(" X");
5021 tilelabel[i].text_is_1byte = true;
5022 tilegcd[i].gd.label = &tilelabel[i];
5023 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5024 tilegcd[i++].creator = GLabelCreate;
5025 tlhvarray[0][1] = &tilegcd[i-1];
5026
5027 tilelabel[i].text = (unichar_t *) _(" Y");
5028 tilelabel[i].text_is_1byte = true;
5029 tilegcd[i].gd.label = &tilelabel[i];
5030 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5031 tilegcd[i++].creator = GLabelCreate;
5032 tlhvarray[0][2] = &tilegcd[i-1]; tlhvarray[0][3] = GCD_Glue; tlhvarray[0][4] = NULL;
5033
5034 tilelabel[i].text = (unichar_t *) _("Min");
5035 tilelabel[i].text_is_1byte = true;
5036 tilegcd[i].gd.label = &tilelabel[i];
5037 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5038 tilegcd[i++].creator = GLabelCreate;
5039 tlhvarray[1][0] = &tilegcd[i-1];
5040
5041 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5042 tilegcd[i].gd.cid = CID_TileBBoxMinX;
5043 tilegcd[i++].creator = GTextFieldCreate;
5044 tlhvarray[1][1] = &tilegcd[i-1];
5045
5046 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5047 tilegcd[i].gd.cid = CID_TileBBoxMinY;
5048 tilegcd[i++].creator = GTextFieldCreate;
5049 tlhvarray[1][2] = &tilegcd[i-1]; tlhvarray[1][3] = GCD_Glue; tlhvarray[1][4] = NULL;
5050
5051 tilelabel[i].text = (unichar_t *) _("Max");
5052 tilelabel[i].text_is_1byte = true;
5053 tilegcd[i].gd.label = &tilelabel[i];
5054 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5055 tilegcd[i++].creator = GLabelCreate;
5056 tlhvarray[2][0] = &tilegcd[i-1];
5057
5058 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5059 tilegcd[i].gd.cid = CID_TileBBoxMaxX;
5060 tilegcd[i++].creator = GTextFieldCreate;
5061 tlhvarray[2][1] = &tilegcd[i-1];
5062
5063 tilegcd[i].gd.flags = gg_enabled|gg_visible;
5064 tilegcd[i].gd.cid = CID_TileBBoxMaxY;
5065 tilegcd[i++].creator = GTextFieldCreate;
5066 tlhvarray[2][2] = &tilegcd[i-1]; tlhvarray[2][3] = GCD_Glue; tlhvarray[2][4] = NULL;
5067 tlhvarray[3][0] = NULL;
5068
5069 tilebox[3].gd.flags = gg_enabled|gg_visible;
5070 tilebox[3].gd.u.boxelements = tlhvarray[0];
5071 tilebox[3].creator = GHVBoxCreate;
5072 tlvarray[3] = &tilebox[3]; tlvarray[4] = GCD_Glue; tlvarray[5] = NULL;
5073
5074 tilebox[0].gd.flags = gg_enabled|gg_visible;
5075 tilebox[0].gd.u.boxelements = tlvarray;
5076 tilebox[0].creator = GVBoxCreate;
5077
5078 memset(&mgcd,0,sizeof(mgcd));
5079 memset(&mbox,0,sizeof(mbox));
5080 memset(&mlabel,0,sizeof(mlabel));
5081 memset(&aspects,'\0',sizeof(aspects));
5082
5083 i = 0;
5084 aspects[i].text = (unichar_t *) _("Unicode");
5085 aspects[i].text_is_1byte = true;
5086 aspects[i].selected = true;
5087 aspects[i++].gcd = ubox;
5088
5089 aspects[i].text = (unichar_t *) _("Comment");
5090 aspects[i].text_is_1byte = true;
5091 aspects[i++].gcd = cbox;
5092
5093 aspects[i].text = (unichar_t *) _("Positionings");
5094 aspects[i].text_is_1byte = true;
5095 aspects[i++].gcd = pstbox[pst_position-1];
5096
5097 aspects[i].text = (unichar_t *) _("Pairwise Pos");
5098 aspects[i].text_is_1byte = true;
5099 aspects[i++].gcd = pstbox[pst_pair-1];
5100
5101 aspects[i].text = (unichar_t *) _("Substitutions");
5102 aspects[i].text_is_1byte = true;
5103 aspects[i++].gcd = psgcd[2];
5104
5105 aspects[i].text = (unichar_t *) _("Alt Subs");
5106 aspects[i].text_is_1byte = true;
5107 aspects[i++].gcd = psgcd[3];
5108
5109 aspects[i].text = (unichar_t *) _("Mult Subs");
5110 aspects[i].text_is_1byte = true;
5111 aspects[i++].gcd = psgcd[4];
5112
5113 aspects[i].text = (unichar_t *) _("Ligatures");
5114 aspects[i].text_is_1byte = true;
5115 aspects[i++].gcd = psgcd[5];
5116
5117 ci->lc_aspect = i;
5118 aspects[i].text = (unichar_t *) _("Lig. Carets");
5119 aspects[i].text_is_1byte = true;
5120 aspects[i].nesting = 1;
5121 aspects[i++].gcd = lcbox;
5122
5123 aspects[i].text = (unichar_t *) _("Components");
5124 aspects[i].text_is_1byte = true;
5125 aspects[i++].gcd = cobox;
5126
5127 aspects[i].text = (unichar_t *) _("Counters");
5128 aspects[i].text_is_1byte = true;
5129 aspects[i++].gcd = pstbox[6];
5130
5131 aspects[i].text = (unichar_t *) U_("ΤεΧ & Math"); /* TeX */
5132 aspects[i].text_is_1byte = true;
5133 aspects[i++].gcd = tbox;
5134
5135 ci->vert_aspect = i;
5136 /* GT: "Vert." is an abbreviation for Vertical */
5137 aspects[i].text = (unichar_t *) U_("Vert. Variants");
5138 aspects[i].text_is_1byte = true;
5139 aspects[i].nesting = 1;
5140 aspects[i++].gcd = varbox[0];
5141
5142 /* GT: "Horiz." is an abbreviation for Horizontal */
5143 aspects[i].text = (unichar_t *) U_("Horiz. Variants");
5144 aspects[i].text_is_1byte = true;
5145 aspects[i].nesting = 1;
5146 aspects[i++].gcd = varbox[1];
5147
5148 if ( sc->parent->multilayer ) {
5149 aspects[i].text = (unichar_t *) U_("Tile Size");
5150 aspects[i].text_is_1byte = true;
5151 aspects[i++].gcd = tilebox;
5152 }
5153
5154 if ( last_gi_aspect<i )
5155 aspects[last_gi_aspect].selected = true;
5156
5157 mgcd[0].gd.pos.x = 4; mgcd[0].gd.pos.y = 6;
5158 mgcd[0].gd.u.tabs = aspects;
5159 mgcd[0].gd.flags = gg_visible | gg_enabled | gg_tabset_vert;
5160 mgcd[0].gd.cid = CID_Tabs;
5161 mgcd[0].gd.handle_controlevent = CI_AspectChange;
5162 mgcd[0].creator = GTabSetCreate;
5163 mvarray[0] = &mgcd[0]; mvarray[1] = NULL;
5164
5165 mgcd[1].gd.pos.x = 40; mgcd[1].gd.pos.y = mgcd[0].gd.pos.y+mgcd[0].gd.pos.height+3;
5166 mgcd[1].gd.flags = gg_visible | gg_enabled ;
5167 mlabel[1].text = (unichar_t *) _("< _Prev");
5168 mlabel[1].text_is_1byte = true;
5169 mlabel[1].text_in_resource = true;
5170 mgcd[1].gd.mnemonic = 'P';
5171 mgcd[1].gd.label = &mlabel[1];
5172 mgcd[1].gd.handle_controlevent = CI_NextPrev;
5173 mgcd[1].gd.cid = -1;
5174 mharray1[0] = GCD_Glue; mharray1[1] = &mgcd[1]; mharray1[2] = GCD_Glue;
5175 mgcd[1].creator = GButtonCreate;
5176
5177 mgcd[2].gd.pos.x = -40; mgcd[2].gd.pos.y = mgcd[1].gd.pos.y;
5178 mgcd[2].gd.flags = gg_visible | gg_enabled ;
5179 mlabel[2].text = (unichar_t *) _("_Next >");
5180 mlabel[2].text_is_1byte = true;
5181 mlabel[2].text_in_resource = true;
5182 mgcd[2].gd.label = &mlabel[2];
5183 mgcd[2].gd.mnemonic = 'N';
5184 mgcd[2].gd.handle_controlevent = CI_NextPrev;
5185 mgcd[2].gd.cid = 1;
5186 mharray1[3] = GCD_Glue; mharray1[4] = &mgcd[2]; mharray1[5] = GCD_Glue; mharray1[6] = NULL;
5187 mgcd[2].creator = GButtonCreate;
5188
5189 mbox[2].gd.flags = gg_enabled|gg_visible;
5190 mbox[2].gd.u.boxelements = mharray1;
5191 mbox[2].creator = GHBoxCreate;
5192 mvarray[2] = &mbox[2]; mvarray[3] = NULL;
5193
5194 mgcd[3].gd.pos.x = 25-3; mgcd[3].gd.pos.y = CI_Height-31-3;
5195 mgcd[3].gd.flags = gg_visible | gg_enabled | gg_but_default;
5196 mlabel[3].text = (unichar_t *) _("_OK");
5197 mlabel[3].text_is_1byte = true;
5198 mlabel[3].text_in_resource = true;
5199 mgcd[3].gd.mnemonic = 'O';
5200 mgcd[3].gd.label = &mlabel[3];
5201 mgcd[3].gd.handle_controlevent = CI_OK;
5202 mharray2[0] = GCD_Glue; mharray2[1] = &mgcd[3]; mharray2[2] = GCD_Glue; mharray2[3] = GCD_Glue;
5203 mgcd[3].creator = GButtonCreate;
5204
5205 mgcd[4].gd.pos.x = -25; mgcd[4].gd.pos.y = mgcd[3].gd.pos.y+3;
5206 mgcd[4].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
5207 mlabel[4].text = (unichar_t *) _("_Cancel");
5208 mlabel[4].text_is_1byte = true;
5209 mlabel[4].text_in_resource = true;
5210 mgcd[4].gd.label = &mlabel[4];
5211 mgcd[4].gd.handle_controlevent = CI_Cancel;
5212 mgcd[4].gd.cid = CID_Cancel;
5213 mharray2[4] = GCD_Glue; mharray2[5] = &mgcd[4]; mharray2[6] = GCD_Glue; mharray2[7] = NULL;
5214 mgcd[4].creator = GButtonCreate;
5215
5216 mbox[3].gd.flags = gg_enabled|gg_visible;
5217 mbox[3].gd.u.boxelements = mharray2;
5218 mbox[3].creator = GHBoxCreate;
5219 mvarray[4] = &mbox[3]; mvarray[5] = NULL;
5220 mvarray[6] = NULL;
5221
5222 mbox[0].gd.pos.x = mbox[0].gd.pos.y = 2;
5223 mbox[0].gd.flags = gg_enabled|gg_visible;
5224 mbox[0].gd.u.boxelements = mvarray;
5225 mbox[0].creator = GHVGroupCreate;
5226
5227 GGadgetsCreate(ci->gw,mbox);
5228
5229 GHVBoxSetExpandableRow(mbox[0].ret,0);
5230 GHVBoxSetExpandableCol(mbox[2].ret,gb_expandgluesame);
5231 GHVBoxSetExpandableCol(mbox[3].ret,gb_expandgluesame);
5232
5233 GHVBoxSetExpandableRow(ubox[0].ret,gb_expandglue);
5234 GHVBoxSetExpandableCol(ubox[0].ret,1);
5235 GHVBoxSetExpandableCol(ubox[2].ret,gb_expandgluesame);
5236
5237 GHVBoxSetExpandableRow(cbox[0].ret,1);
5238 GHVBoxSetExpandableCol(cbox[2].ret,gb_expandglue);
5239
5240 for ( i=0; i<6; ++i ) {
5241 GGadget *g = GWidgetGetControl(ci->gw,CID_List+i*100);
5242 GMatrixEditSetNewText(g, newstrings[i]);
5243 if ( i==pst_substitution-1 || i==pst_pair-1 )
5244 GMatrixEditSetColumnCompletion(g,1,CI_GlyphNameCompletion);
5245 else if ( i==pst_alternate-1 || i==pst_multiple-1 ||
5246 i==pst_ligature-1)
5247 GMatrixEditSetColumnCompletion(g,1,CI_GlyphListCompletion);
5248 }
5249 GHVBoxSetExpandableRow(pstbox[pst_pair-1][0].ret,0);
5250 for ( i=0; i<6; ++i )
5251 GMatrixEditSetMouseMoveReporter(psgcd[i][0].ret,CI_SubsPopupPrepare);
5252 GMatrixEditSetMouseMoveReporter(psgcd[pst_pair-1][0].ret,CI_KerningPopupPrepare);
5253 for ( i=6; i<7; ++i ) {
5254 GHVBoxSetExpandableRow(pstbox[i][0].ret,0);
5255 GHVBoxSetExpandableCol(pstbox[i][2].ret,gb_expandgluesame);
5256 }
5257
5258 GHVBoxSetExpandableRow(cobox[0].ret,gb_expandglue);
5259 GHVBoxSetExpandableRow(tbox[0].ret,gb_expandglue);
5260 GHVBoxSetExpandableCol(tbox[0].ret,gb_expandglue);
5261 GHVBoxSetPadding(tbox[0].ret,6,4);
5262 GHVBoxSetExpandableCol(tbox[2].ret,gb_expandglue);
5263
5264 GHVBoxSetExpandableRow(lcbox[0].ret,gb_expandglue);
5265 GHVBoxSetExpandableCol(lcbox[0].ret,gb_expandglue);
5266
5267 GHVBoxSetExpandableRow(varbox[0][0].ret,3);
5268 GHVBoxSetExpandableRow(varbox[1][0].ret,3);
5269
5270 if ( sc->parent->multilayer ) {
5271 GHVBoxSetExpandableRow(tilebox[0].ret,gb_expandglue);
5272 GHVBoxSetExpandableCol(tilebox[2].ret,gb_expandglue);
5273 GHVBoxSetExpandableCol(tilebox[3].ret,gb_expandglue);
5274 }
5275
5276 GHVBoxFitWindow(mbox[0].ret);
5277
5278 if ( font==NULL ) {
5279 memset(&rq,0,sizeof(rq));
5280 rq.utf8_family_name = MONO_UI_FAMILIES;
5281 rq.point_size = 12;
5282 rq.weight = 400;
5283 font = GDrawInstanciateFont(ci->gw,&rq);
5284 font = GResourceFindFont("GlyphInfo.Font",font);
5285 }
5286 for ( i=0; i<5; ++i )
5287 GGadgetSetFont(psgcd[i][0].ret,font);
5288 for ( i=0; i<2; ++i ) {
5289 GCompletionFieldSetCompletion(vargcd[i][1].ret,CI_GlyphNameCompletion);
5290 GCompletionFieldSetCompletionMode(vargcd[i][1].ret,true);
5291 GMatrixEditSetColumnCompletion(vargcd[i][6].ret,0,CI_GlyphNameCompletion);
5292 GMatrixEditSetMouseMoveReporter(vargcd[i][6].ret,CI_ConstructionPopupPrepare);
5293 }
5294
5295 CIFillup(ci);
5296
5297 GWidgetHidePalettes();
5298 GDrawSetVisible(ci->gw,true);
5299 }
5300
CharInfoDestroy(CharInfo * ci)5301 void CharInfoDestroy(CharInfo *ci) {
5302 GDrawDestroyWindow(ci->gw);
5303 }
5304
5305 struct sel_dlg {
5306 int done;
5307 int ok;
5308 FontView *fv;
5309 };
5310
FVParseSelectByPST(FontView * fv,struct lookup_subtable * sub,int search_type)5311 int FVParseSelectByPST(FontView *fv,struct lookup_subtable *sub,
5312 int search_type) {
5313 int first;
5314
5315 first = FVBParseSelectByPST((FontViewBase *) fv,sub,search_type);
5316
5317 if ( first!=-1 )
5318 FVScrollToChar(fv,first);
5319 else if ( !no_windowing_ui )
5320 ff_post_notice(_("Select By ATT..."),_("No glyphs matched"));
5321 if ( !no_windowing_ui )
5322 GDrawRequestExpose(fv->v,NULL,false);
5323 return( true );
5324 }
5325
SelectStuff(struct sel_dlg * sld,GWindow gw)5326 static int SelectStuff(struct sel_dlg *sld,GWindow gw) {
5327 struct lookup_subtable *sub = GGadgetGetListItemSelected(GWidgetGetControl(gw,CID_PST))->userdata;
5328 int search_type = GGadgetIsChecked(GWidgetGetControl(gw,CID_SelectResults)) ? 1 :
5329 GGadgetIsChecked(GWidgetGetControl(gw,CID_MergeResults)) ? 2 :
5330 3;
5331 return( FVParseSelectByPST(sld->fv, sub, search_type));
5332 }
5333
selpst_e_h(GWindow gw,GEvent * event)5334 static int selpst_e_h(GWindow gw, GEvent *event) {
5335 struct sel_dlg *sld = GDrawGetUserData(gw);
5336
5337 if ( event->type==et_close ) {
5338 sld->done = true;
5339 sld->ok = false;
5340 } else if ( event->type==et_char ) {
5341 if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
5342 help("ui/dialogs/selectbyatt.html", NULL);
5343 return( true );
5344 }
5345 return( false );
5346 } else if ( event->type==et_controlevent && event->u.control.subtype == et_buttonactivate ) {
5347 sld->ok = GGadgetGetCid(event->u.control.g);
5348 if ( !sld->ok || SelectStuff(sld,gw))
5349 sld->done = true;
5350 }
5351 return( true );
5352 }
5353
FVSelectByPST(FontView * fv)5354 void FVSelectByPST(FontView *fv) {
5355 struct sel_dlg sld;
5356 GWindow gw;
5357 GRect pos;
5358 GWindowAttrs wattrs;
5359 GGadgetCreateData gcd[14];
5360 GTextInfo label[14];
5361 GGadgetCreateData *varray[20], *harray[8];
5362 int i,j,isgpos, cnt;
5363 OTLookup *otl;
5364 struct lookup_subtable *sub;
5365 GTextInfo *ti;
5366 SplineFont *sf = fv->b.sf;
5367
5368 if ( sf->cidmaster ) sf = sf->cidmaster;
5369 ti = NULL;
5370 for ( j=0; j<2; ++j ) {
5371 cnt = 0;
5372 for ( isgpos=0; isgpos<2; ++isgpos ) {
5373 for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups ; otl!=NULL; otl=otl->next ) {
5374 if ( otl->lookup_type== gsub_single ||
5375 otl->lookup_type== gsub_multiple ||
5376 otl->lookup_type== gsub_alternate ||
5377 otl->lookup_type== gsub_ligature ||
5378 otl->lookup_type== gpos_single ||
5379 otl->lookup_type== gpos_pair ||
5380 otl->lookup_type== gpos_cursive ||
5381 otl->lookup_type== gpos_mark2base ||
5382 otl->lookup_type== gpos_mark2ligature ||
5383 otl->lookup_type== gpos_mark2mark )
5384 for ( sub=otl->subtables; sub!=NULL; sub=sub->next )
5385 if ( sub->kc==NULL ) {
5386 if ( ti!=NULL ) {
5387 ti[cnt].text = (unichar_t *) copy(sub->subtable_name);
5388 ti[cnt].text_is_1byte = true;
5389 ti[cnt].userdata = sub;
5390 ti[cnt].selected = cnt==0;
5391 }
5392 ++cnt;
5393 }
5394 }
5395 }
5396 if ( cnt==0 ) {
5397 ff_post_notice(_("No Lookups"), _("No applicable lookup subtables"));
5398 return;
5399 }
5400 if ( ti==NULL )
5401 ti = calloc(cnt+1,sizeof(GTextInfo));
5402 }
5403
5404 CharInfoInit();
5405
5406 memset(&sld,0,sizeof(sld));
5407 sld.fv = fv;
5408 memset(&wattrs,0,sizeof(wattrs));
5409 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
5410 wattrs.event_masks = ~(1<<et_charup);
5411 wattrs.restrict_input_to_me = 1;
5412 wattrs.undercursor = 1;
5413 wattrs.cursor = ct_pointer;
5414 wattrs.utf8_window_title = _("Select By Lookup Subtable");
5415 wattrs.is_dlg = true;
5416 pos.x = pos.y = 0;
5417 pos.width = GGadgetScale(GDrawPointsToPixels(NULL,160));
5418 pos.height = GDrawPointsToPixels(NULL,204);
5419 gw = GDrawCreateTopWindow(NULL,&pos,selpst_e_h,&sld,&wattrs);
5420
5421 memset(&gcd,0,sizeof(gcd));
5422 memset(&label,0,sizeof(label));
5423
5424 i=j=0;
5425
5426 label[i].text = (unichar_t *) _("Select Glyphs in lookup subtable");
5427 label[i].text_is_1byte = true;
5428 gcd[i].gd.label = &label[i];
5429 gcd[i].gd.flags = gg_enabled|gg_visible;
5430 gcd[i++].creator = GLabelCreate;
5431 varray[j++] = &gcd[i-1]; varray[j++] = NULL;
5432
5433 gcd[i].gd.label = &ti[0];
5434 gcd[i].gd.pos.x = 10; gcd[i].gd.pos.y = 5+4;
5435 gcd[i].gd.flags = gg_enabled|gg_visible/*|gg_list_exactlyone*/;
5436 gcd[i].gd.u.list = ti;
5437 gcd[i].gd.cid = CID_PST;
5438 gcd[i++].creator = GListButtonCreate;
5439 varray[j++] = &gcd[i-1]; varray[j++] = NULL;
5440 varray[j++] = GCD_Glue; varray[j++] = NULL;
5441
5442 label[i].text = (unichar_t *) _("Select Results");
5443 label[i].text_is_1byte = true;
5444 gcd[i].gd.label = &label[i];
5445 gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+26;
5446 gcd[i].gd.flags = gg_enabled|gg_visible|gg_cb_on;
5447 gcd[i].gd.popup_msg = _("Set the selection of the font view to the glyphs\nfound by this search");
5448 gcd[i].gd.cid = CID_SelectResults;
5449 gcd[i++].creator = GRadioCreate;
5450 varray[j++] = &gcd[i-1]; varray[j++] = NULL;
5451
5452 label[i].text = (unichar_t *) _("Merge Results");
5453 label[i].text_is_1byte = true;
5454 gcd[i].gd.label = &label[i];
5455 gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+15;
5456 gcd[i].gd.flags = gg_enabled|gg_visible;
5457 gcd[i].gd.popup_msg = _("Expand the selection of the font view to include\nall the glyphs found by this search");
5458 gcd[i].gd.cid = CID_MergeResults;
5459 gcd[i++].creator = GRadioCreate;
5460 varray[j++] = &gcd[i-1]; varray[j++] = NULL;
5461
5462 label[i].text = (unichar_t *) _("Restrict Selection");
5463 label[i].text_is_1byte = true;
5464 gcd[i].gd.label = &label[i];
5465 gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+15;
5466 gcd[i].gd.flags = gg_enabled|gg_visible;
5467 gcd[i].gd.popup_msg = _("Only search the selected glyphs, and unselect\nany characters which do not match this search");
5468 gcd[i].gd.cid = CID_RestrictSelection;
5469 gcd[i++].creator = GRadioCreate;
5470 varray[j++] = &gcd[i-1]; varray[j++] = NULL;
5471 varray[j++] = GCD_Glue; varray[j++] = NULL;
5472
5473 gcd[i].gd.pos.x = 15-3; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+22;
5474 gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
5475 label[i].text = (unichar_t *) _("_OK");
5476 label[i].text_is_1byte = true;
5477 label[i].text_in_resource = true;
5478 gcd[i].gd.mnemonic = 'O';
5479 gcd[i].gd.label = &label[i];
5480 gcd[i].gd.cid = true;
5481 gcd[i++].creator = GButtonCreate;
5482 harray[0] = GCD_Glue; harray[1] = &gcd[i-1]; harray[2] = GCD_Glue;
5483
5484 gcd[i].gd.pos.x = -15; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+3;
5485 gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
5486 label[i].text = (unichar_t *) _("_Cancel");
5487 label[i].text_is_1byte = true;
5488 label[i].text_in_resource = true;
5489 gcd[i].gd.label = &label[i];
5490 gcd[i].gd.mnemonic = 'C';
5491 gcd[i].gd.cid = false;
5492 gcd[i++].creator = GButtonCreate;
5493 harray[3] = GCD_Glue; harray[4] = &gcd[i-1]; harray[5] = GCD_Glue;
5494 harray[6] = NULL;
5495
5496 gcd[i].gd.flags = gg_enabled|gg_visible;
5497 gcd[i].gd.u.boxelements = harray;
5498 gcd[i].creator = GHBoxCreate;
5499 varray[j++] = &gcd[i++]; varray[j++] = NULL; varray[j++] = NULL;
5500
5501 gcd[i].gd.pos.x = gcd[i].gd.pos.y = 2;
5502 gcd[i].gd.flags = gg_enabled|gg_visible;
5503 gcd[i].gd.u.boxelements = varray;
5504 gcd[i].creator = GHVGroupCreate;
5505
5506 GGadgetsCreate(gw,gcd+i);
5507 GTextInfoListFree(ti);
5508 GHVBoxSetExpandableRow(gcd[i].ret,gb_expandglue);
5509 GHVBoxSetExpandableCol(gcd[i-1].ret,gb_expandgluesame);
5510 GHVBoxFitWindow(gcd[i].ret);
5511
5512 GDrawSetVisible(gw,true);
5513 while ( !sld.done )
5514 GDrawProcessOneEvent(NULL);
5515 if ( sld.ok ) {
5516 }
5517 GDrawDestroyWindow(gw);
5518 }
5519
CharInfoInit(void)5520 void CharInfoInit(void) {
5521 static GTextInfo *lists[] = { glyphclasses, std_colors, truefalse, NULL };
5522 static int done = 0;
5523 int i, j;
5524 static char **cnames[] = { newstrings, NULL };
5525 static struct col_init *col_inits[] = { extensionpart, altuniinfo,
5526 devtabci,
5527 simplesubsci, ligatureci, altsubsci, multsubsci, simpleposci,
5528 pairposci, NULL };
5529
5530 if ( done )
5531 return;
5532 done = true;
5533 for ( i=0; lists[i]!=NULL; ++i )
5534 for ( j=0; lists[i][j].text!=NULL; ++j )
5535 lists[i][j].text = (unichar_t *) S_((char *) lists[i][j].text);
5536 for ( i=0; cnames[i]!=NULL; ++i )
5537 for ( j=0; cnames[i][j]!=NULL; ++j )
5538 cnames[i][j] = _(cnames[i][j]);
5539 for ( i=0; col_inits[i]!=NULL; ++i )
5540 for ( j=0; col_inits[i][j].title!=NULL; ++j )
5541 col_inits[i][j].title=_(col_inits[i][j].title);
5542 }
5543