Line data Source code
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 : #include "fontforgeui.h"
29 : #include "fvcomposite.h"
30 : #include "fvfonts.h"
31 : #include "lookups.h"
32 : #include "psfont.h"
33 : #include "splinefill.h"
34 : #include "splineutil.h"
35 : #include "tottfgpos.h"
36 : #include <ustring.h>
37 : #include <gkeysym.h>
38 : #include <utype.h>
39 : #include <unistd.h>
40 :
41 :
42 : GTextInfo sizes[] = {
43 : { (unichar_t *) "24", NULL, 0, 0, (void *) 24, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
44 : { (unichar_t *) "36", NULL, 0, 0, (void *) 36, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
45 : { (unichar_t *) "48", NULL, 0, 0, (void *) 48, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
46 : { (unichar_t *) "72", NULL, 0, 0, (void *) 72, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
47 : { (unichar_t *) "96", NULL, 0, 0, (void *) 96, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
48 : { (unichar_t *) "200", NULL, 0, 0, (void *) 200, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
49 : GTEXTINFO_EMPTY
50 : };
51 : enum sortby { sb_first, sb_second, sb_kern };
52 : GTextInfo sortby[] = {
53 : { (unichar_t *) N_("First Char"), NULL, 0, 0, (void *) sb_first, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
54 : { (unichar_t *) N_("Second Char"), NULL, 0, 0, (void *) sb_second, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
55 : { (unichar_t *) N_("Kern Size"), NULL, 0, 0, (void *) sb_kern, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
56 : GTEXTINFO_EMPTY
57 : };
58 :
59 0 : void SFShowLigatures(SplineFont *sf,SplineChar *searchfor) {
60 : int i, cnt;
61 0 : char **choices=NULL;
62 0 : int *where=NULL;
63 : SplineChar *sc, *sc2;
64 : char *pt, *line;
65 : char *start, *end, ch;
66 : PST *pst;
67 :
68 : while ( 1 ) {
69 0 : for ( i=cnt=0; i<sf->glyphcnt; ++i ) {
70 0 : if ( (sc=sf->glyphs[i])!=NULL && SCDrawsSomething(sc) ) {
71 0 : for ( pst=sc->possub; pst!=NULL; pst=pst->next )
72 0 : if ( pst->type==pst_ligature &&
73 0 : (searchfor==NULL || PSTContains(pst->u.lig.components,searchfor->name))) {
74 0 : if ( choices!=NULL ) {
75 0 : line = pt = malloc((strlen(sc->name)+13+3*strlen(pst->u.lig.components)));
76 0 : strcpy(pt,sc->name);
77 0 : pt += strlen(pt);
78 0 : if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 ) {
79 0 : *pt++='(';
80 0 : pt = utf8_idpb(pt,sc->unicodeenc,0);
81 0 : *pt++=')';
82 : }
83 : /* *pt++ = 0x21d0;*/ /* left arrow */
84 0 : strcpy(pt," ⇐ "); pt += strlen(pt);
85 0 : for ( start= pst->u.lig.components; ; start=end ) {
86 0 : while ( *start==' ' ) ++start;
87 0 : if ( *start=='\0' )
88 0 : break;
89 0 : for ( end=start+1; *end!='\0' && *end!=' '; ++end );
90 0 : ch = *end;
91 0 : *end = '\0';
92 0 : strcpy( pt,start );
93 0 : pt += strlen(pt);
94 0 : sc2 = SFGetChar(sf,-1,start);
95 0 : *end = ch;
96 0 : if ( sc2!=NULL && sc2->unicodeenc!=-1 && sc2->unicodeenc<0x10000 ) {
97 0 : *pt++='(';
98 0 : *pt++ = sc2->unicodeenc;
99 0 : *pt++=')';
100 : }
101 0 : *pt++ = ' ';
102 0 : }
103 0 : pt[-1] = '\0';
104 0 : choices[cnt] = line;
105 0 : where[cnt] = i;
106 : }
107 0 : ++cnt;
108 : }
109 : }
110 : }
111 0 : if ( choices!=NULL )
112 0 : break;
113 0 : choices = malloc((cnt+2)*sizeof(unichar_t *));
114 0 : where = malloc((cnt+1)*sizeof(int));
115 0 : if ( cnt==0 ) {
116 0 : choices[0] = copy("<No Ligatures>");
117 0 : where[0] = -1;
118 0 : choices[1] = NULL;
119 0 : break;
120 : }
121 0 : }
122 0 : choices[cnt] = NULL;
123 0 : i = gwwv_choose(_("Ligatures"),(const char **) choices,cnt,0,_("Select a ligature to view"));
124 0 : if ( i!=-1 && where[i]!=-1 )
125 0 : CharViewCreate(sf->glyphs[where[i]],(FontView *) sf->fv,-1);
126 0 : free(where);
127 0 : for ( i=0; i<cnt; ++i )
128 0 : free(choices[i]);
129 0 : free(choices);
130 0 : }
131 :
132 : struct kerns {
133 : SplineChar *first;
134 : SplineChar *second;
135 : int newoff, newyoff;
136 : unsigned int r2l: 1;
137 : KernPair *kp;
138 : AnchorClass *ac;
139 : };
140 :
141 : typedef struct kpdata {
142 : GWindow gw,v;
143 : int vwidth;
144 : SplineFont *sf;
145 : SplineChar *sc; /* If set then restrict to kerns of this char */
146 : /* in either position */
147 : AnchorClass *ac; /* If set then don't do kerns, but look for */
148 : /* anchor combos with this class. If -1 */
149 : /* then all anchor combos with any class */
150 : struct kerns *kerns; /* All the kerns we care about */
151 : int layer;
152 : int kcnt, firstcnt;
153 : BDFFont *bdf;
154 : int header_height;
155 : int sb_width;
156 : GFont *font;
157 : int fh, as;
158 : int uh, wh, off_top, selected, last_index, vpad;
159 : int pressed_x, old_val;
160 : unsigned int done:1;
161 : unsigned int first:1;
162 : unsigned int pressed:1;
163 : unsigned int movecursor:1;
164 : } KPData;
165 :
166 : #define CID_Size 1001
167 : #define CID_SortBy 1002
168 : #define CID_ScrollBar 1003
169 : #define CID_OK 1004
170 : #define CID_Cancel 1005
171 :
172 0 : static int firstcmpr(const void *_k1, const void *_k2) {
173 0 : const struct kerns *k1 = _k1, *k2 = _k2;
174 :
175 0 : if ( k1->first==k2->first ) /* If same first char, use second char as tie breaker */
176 0 : return( k1->second->unicodeenc-k2->second->unicodeenc );
177 :
178 0 : return( k1->first->unicodeenc-k2->first->unicodeenc );
179 : }
180 :
181 0 : static int secondcmpr(const void *_k1, const void *_k2) {
182 0 : const struct kerns *k1 = _k1, *k2 = _k2;
183 :
184 0 : if ( k1->second==k2->second ) /* If same second char, use first char as tie breaker */
185 0 : return( k1->first->unicodeenc-k2->first->unicodeenc );
186 :
187 0 : return( k1->second->unicodeenc-k2->second->unicodeenc );
188 : }
189 :
190 0 : static int offcmpr(const void *_k1, const void *_k2) {
191 0 : const struct kerns *k1 = _k1, *k2 = _k2;
192 : int off1, off2;
193 :
194 0 : if ( (off1=k1->newoff)<0 ) off1 = -off1;
195 0 : if ( (off2=k2->newoff)<0 ) off2 = -off2;
196 :
197 0 : if ( off1!=off2 ) /* If same offset, use first char as tie breaker */
198 0 : return( off1-off2 );
199 :
200 0 : if ( k1->first!=k2->first ) /* If same first char, use second char as tie breaker */
201 0 : return( k1->first->unicodeenc-k2->first->unicodeenc );
202 :
203 0 : return( k1->second->unicodeenc-k2->second->unicodeenc );
204 : }
205 :
206 0 : static void KPSortEm(KPData *kpd,enum sortby sort_func) {
207 : int oldenc;
208 :
209 0 : if ( sort_func==sb_first || sort_func==sb_second ) {
210 0 : if ( kpd->sc!=NULL ) {
211 0 : oldenc = kpd->sc->unicodeenc;
212 0 : kpd->sc->unicodeenc = -1;
213 : }
214 0 : qsort(kpd->kerns,kpd->kcnt,sizeof(struct kerns),
215 : sort_func==sb_first ? firstcmpr : secondcmpr );
216 0 : if ( kpd->sc!=NULL )
217 0 : kpd->sc->unicodeenc = oldenc;
218 : } else
219 0 : qsort(kpd->kerns,kpd->kcnt,sizeof(struct kerns), offcmpr );
220 :
221 0 : if ( sort_func==sb_first ) {
222 0 : int cnt=1, i;
223 0 : for ( i=1; i<kpd->kcnt; ++i ) {
224 0 : if ( kpd->kerns[i].first!=kpd->kerns[i-1].first )
225 0 : ++cnt;
226 : }
227 0 : kpd->firstcnt = cnt;
228 : }
229 0 : }
230 :
231 0 : static void CheckLeftRight(struct kerns *k) {
232 : /* flag any hebrew/arabic entries */
233 :
234 : /* Figure that there won't be any mixed orientation kerns (no latin "A" with hebrew "Alef" kern) */
235 : /* but there might be some hebrew/arabic ligatures or something that */
236 : /* we don't recognize as right-to-left (ie. not in unicode) */
237 0 : if ( SCRightToLeft(k->first) || SCRightToLeft(k->second) )
238 0 : k->r2l = true;
239 : else
240 0 : k->r2l = false;
241 0 : }
242 :
243 0 : static void KPBuildKernList(KPData *kpd) {
244 : int i, cnt;
245 : KernPair *kp;
246 :
247 0 : if ( kpd->sc!=NULL ) {
248 : while ( 1 ) {
249 0 : for ( cnt=0, kp=kpd->sc->kerns; kp!=NULL; kp=kp->next ) {
250 0 : if ( kpd->kerns!=NULL ) {
251 0 : kpd->kerns[cnt].first = kpd->sc;
252 0 : kpd->kerns[cnt].second = kp->sc;
253 0 : kpd->kerns[cnt].newoff = kp->off;
254 0 : kpd->kerns[cnt].newyoff = 0;
255 0 : kpd->kerns[cnt].kp = kp;
256 0 : kpd->kerns[cnt].ac = NULL;
257 0 : CheckLeftRight(&kpd->kerns[cnt]);
258 : }
259 0 : ++cnt;
260 : }
261 0 : for ( i=0; i<kpd->sf->glyphcnt; ++i ) if ( kpd->sf->glyphs[i]!=NULL ) {
262 0 : for ( kp = kpd->sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
263 0 : if ( kp->sc == kpd->sc ) {
264 0 : if ( kpd->kerns!=NULL ) {
265 0 : kpd->kerns[cnt].first = kpd->sf->glyphs[i];
266 0 : kpd->kerns[cnt].second = kp->sc;
267 0 : kpd->kerns[cnt].newoff = kp->off;
268 0 : kpd->kerns[cnt].newyoff = 0;
269 0 : kpd->kerns[cnt].kp = kp;
270 0 : kpd->kerns[cnt].ac = NULL;
271 0 : CheckLeftRight(&kpd->kerns[cnt]);
272 : }
273 0 : ++cnt;
274 0 : break;
275 : }
276 : }
277 : }
278 0 : if ( kpd->kerns!=NULL )
279 0 : break;
280 0 : if ( cnt==0 )
281 0 : return;
282 0 : kpd->kerns = calloc(cnt+1, sizeof(struct kerns));
283 0 : kpd->kcnt = cnt;
284 0 : }
285 : } else {
286 : while ( 1 ) {
287 0 : for ( cnt=i=0; i<kpd->sf->glyphcnt; ++i ) if ( kpd->sf->glyphs[i]!=NULL ) {
288 0 : for ( kp = kpd->sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
289 0 : if ( kpd->kerns!=NULL ) {
290 0 : kpd->kerns[cnt].first = kpd->sf->glyphs[i];
291 0 : kpd->kerns[cnt].second = kp->sc;
292 0 : kpd->kerns[cnt].newoff = kp->off;
293 0 : kpd->kerns[cnt].newyoff = 0;
294 0 : kpd->kerns[cnt].kp = kp;
295 0 : kpd->kerns[cnt].ac = NULL;
296 0 : CheckLeftRight(&kpd->kerns[cnt]);
297 : }
298 0 : ++cnt;
299 : }
300 : }
301 0 : if ( kpd->kerns!=NULL )
302 0 : break;
303 0 : if ( cnt==0 )
304 0 : return;
305 0 : kpd->kerns = calloc(cnt+1, sizeof(struct kerns));
306 0 : kpd->kcnt = cnt;
307 0 : }
308 : }
309 0 : KPSortEm(kpd,sb_first);
310 : }
311 :
312 0 : static void AnchorRefigure(KPData *kpd) {
313 : AnchorPoint *ap1, *ap2;
314 : DBounds bb;
315 : int i;
316 :
317 0 : for ( i=0; i<kpd->kcnt; ++i ) {
318 0 : struct kerns *k= &kpd->kerns[i];
319 0 : for ( ap1=k->first->anchor; ap1!=NULL && ap1->anchor!=k->ac; ap1=ap1->next );
320 0 : for ( ap2=k->second->anchor; ap2!=NULL && ap2->anchor!=k->ac; ap2=ap2->next );
321 0 : if ( ap1!=NULL && ap2!=NULL ) {
322 0 : if ( k->r2l ) {
323 0 : SplineCharQuickBounds(k->second,&bb);
324 0 : k->newoff = k->second->width-ap1->me.x + ap2->me.x;
325 : } else
326 0 : k->newoff = -k->first->width+ap1->me.x-ap2->me.x;
327 0 : k->newyoff = ap1->me.y-ap2->me.y;
328 : }
329 : }
330 0 : }
331 :
332 0 : static void KPBuildAnchorList(KPData *kpd) {
333 : int i, j, cnt;
334 : AnchorClass *ac;
335 : AnchorPoint *ap1, *ap2, *temp;
336 0 : SplineFont *sf = kpd->sf;
337 : DBounds bb;
338 :
339 0 : if ( kpd->sc!=NULL ) {
340 : while ( 1 ) {
341 0 : cnt = 0;
342 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
343 0 : if ( (ac = AnchorClassMatch(kpd->sc,sf->glyphs[i],kpd->ac,&ap1,&ap2)) ||
344 0 : (ac = AnchorClassMatch(sf->glyphs[i],kpd->sc,kpd->ac,&ap1,&ap2)) ) {
345 0 : if ( kpd->kerns!=NULL ) {
346 0 : struct kerns *k = &kpd->kerns[cnt];
347 0 : switch ( ap1->type ) {
348 : case at_cexit: case at_basechar: case at_baselig: case at_basemark:
349 0 : k->first = kpd->sc;
350 0 : k->second = sf->glyphs[i];
351 0 : break;
352 : case at_centry: case at_mark:
353 0 : k->first = sf->glyphs[i];
354 0 : k->second = kpd->sc;
355 0 : temp = ap1; ap1=ap2; ap2=temp;
356 0 : break;
357 : }
358 0 : CheckLeftRight(k);
359 0 : if ( k->r2l ) {
360 0 : SplineCharQuickBounds(k->second,&bb);
361 0 : k->newoff = k->second->width-ap1->me.x + ap2->me.x;
362 : } else
363 0 : k->newoff = -k->first->width+ap1->me.x-ap2->me.x;
364 0 : k->newyoff = ap1->me.y-ap2->me.y;
365 0 : k->ac = ac;
366 0 : k->kp = NULL;
367 : }
368 0 : ++cnt;
369 : }
370 : }
371 0 : if ( kpd->kerns!=NULL )
372 0 : break;
373 0 : if ( cnt==0 )
374 0 : return;
375 0 : kpd->kerns = malloc((cnt+1)*sizeof(struct kerns));
376 0 : kpd->kcnt = cnt;
377 0 : }
378 : } else {
379 : while ( 1 ) {
380 0 : cnt = 0;
381 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->anchor ) {
382 0 : if ( kpd->ac!=(AnchorClass *) -1 ) {
383 0 : for ( temp = sf->glyphs[i]->anchor; temp!=NULL && temp->anchor!=kpd->ac; temp=temp->next );
384 0 : if ( temp==NULL )
385 0 : continue;
386 : }
387 0 : for ( j=0; j<sf->glyphcnt; ++j ) if ( sf->glyphs[j]!=NULL ) {
388 0 : if ( (ac = AnchorClassMatch(sf->glyphs[i],sf->glyphs[j],kpd->ac,&ap1,&ap2)) ) {
389 0 : if ( kpd->kerns!=NULL ) {
390 0 : struct kerns *k = &kpd->kerns[cnt];
391 0 : k->first = sf->glyphs[i];
392 0 : k->second = sf->glyphs[j];
393 0 : CheckLeftRight(k);
394 0 : if ( k->r2l ) {
395 0 : SplineCharQuickBounds(k->second,&bb);
396 0 : k->newoff = k->second->width-ap1->me.x + ap2->me.x;
397 : } else
398 0 : k->newoff = -k->first->width+ap1->me.x-ap2->me.x;
399 0 : k->newyoff = ap1->me.y-ap2->me.y;
400 0 : k->ac = ac;
401 0 : k->kp = NULL;
402 : }
403 0 : ++cnt;
404 : }
405 : }
406 : }
407 0 : if ( kpd->kerns!=NULL )
408 0 : break;
409 0 : if ( cnt==0 )
410 0 : return;
411 0 : kpd->kerns = malloc((cnt+1)*sizeof(struct kerns));
412 0 : kpd->kcnt = cnt;
413 0 : }
414 : }
415 0 : KPSortEm(kpd,sb_first);
416 0 : AnchorRefigure(kpd);
417 : }
418 :
419 0 : static void KPScrollTo(KPData *kpd, unichar_t uch, enum sortby sort) {
420 : int i;
421 :
422 0 : if ( sort==sb_first ) {
423 0 : for ( i=0; i<kpd->kcnt && kpd->kerns[i].first->unicodeenc<uch; ++i );
424 : } else {
425 0 : for ( i=0; i<kpd->kcnt && kpd->kerns[i].second->unicodeenc<uch; ++i );
426 : }
427 0 : if ( kpd->wh<=2 )
428 : /* As is */;
429 0 : else if ( kpd->wh<5 )
430 0 : --i;
431 : else
432 0 : i -= kpd->wh/5;
433 :
434 0 : if ( i>kpd->kcnt-kpd->wh )
435 0 : i = kpd->kcnt-kpd->wh;
436 0 : if ( i<0 )
437 0 : i = 0;
438 0 : if ( i!=kpd->off_top ) {
439 0 : int off = i-kpd->off_top;
440 0 : kpd->off_top = i;
441 0 : GScrollBarSetPos(GWidgetGetControl(kpd->gw,CID_ScrollBar),kpd->off_top);
442 0 : GDrawScroll(kpd->v,NULL,0,off*kpd->uh);
443 : }
444 0 : }
445 :
446 0 : static void BaseFillFromBDFC(struct _GImage *base,BDFChar *bdfc) {
447 0 : base->data = bdfc->bitmap;
448 0 : base->bytes_per_line = bdfc->bytes_per_line;
449 0 : base->width = bdfc->xmax-bdfc->xmin+1;
450 0 : base->height = bdfc->ymax-bdfc->ymin+1;
451 0 : }
452 :
453 0 : static void KP_ExposeKerns(KPData *kpd,GWindow pixmap,GRect *rect) {
454 : GRect old, subclip, subold, sel;
455 : struct _GImage base;
456 : GImage gi;
457 : int index1, index2;
458 : BDFChar *bdfc1, *bdfc2;
459 0 : int i, as, x, em = kpd->sf->ascent+kpd->sf->descent, yoff;
460 : int first, last;
461 : struct kerns *kern;
462 : char buffer[140];
463 :
464 0 : first = rect->y/kpd->uh;
465 0 : last = (rect->y+rect->height+kpd->uh-1)/kpd->uh;
466 :
467 0 : for ( i=first; i<=last && i+kpd->off_top<kpd->kcnt; ++i ) {
468 0 : kern = &kpd->kerns[i+kpd->off_top];
469 0 : index1 = kern->first->orig_pos;
470 0 : if ( kpd->bdf->glyphs[index1]==NULL )
471 0 : BDFPieceMeal(kpd->bdf,index1);
472 0 : index2 = kern->second->orig_pos;
473 0 : if ( kpd->bdf->glyphs[index2]==NULL )
474 0 : BDFPieceMeal(kpd->bdf,index2);
475 : }
476 :
477 0 : as = kpd->vpad + kpd->sf->ascent * kpd->bdf->pixelsize / em;
478 :
479 0 : memset(&gi,'\0',sizeof(gi));
480 0 : memset(&base,'\0',sizeof(base));
481 0 : gi.u.image = &base;
482 0 : base.image_type = it_index;
483 0 : base.clut = kpd->bdf->clut;
484 0 : GDrawSetDither(NULL, false);
485 :
486 0 : GDrawPushClip(pixmap,rect,&old);
487 0 : GDrawSetFont(pixmap,kpd->font);
488 0 : GDrawSetLineWidth(pixmap,0);
489 0 : GDrawFillRect(pixmap,rect,GDrawGetDefaultBackground(NULL));
490 0 : subclip = *rect;
491 0 : for ( i=first; i<=last && i+kpd->off_top<kpd->kcnt; ++i ) {
492 0 : subclip.y = i*kpd->uh; subclip.height = kpd->uh;
493 0 : GDrawPushClip(pixmap,&subclip,&subold);
494 :
495 0 : kern = &kpd->kerns[i+kpd->off_top];
496 0 : index1 = kern->first->orig_pos;
497 0 : index2 = kern->second->orig_pos;
498 0 : bdfc1 = kpd->bdf->glyphs[index1];
499 0 : bdfc2 = kpd->bdf->glyphs[index2];
500 :
501 0 : BaseFillFromBDFC(&base,bdfc1);
502 0 : base.trans = base.clut->trans_index = -1;
503 : /* the peculiar behavior concerning xmin/xmax is because the bitmaps */
504 : /* don't contain the side-bearings, we have to add that spacing manually */
505 0 : if ( !kern->r2l ) {
506 0 : GDrawDrawImage(pixmap,&gi,NULL, 10,subclip.y+as-bdfc1->ymax);
507 0 : x = 10 + (bdfc1->width-bdfc1->xmin) + bdfc2->xmin +
508 0 : (kern->newoff*kpd->bdf->pixelsize/em);
509 : } else {
510 0 : x = kpd->vwidth-10-(bdfc1->xmax-bdfc1->xmin);
511 0 : GDrawDrawImage(pixmap,&gi,NULL, x,subclip.y+as-bdfc1->ymax);
512 0 : x -= bdfc1->xmin + (bdfc2->width-bdfc2->xmin) +
513 0 : (kern->newoff*kpd->bdf->pixelsize/em);
514 : }
515 0 : BaseFillFromBDFC(&base,bdfc2);
516 : #ifndef _BrokenBitmapImages
517 0 : base.trans = base.clut->trans_index = 0;
518 : #endif
519 0 : yoff = (kern->newyoff*kpd->bdf->pixelsize/em);
520 0 : GDrawDrawImage(pixmap,&gi,NULL, x,subclip.y+as-bdfc2->ymax-yoff);
521 0 : GDrawDrawLine(pixmap,0,subclip.y+kpd->uh-1,
522 0 : subclip.x+subclip.width,subclip.y+kpd->uh-1,0x000000);
523 0 : if ( kern->kp!=NULL )
524 0 : sprintf( buffer, "%d ", kern->newoff);
525 : else
526 0 : sprintf( buffer, "%d,%d ", kern->newoff, kern->newyoff );
527 0 : if ( kern->ac!=NULL )
528 0 : strncat(buffer,kern->ac->name,sizeof(buffer)-strlen(buffer)-1);
529 0 : GDrawDrawText8(pixmap,15,subclip.y+kpd->uh-kpd->fh+kpd->as,buffer,-1,
530 0 : kern->kp!=NULL && kern->newoff!=kern->kp->off ? 0xff0000 : 0x000000 );
531 0 : if ( i+kpd->off_top==kpd->selected ) {
532 0 : sel.x = 0; sel.width = kpd->vwidth-1;
533 0 : sel.y = subclip.y; sel.height = kpd->uh-2;
534 0 : GDrawDrawRect(pixmap,&sel,0x000000);
535 : }
536 0 : GDrawPopClip(pixmap,&subold);
537 : }
538 : #ifndef _BrokenBitmapImages
539 0 : base.clut->trans_index = -1;
540 : #endif
541 0 : GDrawPopClip(pixmap,&old);
542 0 : GDrawSetDither(NULL, true);
543 0 : }
544 :
545 0 : static void KP_RefreshSel(KPData *kpd,int index) {
546 0 : Color col = index==kpd->selected ? 0x000000 : GDrawGetDefaultBackground(NULL);
547 : GRect sel;
548 :
549 0 : if ( index==-1 )
550 0 : return;
551 0 : sel.x = 0; sel.width = kpd->vwidth-1;
552 0 : sel.y = (index-kpd->off_top)*kpd->uh; sel.height = kpd->uh-2;
553 0 : GDrawSetLineWidth(kpd->v,0);
554 0 : GDrawDrawRect(kpd->v,&sel,col);
555 : }
556 :
557 0 : static void KP_RefreshKP(KPData *kpd,int index) {
558 : GRect sel;
559 :
560 0 : if ( index<kpd->off_top || index>kpd->off_top+kpd->wh )
561 0 : return;
562 0 : sel.x = 0; sel.width = kpd->vwidth;
563 0 : sel.y = (index-kpd->off_top)*kpd->uh; sel.height = kpd->uh;
564 0 : GDrawRequestExpose(kpd->v,&sel,false);
565 : }
566 :
567 0 : static void KP_KernClassAlter(KPData *kpd,int index) {
568 0 : KernPair *kp = kpd->kerns[index].kp;
569 : int kc_pos, kc_pos2;
570 0 : KernClass *kc = SFFindKernClass(kpd->sf,kpd->kerns[index].first,kpd->kerns[index].second,
571 : &kc_pos,false);
572 : int i;
573 :
574 0 : if ( kc==NULL )
575 0 : return;
576 :
577 0 : for ( i=0; i<kpd->kcnt; ++i ) if ( i!=index &&
578 0 : kpd->kerns[i].kp->kcid==kp->kcid &&
579 0 : kpd->kerns[i].kp->off==kp->off ) {
580 0 : if ( SFFindKernClass(kpd->sf,kpd->kerns[i].first,kpd->kerns[i].second,
581 0 : &kc_pos2,false)==kc && kc_pos==kc_pos2 ) {
582 0 : kpd->kerns[i].newoff = kpd->kerns[index].newoff;
583 0 : KP_RefreshKP(kpd,i);
584 : }
585 : }
586 : }
587 :
588 0 : static BDFChar *KP_Inside(KPData *kpd, GEvent *e) {
589 : struct kerns *kern;
590 : int index1, index2, i;
591 0 : int baseline, x, em = kpd->sf->ascent+kpd->sf->descent;
592 : BDFChar *bdfc1, *bdfc2;
593 :
594 0 : i = e->u.mouse.y/kpd->uh + kpd->off_top;
595 0 : if ( i>=kpd->kcnt )
596 0 : return( NULL );
597 :
598 0 : kern = &kpd->kerns[i];
599 0 : index1 = kern->first->orig_pos;
600 0 : index2 = kern->second->orig_pos;
601 0 : bdfc1 = kpd->bdf->glyphs[index1];
602 0 : bdfc2 = kpd->bdf->glyphs[index2];
603 0 : if ( bdfc1 ==NULL || bdfc2==NULL )
604 0 : return( NULL );
605 0 : if ( !kern->r2l )
606 0 : x = 10 + (bdfc1->width-bdfc1->xmin) + bdfc2->xmin +
607 0 : (kpd->kerns[i].newoff*kpd->bdf->pixelsize/em);
608 : else
609 0 : x = kpd->vwidth-10- (bdfc1->xmax-bdfc1->xmin) - bdfc1->xmin -
610 0 : (bdfc2->width-bdfc2->xmin) -
611 0 : (kern->newoff*kpd->bdf->pixelsize/em);
612 0 : if ( e->u.mouse.x < x || e->u.mouse.x>= x+bdfc2->xmax-bdfc2->xmin )
613 0 : return( NULL );
614 :
615 0 : baseline = (i-kpd->off_top)*kpd->uh + kpd->sf->ascent * kpd->bdf->pixelsize / em + kpd->vpad;
616 0 : if ( e->u.mouse.y < baseline-bdfc2->ymax || e->u.mouse.y >= baseline-bdfc2->ymin )
617 0 : return( NULL );
618 :
619 0 : return( bdfc2 );
620 : }
621 :
622 0 : static void KP_SetCursor(KPData *kpd, int ismove ) {
623 :
624 0 : if ( kpd->movecursor!=ismove ) {
625 0 : GDrawSetCursor(kpd->v,ismove ? ct_leftright : ct_mypointer );
626 0 : kpd->movecursor = ismove;
627 : }
628 0 : }
629 :
630 0 : static BDFChar *KP_Cursor(KPData *kpd, GEvent *e) {
631 0 : if ( kpd->ac==NULL ) {
632 0 : BDFChar *bdfc2 = KP_Inside(kpd,e);
633 :
634 0 : KP_SetCursor(kpd,bdfc2!=NULL );
635 0 : return( bdfc2 );
636 : }
637 0 : return( NULL );
638 : }
639 :
640 0 : static void KP_ScrollTo(KPData *kpd,int where) {
641 : /* Make sure the line "where" is visible */
642 :
643 0 : if ( where<kpd->off_top || where>=kpd->off_top+kpd->wh ) {
644 0 : where -= kpd->wh/4;
645 0 : if ( where>kpd->kcnt-kpd->wh )
646 0 : where = kpd->kcnt-kpd->wh;
647 0 : if ( where<0 ) where = 0;
648 0 : kpd->off_top = where;
649 0 : GScrollBarSetPos(GWidgetGetControl(kpd->gw,CID_ScrollBar),where);
650 0 : GDrawRequestExpose(kpd->v,NULL,false);
651 : }
652 0 : }
653 :
654 0 : static void KPRemove(KPData *kpd) {
655 0 : if ( kpd->selected!=-1 ) {
656 0 : kpd->kerns[kpd->selected].newoff = 0;
657 0 : GDrawRequestExpose(kpd->v,NULL,false);
658 : }
659 0 : }
660 :
661 0 : static void KP_Commands(KPData *kpd, GEvent *e) {
662 : int old_sel, amount;
663 :
664 0 : switch( e->u.chr.keysym ) {
665 : case '\177':
666 0 : KPRemove(kpd);
667 0 : break;
668 : case 'z': case 'Z':
669 0 : if ( e->u.chr.state&ksm_control ) {
670 0 : if ( kpd->last_index!=-1 ) {
671 0 : kpd->kerns[kpd->last_index].newoff = kpd->old_val;
672 0 : KP_RefreshKP(kpd,kpd->last_index);
673 0 : if ( kpd->kerns[kpd->last_index].kp->kcid!=0 )
674 0 : KP_KernClassAlter(kpd,kpd->last_index);
675 0 : kpd->last_index = -1;
676 : }
677 0 : } else if ( e->u.chr.state&ksm_meta ) {
678 0 : if ( kpd->selected!=-1 ) {
679 0 : kpd->kerns[kpd->selected].newoff = kpd->kerns[kpd->selected].kp->off;
680 0 : KP_RefreshKP(kpd,kpd->selected);
681 0 : if ( kpd->kerns[kpd->selected].kp->kcid!=0 )
682 0 : KP_KernClassAlter(kpd,kpd->selected);
683 0 : kpd->last_index = -1;
684 : }
685 : }
686 0 : break;
687 : case GK_Up: case GK_KP_Up:
688 0 : old_sel = kpd->selected;
689 0 : if ( kpd->selected<=0 )
690 0 : kpd->selected = kpd->kcnt-1;
691 : else
692 0 : --kpd->selected;
693 0 : KP_RefreshSel(kpd,old_sel);
694 0 : KP_RefreshSel(kpd,kpd->selected);
695 0 : KP_ScrollTo(kpd,kpd->selected);
696 0 : break;
697 : case GK_Down: case GK_KP_Down:
698 0 : old_sel = kpd->selected;
699 0 : if ( kpd->selected==-1 || kpd->selected==kpd->kcnt-1 )
700 0 : kpd->selected = 0;
701 : else
702 0 : ++kpd->selected;
703 0 : KP_RefreshSel(kpd,old_sel);
704 0 : KP_RefreshSel(kpd,kpd->selected);
705 0 : KP_ScrollTo(kpd,kpd->selected);
706 0 : break;
707 : case GK_Left: case GK_KP_Left: case GK_Right: case GK_KP_Right:
708 0 : amount = e->u.chr.keysym==GK_Left || e->u.chr.keysym==GK_KP_Left? -1 : 1;
709 0 : if ( e->u.chr.state&(ksm_shift|ksm_control|ksm_meta) ) amount *= 10;
710 0 : if ( kpd->selected!=-1 ) {
711 0 : KP_ScrollTo(kpd,kpd->selected);
712 0 : kpd->last_index = kpd->selected;
713 0 : kpd->old_val = kpd->kerns[kpd->selected].newoff;
714 0 : kpd->kerns[kpd->selected].newoff += amount;
715 0 : KP_RefreshKP(kpd,kpd->selected);
716 0 : if ( kpd->kerns[kpd->selected].kp->kcid!=0 )
717 0 : KP_KernClassAlter(kpd,kpd->selected);
718 : }
719 0 : break;
720 : }
721 0 : }
722 :
723 0 : static void KPV_Resize(KPData *kpd) {
724 : GRect size;
725 : GGadget *sb;
726 :
727 0 : GDrawGetSize(kpd->v,&size);
728 0 : kpd->wh = size.height/kpd->uh;
729 :
730 0 : sb = GWidgetGetControl(kpd->gw,CID_ScrollBar);
731 0 : GScrollBarSetBounds(sb,0,kpd->kcnt,kpd->wh);
732 0 : if ( kpd->off_top>kpd->kcnt-kpd->wh )
733 0 : kpd->off_top = kpd->kcnt-kpd->wh;
734 0 : if ( kpd->off_top<0 )
735 0 : kpd->off_top = 0;
736 0 : GScrollBarSetPos(sb,kpd->off_top);
737 0 : kpd->vwidth = size.width;
738 0 : GDrawRequestExpose(kpd->v,NULL,false);
739 0 : GDrawRequestExpose(kpd->gw,NULL,false);
740 0 : }
741 :
742 0 : static void KP_Resize(KPData *kpd) {
743 :
744 0 : kpd->uh = (4*kpd->bdf->pixelsize/3)+kpd->fh+6;
745 0 : kpd->vpad = kpd->bdf->pixelsize/5 + 3;
746 0 : }
747 :
748 0 : static int KP_ChangeSize(GGadget *g, GEvent *e) {
749 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
750 0 : KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
751 0 : int newsize = (intpt) (GGadgetGetListItemSelected(g)->userdata);
752 : BDFFont *temp;
753 0 : if ( newsize==kpd->bdf->pixelsize )
754 0 : return( true );
755 0 : temp = SplineFontPieceMeal(kpd->sf,kpd->layer,newsize,72,true,NULL);
756 0 : BDFFontFree(kpd->bdf);
757 0 : kpd->bdf = temp;
758 0 : KP_Resize(kpd);
759 0 : KPV_Resize(kpd);
760 : }
761 0 : return( true );
762 : }
763 :
764 0 : static int KP_ChangeSort(GGadget *g, GEvent *e) {
765 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
766 0 : KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
767 0 : KernPair *old = kpd->selected==-1 ? NULL : kpd->kerns[kpd->selected].kp;
768 : int i;
769 :
770 0 : KPSortEm(kpd,GGadgetGetFirstListSelectedItem(g));
771 0 : for ( i=0 ; i<kpd->kcnt; ++i )
772 0 : if ( kpd->kerns[i].kp==old ) {
773 0 : kpd->selected = i;
774 0 : KP_ScrollTo(kpd,i);
775 0 : break;
776 : }
777 0 : GDrawRequestExpose(kpd->v,NULL,false);
778 : }
779 0 : return( true );
780 : }
781 :
782 0 : static int KP_Scrolled(GGadget *g, GEvent *e) {
783 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_scrollbarchange ) {
784 0 : KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
785 0 : int newpos = kpd->off_top;
786 :
787 0 : switch( e->u.control.u.sb.type ) {
788 : case et_sb_top:
789 0 : newpos = 0;
790 0 : break;
791 : case et_sb_halfup:
792 : case et_sb_uppage:
793 0 : newpos -= kpd->wh==1?1:kpd->wh-1;
794 0 : break;
795 : case et_sb_up:
796 0 : newpos -= 1;
797 0 : break;
798 : case et_sb_halfdown:
799 : case et_sb_down:
800 0 : newpos += 1;
801 0 : break;
802 : case et_sb_downpage:
803 0 : newpos += kpd->wh==1?1:kpd->wh-1;
804 0 : break;
805 : case et_sb_bottom:
806 0 : newpos = kpd->kcnt-kpd->wh;
807 0 : break;
808 : case et_sb_thumb:
809 : case et_sb_thumbrelease:
810 0 : newpos = e->u.control.u.sb.pos;
811 0 : break;
812 : }
813 0 : if ( newpos>kpd->kcnt-kpd->wh )
814 0 : newpos = kpd->kcnt-kpd->wh;
815 0 : if ( newpos<0 )
816 0 : newpos = 0;
817 0 : if ( newpos!=kpd->off_top ) {
818 0 : int off = newpos-kpd->off_top;
819 0 : kpd->off_top = newpos;
820 0 : GScrollBarSetPos(g,kpd->off_top);
821 0 : GDrawScroll(kpd->v,NULL,0,off*kpd->uh);
822 : }
823 : }
824 0 : return( true );
825 : }
826 :
827 0 : static int KP_OK(GGadget *g, GEvent *e) {
828 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
829 0 : KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
830 : int i;
831 : FontView *fv; MetricsView *mv;
832 :
833 0 : for ( i=0; i<kpd->kcnt; ++i ) if ( kpd->kerns[i].kp!=NULL )
834 0 : if ( kpd->kerns[i].newoff != kpd->kerns[i].kp->off ) {
835 0 : kpd->kerns[i].kp->off = kpd->kerns[i].newoff;
836 0 : kpd->sf->changed = true;
837 0 : for ( fv=(FontView *) kpd->sf->fv; fv!=NULL; fv = (FontView *) (fv->b.nextsame) ) {
838 0 : for ( mv=fv->b.sf->metrics; mv!=NULL; mv=mv->next )
839 0 : MVRefreshChar(mv,kpd->kerns[i].first);
840 : }
841 : }
842 0 : kpd->done = true;
843 : }
844 0 : return( true );
845 : }
846 :
847 0 : static int KP_Cancel(GGadget *g, GEvent *e) {
848 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
849 0 : KPData *kpd = GDrawGetUserData(GGadgetGetWindow(g));
850 0 : kpd->done = true;
851 : }
852 0 : return( true );
853 : }
854 :
855 0 : static void KPMenuRemove(GWindow gw,struct gmenuitem *mi,GEvent *e) {
856 0 : KPData *kpd = GDrawGetUserData(gw);
857 0 : KPRemove(kpd);
858 0 : }
859 :
860 0 : static void KPKPCloseup(KPData *kpd) {
861 0 : if ( kpd->selected!=-1 ) {
862 0 : struct kerns *k = &kpd->kerns[kpd->selected];
863 0 : int oldoff = k->kp->off;
864 0 : k->kp->off = k->newoff;
865 0 : KernPairD(k->first->parent,k->first,k->second,kpd->layer,false);
866 0 : k->newoff = k->kp->off;
867 0 : k->kp->off = oldoff;
868 0 : GDrawRequestExpose(kpd->v,NULL,false);
869 0 : kpd->selected = -1;
870 : }
871 0 : }
872 :
873 0 : static void KPAC(KPData *kpd, int base) {
874 0 : if ( kpd->selected!=-1 ) {
875 0 : struct kerns *k = &kpd->kerns[kpd->selected];
876 0 : SplineChar *sc = base ? k->first : k->second;
877 : AnchorPoint *ap;
878 0 : for ( ap=sc->anchor; ap!=NULL && ap->anchor!=k->ac; ap=ap->next );
879 0 : if ( ap!=NULL ) {
880 : /* There is currently no way to modify anchors in this dlg */
881 : /* so the anchor will be right. On the other hand we might */
882 : /* need to reinit all other combinations which use this point */
883 0 : AnchorControl(sc,ap,kpd->layer);
884 0 : AnchorRefigure(kpd);
885 0 : GDrawRequestExpose(kpd->v,NULL,false);
886 : }
887 : }
888 0 : }
889 :
890 0 : static void KPMenuKPCloseup(GWindow gw,struct gmenuitem *mi,GEvent *e) {
891 0 : KPData *kpd = GDrawGetUserData(gw);
892 0 : KPKPCloseup(kpd);
893 0 : }
894 :
895 0 : static void KPMenuACB(GWindow gw,struct gmenuitem *mi,GEvent *e) {
896 0 : KPData *kpd = GDrawGetUserData(gw);
897 0 : KPAC(kpd,true);
898 0 : }
899 :
900 0 : static void KPMenuACM(GWindow gw,struct gmenuitem *mi,GEvent *e) {
901 0 : KPData *kpd = GDrawGetUserData(gw);
902 0 : KPAC(kpd,false);
903 0 : }
904 :
905 : static GMenuItem kernmenu[] = {
906 : { { (unichar_t *) N_("C_lear"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\177', 0, NULL, NULL, KPMenuRemove, 0 },
907 : { { (unichar_t *) N_("Kern Pair Closeup"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\0', 0, NULL, NULL, KPMenuKPCloseup, 0 },
908 : GMENUITEM_EMPTY
909 : };
910 :
911 : static GMenuItem acmenu[] = {
912 : { { (unichar_t *) N_("Anchor Control for Base"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\0', 0, NULL, NULL, KPMenuACB, 0 },
913 : { { (unichar_t *) N_("Anchor Control for Mark"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'N' }, '\0', 0, NULL, NULL, KPMenuACM, 0 },
914 : GMENUITEM_EMPTY
915 : };
916 :
917 : static unichar_t upopupbuf[100];
918 :
919 0 : static int kpdv_e_h(GWindow gw, GEvent *event) {
920 0 : KPData *kpd = GDrawGetUserData(gw);
921 : int index, old_sel, temp;
922 : char buffer[100];
923 : static int done=false;
924 :
925 0 : switch ( event->type ) {
926 : case et_expose:
927 0 : KP_ExposeKerns(kpd,gw,&event->u.expose.rect);
928 0 : break;
929 : case et_char:
930 0 : if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
931 0 : help("kernpairs.html");
932 0 : return( true );
933 : }
934 0 : KP_Commands(kpd,event);
935 0 : break;
936 : case et_mousedown:
937 0 : GGadgetEndPopup();
938 0 : kpd->pressed = true;
939 0 : index = kpd->off_top + event->u.mouse.y/kpd->uh;
940 0 : if ( index>=kpd->kcnt )
941 0 : index = -1;
942 0 : if ( index!=kpd->selected ) {
943 0 : old_sel = kpd->selected;
944 0 : kpd->selected = index;
945 0 : KP_RefreshSel(kpd,old_sel);
946 0 : KP_RefreshSel(kpd,index);
947 : }
948 0 : if ( event->u.mouse.button==3 && index>=0 ) {
949 0 : if ( !done ) {
950 : int i;
951 0 : for ( i=0; kernmenu[i].ti.text!=NULL || kernmenu[i].ti.line; ++i )
952 0 : if ( kernmenu[i].ti.text!=NULL )
953 0 : kernmenu[i].ti.text = (unichar_t *) _((char *) kernmenu[i].ti.text);
954 0 : for ( i=0; acmenu[i].ti.text!=NULL || acmenu[i].ti.line; ++i )
955 0 : if ( acmenu[i].ti.text!=NULL )
956 0 : acmenu[i].ti.text = (unichar_t *) _((char *) acmenu[i].ti.text);
957 0 : done = true;
958 : }
959 0 : if ( kpd->ac==NULL )
960 0 : GMenuCreatePopupMenu(gw,event, kernmenu);
961 : else
962 0 : GMenuCreatePopupMenu(gw,event, acmenu);
963 0 : } else if ( KP_Cursor(kpd,event)!=NULL ) {
964 0 : kpd->pressed_x = event->u.mouse.x;
965 0 : kpd->old_val = kpd->kerns[index].newoff;
966 : } else
967 0 : kpd->pressed_x = -1;
968 0 : break;
969 : case et_mouseup:
970 0 : if ( kpd->pressed_x!=-1 )
971 0 : kpd->last_index = kpd->selected;
972 : else
973 0 : kpd->last_index = -1;
974 0 : if ( kpd->selected>=0 && event->u.mouse.clicks>1 ) {
975 0 : if ( kpd->ac==NULL )
976 0 : KPKPCloseup(kpd);
977 : else
978 0 : KPAC(kpd,true);
979 0 : return( true );
980 : }
981 : /* Fall through... */
982 : case et_mousemove:
983 0 : GGadgetEndPopup();
984 0 : index = kpd->off_top + event->u.mouse.y/kpd->uh;
985 0 : if ( !kpd->pressed && index<kpd->kcnt ) {
986 0 : sprintf( buffer, "%.20s %d U+%04x",
987 0 : kpd->kerns[index].first->name,
988 0 : kpd->kerns[index].first->orig_pos,
989 0 : kpd->kerns[index].first->unicodeenc );
990 0 : if ( kpd->kerns[index].first->unicodeenc==-1 )
991 0 : strcpy(buffer+strlen(buffer)-4, "????");
992 0 : sprintf( buffer+strlen(buffer), " + %.20s %d U+%04x",
993 0 : kpd->kerns[index].second->name,
994 0 : kpd->kerns[index].second->orig_pos,
995 0 : kpd->kerns[index].second->unicodeenc );
996 0 : if ( kpd->kerns[index].second->unicodeenc==-1 )
997 0 : strcpy(buffer+strlen(buffer)-4, "????");
998 0 : uc_strcpy(upopupbuf,buffer);
999 0 : GGadgetPreparePopup(gw,upopupbuf);
1000 0 : KP_Cursor(kpd,event);
1001 0 : } else if ( kpd->pressed && kpd->pressed_x!=-1 ) {
1002 0 : if ( kpd->ac!=NULL ) {
1003 : /* Nothing to be done. That's what I find so wonderful. Happy Days */
1004 0 : } else if ( index==kpd->selected ) {
1005 0 : KP_SetCursor(kpd,true);
1006 0 : temp = kpd->old_val + (event->u.mouse.x-kpd->pressed_x)*(kpd->sf->ascent+kpd->sf->descent)/kpd->bdf->pixelsize;
1007 0 : if ( temp!=kpd->kerns[index].newoff ) {
1008 0 : kpd->kerns[index].newoff = temp;
1009 0 : KP_RefreshKP(kpd,index);
1010 : }
1011 : } else {
1012 0 : if ( kpd->movecursor ) {
1013 0 : kpd->kerns[kpd->selected].newoff = kpd->old_val;
1014 0 : KP_SetCursor(kpd,false);
1015 0 : KP_RefreshKP(kpd,kpd->selected);
1016 : }
1017 : }
1018 0 : if ( kpd->ac==NULL && kpd->kerns[index].kp->kcid!=0 && event->type==et_mouseup )
1019 0 : KP_KernClassAlter(kpd,index);
1020 : }
1021 0 : if ( event->type==et_mouseup )
1022 0 : kpd->pressed = false;
1023 0 : break;
1024 : case et_resize:
1025 0 : KPV_Resize(kpd);
1026 0 : break;
1027 : }
1028 0 : return( true );
1029 : }
1030 :
1031 0 : static void kpdpopup(KPData *kpd) {
1032 : char buffer[100];
1033 :
1034 0 : if ( kpd->ac==NULL ) {
1035 0 : sprintf( buffer, "total kern pairs=%d\nchars starting kerns=%d",
1036 : kpd->kcnt, kpd->firstcnt );
1037 : } else {
1038 0 : sprintf( buffer, "total anchored pairs=%d\nbase char cnt=%d",
1039 : kpd->kcnt, kpd->firstcnt );
1040 : }
1041 0 : uc_strcpy(upopupbuf,buffer);
1042 0 : GGadgetPreparePopup(kpd->gw,upopupbuf);
1043 0 : }
1044 :
1045 0 : static int kpd_e_h(GWindow gw, GEvent *event) {
1046 0 : if ( event->type==et_close ) {
1047 0 : KPData *kpd = GDrawGetUserData(gw);
1048 0 : kpd->done = true;
1049 0 : } else if ( event->type == et_mousemove ) {
1050 0 : kpdpopup(GDrawGetUserData(gw));
1051 0 : } else if ( event->type == et_expose ) {
1052 0 : KPData *kpd = GDrawGetUserData(gw);
1053 : GRect size, sbsize;
1054 0 : GDrawGetSize(kpd->v,&size);
1055 0 : GGadgetGetSize(GWidgetGetControl(kpd->gw,CID_ScrollBar),&sbsize);
1056 0 : GDrawSetLineWidth(gw,0);
1057 0 : GDrawDrawLine(gw,size.x,size.y-1,sbsize.x+sbsize.width-1,size.y-1,0x000000);
1058 0 : GDrawDrawLine(gw,size.x,size.y+size.height,sbsize.x+sbsize.width-1,size.y+size.height,0x000000);
1059 0 : GDrawDrawLine(gw,size.x-1,size.y-1,size.x-1,size.y+size.height,0x000000);
1060 0 : } else if ( event->type == et_char ) {
1061 0 : if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1062 0 : help("kernpairs.html");
1063 0 : return( true );
1064 : }
1065 0 : if ( event->u.chr.chars[0]!='\0' && event->u.chr.chars[1]=='\0' ) {
1066 0 : enum sortby sort = GGadgetGetFirstListSelectedItem(GWidgetGetControl(gw,CID_SortBy));
1067 0 : KPData *kpd = GDrawGetUserData(gw);
1068 0 : if ( sort!=sb_kern ) {
1069 0 : KPScrollTo(kpd,event->u.chr.chars[0],sort);
1070 0 : return( true );
1071 : } else
1072 0 : GDrawBeep(NULL);
1073 : }
1074 0 : return( false );
1075 0 : } else if ( event->type == et_resize && event->u.resize.sized ) {
1076 0 : KP_Resize((KPData *) GDrawGetUserData(gw) );
1077 : }
1078 0 : return( true );
1079 : }
1080 :
1081 0 : void SFShowKernPairs(SplineFont *sf,SplineChar *sc,AnchorClass *ac,int layer) {
1082 : KPData kpd;
1083 : GRect pos;
1084 : GWindow gw;
1085 : GWindowAttrs wattrs;
1086 : GGadgetCreateData gcd[9], boxes[6], *hvarray[3][3], *harray[3], *barray[10], *varray[5];
1087 : GTextInfo label[9];
1088 : FontRequest rq;
1089 : int as, ds, ld,i;
1090 : static int done=false;
1091 : static GFont *font=NULL;
1092 :
1093 0 : memset(&kpd,0,sizeof(kpd));
1094 0 : kpd.sf = sf;
1095 0 : kpd.sc = sc;
1096 0 : kpd.ac = ac;
1097 0 : kpd.layer = layer;
1098 0 : kpd.first = true;
1099 0 : kpd.last_index = kpd.selected = -1;
1100 0 : if ( ac==NULL )
1101 0 : KPBuildKernList(&kpd);
1102 : else
1103 0 : KPBuildAnchorList(&kpd);
1104 0 : if ( kpd.kcnt==0 )
1105 0 : return;
1106 :
1107 0 : memset(&wattrs,0,sizeof(wattrs));
1108 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1109 0 : wattrs.event_masks = ~(1<<et_charup);
1110 0 : wattrs.restrict_input_to_me = 1;
1111 0 : wattrs.undercursor = 1;
1112 0 : wattrs.cursor = ct_pointer;
1113 0 : wattrs.utf8_window_title = ac==NULL?_("Kern Pairs"):_("Anchored Pairs");
1114 0 : wattrs.is_dlg = true;
1115 0 : pos.x = pos.y = 0;
1116 0 : pos.width = GGadgetScale(200);
1117 0 : pos.height = GDrawPointsToPixels(NULL,500);
1118 0 : kpd.gw = gw = GDrawCreateTopWindow(NULL,&pos,kpd_e_h,&kpd,&wattrs);
1119 :
1120 0 : memset(&label,0,sizeof(label));
1121 0 : memset(&gcd,0,sizeof(gcd));
1122 0 : memset(&boxes,0,sizeof(boxes));
1123 :
1124 0 : label[0].text = (unichar_t *) _("_Size:");
1125 0 : label[0].text_is_1byte = true;
1126 0 : label[0].text_in_resource = true;
1127 0 : gcd[0].gd.label = &label[0];
1128 0 : gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5+6;
1129 0 : gcd[0].gd.flags = gg_enabled|gg_visible;
1130 0 : gcd[0].creator = GLabelCreate;
1131 0 : hvarray[0][0] = &gcd[0];
1132 :
1133 0 : gcd[1].gd.label = &sizes[1]; gcd[1].gd.label->selected = true;
1134 0 : gcd[1].gd.pos.x = 50; gcd[1].gd.pos.y = 5;
1135 0 : gcd[1].gd.flags = gg_enabled|gg_visible;
1136 0 : gcd[1].gd.cid = CID_Size;
1137 0 : gcd[1].gd.u.list = sizes;
1138 0 : gcd[1].gd.handle_controlevent = KP_ChangeSize;
1139 0 : gcd[1].creator = GListButtonCreate;
1140 0 : hvarray[0][1] = &gcd[1]; hvarray[0][2] = NULL;
1141 :
1142 0 : label[2].text = (unichar_t *) _("Sort By:");
1143 0 : label[2].text_is_1byte = true;
1144 0 : gcd[2].gd.label = &label[2];
1145 0 : gcd[2].gd.pos.x = gcd[0].gd.pos.x; gcd[2].gd.pos.y = gcd[0].gd.pos.y+25;
1146 0 : gcd[2].gd.flags = gg_enabled|gg_visible;
1147 0 : gcd[2].creator = GLabelCreate;
1148 0 : hvarray[1][0] = &gcd[2];
1149 :
1150 0 : if ( !done ) {
1151 0 : done = true;
1152 0 : for ( i=0; sortby[i].text!=NULL; ++i )
1153 0 : sortby[i].text = (unichar_t *) _((char *) sortby[i].text);
1154 : }
1155 :
1156 0 : gcd[3].gd.label = &sortby[0]; gcd[3].gd.label->selected = true;
1157 0 : gcd[3].gd.pos.x = 50; gcd[3].gd.pos.y = gcd[1].gd.pos.y+25;
1158 0 : gcd[3].gd.flags = gg_enabled|gg_visible;
1159 0 : gcd[3].gd.cid = CID_SortBy;
1160 0 : gcd[3].gd.u.list = sortby;
1161 0 : gcd[3].gd.handle_controlevent = KP_ChangeSort;
1162 0 : gcd[3].creator = GListButtonCreate;
1163 0 : hvarray[1][1] = &gcd[3]; hvarray[1][2] = NULL; hvarray[2][0] = NULL;
1164 :
1165 0 : boxes[2].gd.flags = gg_enabled|gg_visible;
1166 0 : boxes[2].gd.u.boxelements = hvarray[0];
1167 0 : boxes[2].creator = GHVBoxCreate;
1168 0 : varray[0] = &boxes[2];
1169 :
1170 0 : gcd[4].gd.pos.width = 40;
1171 0 : gcd[4].gd.pos.height = 250;
1172 0 : gcd[4].gd.flags = gg_visible | gg_enabled;
1173 0 : gcd[4].gd.u.drawable_e_h = kpdv_e_h;
1174 0 : gcd[4].creator = GDrawableCreate;
1175 :
1176 0 : gcd[5].gd.flags = gg_enabled|gg_visible|gg_sb_vert;
1177 0 : gcd[5].gd.cid = CID_ScrollBar;
1178 0 : gcd[5].gd.handle_controlevent = KP_Scrolled;
1179 0 : gcd[5].creator = GScrollBarCreate;
1180 0 : harray[0] = &gcd[4]; harray[1] = &gcd[5]; harray[2] = NULL;
1181 :
1182 0 : boxes[3].gd.flags = gg_enabled|gg_visible;
1183 0 : boxes[3].gd.u.boxelements = harray;
1184 0 : boxes[3].creator = GHBoxCreate;
1185 0 : varray[1] = &boxes[3];
1186 :
1187 0 : gcd[6].gd.pos.x = 20-3; gcd[6].gd.pos.y = 17+37;
1188 0 : gcd[6].gd.pos.width = -1; gcd[6].gd.pos.height = 0;
1189 0 : gcd[6].gd.flags = gg_visible | gg_enabled | gg_but_default;
1190 0 : label[6].text = (unichar_t *) _("_OK");
1191 0 : label[6].text_is_1byte = true;
1192 0 : label[6].text_in_resource = true;
1193 0 : gcd[6].gd.label = &label[6];
1194 0 : gcd[6].gd.cid = CID_OK;
1195 0 : gcd[6].gd.handle_controlevent = KP_OK;
1196 0 : gcd[6].creator = GButtonCreate;
1197 :
1198 0 : gcd[7].gd.pos.x = -20; gcd[7].gd.pos.y = gcd[6].gd.pos.y+3;
1199 0 : gcd[7].gd.pos.width = -1; gcd[7].gd.pos.height = 0;
1200 0 : gcd[7].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1201 0 : label[7].text = (unichar_t *) _("_Cancel");
1202 0 : label[7].text_is_1byte = true;
1203 0 : label[7].text_in_resource = true;
1204 0 : gcd[7].gd.label = &label[7];
1205 0 : gcd[7].gd.cid = CID_Cancel;
1206 0 : gcd[7].gd.handle_controlevent = KP_Cancel;
1207 0 : gcd[7].creator = GButtonCreate;
1208 0 : barray[0] = GCD_Glue; barray[1] = &gcd[6]; barray[2] = GCD_Glue;
1209 0 : barray[3] = GCD_Glue; barray[4] = &gcd[7]; barray[5] = GCD_Glue; barray[6] = NULL;
1210 :
1211 0 : boxes[4].gd.flags = gg_enabled|gg_visible;
1212 0 : boxes[4].gd.u.boxelements = barray;
1213 0 : boxes[4].creator = GHBoxCreate;
1214 0 : varray[2] = &boxes[4];
1215 0 : varray[3] = NULL;
1216 :
1217 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
1218 0 : boxes[0].gd.u.boxelements = varray;
1219 0 : boxes[0].creator = GVBoxCreate;
1220 :
1221 :
1222 0 : GGadgetsCreate(gw,boxes);
1223 :
1224 0 : GHVBoxSetExpandableRow(boxes[0].ret,1);
1225 0 : GHVBoxSetExpandableCol(boxes[3].ret,0);
1226 0 : GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
1227 0 : GHVBoxSetPadding(boxes[0].ret,0,2);
1228 0 : GHVBoxSetPadding(boxes[3].ret,0,0);
1229 0 : kpd.v = GDrawableGetWindow(gcd[4].ret);;
1230 :
1231 0 : GGadgetGetSize(gcd[4].ret,&pos);
1232 0 : kpd.sb_width = pos.width;
1233 0 : GGadgetGetSize(gcd[3].ret,&pos);
1234 0 : kpd.header_height = pos.y+pos.height+4;
1235 :
1236 0 : kpd.bdf = SplineFontPieceMeal(kpd.sf,kpd.layer,(intpt) (gcd[1].gd.label->userdata),72,true,NULL);
1237 :
1238 0 : if ( font==NULL ) {
1239 0 : memset(&rq,'\0',sizeof(rq));
1240 0 : rq.utf8_family_name = SANS_UI_FAMILIES;
1241 0 : rq.point_size = -12;
1242 0 : rq.weight = 400;
1243 0 : font = GDrawInstanciateFont(gw,&rq);
1244 0 : font = GResourceFindFont("Combinations.Font",font);
1245 : }
1246 0 : kpd.font = font;
1247 0 : GDrawWindowFontMetrics(gw,kpd.font,&as,&ds,&ld);
1248 0 : kpd.fh = as+ds; kpd.as = as;
1249 :
1250 0 : kpd.uh = (4*kpd.bdf->pixelsize/3)+kpd.fh+6;
1251 0 : kpd.vpad = kpd.bdf->pixelsize/5 + 3;
1252 :
1253 0 : GHVBoxFitWindow(boxes[0].ret);
1254 :
1255 0 : GDrawSetVisible(kpd.v,true);
1256 0 : GDrawSetVisible(kpd.gw,true);
1257 0 : while ( !kpd.done )
1258 0 : GDrawProcessOneEvent(NULL);
1259 0 : free( kpd.kerns );
1260 0 : GDrawDestroyWindow(gw);
1261 : }
|