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 "autotrace.h"
29 : #include "autowidth.h"
30 : #include "bitmapchar.h"
31 : #include "bvedit.h"
32 : #include "cvundoes.h"
33 : #include "fontforgeui.h"
34 : #include "fvcomposite.h"
35 : #include "fvfonts.h"
36 : #include "lookups.h"
37 : #include "mm.h"
38 : #include "splinefill.h"
39 : #include "splineoverlap.h"
40 : #include "splineutil.h"
41 : #include "splineutil2.h"
42 : #include "tottfgpos.h"
43 : #include <gkeysym.h>
44 : #include <gresource.h>
45 : #include <gresedit.h>
46 : #include <string.h>
47 : #include <ustring.h>
48 : #include <utype.h>
49 : #include <math.h>
50 : #include <stdio.h>
51 :
52 : #include "collabclientui.h"
53 : #include "gfile.h"
54 : #include "wordlistparser.h"
55 : extern char* SFDCreateUndoForLookup( SplineFont *sf, int lookup_type ) ;
56 :
57 :
58 : int mv_width = 800, mv_height = 300;
59 : int mvshowgrid = mv_hidegrid;
60 : int mv_type = mv_widthonly;
61 : static int mv_antialias = true;
62 : static double mv_scales[] = { 8.0, 4.0, 2.0, 1.5, 1.0, 2.0/3.0, .5, 1.0/3.0, .25, .2, 1.0/6.0, .125, .1 };
63 : #define SCALE_INDEX_NORMAL 4
64 :
65 : static Color widthcol = 0x808080;
66 : static Color italicwidthcol = 0x909090;
67 : static Color selglyphcol = 0x909090;
68 : static Color kernlinecol = 0x008000;
69 : static Color rbearinglinecol = 0x000080;
70 :
71 : int pref_mv_shift_and_arrow_skip = 10;
72 : int pref_mv_control_shift_and_arrow_skip = 5;
73 :
74 : static void MVSelectChar(MetricsView *mv, int i);
75 : static void MVSelectSetForAll(MetricsView *mv, int selected );
76 : static void MVMoveInWordListByOffset( MetricsView *mv, int offset );
77 :
78 0 : static int MVMoveToNextInWordList(GGadget *g, GEvent *e)
79 : {
80 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
81 0 : MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g));
82 0 : MVMoveInWordListByOffset( mv, 1 );
83 : }
84 0 : return 1;
85 : }
86 0 : static int MVMoveToPrevInWordList(GGadget *g, GEvent *e)
87 : {
88 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
89 0 : MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g));
90 0 : MVMoveInWordListByOffset( mv, -1 );
91 : }
92 0 : return 1;
93 : }
94 :
95 0 : static void MVMoveInTableByColumnByOffset(MetricsView *mv, int offset) {
96 0 : int current_pos = 0;
97 : // Find the currently selected record.
98 0 : for (current_pos = 0; current_pos < mv->clen && mv->perchar[current_pos].selected == 0; current_pos ++);
99 : // Return on failure.
100 0 : if (current_pos >= mv->clen || mv->perchar[current_pos].selected == 0) return;
101 : // Ensure that we can move ahead the selected number of records. Return otherwise.
102 0 : if (current_pos + offset >= mv->clen) return;
103 : // Change the selection.
104 0 : mv->perchar[current_pos].selected = 0;
105 0 : mv->perchar[current_pos + offset].selected = 1;
106 : // Find the currently selected gadget.
107 0 : GGadget *current_gadget = GWindowGetFocusGadgetOfWindow(mv->gw);
108 : // Find which control in the current record it is.
109 0 : int current_gadget_type = 0; // 0 is nothing, 1 is Name, 2 is Width, 3 is LBearing, 4 is RBearing, 5 is Kern.
110 : // We do not currently use this value, but it seems likely to be useful.
111 0 : GGadget *target_gadget = NULL;
112 0 : if (current_gadget == mv->perchar[current_pos].name) {
113 0 : current_gadget_type = 1;
114 0 : target_gadget = mv->perchar[current_pos+offset].name;
115 0 : } else if (current_gadget == mv->perchar[current_pos].width) {
116 0 : current_gadget_type = 2;
117 0 : target_gadget = mv->perchar[current_pos+offset].width;
118 0 : } else if (current_gadget == mv->perchar[current_pos].lbearing) {
119 0 : current_gadget_type = 3;
120 0 : target_gadget = mv->perchar[current_pos+offset].lbearing;
121 0 : } else if (current_gadget == mv->perchar[current_pos].rbearing) {
122 0 : current_gadget_type = 4;
123 0 : target_gadget = mv->perchar[current_pos+offset].rbearing;
124 0 : } else if (current_gadget == mv->perchar[current_pos].kern) {
125 0 : current_gadget_type = 5;
126 0 : target_gadget = mv->perchar[current_pos+offset].kern;
127 : }
128 : // Abort if there is no selected control for the current record.
129 0 : if (current_gadget_type == 0) return;
130 : // Change the control focus.
131 0 : if (target_gadget != NULL) {
132 0 : GWidgetIndicateFocusGadget(target_gadget);
133 : }
134 0 : return;
135 : }
136 :
137 : /**
138 : * This doesn't need to be a perfect test by any means. It should
139 : * return true if the currently active kerning lookup includes some
140 : * class based kerning which might require GUI elements other than the
141 : * currently active one to be drawn. The only price to pay by
142 : * returning true all the time is a slight performance one when
143 : * redrawing something that doesn't absolutely need to be redrawn.
144 : */
145 0 : static int haveClassBasedKerningInView( MetricsView* mv )
146 : {
147 0 : if( mv->cur_subtable )
148 : {
149 0 : return mv->cur_subtable->kc > 0;
150 : }
151 0 : return 0;
152 : }
153 :
154 0 : static SplineChar* getSelectedChar( MetricsView* mv ) {
155 0 : int i=0;
156 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
157 0 : if ( mv->perchar[i].selected ) {
158 0 : return mv->chars[i];
159 : }
160 : }
161 0 : if( mv->glyphcnt==1 ) {
162 0 : return mv->chars[0];
163 : }
164 0 : return 0;
165 : }
166 :
167 :
168 0 : static void selectUserChosenWordListGlyphs( MetricsView *mv, void* userdata )
169 : {
170 0 : printf("selectUserChosenWordListGlyphs(top)\n");
171 0 : MVSelectSetForAll( mv, 0 );
172 : // The previous check thought that userdata was in integer and wanted to verify that
173 : // it was positive and not equal to -1 or to -2. Frank changed it.
174 0 : if( userdata != NULL)
175 : {
176 0 : if (userdata == (void*)(-1) || userdata == (void*)(-2))
177 0 : fprintf(stderr, "Possible error; see the code here.\n");
178 :
179 0 : WordListLine wll = (WordListLine)userdata;
180 0 : for( ; wll->sc; wll++ ) {
181 0 : if( wll->isSelected ) {
182 0 : MVSelectChar( mv, wll->currentGlyphIndex );
183 : }
184 : }
185 : }
186 0 : }
187 :
188 0 : static int MVGetSplineFontPieceMealFlags( MetricsView *mv )
189 : {
190 0 : int ret = 0;
191 :
192 0 : ret = pf_ft_recontext;
193 :
194 0 : if( mv->antialias )
195 0 : ret |= pf_antialias;
196 0 : if( !mv->usehinting )
197 0 : ret |= pf_ft_nohints;
198 :
199 0 : return ret;
200 : }
201 :
202 :
203 0 : void MVColInit( void ) {
204 : static int cinit=false;
205 0 : GResStruct mvcolors[] = {
206 : { "AdvanceWidthColor", rt_color, &widthcol, NULL, 0 },
207 : { "ItalicAdvanceColor", rt_color, &italicwidthcol, NULL, 0 },
208 : { "SelectedGlyphColor", rt_color, &selglyphcol, NULL, 0 },
209 : { "KernLineColor", rt_color, &kernlinecol, NULL, 0 },
210 : { "SideBearingLineColor", rt_color, &rbearinglinecol, NULL, 0 },
211 : GRESSTRUCT_EMPTY
212 : };
213 0 : if ( !cinit ) {
214 0 : GResourceFind( mvcolors, "MetricsView.");
215 0 : cinit = true;
216 : }
217 0 : }
218 :
219 : static int MVSetVSb(MetricsView *mv);
220 :
221 0 : static int MVShowGrid(MetricsView *mv) {
222 0 : if ( mv->showgrid==mv_hidegrid || (mv->showgrid==mv_hidemovinggrid && mv->pressed ))
223 0 : return( false );
224 :
225 0 : return( true );
226 : }
227 :
228 0 : static void MVDrawLine(MetricsView *mv,GWindow pixmap,
229 : int xtop, int top,int xbot,int bot,Color col) {
230 0 : if ( mv->showgrid == mv_partialgrid ) {
231 : int y1, y2;
232 : int x1, x2;
233 0 : y1 = bot + ( top- bot)/4;
234 0 : x1 = xbot + (xtop-xbot)/4;
235 0 : y2 = bot + 4*( top- bot)/5;
236 0 : x2 = xbot + 4*(xtop-xbot)/5;
237 0 : GDrawDrawLine(pixmap,xtop,top,x2,y2,col);
238 0 : GDrawDrawLine(pixmap,x1,y1,xbot,bot,col);
239 : } else
240 0 : GDrawDrawLine(pixmap,xtop,top,xbot,bot,col);
241 0 : }
242 :
243 0 : static void MVSubVExpose(MetricsView *mv, GWindow pixmap, GEvent *event) {
244 : /* Expose routine for vertical metrics */
245 : GRect *clip;
246 : int xbase, y, si, i, x, width, height;
247 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
248 0 : int as = rint(iscale*mv->pixelsize*mv->sf->ascent/(double) (mv->sf->ascent+mv->sf->descent));
249 : BDFChar *bdfc;
250 : struct _GImage base;
251 : GImage gi;
252 : GClut clut;
253 :
254 0 : clip = &event->u.expose.rect;
255 :
256 0 : xbase = mv->vwidth/2;
257 0 : if ( mv->showgrid )
258 0 : GDrawDrawLine(pixmap,xbase,0,xbase,mv->vheight,widthcol);
259 :
260 0 : if ( mv->bdf==NULL && MVShowGrid(mv) ) {
261 0 : y = mv->perchar[0].dy-mv->yoff;
262 0 : MVDrawLine(mv,pixmap,0,y,mv->vwidth,y,widthcol);
263 : }
264 :
265 0 : si = -1;
266 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
267 0 : if ( mv->perchar[i].selected ) si = i;
268 0 : y = mv->perchar[i].dy-mv->yoff;
269 0 : if ( mv->bdf==NULL && MVShowGrid(mv)) {
270 0 : int yp = y+mv->perchar[i].dheight+mv->perchar[i].kernafter;
271 0 : MVDrawLine(mv,pixmap,0, yp,mv->vwidth,yp,
272 0 : mv->type==mv_kernonly && i!=mv->glyphcnt-1 ?kernlinecol :
273 0 : mv->type==mv_widthonly ?rbearinglinecol :
274 : widthcol);
275 : }
276 0 : y += mv->perchar[i].yoff;
277 0 : bdfc = mv->bdf==NULL ? BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos) :
278 0 : BDFGetMergedChar( mv->bdf->glyphs[mv->glyphs[i].sc->orig_pos]);
279 0 : if ( bdfc==NULL )
280 0 : continue;
281 0 : y += as-rint(iscale * bdfc->ymax);
282 0 : if ( mv->perchar[i].selected )
283 0 : y += mv->activeoff;
284 0 : x = xbase - rint(iscale * (mv->pixelsize/2 + bdfc->xmin) - mv->perchar[i].xoff);
285 0 : width = bdfc->xmax-bdfc->xmin+1; height = bdfc->ymax-bdfc->ymin+1;
286 0 : if ( clip->y+clip->height<y )
287 0 : break;
288 0 : if ( y+iscale*height>=clip->y && x<clip->x+clip->width && x+iscale*width >= clip->x ) {
289 0 : memset(&gi,'\0',sizeof(gi));
290 0 : memset(&base,'\0',sizeof(base));
291 0 : memset(&clut,'\0',sizeof(clut));
292 0 : gi.u.image = &base;
293 0 : base.clut = &clut;
294 0 : if ( !bdfc->byte_data ) {
295 0 : base.image_type = it_mono;
296 0 : clut.clut_len = 2;
297 0 : clut.clut[0] = 0xffffff;
298 0 : if ( mv->perchar[i].selected )
299 0 : clut.clut[1] = selglyphcol;
300 : } else {
301 : int scale, l;
302 : Color fg, bg;
303 0 : if ( mv->bdf!=NULL )
304 0 : scale = BDFDepth(mv->bdf);
305 : else
306 0 : scale = BDFDepth(mv->show);
307 0 : base.image_type = it_index;
308 0 : clut.clut_len = 1<<scale;
309 0 : bg = view_bgcol;
310 0 : fg = ( mv->perchar[i].selected ) ? selglyphcol : 0x000000;
311 0 : for ( l=0; l<(1<<scale); ++l )
312 0 : clut.clut[l] =
313 0 : COLOR_CREATE(
314 : COLOR_RED(bg) + (l*(COLOR_RED(fg)-COLOR_RED(bg)))/((1<<scale)-1),
315 : COLOR_GREEN(bg) + (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg)))/((1<<scale)-1),
316 : COLOR_BLUE(bg) + (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg)))/((1<<scale)-1) );
317 : }
318 0 : base.data = bdfc->bitmap;
319 0 : base.bytes_per_line = bdfc->bytes_per_line;
320 0 : base.width = width;
321 0 : base.height = height;
322 0 : if ( mv->pixelsize_set_by_window || mv->scale_index==SCALE_INDEX_NORMAL )
323 0 : GDrawDrawGlyph(pixmap,&gi,NULL,x,y);
324 : else
325 0 : GDrawDrawImageMagnified(pixmap, &gi, NULL, x,y,
326 0 : (int) rint((width*mv_scales[mv->scale_index])),
327 0 : (int) rint((height*mv_scales[mv->scale_index])));
328 : }
329 0 : if ( mv->bdf!=NULL ) BDFCharFree( bdfc );
330 : }
331 0 : if ( si!=-1 && mv->bdf==NULL && MVShowGrid(mv) && mv->type==mv_kernwidth ) {
332 0 : y = mv->perchar[si].dy-mv->yoff;
333 0 : if ( si!=0 )
334 0 : MVDrawLine(mv,pixmap,0,y,mv->vwidth,y,kernlinecol);
335 0 : y += mv->perchar[si].dheight+mv->perchar[si].kernafter;
336 0 : MVDrawLine(mv,pixmap,0,y,mv->vwidth,y,rbearinglinecol);
337 : }
338 0 : }
339 :
340 0 : static void MVSubExpose(MetricsView *mv, GWindow pixmap, GEvent *event) {
341 : GRect old, *clip;
342 : int x,y,ybase, width,height, i;
343 : BDFChar *bdfc;
344 : struct _GImage base;
345 : GImage gi;
346 : GClut clut;
347 : int si;
348 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
349 0 : double s = sin(-mv->sf->italicangle*3.1415926535897932/180.);
350 0 : int x_iaoffh = 0, x_iaoffl = 0;
351 :
352 0 : clip = &event->u.expose.rect;
353 0 : GDrawPushClip(pixmap,clip,&old);
354 0 : GDrawSetLineWidth(pixmap,0);
355 :
356 0 : if ( mv->vertical ) {
357 0 : MVSubVExpose(mv,pixmap,event);
358 0 : GDrawPopClip(pixmap,&old);
359 0 : return;
360 : }
361 :
362 0 : ybase = mv->ybaseline - mv->yoff;
363 :
364 0 : if ( mv->showgrid )
365 0 : GDrawDrawLine(pixmap,0,ybase,mv->dwidth,ybase,widthcol);
366 :
367 0 : if ( mv->bdf==NULL && MVShowGrid(mv) ) {
368 0 : x = mv->perchar[0].dx-mv->xoff;
369 0 : if ( mv->right_to_left )
370 0 : x = mv->vwidth - x - mv->perchar[0].dwidth - mv->perchar[0].kernafter;
371 0 : MVDrawLine(mv,pixmap,x,0,x,mv->vheight,widthcol);
372 0 : x_iaoffh = rint(ybase*s), x_iaoffl = rint((mv->vheight-ybase)*s);
373 0 : if ( ItalicConstrained && x_iaoffh!=0 ) {
374 0 : MVDrawLine(mv,pixmap,x+x_iaoffh,0,x-x_iaoffl,mv->vheight,italicwidthcol);
375 : }
376 : }
377 0 : si = -1;
378 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
379 0 : if ( mv->perchar[i].selected ) si = i;
380 0 : x = mv->perchar[i].dx-mv->xoff;
381 0 : if ( mv->right_to_left )
382 0 : x = mv->vwidth - x - mv->perchar[i].dwidth - mv->perchar[i].kernafter;
383 0 : if ( mv->bdf==NULL && MVShowGrid(mv) ) {
384 0 : int xp = x+mv->perchar[i].dwidth+mv->perchar[i].kernafter;
385 0 : MVDrawLine(mv,pixmap,xp, 0,xp,mv->vheight,
386 0 : mv->type==mv_kernonly && i!=mv->glyphcnt-1 ?kernlinecol :
387 0 : mv->type==mv_widthonly ?rbearinglinecol :
388 : widthcol);
389 0 : if ( ItalicConstrained && x_iaoffh!=0 ) {
390 0 : MVDrawLine(mv,pixmap,xp+x_iaoffh,0,xp-x_iaoffl,mv->vheight,italicwidthcol);
391 : }
392 : }
393 0 : if ( mv->right_to_left )
394 0 : x += mv->perchar[i].kernafter-mv->perchar[i].xoff;
395 : else
396 0 : x += mv->perchar[i].xoff;
397 0 : bdfc = mv->bdf==NULL ? BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos) :
398 0 : BDFGetMergedChar( mv->bdf->glyphs[mv->glyphs[i].sc->orig_pos]);
399 0 : if ( bdfc==NULL )
400 0 : continue;
401 0 : x += rint( iscale * bdfc->xmin );
402 0 : if ( mv->perchar[i].selected )
403 0 : x += mv->activeoff;
404 0 : y = ybase - rint( iscale * bdfc->ymax ) - (iscale-1) - mv->perchar[i].yoff;
405 0 : width = bdfc->xmax-bdfc->xmin+1; height = bdfc->ymax-bdfc->ymin+1;
406 0 : if ( !mv->right_to_left && clip->x+clip->width<x )
407 0 : break;
408 0 : if ( x+rint(iscale*width)>=clip->x && y<clip->y+clip->height && y+rint(iscale*height) >= clip->y ) {
409 0 : memset(&gi,'\0',sizeof(gi));
410 0 : memset(&base,'\0',sizeof(base));
411 0 : memset(&clut,'\0',sizeof(clut));
412 0 : gi.u.image = &base;
413 0 : base.clut = &clut;
414 0 : if ( !bdfc->byte_data ) {
415 0 : base.image_type = it_mono;
416 0 : clut.clut_len = 2;
417 0 : clut.clut[0] = 0xffffff;
418 0 : if ( mv->perchar[i].selected )
419 0 : clut.clut[1] = selglyphcol;
420 : } else {
421 0 : int lscale = 3000/mv->pixelsize, l;
422 : Color fg, bg;
423 : int scale;
424 0 : if ( mv->bdf!=NULL )
425 0 : lscale = BDFDepth(mv->bdf);
426 : else
427 0 : lscale = BDFDepth(mv->show);
428 0 : base.image_type = it_index;
429 0 : scale = lscale==8?256:lscale==4?16:4;
430 0 : clut.clut_len = scale;
431 0 : bg = view_bgcol;
432 0 : fg = ( mv->perchar[i].selected ) ? selglyphcol : 0x000000;
433 0 : for ( l=0; l<scale; ++l )
434 0 : clut.clut[l] =
435 0 : COLOR_CREATE(
436 : COLOR_RED(bg) + ((int32) (l*(COLOR_RED(fg)-COLOR_RED(bg))))/(scale-1),
437 : COLOR_GREEN(bg) + ((int32) (l*(COLOR_GREEN(fg)-COLOR_GREEN(bg))))/(scale-1),
438 : COLOR_BLUE(bg) + ((int32) (l*(COLOR_BLUE(fg)-COLOR_BLUE(bg))))/(scale-1) );
439 : }
440 0 : base.data = bdfc->bitmap;
441 0 : base.bytes_per_line = bdfc->bytes_per_line;
442 0 : base.width = width;
443 0 : base.height = height;
444 0 : if ( mv->pixelsize_set_by_window || mv->scale_index==SCALE_INDEX_NORMAL )
445 0 : GDrawDrawGlyph(pixmap,&gi,NULL,x,y);
446 : else
447 0 : GDrawDrawImageMagnified(pixmap, &gi, NULL, x,y,
448 0 : (int) rint((width*mv_scales[mv->scale_index])),
449 0 : (int) rint((height*mv_scales[mv->scale_index])));
450 : }
451 0 : if ( mv->bdf!=NULL ) BDFCharFree( bdfc );
452 : }
453 0 : if ( si!=-1 && mv->bdf==NULL && MVShowGrid(mv) && mv->type==mv_kernwidth ) {
454 0 : x = mv->perchar[si].dx-mv->xoff;
455 0 : if ( mv->right_to_left )
456 0 : x = mv->vwidth - x;
457 0 : if ( si!=0 )
458 0 : MVDrawLine(mv,pixmap,x,0,x,mv->vheight,kernlinecol);
459 0 : if ( mv->right_to_left )
460 0 : x -= mv->perchar[si].dwidth+mv->perchar[si].kernafter;
461 : else
462 0 : x += mv->perchar[si].dwidth+mv->perchar[si].kernafter;
463 0 : MVDrawLine(mv,pixmap,x, 0,x,mv->vheight,rbearinglinecol);
464 : }
465 0 : GDrawPopClip(pixmap,&old);
466 : }
467 :
468 0 : static void MVExpose(MetricsView *mv, GWindow pixmap, GEvent *event) {
469 : GRect old, *clip;
470 : int x;
471 0 : int ke = mv->height-mv->sbh-(mv->fh+4);
472 :
473 0 : clip = &event->u.expose.rect;
474 0 : if ( clip->y+clip->height < mv->topend )
475 0 : return;
476 0 : GDrawPushClip(pixmap,clip,&old);
477 0 : GDrawSetLineWidth(pixmap,0);
478 0 : for ( x=mv->mwidth; x<mv->width; x+=mv->mwidth ) {
479 0 : GDrawDrawLine(pixmap,x,mv->displayend,x,ke,0x000000);
480 0 : GDrawDrawLine(pixmap,x+mv->mwidth/2,ke,x+mv->mwidth/2,mv->height-mv->sbh,0x000000);
481 : }
482 0 : GDrawDrawLine(pixmap,0,mv->topend,mv->width,mv->topend,0x000000);
483 0 : GDrawDrawLine(pixmap,0,mv->displayend,mv->width,mv->displayend,0x000000);
484 0 : GDrawDrawLine(pixmap,0,mv->displayend+mv->fh+4,mv->width,mv->displayend+mv->fh+4,0x000000);
485 0 : GDrawDrawLine(pixmap,0,mv->displayend+2*(mv->fh+4),mv->width,mv->displayend+2*(mv->fh+4),0x000000);
486 0 : GDrawDrawLine(pixmap,0,mv->displayend+3*(mv->fh+4),mv->width,mv->displayend+3*(mv->fh+4),0x000000);
487 0 : GDrawDrawLine(pixmap,0,mv->displayend+4*(mv->fh+4),mv->width,mv->displayend+4*(mv->fh+4),0x000000);
488 0 : GDrawDrawLine(pixmap,0,mv->displayend+5*(mv->fh+4),mv->width,mv->displayend+5*(mv->fh+4),0x000000);
489 0 : GDrawPopClip(pixmap,&old);
490 : }
491 :
492 0 : static void MVSetSubtables(SplineFont *sf) {
493 : GTextInfo **ti;
494 : OTLookup *otl;
495 : struct lookup_subtable *sub;
496 : int cnt, doit;
497 : MetricsView *mvs;
498 : int selected;
499 :
500 0 : if ( sf->cidmaster ) sf = sf->cidmaster;
501 :
502 : /* There might be more than one metricsview wandering around. Update them all */
503 0 : for ( mvs = sf->metrics; mvs!=NULL; mvs=mvs->next ) {
504 0 : selected = false;
505 0 : for ( doit = 0; doit<2; ++doit ) {
506 0 : cnt = 0;
507 0 : for ( otl=sf->gpos_lookups; otl!=NULL; otl=otl->next ) {
508 0 : if ( otl->lookup_type == gpos_pair && FeatureTagInFeatureScriptList(
509 0 : mvs->vertical?CHR('v','k','r','n') : CHR('k','e','r','n'),
510 : otl->features)) {
511 0 : for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
512 0 : if ( doit ) {
513 0 : ti[cnt] = calloc(1,sizeof(GTextInfo));
514 0 : ti[cnt]->text = utf82u_copy(sub->subtable_name);
515 0 : ti[cnt]->userdata = sub;
516 0 : if ( sub==mvs->cur_subtable )
517 0 : ti[cnt]->selected = selected = true;
518 0 : ti[cnt]->disabled = sub->kc!=NULL;
519 0 : ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
520 : }
521 0 : ++cnt;
522 : }
523 : }
524 : }
525 0 : if ( !doit )
526 0 : ti = calloc(cnt+3,sizeof(GTextInfo *));
527 : else {
528 0 : if ( cnt!=0 ) {
529 0 : ti[cnt] = calloc(1,sizeof(GTextInfo));
530 0 : ti[cnt]->line = true;
531 0 : ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
532 0 : ++cnt;
533 : }
534 0 : ti[cnt] = calloc(1,sizeof(GTextInfo));
535 0 : ti[cnt]->text = utf82u_copy(_("New Lookup Subtable..."));
536 0 : ti[cnt]->userdata = NULL;
537 0 : ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT;
538 0 : ti[cnt]->selected = !selected;
539 0 : ++cnt;
540 0 : ti[cnt] = calloc(1,sizeof(GTextInfo));
541 : }
542 : }
543 0 : if ( !selected )
544 0 : mvs->cur_subtable = NULL;
545 :
546 0 : GGadgetSetList(mvs->subtable_list,ti,false);
547 : }
548 0 : }
549 :
550 0 : static void MVSetFeatures(MetricsView *mv) {
551 0 : SplineFont *sf = mv->sf;
552 : int i, j, cnt;
553 0 : GTextInfo **ti=NULL;
554 0 : uint32 *tags = NULL, script, lang;
555 : char buf[16];
556 : uint32 *stds;
557 0 : const unichar_t *pt = _GGadgetGetTitle(mv->script);
558 :
559 0 : if ( sf->cidmaster ) sf=sf->cidmaster;
560 :
561 0 : script = DEFAULT_SCRIPT;
562 0 : lang = DEFAULT_LANG;
563 0 : if ( u_strlen(pt)>=4 )
564 0 : script = (pt[0]<<24) | (pt[1]<<16) | (pt[2]<<8) | pt[3];
565 0 : if ( pt[4]=='{' && u_strlen(pt)>=9 )
566 0 : lang = (pt[5]<<24) | (pt[6]<<16) | (pt[7]<<8) | pt[8];
567 0 : if ( (uint32)mv->oldscript!=script || (uint32)mv->oldlang!=lang )
568 0 : stds = StdFeaturesOfScript(script);
569 : else { /* features list may have changed, but retain those set */
570 : int32 len, sc;
571 0 : ti = GGadgetGetList(mv->features,&len);
572 0 : stds = malloc((len+1)*sizeof(uint32));
573 0 : for ( i=sc=0; i<len; ++i ) if ( ti[i]->selected )
574 0 : stds[sc++] = (uint32) (intpt) ti[i]->userdata;
575 0 : stds[sc] = 0;
576 : }
577 :
578 0 : tags = SFFeaturesInScriptLang(sf,-2,script,lang);
579 : /* Never returns NULL */
580 0 : for ( cnt=0; tags[cnt]!=0; ++cnt );
581 :
582 : /*qsort(tags,cnt,sizeof(uint32),tag_comp);*/ /* The glist will do this for us */
583 :
584 0 : ti = malloc((cnt+2)*sizeof(GTextInfo *));
585 0 : for ( i=0; i<cnt; ++i ) {
586 0 : ti[i] = calloc( 1,sizeof(GTextInfo));
587 0 : ti[i]->fg = ti[i]->bg = COLOR_DEFAULT;
588 0 : if ( (tags[i]>>24)<' ' || (tags[i]>>24)>0x7e )
589 0 : sprintf( buf, "<%d,%d>", tags[i]>>16, tags[i]&0xffff );
590 : else {
591 0 : buf[0] = tags[i]>>24; buf[1] = tags[i]>>16; buf[2] = tags[i]>>8; buf[3] = tags[i]; buf[4] = 0;
592 : }
593 0 : ti[i]->text = uc_copy(buf);
594 0 : ti[i]->userdata = (void *) (intpt) tags[i];
595 0 : for ( j=0; stds[j]!=0; ++j ) {
596 0 : if ( stds[j] == tags[i] ) {
597 0 : ti[i]->selected = true;
598 0 : break;
599 : }
600 : }
601 : }
602 0 : ti[i] = calloc(1,sizeof(GTextInfo));
603 0 : GGadgetSetList(mv->features,ti,false);
604 0 : mv->oldscript = script; mv->oldlang = lang;
605 0 : }
606 :
607 0 : static void MVSelectSubtable(MetricsView *mv, struct lookup_subtable *sub) {
608 : int32 len; int i;
609 0 : GTextInfo **old = GGadgetGetList(mv->subtable_list,&len);
610 :
611 0 : for ( i=0; i<len && (old[i]->userdata!=sub || old[i]->line); ++i )
612 : {
613 : // nothing //
614 : }
615 : // printf("MVSelectSubtable() i:%d sub:%p\n", i, sub );
616 0 : GGadgetSelectOneListItem(mv->subtable_list,i);
617 0 : if ( sub )
618 0 : mv->cur_subtable = sub;
619 0 : }
620 :
621 0 : static void MVRedrawI(MetricsView *mv,int i,int oldxmin,int oldxmax) {
622 : GRect r;
623 : BDFChar *bdfc;
624 0 : int off = 0;
625 :
626 0 : if ( mv->right_to_left || mv->vertical ) {
627 : /* right to left clipping is hard to think about, it doesn't happen */
628 : /* often enough (I think) for me to put the effort to make it efficient */
629 0 : GDrawRequestExpose(mv->v,NULL,false);
630 0 : return;
631 : }
632 0 : if ( mv->perchar[i].selected )
633 0 : off = mv->activeoff;
634 0 : r.y = 0; r.height = mv->vheight;
635 0 : r.x = mv->perchar[i].dx-mv->xoff; r.width = mv->perchar[i].dwidth;
636 0 : if ( mv->perchar[i].kernafter>0 )
637 0 : r.width += mv->perchar[i].kernafter;
638 0 : if ( mv->perchar[i].xoff<0 ) {
639 0 : r.x += mv->perchar[i].xoff;
640 0 : r.width -= mv->perchar[i].xoff;
641 : } else
642 0 : r.width += mv->perchar[i].xoff;
643 0 : bdfc = mv->bdf==NULL ? BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos) :
644 0 : mv->bdf->glyphs[mv->glyphs[i].sc->orig_pos];
645 0 : if ( bdfc==NULL )
646 0 : return;
647 0 : if ( bdfc->xmax+off+1>r.width ) r.width = bdfc->xmax+off+1;
648 0 : if ( oldxmax+1>r.width ) r.width = oldxmax+1;
649 0 : if ( bdfc->xmin+off<0 ) {
650 0 : r.x += bdfc->xmin+off;
651 0 : r.width -= bdfc->xmin+off;
652 : }
653 0 : if ( oldxmin<bdfc->xmin ) {
654 0 : r.width += (bdfc->xmin+off-oldxmin);
655 0 : r.x -= (bdfc->xmin+off-oldxmin);
656 : }
657 0 : if ( mv->right_to_left )
658 0 : r.x = mv->dwidth - r.x - r.width;
659 0 : GDrawRequestExpose(mv->v,&r,false);
660 0 : if ( mv->perchar[i].selected && i!=0 ) {
661 0 : struct lookup_subtable *sub = mv->glyphs[i].kp!=NULL ? mv->glyphs[i].kp->subtable : mv->glyphs[i].kc!=NULL && mv->glyphs[i].kc->offsets[mv->glyphs[i].kc_index]!=0 ? mv->glyphs[i].kc->subtable : NULL;
662 0 : if ( sub!=NULL )
663 0 : MVSelectSubtable(mv,sub);
664 : }
665 : }
666 :
667 0 : static void MVDeselectChar(MetricsView *mv, int i) {
668 :
669 0 : mv->perchar[i].selected = false;
670 0 : if ( mv->perchar[i].name!=NULL )
671 0 : GGadgetSetEnabled(mv->perchar[i].name,mv->bdf==NULL);
672 0 : MVRedrawI(mv,i,0,0);
673 0 : }
674 :
675 0 : static void MVSelectSubtableForScript(MetricsView *mv,uint32 script) {
676 : int32 len;
677 0 : GTextInfo **ti = GGadgetGetList(mv->subtable_list,&len);
678 : struct lookup_subtable *sub;
679 : int i;
680 :
681 0 : if ( mv->cur_subtable != NULL && FeatureScriptTagInFeatureScriptList(
682 0 : mv->vertical?CHR('v','k','r','n') : CHR('k','e','r','n'),script,
683 0 : mv->cur_subtable->lookup->features ))
684 0 : return;
685 :
686 0 : sub = NULL;
687 0 : for ( i=0; i<len; ++i )
688 0 : if ( ti[i]->userdata!=NULL &&
689 0 : FeatureScriptTagInFeatureScriptList(
690 0 : mv->vertical?CHR('v','k','r','n') : CHR('k','e','r','n'),
691 0 : script,((struct lookup_subtable *) (ti[i]->userdata))->lookup->features)) {
692 0 : sub = ti[i]->userdata;
693 0 : break;
694 : }
695 0 : if ( sub!=NULL )
696 0 : MVSelectSubtable(mv,sub);
697 : }
698 :
699 :
700 0 : static void MVSelectChar(MetricsView *mv, int i) {
701 :
702 0 : if ( i>=mv->glyphcnt || i<0 )
703 0 : return;
704 0 : mv->perchar[i].selected = true;
705 0 : if ( mv->perchar[i].name!=NULL )
706 0 : GGadgetSetEnabled(mv->perchar[i].name,false);
707 0 : if ( mv->glyphs[i].kp!=NULL )
708 0 : MVSelectSubtable(mv,mv->glyphs[i].kp->subtable);
709 0 : else if ( mv->glyphs[i].kc!=NULL && mv->glyphs[i].kc->offsets[mv->glyphs[i].kc_index]!=0 )
710 0 : MVSelectSubtable(mv,mv->glyphs[i].kc->subtable);
711 : else
712 0 : MVSelectSubtableForScript(mv,SCScriptFromUnicode(mv->glyphs[i].sc));
713 0 : MVRedrawI(mv,i,0,0);
714 : }
715 :
716 0 : static void MVDoSelect(MetricsView *mv, int i) {
717 : int j;
718 :
719 0 : for ( j=0; j<mv->glyphcnt; ++j )
720 0 : if ( j!=i && mv->perchar[j].selected )
721 0 : MVDeselectChar(mv,j);
722 0 : MVSelectChar(mv,i);
723 0 : }
724 :
725 0 : static void MVSelectSetForAll(MetricsView *mv, int selected )
726 : {
727 : int i;
728 :
729 0 : for ( i=0 ; i<mv->glyphcnt; ++i )
730 : {
731 0 : if( selected )
732 0 : MVSelectChar(mv,i);
733 : else
734 0 : MVDeselectChar(mv,i);
735 : }
736 0 : }
737 :
738 0 : void MVRefreshChar(MetricsView *mv, SplineChar *sc) {
739 : int i;
740 0 : for ( i=0; i<mv->glyphcnt; ++i ) if ( mv->glyphs[i].sc == sc )
741 0 : MVRedrawI(mv,i,0,0);
742 0 : }
743 :
744 0 : static void MVRefreshValues(MetricsView *mv, int i) {
745 : char buf[40];
746 : DBounds bb;
747 0 : SplineChar *sc = mv->glyphs[i].sc;
748 : int kern_offset;
749 :
750 0 : SplineCharFindBounds(sc,&bb);
751 :
752 0 : if( !mv->perchar[i].name )
753 0 : return;
754 0 : GGadgetSetTitle8(mv->perchar[i].name,sc->name);
755 :
756 0 : if( !mv->perchar[i].width )
757 0 : return;
758 :
759 : //printf("MVRefreshValues() **** setting width to %d\n", sc->width );
760 0 : sprintf(buf,"%d",mv->vertical ? sc->vwidth : sc->width);
761 0 : GGadgetSetTitle8(mv->perchar[i].width,buf);
762 :
763 0 : sprintf(buf,"%.2f",mv->vertical ? sc->parent->ascent-(double) bb.maxy : (double) bb.minx);
764 0 : if ( buf[strlen(buf)-1]=='0' ) {
765 0 : buf[strlen(buf)-1] = '\0';
766 0 : if ( buf[strlen(buf)-1]=='0' ) {
767 0 : buf[strlen(buf)-1] = '\0';
768 0 : if ( buf[strlen(buf)-1]=='.' )
769 0 : buf[strlen(buf)-1] = '\0';
770 : }
771 : }
772 0 : GGadgetSetTitle8(mv->perchar[i].lbearing,buf);
773 :
774 0 : sprintf(buf,"%.2f",(double) (mv->vertical ? sc->vwidth-(sc->parent->ascent-bb.miny) : sc->width-bb.maxx));
775 0 : if ( buf[strlen(buf)-1]=='0' ) {
776 0 : buf[strlen(buf)-1] = '\0';
777 0 : if ( buf[strlen(buf)-1]=='0' ) {
778 0 : buf[strlen(buf)-1] = '\0';
779 0 : if ( buf[strlen(buf)-1]=='.' )
780 0 : buf[strlen(buf)-1] = '\0';
781 : }
782 : }
783 0 : GGadgetSetTitle8(mv->perchar[i].rbearing,buf);
784 :
785 0 : kern_offset = 0x7ffffff;
786 0 : if ( mv->glyphs[i].kp!=NULL )
787 0 : kern_offset = mv->glyphs[i].kp->off;
788 0 : else if ( mv->glyphs[i].kc!=NULL )
789 0 : kern_offset = mv->glyphs[i].kc->offsets[ mv->glyphs[i].kc_index ];
790 0 : if( !mv->perchar[i+1].kern )
791 0 : return;
792 :
793 0 : if ( kern_offset!=0x7ffffff && i!=mv->glyphcnt-1 ) {
794 0 : sprintf(buf,"%d",kern_offset);
795 0 : GGadgetSetTitle8(mv->perchar[i+1].kern,buf);
796 0 : } else if ( i!=mv->glyphcnt-1 )
797 0 : GGadgetSetTitle8(mv->perchar[i+1].kern,"");
798 : }
799 :
800 0 : static void MVMakeLabels(MetricsView *mv) {
801 : static GBox small = GBOX_EMPTY;
802 : GGadgetData gd;
803 : GTextInfo label;
804 :
805 0 : small.main_background = small.main_foreground = COLOR_DEFAULT;
806 0 : memset(&gd,'\0',sizeof(gd));
807 0 : memset(&label,'\0',sizeof(label));
808 :
809 0 : mv->mwidth = GGadgetScale(60);
810 0 : mv->displayend = mv->height- mv->sbh - 5*(mv->fh+4);
811 : /* We might not have set mv->vheight-2 yet */
812 0 : if ( mv->pixelsize_set_by_window )
813 0 : mv->pixelsize = mv_scales[mv->scale_index]*(mv->displayend - mv->topend - 4);
814 :
815 0 : label.text = (unichar_t *) _("Name:");
816 0 : label.text_is_1byte = true;
817 0 : label.font = mv->font;
818 0 : gd.pos.x = 2; gd.pos.width = mv->mwidth-4;
819 0 : gd.pos.y = mv->displayend+2;
820 0 : gd.pos.height = mv->fh;
821 0 : gd.label = &label;
822 0 : gd.box = &small;
823 0 : gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels | gg_dontcopybox;
824 0 : mv->namelab = GLabelCreate(mv->gw,&gd,NULL);
825 :
826 0 : label.text = (unichar_t *) (mv->vertical ? _("Height:") : _("Width:") );
827 0 : gd.pos.y += mv->fh+4;
828 0 : mv->widthlab = GLabelCreate(mv->gw,&gd,NULL);
829 :
830 : /* GT: Top/Left (side) bearing */
831 0 : label.text = (unichar_t *) (mv->vertical ? _("TBearing:") : _("LBearing:") );
832 0 : gd.pos.y += mv->fh+4;
833 0 : mv->lbearinglab = GLabelCreate(mv->gw,&gd,NULL);
834 :
835 : /* GT: Bottom/Right (side) bearing */
836 0 : label.text = (unichar_t *) (mv->vertical ? _("BBearing:") : _("RBearing:") );
837 0 : gd.pos.y += mv->fh+4;
838 0 : mv->rbearinglab = GLabelCreate(mv->gw,&gd,NULL);
839 :
840 0 : label.text = (unichar_t *) (mv->vertical ? _("VKern:") : _("Kern:"));
841 0 : gd.pos.y += mv->fh+4;
842 0 : mv->kernlab = GLabelCreate(mv->gw,&gd,NULL);
843 0 : }
844 :
845 : static int MV_KernChanged(GGadget *g, GEvent *e);
846 : static int MV_RBearingChanged(GGadget *g, GEvent *e);
847 : static int MV_LBearingChanged(GGadget *g, GEvent *e);
848 : static int MV_WidthChanged(GGadget *g, GEvent *e);
849 :
850 0 : static void MVCreateFields(MetricsView *mv,int i) {
851 : static GBox small = GBOX_EMPTY;
852 : GGadgetData gd;
853 : GTextInfo label;
854 : static unichar_t nullstr[1] = { 0 };
855 : int j;
856 : extern GBox _GGadget_gtextfield_box;
857 0 : int udaidx = 1; // we leave element zero to be NULL to allow bounds checking.
858 :
859 0 : small = _GGadget_gtextfield_box;
860 0 : small.flags = 0;
861 0 : small.border_type = bt_none;
862 0 : small.border_shape = bs_rect;
863 0 : small.border_width = 0;
864 0 : small.padding = 0;
865 :
866 0 : memset(&gd,'\0',sizeof(gd));
867 0 : memset(&label,'\0',sizeof(label));
868 0 : memset(mv->perchar[i].updownkparray,'\0',sizeof(GGadget*)*10);
869 0 : label.text = nullstr;
870 0 : label.font = mv->font;
871 0 : mv->perchar[i].mx = gd.pos.x = mv->mbase+(i+1-mv->coff)*mv->mwidth+2;
872 0 : mv->perchar[i].mwidth = gd.pos.width = mv->mwidth-4;
873 0 : gd.pos.y = mv->displayend+2;
874 0 : gd.pos.height = mv->fh;
875 0 : gd.label = &label;
876 0 : gd.box = &small;
877 0 : gd.flags = gg_visible | gg_pos_in_pixels | gg_dontcopybox;
878 0 : if ( mv->bdf==NULL )
879 0 : gd.flags |= gg_enabled;
880 0 : mv->perchar[i].name = GLabelCreate(mv->gw,&gd,(void *) (intpt) i);
881 0 : if ( mv->perchar[i].selected )
882 0 : GGadgetSetEnabled(mv->perchar[i].name,false);
883 :
884 0 : gd.pos.y += mv->fh+4;
885 0 : gd.handle_controlevent = MV_WidthChanged;
886 0 : mv->perchar[i].width = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i);
887 0 : mv->perchar[i].updownkparray[udaidx++] = mv->perchar[i].width;
888 :
889 0 : gd.pos.y += mv->fh+4;
890 0 : gd.handle_controlevent = MV_LBearingChanged;
891 0 : mv->perchar[i].lbearing = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i);
892 0 : mv->perchar[i].updownkparray[udaidx++] = mv->perchar[i].lbearing;
893 :
894 0 : gd.pos.y += mv->fh+4;
895 0 : gd.handle_controlevent = MV_RBearingChanged;
896 0 : mv->perchar[i].rbearing = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i);
897 0 : mv->perchar[i].updownkparray[udaidx++] = mv->perchar[i].rbearing;
898 :
899 0 : if ( i!=0 ) {
900 0 : gd.pos.y += mv->fh+4;
901 0 : gd.pos.x -= mv->mwidth/2;
902 0 : gd.handle_controlevent = MV_KernChanged;
903 0 : mv->perchar[i].kern = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i);
904 0 : if( i==1 ) {
905 0 : mv->perchar[i-1].updownkparray[udaidx] = mv->perchar[i].kern;
906 : }
907 0 : mv->perchar[i].updownkparray[udaidx++] = mv->perchar[i].kern;
908 :
909 0 : if ( i>=mv->glyphcnt ) {
910 0 : for ( j=mv->glyphcnt+1; j<=i ; ++ j )
911 0 : mv->perchar[j].dx = mv->perchar[j-1].dx;
912 0 : mv->glyphcnt = i+1;
913 : }
914 : }
915 :
916 0 : GWidgetIndicateFocusGadget(mv->text);
917 0 : }
918 :
919 : static void MVSetSb(MetricsView *mv);
920 : static int MVSetVSb(MetricsView *mv);
921 :
922 0 : void MVRefreshMetric(MetricsView *mv) {
923 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
924 0 : double scale = iscale*mv->pixelsize/(double) (mv->sf->ascent+mv->sf->descent);
925 0 : SplineFont *sf = mv->sf;
926 : int cnt;
927 : // Count the valid glyphs and segfault if there is no null splinechar terminator.
928 0 : for ( cnt=0; mv->glyphs[cnt].sc!=NULL; ++cnt );
929 : // Calculate positions.
930 0 : int x = 10; int y = 10;
931 0 : for ( int i=0; i<cnt; ++i ) {
932 0 : MVRefreshValues(mv,i);
933 0 : SplineChar * sc = mv->glyphs[i].sc;
934 0 : BDFChar * bdfc = mv->bdf!=NULL ? mv->bdf->glyphs[sc->orig_pos] : BDFPieceMealCheck(mv->show,sc->orig_pos);
935 0 : mv->perchar[i].dwidth = rint(iscale * bdfc->width);
936 0 : mv->perchar[i].dx = x;
937 0 : mv->perchar[i].xoff = rint(iscale * mv->glyphs[i].vr.xoff);
938 0 : mv->perchar[i].yoff = rint(iscale * mv->glyphs[i].vr.yoff);
939 0 : mv->perchar[i].kernafter = rint(iscale * mv->glyphs[i].vr.h_adv_off);
940 0 : x += mv->perchar[i].dwidth + mv->perchar[i].kernafter;
941 :
942 0 : mv->perchar[i].dheight = rint(sc->vwidth*scale);
943 0 : mv->perchar[i].dy = y;
944 0 : if ( mv->vertical ) {
945 0 : mv->perchar[i].kernafter = rint( iscale * mv->glyphs[i].vr.v_adv_off);
946 0 : y += mv->perchar[i].dheight + mv->perchar[i].kernafter;
947 : }
948 : }
949 0 : MVSetVSb(mv);
950 0 : MVSetSb(mv);
951 0 : }
952 :
953 0 : static void MVRemetric(MetricsView *mv) {
954 : SplineChar *anysc, *goodsc;
955 : int i, cnt, x, y, goodpos;
956 0 : const unichar_t *_script = _GGadgetGetTitle(mv->script);
957 : uint32 script, lang, *feats;
958 : char buf[20];
959 : int32 len;
960 : GTextInfo **ti;
961 : SplineChar *sc;
962 : BDFChar *bdfc;
963 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
964 0 : double scale = iscale*mv->pixelsize/(double) (mv->sf->ascent+mv->sf->descent);
965 : SplineFont *sf;
966 :
967 0 : anysc = goodsc = NULL; goodpos = -1;
968 : // We recurse through all of the characters in the metrics view.
969 0 : for ( i=0; i<mv->clen && mv->chars[i] ; ++i ) {
970 : // We assign the first splinechar to anysc.
971 0 : if ( anysc==NULL ) anysc = mv->chars[i];
972 : // We assign the first splinechar of a non-default script to goodsc.
973 0 : if ( SCScriptFromUnicode(mv->chars[i])!=DEFAULT_SCRIPT ) {
974 0 : goodsc = mv->chars[i];
975 0 : goodpos = i;
976 0 : break;
977 : }
978 : }
979 0 : if ( _script[0]=='D' && _script[1]=='F' && _script[2]=='L' && _script[3]=='T' ) {
980 0 : if ( goodsc!=NULL ) {
981 : /* Set the script */ /* Remember if we get here the script is DFLT */
982 : // To be clear, in this case, we set the script of the metrics view according to the first non-default script in the set of selected characters.
983 0 : script = SCScriptFromUnicode(goodsc);
984 0 : buf[0] = script>>24; buf[1] = script>>16; buf[2] = script>>8; buf[3] = script;
985 0 : strcpy(buf+4,"{dflt}");
986 0 : GGadgetSetTitle8(mv->script,buf);
987 0 : MVSelectSubtableForScript(mv,script);
988 0 : MVSetFeatures(mv);
989 : }
990 : } else {
991 0 : if ( anysc==NULL ) {
992 : /* If we get here the script is not DFLT */
993 0 : GGadgetSetTitle8(mv->script,"DFLT{dflt}");
994 : // Why do se set the title to DFLT then?
995 0 : MVSetFeatures(mv);
996 : }
997 : }
998 0 : _script = _GGadgetGetTitle(mv->script);
999 0 : script = DEFAULT_SCRIPT; lang = DEFAULT_LANG;
1000 0 : if ( u_strlen(_script)>=4 && (u_strchr(_script,'{')==NULL || u_strchr(_script,'{')-_script>=4)) {
1001 : // If there is a four-character script identifier, pack it in script.
1002 : // If there is a language identifier, pack that in lang.
1003 : unichar_t *pt;
1004 0 : script = (_script[0]<<24) | (_script[1]<<16) | (_script[2]<<8) | _script[3];
1005 0 : if ( (pt = u_strchr(_script,'{'))!=NULL && u_strlen(pt+1)>=4 &&
1006 0 : (u_strchr(pt+1,'}')==NULL || u_strchr(pt+1,'}')-(pt+1)>=4 ))
1007 0 : lang = (pt[1]<<24) | (pt[2]<<16) | (pt[3]<<8) | pt[4];
1008 : }
1009 :
1010 : // Parse the current list of features into feats.
1011 0 : ti = GGadgetGetList(mv->features,&len);
1012 0 : for ( i=cnt=0; i<len; ++i )
1013 0 : if ( ti[i]->selected ) ++cnt;
1014 0 : feats = calloc(cnt+1,sizeof(uint32));
1015 0 : for ( i=cnt=0; i<len; ++i )
1016 0 : if ( ti[i]->selected )
1017 0 : feats[cnt++] = (intpt) ti[i]->userdata;
1018 :
1019 : // Regenerate glyphs for the selected characters according to features, script, and resolution.
1020 0 : free(mv->glyphs); mv->glyphs = NULL;
1021 0 : sf = mv->sf;
1022 0 : if ( sf->cidmaster ) sf = sf->cidmaster;
1023 0 : mv->glyphs = ApplyTickedFeatures(sf,feats,script, lang, mv->pixelsize, mv->chars);
1024 0 : free(feats);
1025 0 : if ( goodsc!=NULL )
1026 0 : mv->right_to_left = SCRightToLeft(goodsc)?1:0;
1027 :
1028 : // Count the valid glyphs and segfault if there is no null splinechar terminator.
1029 0 : for ( cnt=0; mv->glyphs[cnt].sc!=NULL; ++cnt );
1030 : // If there are too many relative to the available rows, make space.
1031 0 : if ( cnt>=mv->max ) {
1032 0 : int oldmax=mv->max;
1033 0 : mv->max = cnt+10;
1034 0 : mv->perchar = realloc(mv->perchar,mv->max*sizeof(struct metricchar));
1035 0 : memset(mv->perchar+oldmax,'\0',(mv->max-oldmax)*sizeof(struct metricchar));
1036 : }
1037 : // Null names of controls in rows to be abandoned, starting at the last valid glyph and continuing to the end of mv->glyphs.
1038 : // This may segfault here if mv->max is less than mv->glyphcnt, thus if cnt was 10 less than mv->glyphcnt.
1039 : // It may segfault in GGadgetSetTitle if the gadgets do not exist.
1040 0 : for ( i=cnt; i<mv->glyphcnt; ++i ) {
1041 : static unichar_t nullstr[] = { 0 };
1042 0 : GGadgetSetTitle(mv->perchar[i].name,nullstr);
1043 0 : GGadgetSetTitle(mv->perchar[i].width,nullstr);
1044 0 : GGadgetSetTitle(mv->perchar[i].lbearing,nullstr);
1045 0 : GGadgetSetTitle(mv->perchar[i].rbearing,nullstr);
1046 0 : if ( mv->perchar[i].kern!=NULL )
1047 0 : GGadgetSetTitle(mv->perchar[i].kern,nullstr);
1048 : }
1049 : // So we set mv->glyphcnt to something possibly less than the size of mv->glyphs.
1050 0 : mv->glyphcnt = cnt;
1051 : // We now populate any new rows with controls.
1052 0 : for ( i=0; i<cnt; ++i ) {
1053 0 : if ( mv->perchar[i].width==NULL ) {
1054 0 : MVCreateFields(mv,i);
1055 : }
1056 : }
1057 : // Refresh.
1058 0 : MVRefreshMetric(mv);
1059 0 : }
1060 :
1061 0 : void MVReKern(MetricsView *mv) {
1062 0 : MVRemetric(mv);
1063 0 : GDrawRequestExpose(mv->v,NULL,false);
1064 0 : }
1065 :
1066 0 : void MVRegenChar(MetricsView *mv, SplineChar *sc) {
1067 : int i;
1068 :
1069 0 : if( !sc->suspendMetricsViewEventPropagation )
1070 : {
1071 0 : if ( mv->bdf==NULL && sc->orig_pos<mv->show->glyphcnt )
1072 : {
1073 0 : BDFCharFree(mv->show->glyphs[sc->orig_pos]);
1074 0 : mv->show->glyphs[sc->orig_pos] = NULL;
1075 : }
1076 : }
1077 :
1078 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
1079 0 : MVRefreshValues(mv,i);
1080 : }
1081 0 : for ( i=0; i<mv->glyphcnt; ++i )
1082 : {
1083 0 : if ( mv->glyphs[i].sc == sc )
1084 0 : break;
1085 : }
1086 0 : if ( i>=mv->glyphcnt )
1087 0 : return; /* Not displayed */
1088 0 : MVRemetric(mv);
1089 0 : GDrawRequestExpose(mv->v,NULL,false);
1090 : }
1091 :
1092 0 : static void MVChangeDisplayFont(MetricsView *mv, BDFFont *bdf) {
1093 : int i;
1094 :
1095 0 : if ( mv->bdf==bdf )
1096 0 : return;
1097 0 : if ( (mv->bdf==NULL) != (bdf==NULL) ) {
1098 0 : for ( i=0; i<mv->max; ++i ) if ( mv->perchar[i].width!=NULL ) {
1099 0 : GGadgetSetEnabled(mv->perchar[i].width,bdf==NULL);
1100 0 : GGadgetSetEnabled(mv->perchar[i].lbearing,bdf==NULL);
1101 0 : GGadgetSetEnabled(mv->perchar[i].rbearing,bdf==NULL);
1102 0 : if ( i!=0 )
1103 0 : GGadgetSetEnabled(mv->perchar[i].kern,bdf==NULL);
1104 : }
1105 : }
1106 0 : if ( mv->bdf==NULL ) {
1107 0 : BDFFontFree(mv->show);
1108 0 : mv->show = NULL;
1109 0 : } else if ( bdf==NULL ) {
1110 0 : BDFFontFree(mv->show);
1111 0 : mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi,
1112 : MVGetSplineFontPieceMealFlags( mv ), NULL );
1113 : }
1114 0 : mv->bdf = bdf;
1115 0 : MVRemetric(mv);
1116 : }
1117 :
1118 0 : static int isValidInt(unichar_t *end) {
1119 0 : if ( *end && !(*end=='-' && end[1]=='\0'))
1120 0 : return 0;
1121 0 : return 1;
1122 : }
1123 :
1124 : /*
1125 : * Unused
1126 : static int GGadgetToInt(GGadget *g)
1127 : {
1128 : unichar_t *end;
1129 : int val = u_strtol(_GGadgetGetTitle(g),&end,10);
1130 : return val;
1131 : }
1132 : */
1133 :
1134 0 : static real GGadgetToReal(GGadget *g)
1135 : {
1136 : unichar_t *end;
1137 0 : real val = u_strtod(_GGadgetGetTitle(g),&end);
1138 0 : return val;
1139 : }
1140 :
1141 0 : static void MV_handle_collabclient_maybeSnapshot( MetricsView *mv, SplineChar *sc ) {
1142 0 : if ( collabclient_inSessionFV(&mv->fv->b) ) {
1143 0 : int dohints = 0;
1144 0 : SCPreserveState( sc, dohints );
1145 : }
1146 0 : }
1147 :
1148 :
1149 : /* If we are in a collab session, then send the redo through */
1150 : /* to the server to update other clients to our state. */
1151 0 : static void MV_handle_collabclient_sendRedo( MetricsView *mv, SplineChar *sc ) {
1152 0 : if( collabclient_inSessionFV( &mv->fv->b ) ) {
1153 0 : collabclient_sendRedo_SC( sc, UNDO_LAYER_UNKNOWN );
1154 :
1155 : /* CharViewBase* cv = sc->views; */
1156 : /* if( !cv ) */
1157 : /* cv = CharViewCreate( sc, mv->fv, -1 ); */
1158 : /* collabclient_sendRedo( cv ); */
1159 : }
1160 0 : }
1161 :
1162 0 : static int MV_WidthChanged(GGadget *g, GEvent *e) {
1163 : /* This routines called during "Advanced Width Metrics" viewing */
1164 : /* any time "Width" changed or screen is updated */
1165 0 : MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g));
1166 0 : int which = (intpt) GGadgetGetUserData(g);
1167 : int i;
1168 :
1169 0 : if ( e->type!=et_controlevent )
1170 0 : return( true );
1171 0 : if ( which>=mv->glyphcnt )
1172 0 : return( true );
1173 0 : if ( e->u.control.subtype == et_textchanged ) {
1174 : unichar_t *end;
1175 0 : int val = u_strtol(_GGadgetGetTitle(g),&end,10);
1176 0 : SplineChar *sc = mv->glyphs[which].sc;
1177 0 : if (!isValidInt(end))
1178 0 : GDrawBeep(NULL);
1179 0 : else if ( !mv->vertical && val!=sc->width ) {
1180 : // dumpUndoChain( "before SCPreserveWidth...", sc, &sc->layers[ly_fore].undoes );
1181 0 : SCPreserveWidth(sc);
1182 0 : if( collabclient_inSessionFV( &mv->fv->b ) ) {
1183 0 : int dohints = 0;
1184 0 : SCPreserveState( sc, dohints );
1185 : }
1186 :
1187 : // set i to the correct column that has the active width gadget
1188 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
1189 0 : if ( mv->perchar[i].width == g )
1190 0 : break;
1191 : }
1192 :
1193 : // Adjust the lbearing to consume or surrender half of the
1194 : // change that the width value is undergoing.
1195 0 : real offset = GGadgetToReal(mv->perchar[i].lbearing);
1196 0 : offset += (val - sc->width * 1.0)/2;
1197 : real transform[6];
1198 0 : transform[0] = transform[3] = 1.0;
1199 0 : transform[1] = transform[2] = transform[5] = 0;
1200 : DBounds bb;
1201 0 : SplineCharFindBounds(sc,&bb);
1202 0 : transform[4] = offset-bb.minx;
1203 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL, 0 | fvt_alllayers );
1204 :
1205 0 : SCSynchronizeWidth(sc,val,sc->width,NULL);
1206 0 : SCCharChangedUpdate(sc,ly_none);
1207 0 : printf("mv_widthChanged() sending collab\n");
1208 0 : MV_handle_collabclient_sendRedo(mv,sc);
1209 :
1210 0 : } else if ( mv->vertical && val!=sc->vwidth ) {
1211 0 : SCPreserveVWidth(sc);
1212 0 : sc->vwidth = val;
1213 0 : SCCharChangedUpdate(sc,ly_none);
1214 : }
1215 0 : } else if ( e->u.control.subtype == et_textfocuschanged &&
1216 0 : e->u.control.u.tf_focus.gained_focus ) {
1217 0 : for ( i=0 ; i<mv->glyphcnt; ++i )
1218 0 : if ( i!=which && mv->perchar[i].selected )
1219 0 : MVDeselectChar(mv,i);
1220 0 : MVSelectChar(mv,which);
1221 : }
1222 0 : return( true );
1223 : }
1224 :
1225 0 : static int MV_LBearingChanged(GGadget *g, GEvent *e)
1226 : {
1227 : /* This routines called during "Advanced Width Metrics" viewing */
1228 : /* any time "LBrearing" changed or screen is updated */
1229 0 : MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g));
1230 0 : int which = (intpt) GGadgetGetUserData(g);
1231 : int i;
1232 :
1233 0 : if ( e->type!=et_controlevent )
1234 0 : return( true );
1235 0 : if ( which>=mv->glyphcnt )
1236 0 : return( true );
1237 0 : if ( e->u.control.subtype == et_textchanged ) {
1238 : unichar_t *end;
1239 0 : double val = u_strtod(_GGadgetGetTitle(g),&end);
1240 0 : SplineChar *sc = mv->glyphs[which].sc;
1241 : DBounds bb;
1242 0 : SplineCharFindBounds(sc,&bb);
1243 0 : if (!isValidInt(end))
1244 0 : GDrawBeep(NULL);
1245 0 : else if ( !mv->vertical && val!=bb.minx ) {
1246 0 : if ( collabclient_inSessionFV(&mv->fv->b) ) {
1247 0 : int dohints = 0;
1248 0 : SCPreserveState( sc, dohints );
1249 : }
1250 : real transform[6];
1251 0 : transform[0] = transform[3] = 1.0;
1252 0 : transform[1] = transform[2] = transform[5] = 0;
1253 0 : transform[4] = val-bb.minx;
1254 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,0 | fvt_alllayers );
1255 :
1256 : // dumpUndoChain( "LBearing Changed...e", sc, &sc->layers[ly_fore].undoes );
1257 0 : MV_handle_collabclient_sendRedo(mv,sc);
1258 0 : } else if ( mv->vertical && val!=sc->parent->ascent-bb.maxy ) {
1259 : real transform[6];
1260 0 : transform[0] = transform[3] = 1.0;
1261 0 : transform[1] = transform[2] = transform[4] = 0;
1262 0 : transform[5] = sc->parent->ascent-bb.maxy-val;
1263 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL, fvt_dontmovewidth | fvt_alllayers );
1264 : }
1265 :
1266 0 : } else if ( e->u.control.subtype == et_textfocuschanged &&
1267 0 : e->u.control.u.tf_focus.gained_focus ) {
1268 0 : for ( i=0 ; i<mv->glyphcnt; ++i )
1269 0 : if ( i!=which && mv->perchar[i].selected )
1270 0 : MVDeselectChar(mv,i);
1271 0 : MVSelectChar(mv,which);
1272 : }
1273 0 : return( true );
1274 : }
1275 :
1276 0 : static int MV_RBearingChanged(GGadget *g, GEvent *e) {
1277 : /* This routines called during "Advanced Width Metrics" viewing */
1278 : /* any time "RBrearing" changed or screen is updated */
1279 0 : MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g));
1280 0 : int which = (intpt) GGadgetGetUserData(g);
1281 : int i;
1282 :
1283 0 : if ( e->type!=et_controlevent )
1284 0 : return( true );
1285 0 : if ( which>=mv->glyphcnt )
1286 0 : return( true );
1287 0 : if ( e->u.control.subtype == et_textchanged ) {
1288 : unichar_t *end;
1289 0 : int val = u_strtod(_GGadgetGetTitle(g),&end);
1290 0 : SplineChar *sc = mv->glyphs[which].sc;
1291 : DBounds bb;
1292 0 : SplineCharFindBounds(sc,&bb);
1293 0 : if (!isValidInt(end))
1294 0 : GDrawBeep(NULL);
1295 0 : else if ( !mv->vertical && rint(val+bb.maxx)!=sc->width ) {
1296 0 : int newwidth = rint(bb.maxx+val);
1297 0 : SCPreserveWidth(sc);
1298 : /* Width is an integer. Adjust the lbearing so that the rbearing */
1299 : /* remains what was just typed in */
1300 0 : if ( newwidth!=bb.maxx+val ) {
1301 0 : if ( collabclient_inSessionFV(&mv->fv->b) ) {
1302 0 : int dohints = 0;
1303 0 : SCPreserveState( sc, dohints );
1304 : }
1305 : real transform[6];
1306 0 : transform[0] = transform[3] = 1.0;
1307 0 : transform[1] = transform[2] = transform[5] = 0;
1308 0 : transform[4] = newwidth-val-bb.maxx;
1309 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth);
1310 : }
1311 0 : SCSynchronizeWidth(sc,newwidth,sc->width,NULL);
1312 0 : SCCharChangedUpdate(sc,ly_none);
1313 :
1314 : // dumpUndoChain( "RBearing Changed...2", sc, &sc->layers[ly_fore].undoes );
1315 0 : MV_handle_collabclient_sendRedo(mv,sc);
1316 0 : } else if ( mv->vertical && val!=sc->vwidth-(sc->parent->ascent-bb.miny) ) {
1317 0 : double vw = val+(sc->parent->ascent-bb.miny);
1318 0 : SCPreserveWidth(sc);
1319 0 : sc->vwidth = rint(vw);
1320 : /* Width is an integer. Adjust the lbearing so that the rbearing */
1321 : /* remains what was just typed in */
1322 0 : if ( sc->width!=vw ) {
1323 : real transform[6];
1324 0 : transform[0] = transform[3] = 1.0;
1325 0 : transform[1] = transform[2] = transform[4] = 0;
1326 0 : transform[5] = vw-sc->vwidth;
1327 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth);
1328 : }
1329 0 : SCCharChangedUpdate(sc,ly_none);
1330 : }
1331 0 : } else if ( e->u.control.subtype == et_textfocuschanged &&
1332 0 : e->u.control.u.tf_focus.gained_focus ) {
1333 0 : for ( i=0 ; i<mv->glyphcnt; ++i )
1334 0 : if ( i!=which && mv->perchar[i].selected )
1335 0 : MVDeselectChar(mv,i);
1336 0 : MVSelectChar(mv,which);
1337 : }
1338 0 : return( true );
1339 : }
1340 :
1341 0 : static int AskNewKernClassEntry(SplineChar *fsc,SplineChar *lsc,int first_is_0,int second_is_0) {
1342 : char *yesno[3];
1343 0 : yesno[0] = _("_Alter Class");
1344 0 : yesno[1] = _("_Create Pair");
1345 0 : yesno[2] = NULL;
1346 0 : return( gwwv_ask(_("Use Kerning Class?"),(const char **) yesno,0,1,
1347 0 : _("This kerning pair (%.20s and %.20s) is currently part of a kerning class with a 0 offset for this combination. Would you like to alter this kerning class entry (or create a kerning pair for just these two glyphs)?"),
1348 : first_is_0 ? _("{Everything Else}") : fsc->name,
1349 0 : second_is_0 ? _("{Everything Else}") : lsc->name)==0 );
1350 : }
1351 :
1352 :
1353 0 : static int MV_ChangeKerning(MetricsView *mv, int which, int offset, int is_diff) {
1354 0 : SplineChar *sc = mv->glyphs[which].sc;
1355 0 : SplineChar *psc = mv->glyphs[which-1].sc;
1356 0 : KernPair *kp = 0;
1357 : KernClass *kc; int index;
1358 : int i;
1359 0 : struct lookup_subtable *sub = GGadgetGetListItemSelected(mv->subtable_list)->userdata;
1360 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
1361 :
1362 0 : kp = mv->glyphs[which-1].kp;
1363 0 : kc = mv->glyphs[which-1].kc;
1364 0 : index = mv->glyphs[which-1].kc_index;
1365 :
1366 0 : if ( kc!=NULL ) {
1367 0 : if ( index==-1 )
1368 0 : kc = NULL;
1369 0 : else if ( kp != NULL && kp->off != 0 )
1370 0 : kc=NULL;
1371 0 : else if ( (!is_diff && offset==kc->offsets[index]) ||
1372 0 : ( is_diff && offset==0))
1373 0 : return( true ); /* No change, don't bother user */
1374 : /* If there is already a kerning pair, then assume it takes the precedence over the kerning class */
1375 0 : else if ( kc->offsets[index]==0 && !AskNewKernClassEntry(psc,sc,mv->glyphs[which-1].prev_kc0,mv->glyphs[which-1].next_kc0))
1376 0 : kc=NULL;
1377 : else
1378 0 : offset = kc->offsets[index] = is_diff ? kc->offsets[index]+offset : offset;
1379 : }
1380 0 : if ( kc==NULL ) {
1381 0 : if ( sub!=NULL && sub->kc!=NULL ) {
1382 : /* If the subtable we were given contains a kern class, and for some reason */
1383 : /* we can't, or don't want to, use that kern class, then see */
1384 : /* if the lookup contains another subtable with no kern classes */
1385 : /* and use that */
1386 : struct lookup_subtable *s;
1387 0 : for ( s = sub->lookup->subtables; s!=NULL && s->kc!=NULL; s=s->next );
1388 0 : sub = s;
1389 : }
1390 0 : if ( sub==NULL ) {
1391 : struct subtable_data sd;
1392 0 : memset(&sd,0,sizeof(sd));
1393 0 : sd.flags = (mv->vertical ? sdf_verticalkern : sdf_horizontalkern ) |
1394 : sdf_kernclass;
1395 0 : sub = SFNewLookupSubtableOfType(psc->parent,gpos_pair,&sd,mv->layer);
1396 0 : if ( sub==NULL )
1397 0 : return( false );
1398 0 : mv->cur_subtable = sub;
1399 0 : MVSetSubtables(mv->sf);
1400 0 : MVSetFeatures(mv);
1401 : }
1402 :
1403 : /* If we change the kerning offset, then any pixel corrections*/
1404 : /* will no longer apply (they only had meaning with the old */
1405 : /* offset) so free the device table, if any */
1406 0 : if ( kp != NULL && ((!is_diff && kp->off!=offset) || ( is_diff && offset!=0)) ) {
1407 0 : DeviceTableFree(kp->adjust);
1408 0 : kp->adjust = NULL;
1409 : }
1410 :
1411 0 : offset = is_diff && kp != NULL ? kp->off+offset : offset;
1412 : /* If kern offset has been set to zero by user, then cleanup this kerning pair */
1413 0 : if ( kp != NULL && offset == 0 ) {
1414 : KernPair *kpcur, *kpprev;
1415 0 : KernPair **kphead = mv->vertical ? &psc->vkerns : &psc->kerns;
1416 0 : if ( kp == *kphead ) {
1417 0 : *kphead = kp->next;
1418 : } else {
1419 0 : kpprev = *kphead;
1420 0 : for ( kpcur=kpprev->next; kpcur != NULL; kpcur = kpcur->next ) {
1421 0 : if ( kpcur == kp ) {
1422 0 : kpprev->next = kp->next;
1423 0 : break;
1424 : }
1425 0 : kpprev = kpcur;
1426 : }
1427 : }
1428 :
1429 : // avoid dangling refrences to kp
1430 0 : int i = 0;
1431 0 : for( i=0; mv->glyphs[i].sc; i++ ) {
1432 0 : if( i!=which && mv->glyphs[i].kp == kp ) {
1433 0 : mv->glyphs[i].kp = 0;
1434 : }
1435 : }
1436 0 : chunkfree( kp,sizeof(KernPair) );
1437 0 : kp = mv->glyphs[which-1].kp = NULL;
1438 0 : } else if ( offset != 0 ) {
1439 0 : if ( kp==NULL ) {
1440 0 : kp = chunkalloc(sizeof(KernPair));
1441 0 : kp->sc = sc;
1442 0 : if ( !mv->vertical ) {
1443 0 : kp->next = psc->kerns;
1444 0 : psc->kerns = kp;
1445 : } else {
1446 0 : kp->next = psc->vkerns;
1447 0 : psc->vkerns = kp;
1448 : }
1449 0 : mv->glyphs[which-1].kp = kp;
1450 : }
1451 0 : kp->off = offset;
1452 0 : kp->subtable = sub;
1453 0 : if ( !mv->vertical )
1454 0 : MMKern(sc->parent,psc,sc,is_diff?offset:offset-kp->off,sub,kp);
1455 : }
1456 : }
1457 0 : int16 newkernafter = iscale * (offset*mv->pixelsize)/
1458 0 : (mv->sf->ascent+mv->sf->descent);
1459 0 : mv->perchar[which-1].kernafter = newkernafter;
1460 :
1461 0 : if ( mv->vertical ) {
1462 0 : for ( i=which; i<mv->glyphcnt; ++i ) {
1463 0 : mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight +
1464 0 : mv->perchar[i-1].kernafter ;
1465 : }
1466 : } else {
1467 0 : for ( i=which; i<mv->glyphcnt; ++i ) {
1468 0 : mv->perchar[i].dx = mv->perchar[i-1].dx + mv->perchar[i-1].dwidth +
1469 0 : mv->perchar[i-1].kernafter;
1470 : }
1471 : }
1472 :
1473 : /**
1474 : * Class based kerning. If we have altered one pair "Tc" then we
1475 : * want to find any other pairs in the same class that are shown
1476 : * and alter them in a similar way. Note that the update to the
1477 : * value shown is already done as that is taken from the
1478 : * KernClass. We can get away with just calling MVRefreshValues()
1479 : * on the right indexes to update the kern value entry boxes. On
1480 : * the other hand, we have to make sure the guide and glyph
1481 : * display is adjusted accordingly too otherwise the user will not
1482 : * see the currect kerning for all other digraphs in the same
1483 : * class even thuogh the kerning entry box is updated.
1484 : */
1485 0 : if( kc && psc && sc )
1486 : {
1487 : // cache the cell in the kernclass that we are editing for quick comparison
1488 : // in the loop
1489 0 : int pscidx = KernClassFindIndexContaining( kc->firsts, kc->first_cnt, psc->name );
1490 0 : int scidx = KernClassFindIndexContaining( kc->seconds, kc->second_cnt, sc->name );
1491 :
1492 0 : if( pscidx > 0 && scidx > 0 )
1493 : {
1494 0 : for ( i=1; i<mv->glyphcnt; ++i )
1495 : {
1496 : // don't check yourself.
1497 0 : if( i-1 == which )
1498 0 : continue;
1499 :
1500 : /* printf("mv->glyphs[i-1].sc.name:%s\n", mv->glyphs[i-1].sc->name ); */
1501 : /* printf("mv->glyphs[i ].sc.name:%s\n", mv->glyphs[i ].sc->name ); */
1502 :
1503 0 : int pidx = KernClassFindIndexContaining( kc->firsts,
1504 : kc->first_cnt,
1505 0 : mv->glyphs[i-1].sc->name );
1506 : /*
1507 : * Same value for firsts in the kernclass matrix
1508 : */
1509 0 : if( pidx == pscidx )
1510 : {
1511 0 : int idx = KernClassFindIndexContaining( kc->seconds,
1512 : kc->second_cnt,
1513 0 : mv->glyphs[ i ].sc->name );
1514 :
1515 : /*
1516 : * First and Second match, we have the same cell
1517 : * in the kernclass and thus the same kern value
1518 : * should be applied.
1519 : */
1520 0 : if( scidx == idx )
1521 : {
1522 : // update the kern text entry box in the lower part of
1523 : // the window.
1524 0 : MVRefreshValues( mv, i-1 );
1525 :
1526 : //
1527 : // Shift the guide and kerning for this digraph, and move
1528 : // all the glyphs on the right over or back a bit so that things
1529 : // still all fit as expected.
1530 : //
1531 0 : mv->perchar[i-1].kernafter = newkernafter;
1532 : int j;
1533 0 : for ( j=i; j<mv->glyphcnt; ++j ) {
1534 0 : mv->perchar[j].dx = mv->perchar[j-1].dx + mv->perchar[j-1].dwidth +
1535 0 : mv->perchar[j-1].kernafter;
1536 : }
1537 : }
1538 : }
1539 : }
1540 : }
1541 : }
1542 :
1543 : // refresh other kerning input boxes if they are the same characters
1544 : static int MV_ChangeKerning_Nested = 0;
1545 0 : int refreshOtherPairEntries = true;
1546 0 : if( !MV_ChangeKerning_Nested && refreshOtherPairEntries && mv->glyphs[0].sc )
1547 : {
1548 0 : int i = 1;
1549 0 : for( ; mv->glyphs[i].sc; i++ )
1550 : {
1551 0 : if( i != which
1552 0 : && sc == mv->glyphs[i].sc
1553 0 : && psc == mv->glyphs[i-1].sc )
1554 : {
1555 :
1556 0 : GGadget *g = mv->perchar[i].kern;
1557 : unichar_t *end;
1558 0 : int val = u_strtol(_GGadgetGetTitle(g),&end,10);
1559 :
1560 0 : MV_ChangeKerning_Nested = 1;
1561 0 : int which = (intpt) GGadgetGetUserData(g);
1562 0 : MV_ChangeKerning( mv, which, offset, is_diff );
1563 0 : GGadgetSetTitle8( g, tostr(offset) );
1564 0 : MV_ChangeKerning_Nested = 0;
1565 : }
1566 : }
1567 : }
1568 :
1569 0 : mv->sf->changed = true;
1570 0 : GDrawRequestExpose(mv->v,NULL,false);
1571 :
1572 0 : return( true );
1573 : }
1574 :
1575 0 : static int MV_KernChanged(GGadget *g, GEvent *e) {
1576 : /* This routines called during "Advanced Width Metrics" viewing */
1577 : /* any time "Kern:" changed or screen is updated */
1578 0 : MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g));
1579 0 : int which = (intpt) GGadgetGetUserData(g);
1580 : int i;
1581 :
1582 0 : if ( e->type!=et_controlevent )
1583 0 : return( true );
1584 0 : if ( which>mv->glyphcnt-1 || which==0 )
1585 0 : return( true );
1586 0 : if ( e->u.control.subtype == et_textchanged ) {
1587 : unichar_t *end;
1588 0 : int val = u_strtol(_GGadgetGetTitle(g),&end,10);
1589 :
1590 0 : if ( *end && !(*end=='-' && end[1]=='\0'))
1591 0 : GDrawBeep(NULL);
1592 : else {
1593 0 : MV_ChangeKerning(mv,which,val, false);
1594 : }
1595 0 : } else if ( e->u.control.subtype == et_textfocuschanged &&
1596 0 : e->u.control.u.tf_focus.gained_focus ) {
1597 0 : for ( i=0 ; i<mv->glyphcnt; ++i )
1598 0 : if ( i!=which && mv->perchar[i].selected )
1599 0 : MVDeselectChar(mv,i);
1600 0 : MVSelectChar(mv,which);
1601 : }
1602 :
1603 0 : if( haveClassBasedKerningInView(mv) )
1604 : {
1605 0 : MVRefreshMetric(mv);
1606 0 : GDrawRequestExpose(mv->v,NULL,false);
1607 : }
1608 :
1609 0 : return( true );
1610 : }
1611 :
1612 0 : static void MVToggleVertical(MetricsView *mv) {
1613 : int size;
1614 :
1615 0 : mv->vertical = !mv->vertical;
1616 :
1617 0 : GGadgetSetTitle8( mv->widthlab, mv->vertical ? "Height:" : "Width:" );
1618 0 : GGadgetSetTitle8( mv->lbearinglab, mv->vertical ? "TBearing:" : "LBearing:" );
1619 0 : GGadgetSetTitle8( mv->rbearinglab, mv->vertical ? "BBearing:" : "RBearing:" );
1620 0 : GGadgetSetTitle8( mv->kernlab, mv->vertical ? "VKern:" : "Kern:" );
1621 :
1622 0 : if ( mv->vertical )
1623 0 : if ( mv->scale_index<4 ) mv->scale_index = 4;
1624 :
1625 0 : if ( mv->pixelsize_set_by_window ) {
1626 0 : size = (mv->displayend - mv->topend - 4);
1627 0 : if ( mv->dwidth-20<size )
1628 0 : size = mv->dwidth-20;
1629 0 : size *= mv_scales[mv->scale_index];
1630 0 : if ( mv->pixelsize != size ) {
1631 0 : mv->pixelsize = size;
1632 0 : mv->dpi = 72;
1633 0 : if ( mv->bdf==NULL ) {
1634 0 : BDFFontFree(mv->show);
1635 0 : mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->pixelsize,72,
1636 : MVGetSplineFontPieceMealFlags( mv ), NULL );
1637 : }
1638 0 : MVRemetric(mv);
1639 : }
1640 : }
1641 0 : }
1642 :
1643 0 : static SplineChar *MVSCFromUnicode(MetricsView *mv, SplineFont *sf, EncMap *map, int ch,BDFFont *bdf) {
1644 : int i;
1645 : SplineChar *sc;
1646 :
1647 0 : if ( mv->fake_unicode_base && ch>=mv->fake_unicode_base &&
1648 0 : ch<=mv->fake_unicode_base+mv->sf->glyphcnt )
1649 0 : return( mv->sf->glyphs[ch-mv->fake_unicode_base] );
1650 :
1651 0 : i = SFFindSlot(sf,map,ch,NULL);
1652 0 : if ( i==-1 )
1653 0 : return( NULL );
1654 : else {
1655 0 : sc = SFMakeChar(sf,map,i);
1656 0 : if ( bdf!=NULL )
1657 0 : BDFMakeChar(bdf,map,i);
1658 : }
1659 0 : return( sc );
1660 : }
1661 :
1662 0 : static void MVMoveFieldsBy(MetricsView *mv,int diff) {
1663 : int i;
1664 : int y,x;
1665 :
1666 0 : for ( i=0; i<mv->max && mv->perchar[i].width!=NULL; ++i ) {
1667 0 : y = mv->displayend+2;
1668 0 : x = mv->perchar[i].mx-diff;
1669 0 : if ( x<mv->mbase+mv->mwidth ) x = -2*mv->mwidth;
1670 0 : GGadgetMove(mv->perchar[i].name,x,y);
1671 0 : y += mv->fh+4;
1672 0 : GGadgetMove(mv->perchar[i].width,x,y);
1673 0 : y += mv->fh+4;
1674 0 : GGadgetMove(mv->perchar[i].lbearing,x,y);
1675 0 : y += mv->fh+4;
1676 0 : GGadgetMove(mv->perchar[i].rbearing,x,y);
1677 0 : y += mv->fh+4;
1678 0 : if ( i!=0 )
1679 0 : GGadgetMove(mv->perchar[i].kern,x-mv->mwidth/2,y);
1680 : }
1681 0 : }
1682 :
1683 0 : static int MVDisplayedCnt(MetricsView *mv) {
1684 0 : int i, wid = mv->mbase;
1685 :
1686 0 : for ( i=mv->coff; i<mv->glyphcnt; ++i ) {
1687 0 : wid += mv->perchar[i].dwidth;
1688 0 : if ( wid>mv->dwidth )
1689 0 : return( i-mv->coff );
1690 : }
1691 0 : return( i-mv->coff ); /* There's extra room. don't know exactly how much but allow for some */
1692 : }
1693 :
1694 0 : static void MVSetSb(MetricsView *mv) {
1695 0 : int cnt = (mv->dwidth-mv->mbase-mv->mwidth)/mv->mwidth;
1696 0 : int dcnt = MVDisplayedCnt(mv);
1697 :
1698 0 : if ( cnt>dcnt ) cnt = dcnt;
1699 0 : if ( cnt==0 ) cnt = 1;
1700 :
1701 0 : GScrollBarSetBounds(mv->hsb,0,mv->glyphcnt,cnt);
1702 0 : GScrollBarSetPos(mv->hsb,mv->coff);
1703 0 : }
1704 :
1705 0 : static int MVSetVSb(MetricsView *mv) {
1706 : int max, min, ret, yoff;
1707 : int fudge;
1708 :
1709 0 : if ( mv->displayend==0 )
1710 0 : return(0); /* Setting the scroll bar is premature */
1711 :
1712 0 : if ( mv->vertical ) {
1713 0 : min = max = 0;
1714 0 : if ( mv->glyphcnt!=0 )
1715 0 : max = mv->perchar[mv->glyphcnt-1].dy + mv->perchar[mv->glyphcnt-1].dheight;
1716 0 : fudge = 10;
1717 : } else {
1718 0 : SplineFont *sf = mv->sf;
1719 0 : int pixels = mv->pixelsize_set_by_window ? mv->vheight : mv->pixelsize;
1720 0 : fudge = pixels/4;
1721 0 : min = -(pixels*sf->descent)/(sf->ascent+sf->descent);
1722 0 : max = pixels + min;
1723 0 : min *= mv_scales[mv->scale_index];
1724 0 : max *= mv_scales[mv->scale_index];
1725 : }
1726 0 : mv->ybaseline = max;
1727 0 : max += fudge*mv_scales[mv->scale_index] + mv->vheight;
1728 0 : min -= fudge*mv_scales[mv->scale_index];
1729 0 : GScrollBarSetBounds(mv->vsb,min,max,mv->vheight);
1730 0 : yoff = mv->yoff;
1731 0 : if ( yoff+mv->vheight > max )
1732 0 : yoff = max - mv->vheight;
1733 0 : if ( yoff<min ) yoff = min;
1734 0 : ret = yoff!=mv->yoff;
1735 0 : mv->yoff = yoff;
1736 0 : GScrollBarSetPos(mv->vsb,yoff);
1737 0 : return( ret );
1738 : }
1739 :
1740 0 : static void MVHScroll(MetricsView *mv,struct sbevent *sb) {
1741 0 : int newpos = mv->coff;
1742 0 : int cnt = (mv->dwidth-mv->mbase-mv->mwidth)/mv->mwidth;
1743 0 : int dcnt = MVDisplayedCnt(mv);
1744 :
1745 0 : if ( cnt>dcnt ) cnt = dcnt;
1746 0 : if ( cnt==0 ) cnt = 1;
1747 :
1748 0 : switch( sb->type ) {
1749 : case et_sb_top:
1750 0 : newpos = 0;
1751 0 : break;
1752 : case et_sb_uppage:
1753 0 : newpos -= cnt;
1754 0 : break;
1755 : case et_sb_up:
1756 0 : --newpos;
1757 0 : break;
1758 : case et_sb_down:
1759 0 : ++newpos;
1760 0 : break;
1761 : case et_sb_downpage:
1762 0 : newpos += cnt;
1763 0 : break;
1764 : case et_sb_bottom:
1765 0 : newpos = mv->glyphcnt-cnt;
1766 0 : break;
1767 : case et_sb_thumb:
1768 : case et_sb_thumbrelease:
1769 0 : newpos = sb->pos;
1770 0 : break;
1771 : }
1772 0 : if ( newpos>mv->glyphcnt-cnt )
1773 0 : newpos = mv->glyphcnt-cnt;
1774 0 : if ( newpos<0 ) newpos =0;
1775 0 : if ( newpos!=mv->coff ) {
1776 0 : int old = mv->coff;
1777 0 : int diff = newpos-mv->coff;
1778 0 : int charsize = mv->perchar[newpos].dx-mv->perchar[old].dx;
1779 : GRect fieldrect, charrect;
1780 :
1781 0 : mv->coff = newpos;
1782 0 : charrect.x = 0; charrect.width = mv->vwidth;
1783 0 : charrect.y = 0; charrect.height = mv->vheight;
1784 0 : fieldrect.x = mv->mbase+mv->mwidth; fieldrect.width = mv->width-mv->mbase;
1785 0 : fieldrect.y = mv->displayend; fieldrect.height = mv->height-mv->sbh-mv->displayend;
1786 0 : GScrollBarSetBounds(mv->hsb,0,mv->glyphcnt,cnt);
1787 0 : GScrollBarSetPos(mv->hsb,mv->coff);
1788 0 : MVMoveFieldsBy(mv,newpos*mv->mwidth);
1789 0 : GDrawScroll(mv->gw,&fieldrect,-diff*mv->mwidth,0);
1790 0 : mv->xoff = mv->perchar[newpos].dx-mv->perchar[0].dx;
1791 0 : if ( mv->right_to_left ) {
1792 0 : charsize = -charsize;
1793 : }
1794 0 : GDrawScroll(mv->v,&charrect,-charsize,0);
1795 : }
1796 0 : }
1797 :
1798 0 : static void MVVScroll(MetricsView *mv,struct sbevent *sb) {
1799 0 : int newpos = mv->yoff;
1800 : int32 min, max, page;
1801 :
1802 0 : GScrollBarGetBounds(mv->vsb,&min,&max,&page);
1803 0 : switch( sb->type ) {
1804 : case et_sb_top:
1805 0 : newpos = 0;
1806 0 : break;
1807 : case et_sb_uppage:
1808 0 : newpos -= page;
1809 0 : break;
1810 : case et_sb_up:
1811 0 : newpos -= (page)/15;
1812 0 : break;
1813 : case et_sb_down:
1814 0 : newpos += (page)/15;
1815 0 : break;
1816 : case et_sb_downpage:
1817 0 : newpos += page;
1818 0 : break;
1819 : case et_sb_bottom:
1820 0 : newpos = max-page;
1821 0 : break;
1822 : case et_sb_thumb:
1823 : case et_sb_thumbrelease:
1824 0 : newpos = sb->pos;
1825 0 : break;
1826 : }
1827 0 : if ( newpos>max-page )
1828 0 : newpos = max-page;
1829 0 : if ( newpos<min ) newpos = min;
1830 0 : if ( newpos!=mv->yoff ) {
1831 0 : int diff = newpos-mv->yoff;
1832 : GRect charrect;
1833 :
1834 0 : mv->yoff = newpos;
1835 0 : charrect.x = 0; charrect.width = mv->vwidth;
1836 0 : charrect.y = 0; charrect.height = mv->vheight;
1837 0 : GScrollBarSetPos(mv->vsb,mv->yoff);
1838 0 : GDrawScroll(mv->v,&charrect,0,diff);
1839 : }
1840 0 : }
1841 :
1842 0 : static int MVFakeUnicodeOfSc(MetricsView *mv, SplineChar *sc) {
1843 :
1844 0 : if ( sc->unicodeenc!=-1 )
1845 0 : return( sc->unicodeenc );
1846 :
1847 0 : if ( mv->fake_unicode_base==0 ) { /* Not set */
1848 : /* If they have nothing in Supplementary Private Use Area-A use it */
1849 : /* If they have nothing in Supplementary Private Use Area-B use it */
1850 : /* else just use 0xfffd */
1851 : int a, al, ah, b, bl, bh;
1852 : int gid,k,max;
1853 : SplineChar *test;
1854 : SplineFont *_sf, *sf;
1855 0 : sf = mv->sf;
1856 0 : if ( sf->cidmaster ) sf = sf->cidmaster;
1857 0 : k=0;
1858 0 : a = al = ah = b = bl = bh = 0;
1859 0 : max = 0;
1860 : do {
1861 0 : _sf = ( sf->subfontcnt==0 ) ? sf : sf->subfonts[k];
1862 0 : for ( gid=0; gid<_sf->glyphcnt; ++gid ) if ( (test=_sf->glyphs[gid])!=NULL ) {
1863 0 : if ( test->unicodeenc>=0xf0000 && test->unicodeenc<=0xfffff ) {
1864 0 : a = true;
1865 0 : if ( test->unicodeenc<0xf8000 )
1866 0 : al = true;
1867 : else
1868 0 : ah = true;
1869 0 : } else if ( test->unicodeenc>=0x100000 && test->unicodeenc<=0x10ffff ) {
1870 0 : b = true;
1871 0 : if ( test->unicodeenc<0x108000 )
1872 0 : bl = true;
1873 : else
1874 0 : bh = true;
1875 : }
1876 : }
1877 0 : if ( gid>max ) max = gid;
1878 0 : ++k;
1879 0 : } while ( k<sf->subfontcnt );
1880 0 : if ( !a ) /* Nothing in SPUA-A */
1881 0 : mv->fake_unicode_base = 0xf0000;
1882 0 : else if ( !b )
1883 0 : mv->fake_unicode_base = 0x100000;
1884 0 : else if ( max<0x8000 ) {
1885 0 : if ( !al )
1886 0 : mv->fake_unicode_base = 0xf0000;
1887 0 : else if ( !ah )
1888 0 : mv->fake_unicode_base = 0xf8000;
1889 0 : else if ( !bl )
1890 0 : mv->fake_unicode_base = 0x100000;
1891 0 : else if ( !bh )
1892 0 : mv->fake_unicode_base = 0x108000;
1893 : }
1894 0 : if ( mv->fake_unicode_base==0 )
1895 0 : mv->fake_unicode_base = -1;
1896 : }
1897 :
1898 0 : if ( mv->fake_unicode_base==-1 )
1899 0 : return( 0xfffd );
1900 : else
1901 0 : return( mv->fake_unicode_base+sc->orig_pos );
1902 : }
1903 :
1904 0 : static int MVOddMatch(MetricsView *mv,int uni,SplineChar *sc) {
1905 0 : if ( sc->unicodeenc!=-1 )
1906 0 : return( false );
1907 0 : else if ( mv->fake_unicode_base<=0 )
1908 0 : return( uni==0xfffd );
1909 : else
1910 0 : return( uni>=mv->fake_unicode_base && sc->orig_pos == uni-mv->fake_unicode_base );
1911 : }
1912 :
1913 0 : void MVSetSCs(MetricsView *mv, SplineChar **scs) {
1914 : /* set the list of characters being displayed to those in scs */
1915 : int len;
1916 : unichar_t *ustr;
1917 :
1918 0 : for ( len=0; scs[len]!=NULL; ++len );
1919 0 : if ( len>=mv->cmax )
1920 0 : mv->chars = realloc(mv->chars,(mv->cmax=len+10)*sizeof(SplineChar *));
1921 0 : memcpy(mv->chars,scs,(len+1)*sizeof(SplineChar *));
1922 0 : mv->clen = len;
1923 :
1924 0 : ustr = malloc((len+1)*sizeof(unichar_t));
1925 0 : for ( len=0; scs[len]!=NULL; ++len )
1926 0 : if ( scs[len]->unicodeenc>0 )
1927 0 : ustr[len] = scs[len]->unicodeenc;
1928 : else
1929 0 : ustr[len] = MVFakeUnicodeOfSc(mv,scs[len]);
1930 0 : ustr[len] = 0;
1931 0 : GGadgetSetTitle(mv->text,ustr);
1932 0 : free(ustr);
1933 :
1934 0 : MVRemetric(mv);
1935 :
1936 0 : GDrawRequestExpose(mv->v,NULL,false);
1937 0 : }
1938 :
1939 :
1940 0 : static int WordlistEscapedInputStringToRealString_getFakeUnicodeAs_MVFakeUnicodeOfSc( SplineChar *sc, void* udata )
1941 : {
1942 0 : MetricsView *mv = (MetricsView *)udata;
1943 0 : int n = MVFakeUnicodeOfSc( mv, sc );
1944 0 : return n;
1945 : }
1946 :
1947 :
1948 0 : static void MVTextChanged(MetricsView *mv) {
1949 0 : const unichar_t *ret = 0, *pt, *ept, *tpt;
1950 0 : int i,ei, j, start=0, end=0;
1951 : int missing;
1952 0 : int direction_change = false;
1953 0 : SplineChar **hold = NULL;
1954 :
1955 0 : ret = _GGadgetGetTitle(mv->text);
1956 :
1957 : // convert the slash escpae codes and the like to the real string we will use
1958 : // for the metrics window
1959 0 : WordListLine wll = WordlistEscapedInputStringToParsedDataComplex(
1960 : mv->sf, _GGadgetGetTitle(mv->text),
1961 : WordlistEscapedInputStringToRealString_getFakeUnicodeAs_MVFakeUnicodeOfSc, mv );
1962 0 : ret = WordListLine_toustr( wll );
1963 :
1964 0 : if (( ret[0]<0x10000 && isrighttoleft(ret[0]) && !mv->right_to_left ) ||
1965 0 : ( ret[0]<0x10000 && !isrighttoleft(ret[0]) && mv->right_to_left )) {
1966 0 : direction_change = true;
1967 0 : mv->right_to_left = !mv->right_to_left;
1968 : }
1969 0 : for ( pt=ret, i=0; i<mv->clen && *pt!='\0'; ++i, ++pt )
1970 0 : if ( *pt!=mv->chars[i]->unicodeenc &&
1971 0 : !MVOddMatch(mv,*pt,mv->chars[i]))
1972 0 : break;
1973 0 : if ( i==mv->clen && *pt=='\0' )
1974 0 : return; /* Nothing changed */
1975 0 : for ( ept=ret+u_strlen(ret)-1, ei=mv->clen-1; ; --ei, --ept )
1976 0 : if ( ei<0 || ept<ret || (*ept!=mv->chars[ei]->unicodeenc &&
1977 0 : !MVOddMatch(mv,*ept,mv->chars[ei]))) {
1978 0 : ++ei; ++ept;
1979 0 : break;
1980 0 : } else if ( ei<i || ept<pt ) {
1981 0 : ++ei; ++ept;
1982 0 : break;
1983 : }
1984 0 : if ( ei==i && ept==pt )
1985 0 : IError("No change when there should have been one in MV_TextChanged");
1986 0 : if ( u_strlen(ret)>=mv->cmax ) {
1987 0 : int oldmax=mv->cmax;
1988 0 : mv->cmax = u_strlen(ret)+10;
1989 0 : mv->chars = realloc(mv->chars,mv->cmax*sizeof(SplineChar *));
1990 0 : memset(mv->chars+oldmax,'\0',(mv->cmax-oldmax)*sizeof(SplineChar *));
1991 : }
1992 :
1993 0 : missing = 0;
1994 0 : for ( tpt=pt; tpt<ept; ++tpt )
1995 0 : if ( mv->fake_unicode_base>0 && *tpt>=mv->fake_unicode_base &&
1996 0 : *tpt<=mv->fake_unicode_base+mv->sf->glyphcnt )
1997 : /* That's ok */;
1998 0 : else if ( SFFindSlot(mv->sf,mv->fv->b.map,*tpt,NULL)==-1 )
1999 0 : ++missing;
2000 :
2001 0 : if ( ept-pt-missing > ei-i ) {
2002 0 : if ( i<mv->clen ) {
2003 0 : int diff = (ept-pt-missing) - (ei-i);
2004 0 : hold = malloc((mv->clen+diff+6)*sizeof(SplineChar *));
2005 0 : for ( j=mv->clen-1; j>=ei; --j )
2006 0 : hold[j+diff] = mv->chars[j];
2007 0 : start = ei+diff; end = mv->clen+diff;
2008 : }
2009 0 : } else if ( ept-pt-missing != ei-i ) {
2010 0 : int diff = (ept-pt-missing) - (ei-i);
2011 0 : for ( j=ei; j<mv->clen; ++j )
2012 0 : if ( j+diff>=0 )
2013 0 : mv->chars[j+diff] = mv->chars[j];
2014 : }
2015 0 : for ( j=i; pt<ept; ++pt ) {
2016 : SplineChar *sc;
2017 0 : sc = MVSCFromUnicode(mv,mv->sf,mv->fv->b.map,*pt,mv->bdf);
2018 0 : if ( sc!=NULL )
2019 0 : mv->chars[j++] = sc;
2020 : }
2021 0 : if ( hold!=NULL ) {
2022 : /* We had to figure out what sc's there were before we wrote over them*/
2023 : /* but we couldn't put them where they belonged until everything before*/
2024 : /* them was set properly */
2025 0 : for ( j=start; j<end; ++j )
2026 0 : mv->chars[j] = hold[j];
2027 0 : free(hold);
2028 : }
2029 0 : mv->clen = u_strlen(ret)-missing;
2030 0 : mv->chars[mv->clen] = NULL;
2031 0 : MVRemetric(mv);
2032 :
2033 : // handle selecting the default glyph if desired this is slightly
2034 : // complex because we need to handle when there is no selected
2035 : // entry, which is the case just after loading a word list, and
2036 : // then the first line is the right line.
2037 0 : GTextInfo* gt = GGadgetGetListItemSelected(mv->text);
2038 0 : if( !gt )
2039 : {
2040 0 : GTextInfo **ti=NULL;
2041 : int32 len;
2042 0 : ti = GGadgetGetList(mv->text,&len);
2043 0 : if( len )
2044 0 : gt = ti[0];
2045 : }
2046 :
2047 0 : selectUserChosenWordListGlyphs( mv, wll );
2048 0 : GDrawRequestExpose(mv->v,NULL,false);
2049 : }
2050 :
2051 : GTextInfo mv_text_init[] = {
2052 : { (unichar_t *) "", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 1, 0, 1, 0, 0, '\0'},
2053 : { NULL, NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0'},
2054 : { (unichar_t *) N_("Load Word List..."), NULL, 0, 0, (void *) -1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
2055 : { (unichar_t *) N_("Load Glyph Name List..."), NULL, 0, 0, (void *) -2, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
2056 : GTEXTINFO_EMPTY
2057 : };
2058 :
2059 0 : static void MVFigureGlyphNames(MetricsView *mv,const unichar_t *names) {
2060 : char buffer[400], *pt, *start;
2061 : SplineChar *founds[40];
2062 : int i,cnt,ch;
2063 : unichar_t *newtext;
2064 :
2065 0 : u2utf8_strcpy(buffer,names);
2066 0 : start = buffer;
2067 0 : for ( i=0; *start; ) {
2068 0 : while ( *start==' ' ) ++start;
2069 0 : if ( *start=='\0' )
2070 0 : break;
2071 0 : for ( pt=start; *pt && *pt!=' '; ++pt );
2072 0 : ch = *pt; *pt = '\0';
2073 0 : if ( i>=40 )
2074 0 : break;
2075 0 : if ( (founds[i]=SFGetChar(mv->sf,-1,start))!=NULL )
2076 0 : ++i;
2077 0 : *pt = ch;
2078 0 : start = pt;
2079 : }
2080 0 : cnt = i;
2081 :
2082 0 : if ( cnt>=mv->cmax ) {
2083 0 : mv->cmax = mv->clen+cnt+10;
2084 0 : mv->chars = realloc(mv->chars,mv->cmax*sizeof(SplineChar *));
2085 : }
2086 0 : newtext = malloc((cnt+1)*sizeof(unichar_t));
2087 0 : for ( i=0; i<cnt; ++i ) {
2088 0 : newtext[i] = founds[i]->unicodeenc==-1 ?
2089 0 : MVFakeUnicodeOfSc(mv,founds[i]) :
2090 0 : founds[i]->unicodeenc;
2091 0 : mv->chars[i] = founds[i];
2092 : }
2093 0 : newtext[i] = 0;
2094 0 : mv->chars[i] = NULL;
2095 0 : mv->clen = cnt;
2096 0 : MVRemetric(mv);
2097 :
2098 0 : GGadgetSetTitle(mv->text,newtext);
2099 0 : free(newtext);
2100 :
2101 0 : GDrawRequestExpose(mv->v,NULL,false);
2102 0 : }
2103 :
2104 0 : static void MVLoadWordList(MetricsView *mv, int type) {
2105 0 : int words_max = 1024*128;
2106 0 : GTextInfo** words = WordlistLoadFileToGTextInfo( type, words_max );
2107 0 : if ( !words ) {
2108 0 : GGadgetSetTitle8(mv->text,"");
2109 0 : return;
2110 : }
2111 :
2112 0 : if ( words[0] ) {
2113 0 : GGadgetSetList(mv->text,words,true);
2114 0 : GGadgetSetTitle8(mv->text,(char *) (words[0]->text));
2115 0 : if ( type==-2 )
2116 0 : MVFigureGlyphNames(mv,_GGadgetGetTitle(mv->text)+1);
2117 0 : mv->word_index = 0;
2118 : }
2119 0 : GTextInfoArrayFree(words);
2120 : }
2121 :
2122 0 : static int MV_TextChanged(GGadget *g, GEvent *e) {
2123 :
2124 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2125 0 : MetricsView *mv = GGadgetGetUserData(g);
2126 0 : int pos = e->u.control.u.tf_changed.from_pulldown;
2127 0 : if ( pos!=-1 ) {
2128 : int32 len;
2129 0 : GTextInfo **ti = GGadgetGetList(g,&len);
2130 0 : GTextInfo *cur = ti[pos];
2131 0 : int type = (intpt) cur->userdata;
2132 0 : if ( type < 0 )
2133 0 : MVLoadWordList(mv,type);
2134 0 : else if ( cur->text!=NULL ) {
2135 0 : mv->word_index = pos;
2136 0 : if ( cur->text[0]==0x200b ) /* Zero width space, flag for glyph names */
2137 0 : MVFigureGlyphNames(mv,cur->text+1);
2138 : }
2139 : }
2140 0 : MVTextChanged(mv);
2141 : }
2142 0 : return( true );
2143 : }
2144 :
2145 0 : static int MV_ScriptLangChanged(GGadget *g, GEvent *e) {
2146 :
2147 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
2148 0 : const unichar_t *sstr = _GGadgetGetTitle(g);
2149 0 : MetricsView *mv = GGadgetGetUserData(g);
2150 0 : if ( e->u.control.u.tf_changed.from_pulldown!=-1 ) {
2151 0 : GGadgetSetTitle8(g,mv->scriptlangs[e->u.control.u.tf_changed.from_pulldown].userdata );
2152 0 : sstr = _GGadgetGetTitle(g);
2153 : } else {
2154 0 : if ( u_strlen(sstr)<4 || !isalpha(sstr[0]) || !isalnum(sstr[1]) /*|| !isalnum(sstr[2]) || !isalnum(sstr[3])*/ )
2155 0 : return( true );
2156 0 : if ( u_strlen(sstr)==4 )
2157 : /* No language, we'll use default */;
2158 0 : else if ( u_strlen(sstr)!=10 || sstr[4]!='{' || sstr[9]!='}' ||
2159 0 : !isalpha(sstr[5]) || !isalpha(sstr[6]) || !isalpha(sstr[7]) )
2160 0 : return( true );
2161 : }
2162 0 : MVSetFeatures(mv);
2163 0 : if ( mv->clen!=0 )/* if there are no chars, remetricking will set the script field to DFLT */
2164 0 : MVRemetric(mv);
2165 0 : GDrawRequestExpose(mv->v,NULL,false);
2166 : }
2167 0 : return( true );
2168 : }
2169 :
2170 0 : static int MV_FeaturesChanged(GGadget *g, GEvent *e) {
2171 :
2172 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
2173 0 : MetricsView *mv = GGadgetGetUserData(g);
2174 0 : MVRemetric(mv);
2175 0 : GDrawRequestExpose(mv->v,NULL,false);
2176 : }
2177 0 : return( true );
2178 : }
2179 :
2180 0 : void MV_FriendlyFeatures(GGadget *g, int pos) {
2181 : int32 len;
2182 0 : GTextInfo **ti = GGadgetGetList(g,&len);
2183 :
2184 0 : if ( pos<0 || pos>=len )
2185 0 : GGadgetEndPopup();
2186 : else {
2187 0 : const unichar_t *pt = ti[pos]->text;
2188 : uint32 tag;
2189 : int i;
2190 0 : tag = (pt[0]<<24) | (pt[1]<<16) | (pt[2]<<8) | pt[3];
2191 0 : LookupUIInit();
2192 0 : for ( i=0; friendlies[i].friendlyname!=NULL; ++i )
2193 0 : if ( friendlies[i].tag==tag )
2194 0 : break;
2195 0 : if ( friendlies[i].friendlyname!=NULL )
2196 0 : GGadgetPreparePopup8(GGadgetGetWindow(g),friendlies[i].friendlyname);
2197 : }
2198 0 : }
2199 :
2200 0 : static int MV_SubtableChanged(GGadget *g, GEvent *e) {
2201 :
2202 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
2203 0 : MetricsView *mv = GGadgetGetUserData(g);
2204 : int32 len;
2205 0 : GTextInfo **ti = GGadgetGetList(g,&len);
2206 : int i;
2207 : KernPair *kp;
2208 : struct lookup_subtable *sub;
2209 0 : SplineFont *sf = mv->sf;
2210 :
2211 0 : if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
2212 :
2213 0 : if ( ti[len-1]->selected ) {/* New lookup subtable */
2214 : struct subtable_data sd;
2215 0 : memset(&sd,0,sizeof(sd));
2216 0 : sd.flags = (mv->vertical ? sdf_verticalkern : sdf_horizontalkern ) |
2217 0 : sdf_kernpair | sdf_dontedit;
2218 0 : sub = SFNewLookupSubtableOfType(sf,gpos_pair,&sd,mv->layer);
2219 0 : if ( sub==NULL )
2220 0 : return( true );
2221 0 : mv->cur_subtable = sub;
2222 0 : MVSetSubtables(mv->sf);
2223 0 : MVSetFeatures(mv); /* Is this needed? */
2224 0 : } else if ( ti[len-2]->selected ) { /* Idiots. They selected the line, can't have that */
2225 0 : MVSetSubtables(mv->sf);
2226 0 : sub = mv->cur_subtable;
2227 : } else
2228 0 : mv->cur_subtable = GGadgetGetListItemSelected(mv->subtable_list)->userdata;
2229 :
2230 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
2231 0 : if ( mv->perchar[i].selected )
2232 0 : break;
2233 : }
2234 0 : kp = mv->glyphs[i].kp;
2235 0 : if ( kp!=NULL )
2236 0 : kp->subtable = mv->cur_subtable;
2237 : }
2238 0 : return( true );
2239 : }
2240 :
2241 : #define MID_ZoomIn 2002
2242 : #define MID_ZoomOut 2003
2243 : #define MID_Next 2005
2244 : #define MID_Prev 2006
2245 : #define MID_Outline 2007
2246 : #define MID_ShowGrid 2008
2247 : #define MID_HideGrid 2009
2248 : #define MID_PartialGrid 2010
2249 : #define MID_HideGridWhenMoving 2011
2250 : #define MID_NextDef 2012
2251 : #define MID_PrevDef 2013
2252 : #define MID_AntiAlias 2014
2253 : #define MID_FindInFontView 2015
2254 : #define MID_Ligatures 2020
2255 : #define MID_KernPairs 2021
2256 : #define MID_AnchorPairs 2022
2257 : #define MID_Vertical 2023
2258 : #define MID_ReplaceChar 2024
2259 : #define MID_InsertCharB 2025
2260 : #define MID_InsertCharA 2026
2261 : #define MID_Layers 2027
2262 : #define MID_PointSize 2028
2263 : #define MID_Bigger 2029
2264 : #define MID_Smaller 2030
2265 : #define MID_SizeWindow 2031
2266 : #define MID_CharInfo 2201
2267 : #define MID_FindProblems 2216
2268 : #define MID_Transform 2202
2269 : #define MID_Stroke 2203
2270 : #define MID_RmOverlap 2204
2271 : #define MID_Simplify 2205
2272 : #define MID_Correct 2206
2273 : #define MID_BuildAccent 2208
2274 : #define MID_AvailBitmaps 2210
2275 : #define MID_RegenBitmaps 2211
2276 : #define MID_Autotrace 2212
2277 : #define MID_Round 2213
2278 : #define MID_ShowDependents 2222
2279 : #define MID_AddExtrema 2224
2280 : #define MID_CleanupGlyph 2225
2281 : #define MID_TilePath 2226
2282 : #define MID_BuildComposite 2227
2283 : #define MID_Intersection 2229
2284 : #define MID_FindInter 2230
2285 : #define MID_Effects 2231
2286 : #define MID_SimplifyMore 2232
2287 : #define MID_Center 2600
2288 : #define MID_OpenBitmap 2700
2289 : #define MID_OpenOutline 2701
2290 : #define MID_Cut 2101
2291 : #define MID_Copy 2102
2292 : #define MID_Paste 2103
2293 : #define MID_Clear 2104
2294 : #define MID_SelAll 2106
2295 : #define MID_ClearSel 2105
2296 : #define MID_UnlinkRef 2108
2297 : #define MID_Undo 2109
2298 : #define MID_Redo 2110
2299 : #define MID_CopyRef 2107
2300 : #define MID_CopyWidth 2111
2301 : #define MID_CopyLBearing 2125
2302 : #define MID_CopyRBearing 2126
2303 : #define MID_CopyVWidth 2127
2304 : #define MID_Join 2128
2305 : #define MID_Center 2600
2306 : #define MID_SetWidth 2601
2307 : #define MID_SetLBearing 2602
2308 : #define MID_SetRBearing 2603
2309 : #define MID_Thirds 2604
2310 : #define MID_VKernClass 2605
2311 : #define MID_VKernFromHKern 2606
2312 : #define MID_KernOnly 2607
2313 : #define MID_WidthOnly 2608
2314 : #define MID_BothKernWidth 2609
2315 : #define MID_SetBearings 2610
2316 : #define MID_Recent 2703
2317 : #define MID_SetVWidth 2705
2318 : #define MID_RemoveKerns 2707
2319 : #define MID_RemoveVKerns 2709
2320 :
2321 : #define MID_NextLineInWordList 2720
2322 : #define MID_PrevLineInWordList 2721
2323 : #define MID_RenderUsingHinting 2722
2324 :
2325 :
2326 : #define MID_Warnings 3000
2327 :
2328 0 : static void MVMenuOpen(GWindow gw, struct gmenuitem *mi, GEvent *g) {
2329 0 : MetricsView *d = (MetricsView*)GDrawGetUserData(gw);
2330 0 : FontView *fv = NULL;
2331 0 : if (d) {
2332 0 : fv = (FontView*)d->fv;
2333 : }
2334 0 : _FVMenuOpen(fv);
2335 0 : }
2336 :
2337 0 : static void MVMenuClose(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2338 0 : GDrawDestroyWindow(gw);
2339 0 : }
2340 :
2341 0 : static void MVMenuOpenBitmap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2342 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2343 : EncMap *map;
2344 : int i;
2345 :
2346 0 : if ( mv->sf->bitmaps==NULL )
2347 0 : return;
2348 0 : for ( i=0; i<mv->glyphcnt; ++i )
2349 0 : if ( mv->perchar[i].selected )
2350 0 : break;
2351 0 : map = mv->fv->b.map;
2352 0 : if ( i!=mv->glyphcnt )
2353 0 : BitmapViewCreatePick(map->backmap[mv->glyphs[i].sc->orig_pos],mv->fv);
2354 : }
2355 :
2356 0 : static void MVMenuMergeKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2357 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2358 0 : MergeKernInfo(mv->sf,mv->fv->b.map);
2359 0 : }
2360 :
2361 0 : static void MVMenuAddWordList(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
2362 : {
2363 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2364 0 : MVLoadWordList(mv,-1);
2365 0 : GWidgetIndicateFocusGadget( mv->text );
2366 :
2367 : GEvent e;
2368 0 : e.type = et_controlevent;
2369 0 : e.u.control.subtype = et_textchanged;
2370 0 : e.u.control.u.tf_changed.from_pulldown = 0;
2371 0 : MV_TextChanged(mv->text, &e );
2372 0 : }
2373 :
2374 :
2375 0 : static void MVMenuOpenOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2376 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2377 : int i;
2378 :
2379 0 : for ( i=0; i<mv->glyphcnt; ++i )
2380 0 : if ( mv->perchar[i].selected )
2381 0 : break;
2382 0 : if ( i!=mv->glyphcnt )
2383 0 : CharViewCreate(mv->glyphs[i].sc, mv->fv, -1);
2384 0 : }
2385 :
2386 0 : static void MVMenuSave(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2387 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2388 0 : _FVMenuSave(mv->fv);
2389 0 : }
2390 :
2391 0 : static void MVMenuSaveAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2392 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2393 0 : _FVMenuSaveAs(mv->fv);
2394 0 : }
2395 :
2396 0 : static void MVMenuGenerate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2397 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2398 0 : _FVMenuGenerate(mv->fv, false);
2399 0 : }
2400 :
2401 0 : static void MVMenuGenerateFamily(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2402 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2403 0 : _FVMenuGenerate(mv->fv, gf_macfamily);
2404 0 : }
2405 :
2406 0 : static void MVMenuGenerateTTC(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2407 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2408 0 : _FVMenuGenerate(mv->fv, gf_ttc);
2409 0 : }
2410 :
2411 0 : static void MVMenuPrint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2412 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2413 0 : PrintFFDlg(NULL, NULL, mv);
2414 0 : }
2415 :
2416 0 : static void MVUndo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2417 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2418 : int i;
2419 :
2420 0 : if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_undo) )
2421 : /* MVTextChanged(mv) */ ;
2422 : else {
2423 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2424 0 : if ( mv->perchar[i].selected )
2425 0 : break;
2426 0 : if ( i==-1 )
2427 0 : return;
2428 0 : if ( mv->glyphs[i].sc->layers[mv->layer].undoes!=NULL )
2429 0 : SCDoUndo(mv->glyphs[i].sc, mv->layer);
2430 : }
2431 : }
2432 :
2433 0 : static void MVRedo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2434 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2435 : int i;
2436 :
2437 0 : if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_redo) )
2438 : /* MVTextChanged(mv) */ ;
2439 : else {
2440 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2441 0 : if ( mv->perchar[i].selected )
2442 0 : break;
2443 0 : if ( i==-1 )
2444 0 : return;
2445 0 : if ( mv->glyphs[i].sc->layers[mv->layer].redoes!=NULL )
2446 0 : SCDoRedo(mv->glyphs[i].sc, mv->layer);
2447 : }
2448 : }
2449 :
2450 0 : static void MVClear(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2451 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2452 : int i;
2453 : SplineChar *sc;
2454 : BDFFont *bdf;
2455 : extern int onlycopydisplayed;
2456 :
2457 0 : if ( GGadgetActiveGadgetEditCmd(mv->gw, ec_clear) )
2458 : /* MVTextChanged(mv) */;
2459 : else {
2460 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2461 0 : if ( mv->perchar[i].selected )
2462 0 : break;
2463 0 : if ( i==-1 )
2464 0 : return;
2465 0 : sc = mv->glyphs[i].sc;
2466 0 : if ( sc->dependents!=NULL ) {
2467 : int yes;
2468 : char *buts[4];
2469 0 : buts[1] = _("_Unlink");
2470 0 : buts[0] = _("_Yes");
2471 0 : buts[2] = _("_Cancel");
2472 0 : buts[3] = NULL;
2473 0 : yes = gwwv_ask(_("Bad Reference"), (const char **) buts, 1, 2, _("You are attempting to clear %.30s which is referred to by\nanother character. Are you sure you want to clear it?"), sc->name);
2474 0 : if ( yes==2 )
2475 0 : return;
2476 0 : if ( yes==1 )
2477 0 : UnlinkThisReference(NULL, sc, mv->layer);
2478 : }
2479 :
2480 0 : if ( onlycopydisplayed && mv->bdf==NULL ) {
2481 0 : SCClearAll(sc, mv->layer);
2482 0 : } else if ( onlycopydisplayed ) {
2483 0 : BCClearAll(mv->bdf->glyphs[sc->orig_pos]);
2484 : } else {
2485 0 : SCClearAll(sc,mv->layer);
2486 0 : for ( bdf=mv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
2487 0 : BCClearAll(bdf->glyphs[sc->orig_pos]);
2488 : }
2489 : }
2490 : }
2491 :
2492 0 : static void MVCut(GWindow gw, struct gmenuitem *mi, GEvent *e) {
2493 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2494 : int i;
2495 :
2496 0 : if ( GGadgetActiveGadgetEditCmd(mv->gw, ec_cut) )
2497 : /* MVTextChanged(mv) */ ;
2498 : else {
2499 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2500 0 : if ( mv->perchar[i].selected )
2501 0 : break;
2502 0 : if ( i==-1 )
2503 0 : return;
2504 0 : MVCopyChar(&mv->fv->b,mv->bdf,mv->glyphs[i].sc,ct_fullcopy);
2505 0 : MVClear(gw, mi, e); /* mi & e are actually not used */
2506 : }
2507 : }
2508 :
2509 0 : static void MVCopy(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2510 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2511 : int i;
2512 :
2513 0 : if ( GGadgetActiveGadgetEditCmd(mv->gw, ec_copy) )
2514 : /* MVTextChanged(mv) */ ;
2515 : else {
2516 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2517 0 : if ( mv->perchar[i].selected )
2518 0 : break;
2519 0 : if ( i==-1 )
2520 0 : return;
2521 0 : MVCopyChar(&mv->fv->b, mv->bdf, mv->glyphs[i].sc, ct_fullcopy);
2522 : }
2523 : }
2524 :
2525 0 : static void MVMenuCopyRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2526 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2527 : int i;
2528 :
2529 0 : if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL )
2530 0 : return;
2531 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2532 0 : if ( mv->perchar[i].selected )
2533 0 : break;
2534 0 : if ( i==-1 )
2535 0 : return;
2536 0 : MVCopyChar(&mv->fv->b, mv->bdf, mv->glyphs[i].sc, ct_reference);
2537 : }
2538 :
2539 0 : static void MVMenuCopyWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2540 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2541 : int i;
2542 :
2543 0 : if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL )
2544 0 : return;
2545 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2546 0 : if ( mv->perchar[i].selected )
2547 0 : break;
2548 0 : if ( i==-1 )
2549 0 : return;
2550 0 : SCCopyWidth(mv->glyphs[i].sc,
2551 0 : mi->mid==MID_CopyWidth?ut_width:
2552 0 : mi->mid==MID_CopyVWidth?ut_vwidth:
2553 0 : mi->mid==MID_CopyLBearing?ut_lbearing:
2554 : ut_rbearing);
2555 : }
2556 :
2557 0 : static void MVMenuJoin(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2558 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2559 : int i, changed;
2560 : extern float joinsnap;
2561 :
2562 0 : if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL )
2563 0 : return;
2564 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2565 0 : if ( mv->perchar[i].selected )
2566 0 : break;
2567 0 : if ( i==-1 )
2568 0 : return;
2569 0 : SCPreserveLayer(mv->glyphs[i].sc, mv->layer, false);
2570 0 : mv->glyphs[i].sc->layers[mv->layer].splines =
2571 0 : SplineSetJoin(mv->glyphs[i].sc->layers[mv->layer].splines, true, joinsnap, &changed);
2572 0 : if ( changed )
2573 0 : SCCharChangedUpdate(mv->glyphs[i].sc, mv->layer);
2574 : }
2575 :
2576 0 : static void MVPaste(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2577 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2578 : int i;
2579 :
2580 0 : if ( GGadgetActiveGadgetEditCmd(mv->gw, ec_paste) )
2581 : /*MVTextChanged(mv)*/ ; /* Should get an event now */
2582 : else {
2583 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2584 0 : if ( mv->perchar[i].selected )
2585 0 : break;
2586 0 : if ( i==-1 )
2587 0 : return;
2588 0 : PasteIntoMV(&mv->fv->b, mv->bdf, mv->glyphs[i].sc, true);
2589 : }
2590 : }
2591 :
2592 0 : static void MVUnlinkRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2593 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2594 : int i;
2595 : SplineChar *sc;
2596 : RefChar *rf, *next;
2597 :
2598 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2599 0 : if ( mv->perchar[i].selected )
2600 0 : break;
2601 0 : if ( i==-1 )
2602 0 : return;
2603 0 : sc = mv->glyphs[i].sc;
2604 0 : SCPreserveLayer(sc, mv->layer,false);
2605 0 : for ( rf=sc->layers[mv->layer].refs; rf!=NULL ; rf=next ) {
2606 0 : next = rf->next;
2607 0 : SCRefToSplines(sc, rf, mv->layer);
2608 : }
2609 0 : SCCharChangedUpdate(sc, mv->layer);
2610 : }
2611 :
2612 0 : static void MVSelectAll(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2613 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2614 0 : GGadgetActiveGadgetEditCmd(mv->gw, ec_selectall);
2615 0 : }
2616 :
2617 0 : static void MVClearSelection(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2618 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2619 : int i;
2620 :
2621 0 : GWindowClearFocusGadgetOfWindow(mv->gw);
2622 0 : for ( i=0; i<mv->glyphcnt; ++i )
2623 0 : if ( mv->perchar[i].selected )
2624 0 : MVDeselectChar(mv,i);
2625 0 : }
2626 :
2627 0 : static void MVMenuFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2628 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2629 0 : DelayEvent(FontMenuFontInfo, mv->fv);
2630 0 : }
2631 :
2632 0 : static void MVMenuCharInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2633 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2634 : int i;
2635 :
2636 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2637 0 : if ( mv->perchar[i].selected )
2638 0 : break;
2639 0 : if ( i!=-1 )
2640 0 : SCCharInfo(mv->glyphs[i].sc, mv->layer, mv->fv->b.map, -1);
2641 0 : }
2642 :
2643 0 : static void MVMenuShowDependents(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2644 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2645 : int i;
2646 :
2647 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2648 0 : if ( mv->perchar[i].selected )
2649 0 : break;
2650 0 : if ( i!=-1 )
2651 0 : return;
2652 0 : if ( mv->glyphs[i].sc->dependents==NULL )
2653 0 : return;
2654 0 : SCRefBy(mv->glyphs[i].sc);
2655 : }
2656 :
2657 0 : static void MVMenuFindProblems(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2658 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2659 : int i;
2660 :
2661 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2662 0 : if ( mv->perchar[i].selected )
2663 0 : break;
2664 0 : if ( i!=-1 )
2665 0 : FindProblems(mv->fv, NULL, mv->glyphs[i].sc);
2666 0 : }
2667 :
2668 0 : static void MVMenuBitmaps(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2669 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2670 : int i;
2671 :
2672 0 : for ( i=0; i<mv->glyphcnt; ++i )
2673 0 : if ( mv->perchar[i].selected )
2674 0 : break;
2675 0 : if ( i!=mv->glyphcnt )
2676 0 : BitmapDlg(mv->fv, mv->glyphs[i].sc, mi->mid==MID_AvailBitmaps );
2677 0 : else if ( mi->mid==MID_AvailBitmaps )
2678 0 : BitmapDlg(mv->fv, NULL, true );
2679 0 : }
2680 :
2681 0 : static int getorigin(void *d, BasePoint *base, int index) {
2682 0 : SplineChar *sc = (SplineChar *) d;
2683 : DBounds bb;
2684 :
2685 0 : base->x = base->y = 0;
2686 0 : switch ( index ) {
2687 : case 0: /* Character origin */
2688 : /* all done */
2689 0 : break;
2690 : case 1: /* Center of selection */
2691 0 : SplineCharFindBounds(sc,&bb);
2692 0 : base->x = (bb.minx+bb.maxx)/2;
2693 0 : base->y = (bb.miny+bb.maxy)/2;
2694 0 : break;
2695 : default:
2696 0 : return( false );
2697 : }
2698 0 : return( true );
2699 : }
2700 :
2701 0 : static void MVTransFunc(void *_sc, real transform[6], int UNUSED(otype),
2702 : BVTFunc *UNUSED(bvts), enum fvtrans_flags flags ) {
2703 0 : SplineChar *sc = _sc;
2704 0 : FVTrans( (FontViewBase *)sc->parent->fv, sc, transform, NULL, flags);
2705 0 : }
2706 :
2707 0 : static void MVMenuTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2708 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2709 : int i;
2710 :
2711 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2712 0 : if ( mv->perchar[i].selected )
2713 0 : break;
2714 0 : if ( i!=-1 )
2715 0 : TransformDlgCreate( mv->glyphs[i].sc, MVTransFunc, getorigin, true, cvt_none );
2716 0 : }
2717 :
2718 : #ifdef FONTFORGE_CONFIG_TILEPATH
2719 : static void MVMenuTilePath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2720 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2721 : int i;
2722 :
2723 : for ( i=mv->glyphcnt-1; i>=0; --i )
2724 : if ( mv->perchar[i].selected )
2725 : break;
2726 : if ( i!=-1 )
2727 : SCTile(mv->glyphs[i].sc, mv->layer);
2728 : }
2729 : #endif
2730 :
2731 0 : static void _MVMenuOverlap(MetricsView *mv, enum overlap_type ot) {
2732 : int i;
2733 :
2734 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2735 0 : if ( mv->perchar[i].selected )
2736 0 : break;
2737 0 : if ( i!=-1 ) {
2738 0 : SplineChar *sc = mv->glyphs[i].sc;
2739 0 : if ( !SCRoundToCluster(sc, mv->layer, false, 0.03, 0.12))
2740 0 : SCPreserveLayer(sc, mv->layer, false);
2741 0 : MinimumDistancesFree(sc->md);
2742 0 : sc->md = NULL;
2743 0 : sc->layers[mv->layer].splines = SplineSetRemoveOverlap(sc, sc->layers[mv->layer].splines, ot);
2744 0 : SCCharChangedUpdate(sc, mv->layer);
2745 : }
2746 0 : }
2747 :
2748 0 : static void MVMenuOverlap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2749 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2750 0 : _MVMenuOverlap(mv, mi->mid==MID_RmOverlap ? over_remove :
2751 0 : mi->mid==MID_Intersection ? over_intersect :
2752 : over_findinter);
2753 0 : }
2754 :
2755 0 : static void MVMenuInline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2756 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2757 0 : OutlineDlg(NULL, NULL, mv, true);
2758 0 : }
2759 :
2760 0 : static void MVMenuOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2761 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2762 0 : OutlineDlg(NULL, NULL, mv, false);
2763 0 : }
2764 :
2765 0 : static void MVMenuShadow(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2766 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2767 0 : ShadowDlg(NULL, NULL, mv, false);
2768 0 : }
2769 :
2770 0 : static void MVMenuWireframe(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2771 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2772 0 : ShadowDlg(NULL, NULL, mv, true);
2773 0 : }
2774 :
2775 0 : static void MVSimplify( MetricsView *mv,int type ) {
2776 : int i;
2777 : static struct simplifyinfo smpls[] = {
2778 : { sf_normal, 0, 0, 0, 0, 0, 0 },
2779 : { sf_normal,.75,.05,0,-1, 0, 0 },
2780 : { sf_normal,.75,.05,0,-1, 0, 0 }};
2781 0 : struct simplifyinfo *smpl = &smpls[type+1];
2782 :
2783 0 : if ( smpl->linelenmax==-1 ) {
2784 0 : smpl->err = (mv->sf->ascent+mv->sf->descent)/1000.;
2785 0 : smpl->linelenmax = (mv->sf->ascent+mv->sf->descent)/100.;
2786 : }
2787 :
2788 0 : if ( type==1 ) {
2789 0 : if ( !SimplifyDlg(mv->sf,smpl))
2790 0 : return;
2791 0 : if ( smpl->set_as_default )
2792 0 : smpls[1] = *smpl;
2793 : }
2794 :
2795 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2796 0 : if ( mv->perchar[i].selected )
2797 0 : break;
2798 0 : if ( i!=-1 ) {
2799 0 : SplineChar *sc = mv->glyphs[i].sc;
2800 0 : SCPreserveLayer(sc,mv->layer,false);
2801 0 : sc->layers[mv->layer].splines = SplineCharSimplify(sc,sc->layers[mv->layer].splines,smpl);
2802 0 : SCCharChangedUpdate(sc,mv->layer);
2803 : }
2804 : }
2805 :
2806 0 : static void MVMenuSimplify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2807 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2808 0 : MVSimplify(mv, false);
2809 0 : }
2810 :
2811 0 : static void MVMenuSimplifyMore(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2812 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2813 0 : MVSimplify(mv, true);
2814 0 : }
2815 :
2816 0 : static void MVMenuCleanup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2817 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2818 0 : MVSimplify(mv, -1);
2819 0 : }
2820 :
2821 0 : static void MVMenuAddExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2822 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2823 : int i;
2824 0 : SplineFont *sf = mv->sf;
2825 0 : int emsize = sf->ascent+sf->descent;
2826 :
2827 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2828 0 : if ( mv->perchar[i].selected )
2829 0 : break;
2830 0 : if ( i!=-1 ) {
2831 0 : SplineChar *sc = mv->glyphs[i].sc;
2832 0 : SCPreserveLayer(sc, mv->layer, false);
2833 0 : SplineCharAddExtrema(sc, sc->layers[mv->layer].splines, ae_only_good, emsize);
2834 0 : SCCharChangedUpdate(sc, mv->layer);
2835 : }
2836 0 : }
2837 :
2838 0 : static void MVMenuRound2Int(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2839 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2840 : int i;
2841 :
2842 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2843 0 : if ( mv->perchar[i].selected )
2844 0 : break;
2845 0 : if ( i!=-1 ) {
2846 0 : SCPreserveLayer(mv->glyphs[i].sc, mv->layer, false);
2847 0 : SCRound2Int( mv->glyphs[i].sc, mv->layer, 1.0);
2848 : }
2849 0 : }
2850 :
2851 0 : static void MVMenuAutotrace(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
2852 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2853 : int i;
2854 : GCursor ct;
2855 :
2856 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2857 0 : if ( mv->perchar[i].selected )
2858 0 : break;
2859 0 : if ( i!=-1 ) {
2860 0 : ct = GDrawGetCursor(mv->gw);
2861 0 : GDrawSetCursor(mv->gw, ct_watch);
2862 0 : ff_progress_allow_events();
2863 0 : SCAutoTrace(mv->glyphs[i].sc, mv->layer, e!=NULL && (e->u.mouse.state&ksm_shift));
2864 0 : GDrawSetCursor(mv->gw, ct);
2865 : }
2866 0 : }
2867 :
2868 0 : static void MVMenuCorrectDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2869 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2870 : int i;
2871 :
2872 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2873 0 : if ( mv->perchar[i].selected )
2874 0 : break;
2875 0 : if ( i!=-1 ) {
2876 0 : SplineChar *sc = mv->glyphs[i].sc;
2877 0 : int changed = false, refchanged=false;
2878 : RefChar *ref;
2879 0 : int asked=-1;
2880 :
2881 0 : for ( ref=sc->layers[mv->layer].refs; ref!=NULL; ref=ref->next ) {
2882 0 : if ( ref->transform[0]*ref->transform[3]<0 ||
2883 0 : (ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) {
2884 0 : if ( asked==-1 ) {
2885 : char *buts[4];
2886 0 : buts[0] = _("_Unlink");
2887 0 : buts[1] = _("_No");
2888 0 : buts[2] = _("_Cancel");
2889 0 : buts[3] = NULL;
2890 0 : asked = gwwv_ask(_("Flipped Reference"),(const char **) buts,0,2,_("%.50s contains a flipped reference. This cannot be corrected as is. Would you like me to unlink it and then correct it?"), sc->name );
2891 0 : if ( asked==2 )
2892 0 : return;
2893 0 : else if ( asked==1 )
2894 0 : break;
2895 : }
2896 0 : if ( asked==0 ) {
2897 0 : if ( !refchanged ) {
2898 0 : refchanged = true;
2899 0 : SCPreserveLayer(sc,mv->layer,false);
2900 : }
2901 0 : SCRefToSplines(sc,ref,mv->layer);
2902 : }
2903 : }
2904 : }
2905 :
2906 0 : if ( !refchanged )
2907 0 : SCPreserveLayer(sc,mv->layer,false);
2908 0 : sc->layers[mv->layer].splines = SplineSetsCorrect(sc->layers[mv->layer].splines,&changed);
2909 0 : if ( changed || refchanged )
2910 0 : SCCharChangedUpdate(sc,mv->layer);
2911 : }
2912 : }
2913 :
2914 0 : static void _MVMenuBuildAccent(MetricsView *mv,int onlyaccents) {
2915 : int i;
2916 : extern int onlycopydisplayed;
2917 :
2918 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
2919 0 : if ( mv->perchar[i].selected )
2920 0 : break;
2921 0 : if ( i!=-1 ) {
2922 0 : SplineChar *sc = mv->glyphs[i].sc;
2923 0 : if ( SFIsSomethingBuildable(mv->sf,sc,mv->layer,onlyaccents) )
2924 0 : SCBuildComposit(mv->sf,sc,mv->layer,NULL,onlycopydisplayed);
2925 : }
2926 0 : }
2927 :
2928 0 : static void MVMenuBuildAccent(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2929 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2930 0 : _MVMenuBuildAccent(mv, false);
2931 0 : }
2932 :
2933 0 : static void MVMenuBuildComposite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2934 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2935 0 : _MVMenuBuildAccent(mv, true);
2936 0 : }
2937 :
2938 0 : static void MVResetText(MetricsView *mv) {
2939 : unichar_t *new, *pt;
2940 : int i;
2941 :
2942 0 : new = malloc((mv->clen+1)*sizeof(unichar_t));
2943 0 : for ( pt=new, i=0; i<mv->clen; ++i ) {
2944 0 : if ( mv->chars[i]->unicodeenc==-1 )
2945 0 : *pt++ = MVFakeUnicodeOfSc(mv,mv->chars[i]);
2946 : else
2947 0 : *pt++ = mv->chars[i]->unicodeenc;
2948 : }
2949 0 : *pt = '\0';
2950 0 : GGadgetSetTitle(mv->text,new);
2951 0 : free(new );
2952 0 : }
2953 :
2954 0 : static void MVMenuLigatures(GWindow gw,struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2955 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2956 0 : SFShowLigatures(mv->sf, NULL);
2957 0 : }
2958 :
2959 0 : static void MVMenuKernPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
2960 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2961 0 : SFShowKernPairs(mv->sf, NULL, NULL, mv->layer);
2962 0 : }
2963 :
2964 0 : static void MVMenuAnchorPairs(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2965 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2966 0 : SFShowKernPairs(mv->sf, NULL, mi->ti.userdata, mv->layer);
2967 0 : }
2968 :
2969 0 : static void _MVMenuScale( MetricsView *mv, int mid ) {
2970 :
2971 0 : if ( mid==MID_ZoomIn ) {
2972 0 : if ( --mv->scale_index<0 ) mv->scale_index = 0;
2973 : } else {
2974 0 : if ( ++mv->scale_index >= sizeof(mv_scales)/sizeof(mv_scales[0]) )
2975 0 : mv->scale_index = sizeof(mv_scales)/sizeof(mv_scales[0])-1;
2976 : }
2977 :
2978 0 : if ( mv->pixelsize_set_by_window ) {
2979 0 : mv->pixelsize = mv_scales[mv->scale_index]*(mv->vheight - 2);
2980 0 : if ( mv->bdf==NULL ) {
2981 0 : BDFFontFree(mv->show);
2982 0 : mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->pixelsize,72,
2983 : MVGetSplineFontPieceMealFlags( mv ), NULL );
2984 : } else
2985 0 : mv->pixelsize_set_by_window = false;
2986 : }
2987 0 : MVReKern(mv);
2988 0 : MVSetVSb(mv);
2989 0 : }
2990 :
2991 0 : static void MVMenuScale(GWindow gw,struct gmenuitem *mi, GEvent *UNUSED(e)) {
2992 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2993 0 : _MVMenuScale(mv, mi->mid);
2994 0 : }
2995 :
2996 0 : static void MVMenuInsertChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
2997 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
2998 0 : SplineFont *sf = mv->sf;
2999 0 : int i, j, pos = GotoChar(sf,mv->fv->b.map,NULL);
3000 :
3001 0 : if ( pos==-1 || pos>=mv->fv->b.map->enccount )
3002 0 : return;
3003 :
3004 0 : for ( i=0; i<mv->glyphcnt; ++i )
3005 0 : if ( mv->perchar[i].selected )
3006 0 : break;
3007 0 : if ( i!=mv->glyphcnt ) /* Something selected */
3008 : /* Ok... */;
3009 0 : else if ( mi->mid==MID_InsertCharA )
3010 0 : i = mv->glyphcnt;
3011 : else
3012 0 : i = 0;
3013 0 : if ( mi->mid==MID_InsertCharA ) {
3014 0 : if ( i!=mv->glyphcnt )
3015 0 : ++i;
3016 : } else {
3017 0 : if ( i==mv->glyphcnt ) i = 0;
3018 : }
3019 0 : if ( i==mv->glyphcnt )
3020 0 : i = mv->clen;
3021 : else
3022 0 : i = mv->glyphs[i].orig_index; /* Index in the string of chars, not glyphs */
3023 :
3024 0 : if ( mv->clen+1>=mv->cmax ) {
3025 0 : int oldmax=mv->cmax;
3026 0 : mv->cmax = mv->clen+10;
3027 0 : mv->chars = realloc(mv->chars,mv->cmax*sizeof(SplineChar *));
3028 0 : memset(mv->chars+oldmax,'\0',(mv->cmax-oldmax)*sizeof(SplineChar *));
3029 : }
3030 0 : for ( j=mv->clen; j>i; --j )
3031 0 : mv->chars[j] = mv->chars[j-1];
3032 0 : mv->chars[i] = SFMakeChar(sf,mv->fv->b.map,pos);
3033 0 : ++mv->clen;
3034 0 : MVRemetric(mv);
3035 0 : for ( j=0; j<mv->glyphcnt; ++j )
3036 0 : if ( mv->glyphs[j].orig_index==i ) {
3037 0 : MVDoSelect(mv,j);
3038 0 : break;
3039 : }
3040 0 : GDrawRequestExpose(mv->v,NULL,false);
3041 0 : MVResetText(mv);
3042 : }
3043 :
3044 0 : static void MVMenuChangeChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3045 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3046 0 : SplineFont *sf = mv->sf;
3047 : SplineChar *sc;
3048 0 : EncMap *map = mv->fv->b.map;
3049 : int i, pos, gid;
3050 :
3051 0 : for ( i=0; i<mv->glyphcnt; ++i )
3052 0 : if ( mv->perchar[i].selected )
3053 0 : break;
3054 0 : if ( i!=mv->glyphcnt ) {
3055 0 : pos = -1;
3056 0 : i = mv->glyphs[i].orig_index;
3057 0 : sc = mv->chars[ i ];
3058 0 : if ( mi->mid == MID_Next ) {
3059 0 : pos = map->backmap[sc->orig_pos]+1;
3060 0 : } else if ( mi->mid==MID_Prev ) {
3061 0 : pos = map->backmap[sc->orig_pos]-1;
3062 0 : } else if ( mi->mid==MID_NextDef ) {
3063 0 : for ( pos = map->backmap[sc->orig_pos]+1;
3064 0 : pos<map->enccount && ((gid=map->map[pos])==-1 || sf->glyphs[gid]==NULL); ++pos );
3065 0 : if ( pos>=map->enccount )
3066 0 : return;
3067 0 : } else if ( mi->mid==MID_PrevDef ) {
3068 0 : for ( pos = map->backmap[sc->orig_pos]-1;
3069 0 : pos<map->enccount && ((gid=map->map[pos])==-1 || sf->glyphs[gid]==NULL); --pos );
3070 0 : if ( pos<0 )
3071 0 : return;
3072 0 : } else if ( mi->mid==MID_ReplaceChar ) {
3073 0 : pos = GotoChar(sf,mv->fv->b.map,NULL);
3074 0 : if ( pos<0 || pos>=mv->fv->b.map->enccount)
3075 0 : return;
3076 : }
3077 0 : if ( pos>=0 && pos<map->enccount ) {
3078 0 : mv->chars[i] = SFMakeChar(sf,mv->fv->b.map,pos);
3079 0 : MVRemetric(mv);
3080 0 : MVResetText(mv);
3081 0 : GDrawRequestExpose(mv->v,NULL,false);
3082 : }
3083 : }
3084 : }
3085 :
3086 0 : static void MVMenuFindInFontView(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3087 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3088 : int i;
3089 :
3090 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
3091 0 : if ( mv->perchar[i].selected ) {
3092 0 : FVChangeChar(mv->fv, mv->fv->b.map->backmap[mv->glyphs[i].sc->orig_pos]);
3093 0 : GDrawSetVisible(mv->fv->gw, true);
3094 0 : GDrawRaise(mv->fv->gw);
3095 0 : break;
3096 : }
3097 : }
3098 0 : }
3099 :
3100 0 : static void MVMenuShowGrid(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3101 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3102 0 : if ( mi->mid == MID_ShowGrid )
3103 0 : mv->showgrid = mv_showgrid;
3104 0 : else if ( mi->mid == MID_HideGrid )
3105 0 : mv->showgrid = mv_hidegrid;
3106 0 : else if ( mi->mid == MID_PartialGrid )
3107 0 : mv->showgrid = mv_partialgrid;
3108 0 : else if ( mi->mid == MID_HideGridWhenMoving )
3109 0 : mv->showgrid = mv_hidemovinggrid;
3110 0 : mvshowgrid = mv->showgrid;
3111 0 : SavePrefs(true);
3112 0 : GDrawRequestExpose(mv->v, NULL, false);
3113 0 : }
3114 :
3115 0 : static void MVMenuAA(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3116 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3117 :
3118 0 : mv_antialias = mv->antialias = !mv->antialias;
3119 0 : mv->bdf = NULL;
3120 0 : BDFFontFree(mv->show);
3121 0 : mv->show = SplineFontPieceMeal(mv->sf, mv->layer, mv->ptsize, mv->dpi,
3122 : MVGetSplineFontPieceMealFlags( mv ),
3123 : NULL);
3124 0 : GDrawRequestExpose(mv->v,NULL,false);
3125 0 : }
3126 :
3127 :
3128 0 : static void MVMenuRenderUsingHinting(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3129 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3130 :
3131 0 : mv->usehinting = !mv->usehinting;
3132 0 : mv->bdf = NULL;
3133 0 : BDFFontFree(mv->show);
3134 0 : mv->show = SplineFontPieceMeal(mv->sf, mv->layer, mv->ptsize, mv->dpi,
3135 : MVGetSplineFontPieceMealFlags( mv ),
3136 : NULL);
3137 0 : GDrawRequestExpose(mv->v,NULL,false);
3138 0 : }
3139 :
3140 0 : static void MVWindowTitle(char *buffer, int bufsize, MetricsView *mv) {
3141 :
3142 0 : snprintf(buffer,bufsize,
3143 0 : mv->type == mv_kernonly ? _("Kerning Metrics For %.50s") :
3144 0 : mv->type == mv_widthonly ? _("Advance Width Metrics For %.50s") :
3145 : _("Metrics For %.50s"),
3146 0 : mv->sf->fontname);
3147 0 : }
3148 :
3149 0 : static void MVMenuWindowType(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3150 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3151 : char buf[120];
3152 :
3153 0 : mv_type = mv->type = mi->mid==MID_KernOnly ? mv_kernonly :
3154 0 : mi->mid==MID_WidthOnly ? mv_widthonly :
3155 : mv_kernwidth;
3156 0 : MVWindowTitle(buf, sizeof(buf), mv);
3157 0 : GDrawSetWindowTitles8(mv->gw, buf, buf);
3158 0 : GDrawRequestExpose(mv->v, NULL, false);
3159 0 : GDrawRequestExpose(mv->gw, NULL, false);
3160 0 : }
3161 :
3162 0 : static void MVMenuVertical(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3163 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3164 :
3165 0 : if ( !mv->sf->hasvmetrics ) {
3166 0 : if ( mv->vertical )
3167 0 : MVToggleVertical(mv);
3168 : } else
3169 0 : MVToggleVertical(mv);
3170 0 : GDrawRequestExpose(mv->gw, NULL, false);
3171 0 : GDrawRequestExpose(mv->v, NULL, false);
3172 0 : }
3173 :
3174 0 : static void MVMenuShowBitmap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3175 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3176 0 : BDFFont *bdf = mi->ti.userdata;
3177 :
3178 0 : if ( mv->bdf!=bdf ) {
3179 0 : mv->pixelsize_set_by_window = bdf==NULL;
3180 0 : if ( bdf!=NULL ) {
3181 0 : mv->pixelsize = mv->ptsize = bdf->pixelsize;
3182 0 : mv->dpi = 72;
3183 : }
3184 0 : MVChangeDisplayFont(mv, bdf);
3185 0 : GDrawRequestExpose(mv->v, NULL, false);
3186 : }
3187 0 : }
3188 :
3189 0 : static void MVMoveInWordListByOffset( MetricsView *mv, int offset )
3190 : {
3191 0 : if ( mv->word_index!=-1 ) {
3192 : int32 len;
3193 0 : GTextInfo **ti = GGadgetGetList(mv->text,&len);
3194 : /* We subtract 3 because: There are two lines saying "load * list" */
3195 : /* and then a line with a rule on it which we don't want access to */
3196 0 : if ( mv->word_index+offset >=0 && mv->word_index+offset<len-3 ) {
3197 : const unichar_t *tit;
3198 0 : mv->word_index += offset;
3199 0 : GGadgetSelectOneListItem(mv->text,mv->word_index);
3200 0 : tit = _GGadgetGetTitle(mv->text);
3201 0 : if ( tit!=NULL && tit[0]==0x200b )
3202 0 : MVFigureGlyphNames(mv,tit+1);
3203 : else
3204 0 : MVTextChanged(mv);
3205 0 : ti = NULL;
3206 : }
3207 : }
3208 0 : }
3209 :
3210 0 : static void MVMenuNextLineInWordList(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3211 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3212 0 : MVMoveInWordListByOffset( mv, 1 );
3213 0 : }
3214 0 : static void MVMenuPrevLineInWordList(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3215 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3216 0 : MVMoveInWordListByOffset( mv, -1 );
3217 0 : }
3218 :
3219 :
3220 : #define CID_DPI 1002
3221 : #define CID_Size 1003
3222 :
3223 : struct pxsz {
3224 : MetricsView *mv;
3225 : GWindow gw;
3226 : int done;
3227 : };
3228 :
3229 0 : static int PXSZ_OK(GGadget *g, GEvent *e) {
3230 :
3231 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3232 0 : struct pxsz *pxsz = GDrawGetUserData(GGadgetGetWindow(g));
3233 0 : MetricsView *mv = pxsz->mv;
3234 0 : int ptsize, dpi, err=0;
3235 :
3236 0 : ptsize = GetInt8( pxsz->gw, CID_Size, _("Point Size"), &err );
3237 0 : dpi = GetInt8( pxsz->gw, CID_DPI, _("DPI"), &err );
3238 0 : if ( err )
3239 0 : return(true);
3240 0 : if ( ptsize<3 || ptsize>1500 || dpi<10 || dpi > 2000 ) {
3241 0 : ff_post_error(_("Number out of range"),_("Number out of range"));
3242 0 : return( true );
3243 : }
3244 0 : mv->pixelsize_set_by_window = false;
3245 0 : mv->ptsize = ptsize;
3246 0 : mv->dpi = dpi;
3247 0 : mv->pixelsize = rint( (ptsize*dpi)/72.0 );
3248 0 : if ( mv->bdf==NULL )
3249 0 : BDFFontFree(mv->show);
3250 0 : mv->bdf = NULL;
3251 0 : mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi,
3252 : MVGetSplineFontPieceMealFlags( mv ), NULL );
3253 :
3254 0 : MVReKern(mv);
3255 0 : MVSetVSb(mv);
3256 0 : pxsz->done = 2;
3257 : }
3258 0 : return( true );
3259 : }
3260 :
3261 0 : static int PXSZ_Cancel(GGadget *g, GEvent *e) {
3262 :
3263 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
3264 0 : struct pxsz *pxsz = GDrawGetUserData(GGadgetGetWindow(g));
3265 0 : pxsz->done = true;
3266 : }
3267 0 : return( true );
3268 : }
3269 :
3270 0 : static int pxsz_e_h(GWindow gw, GEvent *event) {
3271 0 : struct pxsz *pxsz = GDrawGetUserData(gw);
3272 :
3273 0 : switch ( event->type ) {
3274 : case et_char:
3275 0 : return( false );
3276 : case et_close:
3277 0 : pxsz->done = true;
3278 0 : break;
3279 : }
3280 0 : return( true );
3281 : }
3282 :
3283 0 : static void MVMenuPointSize(GWindow mgw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3284 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(mgw);
3285 : struct pxsz pxsz;
3286 : GRect pos;
3287 : GWindow gw;
3288 : GWindowAttrs wattrs;
3289 : GGadgetCreateData gcd[7], *hvarray[5][3], *barray[8], boxes[3];
3290 : GTextInfo label[7];
3291 : int i,k;
3292 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
3293 : char buffer[20], dbuffer[20];
3294 :
3295 0 : memset(&pxsz,0,sizeof(pxsz));
3296 0 : pxsz.mv = mv;
3297 :
3298 0 : memset(&wattrs,0,sizeof(wattrs));
3299 0 : memset(&gcd,0,sizeof(gcd));
3300 0 : memset(&label,0,sizeof(label));
3301 0 : memset(&boxes,0,sizeof(boxes));
3302 :
3303 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
3304 0 : wattrs.event_masks = ~(1<<et_charup);
3305 0 : wattrs.restrict_input_to_me = true;
3306 0 : wattrs.undercursor = 1;
3307 0 : wattrs.cursor = ct_pointer;
3308 0 : wattrs.utf8_window_title = _("Set Point Size");
3309 0 : wattrs.is_dlg = true;
3310 0 : pos.x = pos.y = 0;
3311 0 : pos.width = 100;
3312 0 : pos.height = 100;
3313 0 : pxsz.gw = gw = GDrawCreateTopWindow(NULL,&pos,pxsz_e_h,&pxsz,&wattrs);
3314 :
3315 0 : k = i = 0;
3316 :
3317 0 : label[k].text = (unichar_t *) _("Point Size:");
3318 0 : label[k].text_is_1byte = true;
3319 0 : gcd[k].gd.label = &label[k];
3320 0 : gcd[k].gd.flags = gg_visible|gg_enabled ;
3321 : /*gcd[k].gd.handle_controlevent = SS_ScriptChanged;*/
3322 0 : gcd[k++].creator = GLabelCreate;
3323 0 : hvarray[i][0] = &gcd[k-1];
3324 :
3325 0 : sprintf( buffer, "%d", (int) rint( mv->ptsize/iscale ));
3326 0 : label[k].text = (unichar_t *) buffer;
3327 0 : label[k].text_is_1byte = true;
3328 0 : gcd[k].gd.label = &label[k];
3329 0 : gcd[k].gd.flags = gg_visible|gg_enabled;
3330 0 : gcd[k].gd.cid = CID_Size;
3331 0 : gcd[k++].creator = GTextFieldCreate;
3332 0 : hvarray[i][1] = &gcd[k-1]; hvarray[i++][2] = NULL;
3333 :
3334 0 : label[k].text = (unichar_t *) _("DPI:");
3335 0 : label[k].text_is_1byte = true;
3336 0 : gcd[k].gd.label = &label[k];
3337 0 : gcd[k].gd.flags = gg_visible|gg_enabled ;
3338 : /*gcd[k].gd.handle_controlevent = SS_ScriptChanged;*/
3339 0 : gcd[k++].creator = GLabelCreate;
3340 0 : hvarray[i][0] = &gcd[k-1];
3341 :
3342 0 : sprintf( dbuffer, "%d", mv->dpi );
3343 0 : label[k].text = (unichar_t *) dbuffer;
3344 0 : label[k].text_is_1byte = true;
3345 0 : gcd[k].gd.label = &label[k];
3346 0 : gcd[k].gd.flags = gg_visible|gg_enabled;
3347 0 : gcd[k].gd.cid = CID_DPI;
3348 0 : gcd[k++].creator = GTextFieldCreate;
3349 0 : hvarray[i][1] = &gcd[k-1]; hvarray[i++][2] = NULL;
3350 :
3351 0 : label[k].text = (unichar_t *) _("_OK");
3352 0 : label[k].text_is_1byte = true;
3353 0 : label[k].text_in_resource = true;
3354 0 : gcd[k].gd.label = &label[k];
3355 0 : gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default;
3356 0 : gcd[k].gd.handle_controlevent = PXSZ_OK;
3357 0 : gcd[k++].creator = GButtonCreate;
3358 :
3359 0 : label[k].text = (unichar_t *) _("_Cancel");
3360 0 : label[k].text_is_1byte = true;
3361 0 : label[k].text_in_resource = true;
3362 0 : gcd[k].gd.label = &label[k];
3363 0 : gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel;
3364 0 : gcd[k].gd.handle_controlevent = PXSZ_Cancel;
3365 0 : gcd[k++].creator = GButtonCreate;
3366 :
3367 0 : barray[0] = barray[2] = barray[3] = barray[4] = barray[6] = GCD_Glue; barray[7] = NULL;
3368 0 : barray[1] = &gcd[k-2]; barray[5] = &gcd[k-1];
3369 0 : hvarray[i][0] = &boxes[2]; hvarray[i][1] = GCD_ColSpan; hvarray[i++][2] = NULL;
3370 0 : hvarray[i][0] = NULL;
3371 :
3372 0 : memset(boxes,0,sizeof(boxes));
3373 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
3374 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
3375 0 : boxes[0].gd.u.boxelements = hvarray[0];
3376 0 : boxes[0].creator = GHVGroupCreate;
3377 :
3378 0 : boxes[2].gd.flags = gg_enabled|gg_visible;
3379 0 : boxes[2].gd.u.boxelements = barray;
3380 0 : boxes[2].creator = GHBoxCreate;
3381 :
3382 0 : GGadgetsCreate(gw,boxes);
3383 0 : GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
3384 0 : GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
3385 :
3386 0 : GHVBoxFitWindow(boxes[0].ret);
3387 :
3388 0 : GDrawSetVisible(gw,true);
3389 0 : while ( !pxsz.done )
3390 0 : GDrawProcessOneEvent(NULL);
3391 0 : GDrawDestroyWindow(gw);
3392 0 : }
3393 :
3394 0 : static void MVMenuSizeWindow(GWindow mgw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3395 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(mgw);
3396 0 : mv->pixelsize_set_by_window = true;
3397 0 : mv->pixelsize = mv_scales[mv->scale_index]*(mv->vheight - 2);
3398 0 : mv->dpi = 72;
3399 0 : mv->ptsize = mv->pixelsize;
3400 0 : if ( mv->bdf==NULL ) {
3401 0 : BDFFontFree(mv->show);
3402 0 : mv->show = SplineFontPieceMeal(
3403 : mv->sf, mv->layer, mv->pixelsize, 72,
3404 : MVGetSplineFontPieceMealFlags( mv ),
3405 : NULL);
3406 : }
3407 0 : MVReKern(mv);
3408 0 : MVSetVSb(mv);
3409 0 : }
3410 :
3411 0 : static void MVMenuChangePointSize(GWindow mgw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3412 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(mgw);
3413 :
3414 0 : if ( mv->pixelsize_set_by_window )
3415 0 : return;
3416 0 : if ( mi->mid==MID_Bigger )
3417 0 : ++(mv->ptsize);
3418 : else
3419 0 : --(mv->ptsize);
3420 0 : mv->pixelsize = rint( (mv->ptsize*mv->dpi)/72.0 );
3421 0 : if ( mv->bdf==NULL )
3422 0 : BDFFontFree(mv->show);
3423 0 : mv->bdf = NULL;
3424 0 : mv->show = SplineFontPieceMeal(mv->sf, mv->layer, mv->ptsize, mv->dpi,
3425 : MVGetSplineFontPieceMealFlags( mv ), NULL);
3426 :
3427 0 : MVReKern(mv);
3428 0 : MVSetVSb(mv);
3429 : }
3430 :
3431 0 : static void MVMenuChangeLayer(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3432 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3433 :
3434 0 : mv->layer = mi->mid;
3435 0 : BDFFontFree(mv->show);
3436 0 : mv->show = SplineFontPieceMeal(mv->sf, mv->layer, mv->ptsize, mv->dpi,
3437 : MVGetSplineFontPieceMealFlags( mv ), NULL);
3438 0 : MVRemetric(mv);
3439 0 : GDrawRequestExpose(mv->v,NULL,false);
3440 0 : }
3441 :
3442 0 : static void MVMenuCenter(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e))
3443 : {
3444 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3445 : int i;
3446 : DBounds bb;
3447 : real transform[6];
3448 : SplineChar *sc;
3449 :
3450 0 : for ( i=0; i<mv->glyphcnt; ++i )
3451 0 : if ( mv->perchar[i].selected )
3452 0 : break;
3453 0 : if ( i!=mv->glyphcnt ) {
3454 0 : sc = mv->glyphs[i].sc;
3455 0 : transform[0] = transform[3] = 1.0;
3456 0 : transform[1] = transform[2] = transform[5] = 0.0;
3457 0 : SplineCharFindBounds(sc,&bb);
3458 0 : if ( mi->mid==MID_Center )
3459 0 : transform[4] = (sc->width-(bb.maxx-bb.minx))/2 - bb.minx;
3460 : else
3461 0 : transform[4] = (sc->width-(bb.maxx-bb.minx))/3 - bb.minx;
3462 0 : if ( transform[4]!=0 )
3463 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL, fvt_dontmovewidth| fvt_alllayers );
3464 : }
3465 0 : }
3466 :
3467 0 : static void MVMenuKernByClasses(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3468 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3469 0 : ShowKernClasses(mv->sf, mv, mv->layer, false);
3470 0 : }
3471 :
3472 0 : static void MVMenuVKernByClasses(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3473 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3474 0 : ShowKernClasses(mv->sf, mv, mv->layer, true);
3475 0 : }
3476 :
3477 0 : static void MVMenuVKernFromHKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3478 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3479 0 : FVVKernFromHKern((FontViewBase *) mv->fv);
3480 0 : }
3481 :
3482 0 : static void MVMenuKPCloseup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3483 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3484 0 : SplineChar *sc1=NULL, *sc2=NULL;
3485 : int i;
3486 :
3487 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
3488 0 : if ( mv->perchar[i].selected ) {
3489 0 : sc1 = mv->glyphs[i].sc;
3490 0 : if ( i+1<mv->glyphcnt )
3491 0 : sc2 = mv->glyphs[i+1].sc;
3492 0 : break;
3493 : }
3494 : }
3495 0 : KernPairD(mv->sf,sc1,sc2,mv->layer,mv->vertical);
3496 0 : }
3497 :
3498 : static GMenuItem2 wnmenu[] = {
3499 : { { (unichar_t *) N_("New O_utline Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("New Outline Window|No Shortcut"), NULL, NULL, MVMenuOpenOutline, MID_OpenOutline },
3500 : { { (unichar_t *) N_("New _Bitmap Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("New Bitmap Window|No Shortcut"), NULL, NULL, MVMenuOpenBitmap, MID_OpenBitmap },
3501 : { { (unichar_t *) N_("New _Metrics Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("New Metrics Window|No Shortcut"), NULL, NULL, /* No function, never avail */NULL, 0 },
3502 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3503 : { { (unichar_t *) N_("Warnings"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Warnings|No Shortcut"), NULL, NULL, _MenuWarnings, MID_Warnings },
3504 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3505 : GMENUITEM2_EMPTY
3506 : };
3507 :
3508 0 : static void MVWindowMenuBuild(GWindow gw,struct gmenuitem *mi,GEvent *e) {
3509 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3510 : int i;
3511 : SplineChar *sc;
3512 : struct gmenuitem *wmi;
3513 :
3514 0 : WindowMenuBuild(gw,mi,e);
3515 :
3516 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
3517 0 : if ( mv->perchar[i].selected )
3518 0 : break;
3519 0 : if ( i==-1 ) sc = NULL; else sc = mv->glyphs[i].sc;
3520 :
3521 0 : for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
3522 0 : switch ( wmi->mid ) {
3523 : case MID_OpenOutline:
3524 0 : wmi->ti.disabled = sc==NULL;
3525 0 : break;
3526 : case MID_OpenBitmap:
3527 0 : mi->ti.disabled = mv->sf->bitmaps==NULL || sc==NULL;
3528 0 : break;
3529 : case MID_Warnings:
3530 0 : wmi->ti.disabled = ErrorWindowExists();
3531 0 : break;
3532 : }
3533 : }
3534 0 : }
3535 :
3536 : static GMenuItem2 dummyitem[] = {
3537 : { { (unichar_t *) N_("Font|_New"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, NULL, NULL, NULL, NULL, 0 },
3538 : GMENUITEM2_EMPTY
3539 : };
3540 : static GMenuItem2 fllist[] = {
3541 : { { (unichar_t *) N_("Font|_New"), (GImage *) "filenew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("New|No Shortcut"), NULL, NULL, MenuNew, 0 },
3542 : { { (unichar_t *) N_("_Open"), (GImage *) "fileopen.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Open|No Shortcut"), NULL, NULL, MVMenuOpen, 0 },
3543 : { { (unichar_t *) N_("Recen_t"), (GImage *) "filerecent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, NULL, dummyitem, MenuRecentBuild, NULL, MID_Recent },
3544 : { { (unichar_t *) N_("_Close"), (GImage *) "fileclose.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Close|No Shortcut"), NULL, NULL, MVMenuClose, 0 },
3545 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3546 : { { (unichar_t *) N_("_Save"), (GImage *) "filesave.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Save|No Shortcut"), NULL, NULL, MVMenuSave, 0 },
3547 : { { (unichar_t *) N_("S_ave as..."), (GImage *) "filesaveas.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Save as...|No Shortcut"), NULL, NULL, MVMenuSaveAs, 0 },
3548 : { { (unichar_t *) N_("_Generate Fonts..."), (GImage *) "filegenerate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Generate Fonts...|No Shortcut"), NULL, NULL, MVMenuGenerate, 0 },
3549 : { { (unichar_t *) N_("Generate Mac _Family..."), (GImage *) "filegeneratefamily.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Generate Mac Family...|No Shortcut"), NULL, NULL, MVMenuGenerateFamily, 0 },
3550 : { { (unichar_t *) N_("Generate TTC..."), (GImage *) "filegeneratefamily.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Generate TTC...|No Shortcut"), NULL, NULL, MVMenuGenerateTTC, 0 },
3551 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3552 : { { (unichar_t *) N_("_Merge Feature Info..."), (GImage *) "filemergefeature.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Merge Kern Info...|No Shortcut"), NULL, NULL, MVMenuMergeKern, 0 },
3553 : { { (unichar_t *) N_("Load _Word List..."), (GImage *) 0, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Load Word List...|No Shortcut"), NULL, NULL, MVMenuAddWordList, 0 },
3554 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3555 : { { (unichar_t *) N_("_Print..."), (GImage *) "fileprint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Print...|No Shortcut"), NULL, NULL, MVMenuPrint, 0 },
3556 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3557 : { { (unichar_t *) N_("Pr_eferences..."), (GImage *) "fileprefs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Preferences...|No Shortcut"), NULL, NULL, MenuPrefs, 0 },
3558 : { { (unichar_t *) N_("_X Resource Editor..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("X Resource Editor...|No Shortcut"), NULL, NULL, MenuXRes, 0 },
3559 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3560 : { { (unichar_t *) N_("_Quit"), (GImage *) "filequit.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'Q' }, H_("Quit|No Shortcut"), NULL, NULL, MenuExit, 0 },
3561 : GMENUITEM2_EMPTY
3562 : };
3563 :
3564 : static GMenuItem2 edlist[] = {
3565 : { { (unichar_t *) N_("_Undo"), (GImage *) "editundo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Undo|No Shortcut"), NULL, NULL, MVUndo, MID_Undo },
3566 : { { (unichar_t *) N_("_Redo"), (GImage *) "editredo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Redo|No Shortcut"), NULL, NULL, MVRedo, MID_Redo },
3567 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3568 : { { (unichar_t *) N_("Cu_t"), (GImage *) "editcut.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Cut|No Shortcut"), NULL, NULL, MVCut, MID_Cut },
3569 : { { (unichar_t *) N_("_Copy"), (GImage *) "editcopy.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Copy|No Shortcut"), NULL, NULL, MVCopy, MID_Copy },
3570 : { { (unichar_t *) N_("C_opy Reference"), (GImage *) "editcopyref.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Copy Reference|No Shortcut"), NULL, NULL, MVMenuCopyRef, MID_CopyRef },
3571 : { { (unichar_t *) N_("Copy _Width"), (GImage *) "editcopywidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Copy Width|No Shortcut"), NULL, NULL, MVMenuCopyWidth, MID_CopyWidth },
3572 : { { (unichar_t *) N_("Copy _VWidth"), (GImage *) "editcopyvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Copy VWidth|No Shortcut"), NULL, NULL, MVMenuCopyWidth, MID_CopyVWidth },
3573 : { { (unichar_t *) N_("Co_py LBearing"), (GImage *) "editcopylbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'p' }, H_("Copy LBearing|No Shortcut"), NULL, NULL, MVMenuCopyWidth, MID_CopyLBearing },
3574 : { { (unichar_t *) N_("Copy RBearin_g"), (GImage *) "editcopyrbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'g' }, H_("Copy RBearing|No Shortcut"), NULL, NULL, MVMenuCopyWidth, MID_CopyRBearing },
3575 : { { (unichar_t *) N_("_Paste"), (GImage *) "editpaste.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Paste|No Shortcut"), NULL, NULL, MVPaste, MID_Paste },
3576 : { { (unichar_t *) N_("C_lear"), (GImage *) "editclear.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Clear|No Shortcut"), NULL, NULL, MVClear, MID_Clear },
3577 : { { (unichar_t *) N_("_Join"), (GImage *) "editjoin.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'J' }, H_("Join|No Shortcut"), NULL, NULL, MVMenuJoin, MID_Join },
3578 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3579 : { { (unichar_t *) N_("Select _All"), (GImage *) "editselect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Select All|No Shortcut"), NULL, NULL, MVSelectAll, MID_SelAll },
3580 : { { (unichar_t *) N_("_Deselect All"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Clear Selection|Escape"), NULL, NULL, MVClearSelection, MID_ClearSel },
3581 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3582 : { { (unichar_t *) N_("U_nlink Reference"), (GImage *) "editunlink.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Unlink Reference|No Shortcut"), NULL, NULL, MVUnlinkRef, MID_UnlinkRef },
3583 : GMENUITEM2_EMPTY
3584 : };
3585 :
3586 : static GMenuItem2 smlist[] = {
3587 : { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify|No Shortcut"), NULL, NULL, MVMenuSimplify, MID_Simplify },
3588 : { { (unichar_t *) N_("Simplify More..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify More...|No Shortcut"), NULL, NULL, MVMenuSimplifyMore, MID_SimplifyMore },
3589 : { { (unichar_t *) N_("Clea_nup Glyph"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Cleanup Glyph|No Shortcut"), NULL, NULL, MVMenuCleanup, MID_CleanupGlyph },
3590 : GMENUITEM2_EMPTY
3591 : };
3592 :
3593 : static GMenuItem2 rmlist[] = {
3594 : { { (unichar_t *) N_("_Remove Overlap"), (GImage *) "overlaprm.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Remove Overlap|No Shortcut"), NULL, NULL, MVMenuOverlap, MID_RmOverlap },
3595 : { { (unichar_t *) N_("_Intersect"), (GImage *) "overlapintersection.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Intersect|No Shortcut"), NULL, NULL, MVMenuOverlap, MID_Intersection },
3596 : { { (unichar_t *) N_("_Find Intersections"), (GImage *) "overlapfindinter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Find Intersections|No Shortcut"), NULL, NULL, MVMenuOverlap, MID_FindInter },
3597 : GMENUITEM2_EMPTY
3598 : };
3599 :
3600 : static GMenuItem2 eflist[] = {
3601 : { { (unichar_t *) N_("_Inline"), (GImage *) "stylesinline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Inline|No Shortcut"), NULL, NULL, MVMenuInline, 0 },
3602 : { { (unichar_t *) N_("_Outline"), (GImage *) "stylesoutline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Outline|No Shortcut"), NULL, NULL, MVMenuOutline, 0 },
3603 : { { (unichar_t *) N_("_Shadow"), (GImage *) "stylesshadow.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Shadow|No Shortcut"), NULL, NULL, MVMenuShadow, 0 },
3604 : { { (unichar_t *) N_("_Wireframe"), (GImage *) "styleswireframe.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Wireframe|No Shortcut"), NULL, NULL, MVMenuWireframe, 0 },
3605 : GMENUITEM2_EMPTY
3606 : };
3607 :
3608 : static GMenuItem2 balist[] = {
3609 : { { (unichar_t *) N_("_Build Accented Glyph"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Accented Glyph|No Shortcut"), NULL, NULL, MVMenuBuildAccent, MID_BuildAccent },
3610 : { { (unichar_t *) N_("Build _Composite Glyph"), (GImage *) "elementbuildcomposite.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Composite Glyph|No Shortcut"), NULL, NULL, MVMenuBuildComposite, MID_BuildComposite },
3611 : GMENUITEM2_EMPTY
3612 : };
3613 :
3614 0 : static void balistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3615 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3616 : int i;
3617 : SplineChar *sc;
3618 :
3619 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
3620 0 : if ( mv->perchar[i].selected )
3621 0 : break;
3622 0 : if ( i==-1 ) sc = NULL; else sc = mv->glyphs[i].sc;
3623 :
3624 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3625 0 : switch ( mi->mid ) {
3626 : case MID_BuildAccent:
3627 0 : mi->ti.disabled = sc==NULL || !SFIsSomethingBuildable(sc->parent, sc, mv->layer, true);
3628 0 : break;
3629 : case MID_BuildComposite:
3630 0 : mi->ti.disabled = sc==NULL || !SFIsSomethingBuildable(sc->parent, sc, mv->layer, false);
3631 0 : break;
3632 : }
3633 : }
3634 0 : }
3635 :
3636 : static GMenuItem2 ellist[] = {
3637 : { { (unichar_t *) N_("_Font Info..."), (GImage *) "elementfontinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Font Info...|No Shortcut"), NULL, NULL, MVMenuFontInfo, 0 },
3638 : { { (unichar_t *) N_("Glyph _Info..."), (GImage *) "elementglyphinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Glyph Info...|No Shortcut"), NULL, NULL, MVMenuCharInfo, MID_CharInfo },
3639 : { { (unichar_t *) N_("S_how Dependent"), (GImage *) "elementshowdep.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Show Dependent|No Shortcut"), NULL, NULL, MVMenuShowDependents, MID_ShowDependents },
3640 : { { (unichar_t *) N_("Find Pr_oblems..."), (GImage *) "elementfindprobs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Find Problems...|No Shortcut"), NULL, NULL, MVMenuFindProblems, MID_FindProblems },
3641 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3642 : { { (unichar_t *) N_("Bitm_ap Strikes Available..."), (GImage *) "elementbitmapsavail.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Bitmap Strikes Available...|No Shortcut"), NULL, NULL, MVMenuBitmaps, MID_AvailBitmaps },
3643 : { { (unichar_t *) N_("Regenerate _Bitmap Glyphs..."), (GImage *) "elementregenbitmaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Regenerate Bitmap Glyphs...|No Shortcut"), NULL, NULL, MVMenuBitmaps, MID_RegenBitmaps },
3644 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3645 : { { (unichar_t *) N_("_Transform..."), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Transform...|No Shortcut"), NULL, NULL, MVMenuTransform, MID_Transform },
3646 : #ifdef FONTFORGE_CONFIG_TILEPATH
3647 : { { (unichar_t *) N_("Tile _Path..."), (GImage *) "elementtilepath.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Tile Path...|No Shortcut"), NULL, NULL, MVMenuTilePath, MID_TilePath },
3648 : #endif
3649 : { { (unichar_t *) N_("_Remove Overlap"), (GImage *) "rmoverlap.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Remove Overlap|No Shortcut"), rmlist, NULL, NULL, MID_RmOverlap },
3650 : { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify|No Shortcut"), smlist, NULL, NULL, MID_Simplify },
3651 : { { (unichar_t *) N_("Add E_xtrema"), (GImage *) "elementaddextrema.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Add Extrema|No Shortcut"), NULL, NULL, MVMenuAddExtrema, MID_AddExtrema },
3652 : { { (unichar_t *) N_("To _Int"), (GImage *) "elementround.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("To Int|No Shortcut"), NULL, NULL, MVMenuRound2Int, MID_Round },
3653 : { { (unichar_t *) N_("Effects"), (GImage *) "elementstyles.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Effects|No Shortcut"), eflist, NULL, NULL, MID_Effects },
3654 : { { (unichar_t *) N_("Autot_race"), (GImage *) "elementautotrace.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Autotrace|No Shortcut"), NULL, NULL, MVMenuAutotrace, MID_Autotrace },
3655 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3656 : { { (unichar_t *) N_("_Correct Direction"), (GImage *) "elementcorrectdir.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Correct Direction|No Shortcut"), NULL, NULL, MVMenuCorrectDir, MID_Correct },
3657 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3658 : { { (unichar_t *) N_("B_uild"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build|No Shortcut"), balist, balistcheck, NULL, MID_BuildAccent },
3659 : GMENUITEM2_EMPTY
3660 : };
3661 :
3662 : static GMenuItem2 dummyall[] = {
3663 : { { (unichar_t *) N_("All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("All|No Shortcut"), NULL, NULL, NULL, 0 },
3664 : GMENUITEM2_EMPTY
3665 : };
3666 :
3667 : /* Builds up a menu containing all the anchor classes */
3668 0 : static void aplistbuild(GWindow base, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3669 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(base);
3670 :
3671 0 : GMenuItemArrayFree(mi->sub);
3672 0 : mi->sub = NULL;
3673 :
3674 0 : _aplistbuild(mi, mv->sf, MVMenuAnchorPairs);
3675 0 : }
3676 :
3677 : static GMenuItem2 cblist[] = {
3678 : { { (unichar_t *) N_("_Kern Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Kern Pairs|No Shortcut"), NULL, NULL, MVMenuKernPairs, MID_KernPairs },
3679 : { { (unichar_t *) N_("_Anchored Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Anchored Pairs|No Shortcut"), dummyall, aplistbuild, MVMenuAnchorPairs, MID_AnchorPairs },
3680 : { { (unichar_t *) N_("_Ligatures"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Ligatures|No Shortcut"), NULL, NULL, MVMenuLigatures, MID_Ligatures },
3681 : GMENUITEM2_EMPTY
3682 : };
3683 :
3684 0 : static void cblistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3685 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3686 0 : SplineFont *sf = mv->sf;
3687 0 : int i, anyligs=0, anykerns=0;
3688 : PST *pst;
3689 :
3690 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
3691 0 : for ( pst=sf->glyphs[i]->possub; pst!=NULL; pst=pst->next ) {
3692 0 : if ( pst->type==pst_ligature ) {
3693 0 : anyligs = true;
3694 0 : if ( anykerns )
3695 0 : break;
3696 : }
3697 : }
3698 0 : if ( (mv->vertical ? sf->glyphs[i]->vkerns : sf->glyphs[i]->kerns)!=NULL ) {
3699 0 : anykerns = true;
3700 0 : if ( anyligs )
3701 0 : break;
3702 : }
3703 : }
3704 :
3705 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3706 0 : switch ( mi->mid ) {
3707 : case MID_Ligatures:
3708 0 : mi->ti.disabled = !anyligs;
3709 0 : break;
3710 : case MID_KernPairs:
3711 0 : mi->ti.disabled = !anykerns;
3712 0 : break;
3713 : case MID_AnchorPairs:
3714 0 : mi->ti.disabled = sf->anchor==NULL;
3715 0 : break;
3716 : }
3717 : }
3718 0 : }
3719 :
3720 : static GMenuItem2 lylist[] = {
3721 : { { (unichar_t *) N_("Layer|Foreground"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 1, 1, 1, 0, 0, 1, 1, 0, '\0' }, NULL, NULL, NULL, MVMenuChangeLayer, ly_fore },
3722 : GMENUITEM2_EMPTY
3723 : };
3724 :
3725 0 : static void lylistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3726 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3727 0 : SplineFont *sf = mv->fv->b.sf;
3728 : int ly;
3729 : GMenuItem *sub;
3730 :
3731 0 : sub = calloc(sf->layer_cnt+1,sizeof(GMenuItem));
3732 0 : for ( ly=ly_fore; ly<sf->layer_cnt; ++ly ) {
3733 0 : sub[ly-1].ti.text = utf82u_copy(sf->layers[ly].name);
3734 0 : sub[ly-1].ti.checkable = true;
3735 0 : sub[ly-1].ti.checked = ly == mv->layer;
3736 0 : sub[ly-1].invoke = MVMenuChangeLayer;
3737 0 : sub[ly-1].mid = ly;
3738 0 : sub[ly-1].ti.fg = sub[ly-1].ti.bg = COLOR_DEFAULT;
3739 : }
3740 0 : GMenuItemArrayFree(mi->sub);
3741 0 : mi->sub = sub;
3742 0 : }
3743 :
3744 : static GMenuItem2 gdlist[] = {
3745 : { { (unichar_t *) N_("_Show"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Show Grid|No Shortcut"), NULL, NULL, MVMenuShowGrid, MID_ShowGrid },
3746 : { { (unichar_t *) N_("_Partial"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Partial Grid|No Shortcut"), NULL, NULL, MVMenuShowGrid, MID_PartialGrid },
3747 : { { (unichar_t *) N_("Hide when _Moving"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Hide Grid when Moving|No Shortcut"), NULL, NULL, MVMenuShowGrid, MID_HideGridWhenMoving },
3748 : { { (unichar_t *) N_("_Hide"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Hide Grid|No Shortcut"), NULL, NULL, MVMenuShowGrid, MID_HideGrid },
3749 : GMENUITEM2_EMPTY
3750 : };
3751 :
3752 0 : static void gdlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3753 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3754 :
3755 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3756 0 : switch ( mi->mid ) {
3757 : case MID_ShowGrid:
3758 0 : mi->ti.checked = mv->showgrid == mv_showgrid;
3759 0 : break;
3760 : case MID_HideGrid:
3761 0 : mi->ti.checked = mv->showgrid == mv_hidegrid;
3762 0 : break;
3763 : case MID_PartialGrid:
3764 0 : mi->ti.checked = mv->showgrid == mv_partialgrid;
3765 0 : break;
3766 : case MID_HideGridWhenMoving:
3767 0 : mi->ti.checked = mv->showgrid == mv_hidemovinggrid;
3768 0 : break;
3769 : }
3770 : }
3771 0 : }
3772 :
3773 : static GMenuItem2 vwlist[] = {
3774 : { { (unichar_t *) N_("Z_oom out"), (GImage *) "viewzoomout.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Zoom out|No Shortcut"), NULL, NULL, MVMenuScale, MID_ZoomOut },
3775 : { { (unichar_t *) N_("Zoom _in"), (GImage *) "viewzoomin.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Zoom in|No Shortcut"), NULL, NULL, MVMenuScale, MID_ZoomIn },
3776 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3777 : { { (unichar_t *) N_("Insert Glyph _After..."), (GImage *) "viewinsertafter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Insert Glyph After...|No Shortcut"), NULL, NULL, MVMenuInsertChar, MID_InsertCharA },
3778 : { { (unichar_t *) N_("Insert Glyph _Before..."), (GImage *) "viewinsertbefore.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Insert Glyph Before...|No Shortcut"), NULL, NULL, MVMenuInsertChar, MID_InsertCharB },
3779 : { { (unichar_t *) N_("_Replace Glyph..."), (GImage *) "viewreplace.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Replace Glyph...|No Shortcut"), NULL, NULL, MVMenuChangeChar, MID_ReplaceChar },
3780 : { { (unichar_t *) N_("_Next Glyph"), (GImage *) "viewnext.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("Next Glyph|No Shortcut"), NULL, NULL, MVMenuChangeChar, MID_Next },
3781 : { { (unichar_t *) N_("_Prev Glyph"), (GImage *) "viewprev.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Prev Glyph|No Shortcut"), NULL, NULL, MVMenuChangeChar, MID_Prev },
3782 : { { (unichar_t *) N_("Next _Defined Glyph"), (GImage *) "viewnextdef.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Next Defined Glyph|No Shortcut"), NULL, NULL, MVMenuChangeChar, MID_NextDef },
3783 : { { (unichar_t *) N_("Prev Defined Gl_yph"), (GImage *) "viewprevdef.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Prev Defined Glyph|No Shortcut"), NULL, NULL, MVMenuChangeChar, MID_PrevDef },
3784 : { { (unichar_t *) N_("Find In Font _View"), (GImage *) "viewfindinfont.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Find In Font View|No Shortcut"), NULL, NULL, MVMenuFindInFontView, MID_FindInFontView },
3785 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3786 : { { (unichar_t *) N_("_Layers"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Layers|No Shortcut"), lylist, lylistcheck, NULL, 0 },
3787 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3788 : { { (unichar_t *) N_("Com_binations"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'b' }, H_("Combinations|No Shortcut"), cblist, cblistcheck, NULL, 0 },
3789 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3790 : { { (unichar_t *) N_("Show _Grid"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Show Grid|No Shortcut"), gdlist, gdlistcheck, MVMenuShowGrid, MID_ShowGrid },
3791 : { { (unichar_t *) N_("_Anti Alias"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'A' }, H_("Anti Alias|No Shortcut"), NULL, NULL, MVMenuAA, MID_AntiAlias },
3792 : { { (unichar_t *) N_("Render using Hinting"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'A' }, H_("Render using Hinting|No Shortcut"), NULL, NULL, MVMenuRenderUsingHinting, MID_RenderUsingHinting },
3793 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3794 : { { (unichar_t *) N_("_Vertical"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, '\0' }, H_("Vertical|No Shortcut"), NULL, NULL, MVMenuVertical, MID_Vertical },
3795 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3796 : { { (unichar_t *) N_("Size set from _Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'O' }, H_("Size set from Window|No Shortcut"), NULL, NULL, MVMenuSizeWindow, MID_SizeWindow },
3797 : { { (unichar_t *) N_("Set Point _Size"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'O' }, H_("Set Point Size|No Shortcut"), NULL, NULL, MVMenuPointSize, MID_PointSize },
3798 : { { (unichar_t *) N_("_Bigger Point Size"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Bigger Point Size|No Shortcut"), NULL, NULL, MVMenuChangePointSize, MID_Bigger },
3799 : { { (unichar_t *) N_("_Smaller Point Size"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Smaller Point Size|No Shortcut"), NULL, NULL, MVMenuChangePointSize, MID_Smaller },
3800 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3801 : { { (unichar_t *) N_("Next _Line in Word List"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'O' }, H_("Next Line in Word List|No Shortcut"), NULL, NULL, MVMenuNextLineInWordList, MID_NextLineInWordList },
3802 : { { (unichar_t *) N_("Previous Line in _Word List"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'O' }, H_("Previous Line in Word List|No Shortcut"), NULL, NULL, MVMenuPrevLineInWordList, MID_PrevLineInWordList },
3803 :
3804 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
3805 : { { (unichar_t *) N_("_Outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'O' }, H_("Outline|No Shortcut"), NULL, NULL, MVMenuShowBitmap, MID_Outline },
3806 : GMENUITEM2_EMPTY,
3807 : /* Some extra room to show bitmaps */
3808 : GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
3809 : GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
3810 : GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY, GMENUITEM2_EMPTY,
3811 : GMENUITEM2_EMPTY
3812 : };
3813 :
3814 0 : static void MVMenuContextualHelp(GWindow UNUSED(base), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3815 0 : help("metricsview.html");
3816 0 : }
3817 :
3818 : static GMenuItem2 tylist[] = {
3819 : { { (unichar_t *) N_("_Kerning only"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Kerning only|No Shortcut"), NULL, NULL, MVMenuWindowType, MID_KernOnly },
3820 : { { (unichar_t *) N_("_Advance Width only"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Advance Width Only|No Shortcut"), NULL, NULL, MVMenuWindowType, MID_WidthOnly },
3821 : { { (unichar_t *) N_("_Both"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Both|No Shortcut"), NULL, NULL, MVMenuWindowType, MID_BothKernWidth },
3822 : GMENUITEM2_EMPTY
3823 : };
3824 :
3825 0 : static void tylistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3826 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3827 :
3828 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3829 0 : switch ( mi->mid ) {
3830 : case MID_KernOnly:
3831 0 : mi->ti.checked = mv->type == mv_kernonly;
3832 0 : break;
3833 : case MID_WidthOnly:
3834 0 : mi->ti.checked = mv->type == mv_widthonly;
3835 0 : break;
3836 : case MID_BothKernWidth:
3837 0 : mi->ti.checked = mv->type == mv_kernwidth;
3838 0 : break;
3839 : }
3840 : }
3841 0 : }
3842 :
3843 :
3844 :
3845 0 : static void MVMenuSetWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3846 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3847 0 : if ( mi->mid == MID_SetVWidth && !mv->sf->hasvmetrics )
3848 0 : return;
3849 0 : SplineChar* sc = getSelectedChar(mv);
3850 0 : printf("MVMenuSetWidth() sc:%p\n",sc);
3851 0 : if(!sc)
3852 0 : return;
3853 :
3854 0 : GenericVSetWidth(mv->fv,sc,
3855 0 : mi->mid==MID_SetWidth?wt_width:
3856 0 : mi->mid==MID_SetLBearing?wt_lbearing:
3857 0 : mi->mid==MID_SetRBearing?wt_rbearing:
3858 0 : mi->mid==MID_SetBearings?wt_bearings:
3859 : wt_vwidth);
3860 : }
3861 :
3862 0 : static void MVMenuRemoveKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3863 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3864 0 : SplineChar* sc = getSelectedChar(mv);
3865 0 : if(!sc)
3866 0 : return;
3867 0 : SCRemoveKern(sc);
3868 : }
3869 0 : static void MVMenuRemoveVKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
3870 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3871 0 : SplineChar* sc = getSelectedChar(mv);
3872 0 : if(!sc)
3873 0 : return;
3874 0 : SCRemoveVKern(sc);
3875 : }
3876 :
3877 : static GMenuItem2 mtlist[] = {
3878 : { { (unichar_t *) N_("_Center in Width"), (GImage *) "metricscenter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Center in Width|No Shortcut"), NULL, NULL, MVMenuCenter, MID_Center },
3879 : { { (unichar_t *) N_("_Thirds in Width"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Thirds in Width|No Shortcut"), NULL, NULL, MVMenuCenter, MID_Thirds },
3880 : { { (unichar_t *) N_("Set _Width..."), (GImage *) "metricssetwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Set Width...|No Shortcut"), NULL, NULL, MVMenuSetWidth, MID_SetWidth },
3881 : { { (unichar_t *) N_("Set _LBearing..."), (GImage *) "metricssetlbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Set LBearing...|No Shortcut"), NULL, NULL, MVMenuSetWidth, MID_SetLBearing },
3882 : { { (unichar_t *) N_("Set _RBearing..."), (GImage *) "metricssetrbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Set RBearing...|No Shortcut"), NULL, NULL, MVMenuSetWidth, MID_SetRBearing },
3883 : { { (unichar_t *) N_("Set Both Bearings..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Set Both Bearings...|No Shortcut"), NULL, NULL, MVMenuSetWidth, MID_SetBearings },
3884 : GMENUITEM2_LINE,
3885 : { { (unichar_t *) N_("Set _Vertical Advance..."), (GImage *) "metricssetvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Set Vertical Advance...|No Shortcut"), NULL, NULL, MVMenuSetWidth, MID_SetVWidth },
3886 : GMENUITEM2_LINE,
3887 : { { (unichar_t *) N_("_Window Type"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Window Type|No Shortcut"), tylist, tylistcheck, NULL, 0 },
3888 : GMENUITEM2_LINE,
3889 : { { (unichar_t *) N_("Ker_n By Classes..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Kern By Classes...|No Shortcut"), NULL, NULL, MVMenuKernByClasses, 0 },
3890 : { { (unichar_t *) N_("VKern By Classes..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("VKern By Classes...|No Shortcut"), NULL, NULL, MVMenuVKernByClasses, MID_VKernClass },
3891 : { { (unichar_t *) N_("VKern From HKern"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("VKern From HKern|No Shortcut"), NULL, NULL, MVMenuVKernFromHKern, MID_VKernFromHKern },
3892 : { { (unichar_t *) N_("Remove Kern _Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Remove Kern Pairs|No Shortcut"), NULL, NULL, MVMenuRemoveKern, MID_RemoveKerns },
3893 : { { (unichar_t *) N_("Remove VKern Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Remove VKern Pairs|No Shortcut"), NULL, NULL, MVMenuRemoveVKern, MID_RemoveVKerns },
3894 : { { (unichar_t *) N_("Kern Pair Closeup..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Kern Pair Closeup...|No Shortcut"), NULL, NULL, MVMenuKPCloseup, 0 },
3895 : GMENUITEM2_EMPTY
3896 : };
3897 :
3898 0 : static void fllistcheck(GWindow UNUSED(gw), struct gmenuitem *mi, GEvent *UNUSED(e)) {
3899 : /*MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);*/
3900 :
3901 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3902 0 : switch ( mi->mid ) {
3903 : case MID_Recent:
3904 0 : mi->ti.disabled = !RecentFilesAny();
3905 0 : break;
3906 : }
3907 : }
3908 0 : }
3909 :
3910 0 : static void edlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3911 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3912 : int i;
3913 :
3914 0 : if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL )
3915 0 : i = -1;
3916 : else
3917 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
3918 0 : if ( mv->perchar[i].selected )
3919 0 : break;
3920 :
3921 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3922 0 : switch ( mi->mid ) {
3923 : case MID_Cut: case MID_Copy:
3924 0 : break;
3925 : case MID_Join:
3926 : case MID_CopyRef: case MID_CopyWidth:
3927 : case MID_CopyLBearing: case MID_CopyRBearing:
3928 : case MID_Clear:
3929 0 : mi->ti.disabled = i==-1;
3930 0 : break;
3931 : case MID_CopyVWidth:
3932 0 : mi->ti.disabled = i==-1 || !mv->sf->hasvmetrics;
3933 0 : break;
3934 : case MID_UnlinkRef:
3935 0 : mi->ti.disabled = i==-1 || mv->glyphs[i].sc->layers[mv->layer].refs==NULL;
3936 0 : break;
3937 : case MID_Paste:
3938 0 : break;
3939 : }
3940 : }
3941 0 : }
3942 :
3943 0 : static void ellistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3944 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
3945 : int i, anybuildable;
3946 : SplineChar *sc;
3947 0 : int order2 = mv->sf->layers[mv->layer].order2;
3948 :
3949 0 : for ( i=mv->glyphcnt-1; i>=0; --i )
3950 0 : if ( mv->perchar[i].selected )
3951 0 : break;
3952 0 : if ( i==-1 ) sc = NULL; else sc = mv->glyphs[i].sc;
3953 :
3954 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
3955 0 : switch ( mi->mid ) {
3956 : case MID_RegenBitmaps:
3957 0 : mi->ti.disabled = mv->sf->bitmaps==NULL;
3958 0 : break;
3959 : case MID_CharInfo:
3960 0 : mi->ti.disabled = sc==NULL /*|| mv->fv->b.cidmaster!=NULL*/;
3961 0 : break;
3962 : case MID_ShowDependents:
3963 0 : mi->ti.disabled = sc==NULL || sc->dependents == NULL;
3964 0 : break;
3965 : case MID_FindProblems:
3966 : case MID_Transform:
3967 0 : mi->ti.disabled = sc==NULL;
3968 0 : break;
3969 : case MID_Effects:
3970 0 : mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps || order2;
3971 0 : break;
3972 : case MID_RmOverlap: case MID_Stroke:
3973 0 : mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps;
3974 0 : break;
3975 : case MID_AddExtrema:
3976 : case MID_Round: case MID_Correct:
3977 0 : mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps;
3978 0 : break;
3979 : #ifdef FONTFORGE_CONFIG_TILEPATH
3980 : case MID_TilePath:
3981 : mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps || ClipBoardToSplineSet()==NULL || order2;
3982 : break;
3983 : #endif
3984 : case MID_Simplify:
3985 0 : mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps;
3986 0 : break;
3987 : case MID_BuildAccent:
3988 0 : anybuildable = false;
3989 0 : if ( sc!=NULL && SFIsSomethingBuildable(mv->sf,sc,mv->layer,false) )
3990 0 : anybuildable = true;
3991 0 : mi->ti.disabled = !anybuildable;
3992 0 : break;
3993 : case MID_Autotrace:
3994 0 : mi->ti.disabled = !(FindAutoTraceName()!=NULL && sc!=NULL &&
3995 0 : sc->layers[ly_back].images!=NULL );
3996 0 : break;
3997 : }
3998 : }
3999 0 : }
4000 :
4001 0 : static void vwlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4002 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
4003 : int i, j, base, aselection;
4004 : BDFFont *bdf;
4005 : char buffer[60];
4006 :
4007 0 : aselection = false;
4008 0 : for ( j=0; j<mv->glyphcnt; ++j )
4009 0 : if ( mv->perchar[j].selected ) {
4010 0 : aselection = true;
4011 0 : break;
4012 : }
4013 :
4014 0 : for ( i=0; vwlist[i].mid!=MID_Outline; ++i )
4015 0 : switch ( vwlist[i].mid ) {
4016 : case MID_ZoomIn:
4017 0 : vwlist[i].ti.disabled = mv->scale_index==0;
4018 0 : break;
4019 : case MID_ZoomOut:
4020 0 : vwlist[i].ti.disabled = mv->scale_index>=sizeof(mv_scales)/sizeof(mv_scales[0])-1;
4021 0 : break;
4022 : case MID_AntiAlias:
4023 0 : vwlist[i].ti.checked = mv->antialias;
4024 0 : vwlist[i].ti.disabled = mv->bdf!=NULL;
4025 0 : break;
4026 : case MID_RenderUsingHinting:
4027 0 : vwlist[i].ti.checked = mv->usehinting;
4028 0 : vwlist[i].ti.disabled = mv->bdf!=NULL;
4029 0 : break;
4030 : case MID_SizeWindow:
4031 0 : vwlist[i].ti.disabled = mv->pixelsize_set_by_window;
4032 0 : vwlist[i].ti.checked = mv->pixelsize_set_by_window;
4033 0 : break;
4034 : case MID_Bigger:
4035 : case MID_Smaller:
4036 0 : vwlist[i].ti.disabled = mv->pixelsize_set_by_window;
4037 0 : break;
4038 : case MID_ReplaceChar:
4039 : case MID_FindInFontView:
4040 : case MID_Next:
4041 : case MID_Prev:
4042 : case MID_NextDef:
4043 : case MID_PrevDef:
4044 0 : vwlist[i].ti.disabled = !aselection;
4045 0 : break;
4046 : case MID_Vertical:
4047 0 : vwlist[i].ti.checked = mv->vertical;
4048 0 : vwlist[i].ti.disabled = !mv->sf->hasvmetrics;
4049 0 : break;
4050 : case MID_Layers:
4051 0 : vwlist[i].ti.disabled = mv->sf->layer_cnt<=2 || mv->sf->multilayer;
4052 0 : break;
4053 : }
4054 0 : vwlist[i].ti.checked = mv->bdf==NULL;
4055 0 : base = i+1;
4056 0 : for ( i=base; vwlist[i].ti.text!=NULL || vwlist[i].ti.line; ++i ) {
4057 0 : free( vwlist[i].ti.text);
4058 0 : vwlist[i].ti.text = NULL;
4059 : }
4060 :
4061 0 : if ( mv->sf->bitmaps!=NULL ) {
4062 0 : for ( bdf = mv->sf->bitmaps, i=base;
4063 0 : i<sizeof(vwlist)/sizeof(vwlist[0])-1 && bdf!=NULL;
4064 0 : ++i, bdf = bdf->next ) {
4065 0 : if ( BDFDepth(bdf)==1 )
4066 0 : sprintf( buffer, _("%d pixel bitmap"), bdf->pixelsize );
4067 : else
4068 0 : sprintf( buffer, _("%d@%d pixel bitmap"),
4069 0 : bdf->pixelsize, BDFDepth(bdf) );
4070 0 : vwlist[i].ti.text = utf82u_copy(buffer);
4071 0 : vwlist[i].ti.checkable = true;
4072 0 : vwlist[i].ti.checked = bdf==mv->bdf;
4073 0 : vwlist[i].ti.userdata = bdf;
4074 0 : vwlist[i].invoke = MVMenuShowBitmap;
4075 0 : vwlist[i].ti.fg = vwlist[i].ti.bg = COLOR_DEFAULT;
4076 : }
4077 : }
4078 0 : GMenuItemArrayFree(mi->sub);
4079 0 : mi->sub = GMenuItem2ArrayCopy(vwlist,NULL);
4080 0 : }
4081 :
4082 0 : static void mtlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
4083 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
4084 0 : SplineChar* sc = getSelectedChar(mv);
4085 :
4086 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
4087 0 : switch ( mi->mid ) {
4088 : case MID_VKernClass:
4089 : case MID_VKernFromHKern:
4090 : case MID_SetVWidth:
4091 0 : mi->ti.disabled = !mv->sf->hasvmetrics;
4092 0 : break;
4093 : case MID_RemoveKerns:
4094 0 : mi->ti.disabled = sc ? sc->kerns==NULL : 1;
4095 0 : break;
4096 : case MID_RemoveVKerns:
4097 0 : mi->ti.disabled = sc ? sc->vkerns==NULL : 1;
4098 0 : break;
4099 :
4100 : }
4101 : }
4102 0 : }
4103 :
4104 : static GMenuItem2 mblist[] = {
4105 : { { (unichar_t *) N_("_File"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("File|No Shortcut"), fllist, fllistcheck, NULL, 0 },
4106 : { { (unichar_t *) N_("_Edit"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Edit|No Shortcut"), edlist, edlistcheck, NULL, 0 },
4107 : { { (unichar_t *) N_("E_lement"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Element|No Shortcut"), ellist, ellistcheck, NULL, 0 },
4108 : { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("View|No Shortcut"), vwlist, vwlistcheck, NULL, 0 },
4109 : { { (unichar_t *) N_("_Metrics"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Metrics|No Shortcut"), mtlist, mtlistcheck, NULL, 0 },
4110 : { { (unichar_t *) N_("_Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Window|No Shortcut"), wnmenu, MVWindowMenuBuild, NULL, 0 },
4111 : { { (unichar_t *) N_("_Help"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Help|No Shortcut"), helplist, NULL, NULL, 0 },
4112 : GMENUITEM2_EMPTY
4113 : };
4114 :
4115 0 : static void MVResize(MetricsView *mv) {
4116 : GRect pos, wsize;
4117 : int i;
4118 : int size;
4119 :
4120 0 : GDrawGetSize(mv->gw,&wsize);
4121 0 : if ( wsize.height < mv->topend+20 + mv->height-mv->displayend ||
4122 0 : wsize.width < 30 ) {
4123 0 : int width= wsize.width < 30 ? 30 : wsize.width;
4124 : int height;
4125 :
4126 0 : if ( wsize.height < mv->topend+20 + mv->height-mv->displayend )
4127 0 : height = mv->topend+20 + mv->height-mv->displayend;
4128 : else
4129 0 : height = wsize.height;
4130 0 : GDrawResize(mv->gw,width,height);
4131 0 : return;
4132 : }
4133 :
4134 0 : mv->width = wsize.width;
4135 0 : mv->displayend = wsize.height - (mv->height-mv->displayend);
4136 0 : mv->height = wsize.height;
4137 :
4138 0 : mv_width = wsize.width; mv_height = wsize.height;
4139 0 : SavePrefs(true);
4140 :
4141 0 : pos.width = wsize.width;
4142 0 : pos.height = mv->sbh;
4143 0 : pos.y = wsize.height - pos.height; pos.x = 0;
4144 0 : GGadgetResize(mv->hsb,pos.width,pos.height);
4145 0 : GGadgetMove(mv->hsb,pos.x,pos.y);
4146 :
4147 0 : mv->dwidth = mv->width - mv->sbh;
4148 0 : GGadgetResize(mv->vsb,mv->sbh,mv->displayend-mv->topend);
4149 0 : GGadgetMove(mv->vsb,wsize.width-mv->sbh,mv->topend);
4150 :
4151 0 : GGadgetResize(mv->features,mv->xstart,mv->displayend - mv->topend);
4152 :
4153 0 : size = (mv->displayend - mv->topend - 4);
4154 0 : if ( mv->dwidth-20<size )
4155 0 : size = mv->dwidth-20;
4156 0 : if ( mv->pixelsize_set_by_window ) {
4157 0 : mv->ptsize = mv->pixelsize = mv_scales[mv->scale_index]*size;
4158 0 : mv->dpi = 72;
4159 0 : if ( mv->bdf==NULL ) {
4160 0 : BDFFontFree(mv->show);
4161 0 : mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi,
4162 : MVGetSplineFontPieceMealFlags( mv ), NULL );
4163 : }
4164 : }
4165 :
4166 0 : for ( i=0; i<mv->max; ++i ) if ( mv->perchar[i].width!=NULL ) {
4167 0 : GGadgetMove(mv->perchar[i].name,mv->perchar[i].mx,mv->displayend+2);
4168 0 : GGadgetMove(mv->perchar[i].width,mv->perchar[i].mx,mv->displayend+2+mv->fh+4);
4169 0 : GGadgetMove(mv->perchar[i].lbearing,mv->perchar[i].mx,mv->displayend+2+2*(mv->fh+4));
4170 0 : GGadgetMove(mv->perchar[i].rbearing,mv->perchar[i].mx,mv->displayend+2+3*(mv->fh+4));
4171 0 : if ( mv->perchar[i].kern!=NULL )
4172 0 : GGadgetMove(mv->perchar[i].kern,mv->perchar[i].mx-mv->perchar[i].mwidth/2,mv->displayend+2+4*(mv->fh+4));
4173 : }
4174 0 : GGadgetMove(mv->namelab,2,mv->displayend+2);
4175 0 : GGadgetMove(mv->widthlab,2,mv->displayend+2+mv->fh+4);
4176 0 : GGadgetMove(mv->lbearinglab,2,mv->displayend+2+2*(mv->fh+4));
4177 0 : GGadgetMove(mv->rbearinglab,2,mv->displayend+2+3*(mv->fh+4));
4178 0 : GGadgetMove(mv->kernlab,2,mv->displayend+2+4*(mv->fh+4));
4179 :
4180 : {
4181 0 : int newwidth = mv->width;
4182 : GRect scriptselector_size;
4183 : GRect charselector_size;
4184 : GRect charselectorNext_size;
4185 : GRect charselectorPrev_size;
4186 : GRect subtable_list_size;
4187 0 : GGadgetGetSize(mv->script, &scriptselector_size);
4188 0 : GGadgetGetSize(mv->text, &charselector_size);
4189 0 : GGadgetGetSize(mv->textPrev, &charselectorPrev_size);
4190 0 : GGadgetGetSize(mv->textNext, &charselectorNext_size);
4191 0 : GGadgetGetSize(mv->subtable_list, &subtable_list_size);
4192 0 : int new_charselector_width = newwidth - charselector_size.x - charselectorNext_size.width - 2 - charselectorPrev_size.width - 2 - subtable_list_size.width - 10 - 10;
4193 0 : if (new_charselector_width < GDrawPointsToPixels(mv->gw,100))
4194 0 : new_charselector_width = GDrawPointsToPixels(mv->gw,100);
4195 0 : int new_charselectorPrev_x = charselector_size.x + new_charselector_width + 4;
4196 0 : int new_charselectorNext_x = new_charselectorPrev_x + charselectorPrev_size.width + 4;
4197 0 : int new_subtableselector_x = new_charselectorNext_x + charselectorNext_size.width + 10;
4198 :
4199 0 : GGadgetResize(mv->text, new_charselector_width, charselector_size.height);
4200 0 : GGadgetMove(mv->textPrev, new_charselectorPrev_x, charselectorPrev_size.y);
4201 0 : GGadgetMove(mv->textNext, new_charselectorNext_x, charselectorNext_size.y);
4202 0 : GGadgetMove(mv->subtable_list, new_subtableselector_x, subtable_list_size.y);
4203 : }
4204 :
4205 0 : mv->vwidth = mv->dwidth-mv->xstart;
4206 0 : mv->vheight = mv->displayend-mv->topend-2;
4207 0 : GDrawResize(mv->v,mv->vwidth, mv->vheight);
4208 0 : MVRemetric(mv);
4209 0 : GDrawRequestExpose(mv->gw,NULL,true);
4210 0 : GDrawRequestExpose(mv->v,NULL,true);
4211 : }
4212 :
4213 0 : static void MVChar(MetricsView *mv,GEvent *event)
4214 : {
4215 0 : if ( event->u.chr.keysym=='s' &&
4216 0 : (event->u.chr.state&ksm_control) &&
4217 0 : (event->u.chr.state&ksm_meta) )
4218 0 : MenuSaveAll(NULL,NULL,NULL);
4219 0 : else if ( event->u.chr.keysym=='I' &&
4220 0 : (event->u.chr.state&ksm_shift) &&
4221 0 : (event->u.chr.state&ksm_meta) )
4222 0 : MVMenuCharInfo(mv->gw,NULL,NULL);
4223 0 : else if ( event->u.chr.keysym == GK_Help ) {
4224 0 : MenuHelp(NULL,NULL,NULL); /* Menu does F1 */
4225 : }
4226 0 : if ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up
4227 0 : || event->u.chr.keysym == GK_Down || event->u.chr.keysym==GK_KP_Down
4228 0 : || event->u.chr.keysym == GK_Left || event->u.chr.keysym==GK_KP_Left
4229 0 : || event->u.chr.keysym == GK_Right || event->u.chr.keysym==GK_KP_Right ) {
4230 0 : if( event->u.chr.state&ksm_meta ) {
4231 0 : int dir = ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ) ? -1
4232 0 : : ( ( event->u.chr.keysym == GK_Down || event->u.chr.keysym==GK_KP_Down ) ? 1 : 0);
4233 0 : GGadget *active = GWindowGetFocusGadgetOfWindow(mv->gw);
4234 0 : GGadget *toSelect = 0;
4235 :
4236 0 : if( active ) {
4237 0 : int i=0, j=0;
4238 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
4239 : // remember here that j=0 is NULL because updownkparray is NULL terminated
4240 : // at both ends.
4241 0 : for ( j=1; j<10 && mv->perchar[i].updownkparray[j]; ++j ) {
4242 0 : if ( active == mv->perchar[i].updownkparray[j] ) {
4243 0 : if( dir != 0 ) {
4244 0 : toSelect = mv->perchar[i].updownkparray[j+dir];
4245 : } else {
4246 0 : int newidx = i;
4247 0 : if( event->u.chr.keysym == GK_Left || event->u.chr.keysym==GK_KP_Left )
4248 0 : newidx--;
4249 0 : if( event->u.chr.keysym == GK_Right || event->u.chr.keysym==GK_KP_Right )
4250 0 : newidx++;
4251 0 : if( newidx < 0 || newidx >= mv->glyphcnt )
4252 0 : return;
4253 0 : toSelect = mv->perchar[newidx].updownkparray[j];
4254 : }
4255 : }
4256 : }
4257 : }
4258 : }
4259 0 : if( toSelect ) {
4260 0 : GWidgetIndicateFocusGadget(toSelect);
4261 : }
4262 0 : return;
4263 : }
4264 : }
4265 0 : if ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ||
4266 0 : event->u.chr.keysym == GK_Down || event->u.chr.keysym==GK_KP_Down ) {
4267 0 : GGadget *active = GWindowGetFocusGadgetOfWindow(mv->gw);
4268 0 : if(!active)
4269 0 : return;
4270 :
4271 : // MIQ: We do not want to increment and decrement the integer
4272 : // value of the kerning word on up/down now, instead we
4273 : // should always move up/down in the list of kerning words.
4274 0 : if( active != mv->text )
4275 : {
4276 : unichar_t *end;
4277 0 : double val = u_strtod(_GGadgetGetTitle(active),&end);
4278 0 : if (isValidInt(end)) {
4279 0 : int dir = ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ) ? 1 : -1;
4280 0 : if( event->u.chr.state&ksm_control && event->u.chr.state&ksm_shift ) {
4281 0 : dir *= pref_mv_control_shift_and_arrow_skip;
4282 : }
4283 0 : else if( event->u.chr.state&ksm_shift ) {
4284 0 : dir *= pref_mv_shift_and_arrow_skip;
4285 : }
4286 0 : val += dir;
4287 : char buf[100];
4288 0 : snprintf(buf,99,"%.0f",val);
4289 0 : GGadgetSetTitle8(active, buf);
4290 :
4291 0 : event->u.control.u.tf_changed.from_pulldown=-1;
4292 0 : event->type=et_controlevent;
4293 0 : event->u.control.subtype = et_textchanged;
4294 0 : GGadgetDispatchEvent(active,event);
4295 :
4296 0 : if( haveClassBasedKerningInView(mv) )
4297 : {
4298 0 : MVRemetric(mv);
4299 0 : GDrawRequestExpose(mv->v,NULL,false);
4300 : }
4301 : }
4302 : }
4303 : }
4304 0 : if ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ||
4305 0 : event->u.chr.keysym == GK_Down || event->u.chr.keysym==GK_KP_Down )
4306 : {
4307 0 : int dir = ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ) ? -1 : 1;
4308 0 : MVMoveInWordListByOffset( mv, dir );
4309 : }
4310 : }
4311 :
4312 0 : static int hitsbit(BDFChar *bc, int x, int y) {
4313 0 : if ( bc->byte_data )
4314 0 : return( bc->bitmap[y*bc->bytes_per_line+x] );
4315 : else
4316 0 : return( bc->bitmap[y*bc->bytes_per_line+(x>>3)]&(1<<(7-(x&7))) );
4317 : }
4318 :
4319 0 : static void _MVSubVMouse(MetricsView *mv,GEvent *event) {
4320 : int i, x, y, j, within, xbase;
4321 : SplineChar *sc;
4322 : int diff;
4323 : int onwidth, onkern;
4324 0 : SplineFont *sf = mv->sf;
4325 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
4326 0 : double scale = iscale*mv->pixelsize/(double) (sf->ascent+sf->descent);
4327 0 : int as = rint(sf->ascent*scale);
4328 :
4329 0 : xbase = mv->vwidth/2;
4330 0 : within = -1;
4331 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
4332 0 : y = mv->perchar[i].dy + mv->perchar[i].yoff;
4333 0 : x = xbase - mv->pixelsize*iscale/2 - mv->perchar[i].xoff;
4334 0 : if ( mv->bdf==NULL ) {
4335 0 : BDFChar *bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos);
4336 0 : if ( event->u.mouse.x >= x+bdfc->xmin &&
4337 0 : event->u.mouse.x <= x+bdfc->xmax &&
4338 0 : event->u.mouse.y <= (y+as)-bdfc->ymin &&
4339 0 : event->u.mouse.y >= (y+as)-bdfc->ymax &&
4340 0 : hitsbit(bdfc,rint(iscale*(event->u.mouse.x-x-bdfc->xmin)),
4341 0 : rint(iscale*(event->u.mouse.y-(y+as-bdfc->ymax)))) )
4342 0 : break;
4343 : }
4344 0 : y += -mv->perchar[i].yoff;
4345 0 : if ( event->u.mouse.y >= y && event->u.mouse.y < y+mv->perchar[i].dheight+ mv->perchar[i].kernafter )
4346 0 : within = i;
4347 : }
4348 0 : if ( i==mv->glyphcnt )
4349 0 : sc = NULL;
4350 : else
4351 0 : sc = mv->glyphs[i].sc;
4352 :
4353 0 : diff = event->u.mouse.y-mv->pressed_y;
4354 0 : onwidth = onkern = false;
4355 0 : if ( sc==NULL ) {
4356 0 : if ( mv->type == mv_kernonly ) {
4357 0 : if ( within!=-1 && within+1<mv->glyphcnt &&
4358 0 : event->u.mouse.y>mv->perchar[within+1].dy-3 ) {
4359 0 : onkern = true; /* subsequent char */
4360 0 : ++within;
4361 0 : } else if ( within>0 &&
4362 0 : event->u.mouse.y<mv->perchar[within].dy+3 )
4363 0 : onkern = true;
4364 0 : } else if ( mv->type == mv_widthonly ) {
4365 0 : if ( within!=-1 && within+1<mv->glyphcnt &&
4366 0 : event->u.mouse.y>mv->perchar[within+1].dy-3 )
4367 0 : onwidth = true; /* subsequent char */
4368 0 : else if ( within>=0 &&
4369 0 : event->u.mouse.y>mv->perchar[within].dy+mv->perchar[within].dheight+mv->perchar[within].kernafter-3 ) {
4370 0 : onwidth = true;
4371 : }
4372 : } else {
4373 0 : if ( within>0 && mv->perchar[within-1].selected &&
4374 0 : event->u.mouse.y<mv->perchar[within].dy+3 )
4375 0 : onwidth = true; /* previous char */
4376 0 : else if ( within!=-1 && within+1<mv->glyphcnt &&
4377 0 : mv->perchar[within+1].selected &&
4378 0 : event->u.mouse.y>mv->perchar[within+1].dy-3 ) {
4379 0 : onkern = true; /* subsequent char */
4380 0 : ++within;
4381 0 : } else if ( within>0 && mv->perchar[within].selected &&
4382 0 : event->u.mouse.y<mv->perchar[within].dy+3 )
4383 0 : onkern = true;
4384 0 : else if ( within>=0 &&
4385 0 : event->u.mouse.y>mv->perchar[within].dy+mv->perchar[within].dheight+mv->perchar[within].kernafter-3 ) {
4386 0 : onwidth = true;
4387 : }
4388 : }
4389 : }
4390 :
4391 0 : if ( event->type != et_mousemove || !mv->pressed ) {
4392 0 : int ct = -1;
4393 0 : if ( mv->bdf!=NULL ||
4394 0 : ( mv->type==mv_kernonly && !onkern ) ||
4395 0 : ( mv->type==mv_widthonly && !onwidth )) {
4396 0 : if ( mv->cursor!=ct_mypointer )
4397 0 : ct = ct_mypointer;
4398 0 : } else if ( sc!=NULL ) {
4399 0 : if ( mv->cursor!=ct_lbearing )
4400 0 : ct = ct_lbearing;
4401 0 : } else if ( onwidth ) {
4402 0 : if ( mv->cursor!=ct_rbearing )
4403 0 : ct = ct_rbearing;
4404 0 : } else if ( onkern ) {
4405 0 : if ( mv->cursor!=ct_kerning )
4406 0 : ct = ct_kerning;
4407 : } else {
4408 0 : if ( mv->cursor!=ct_mypointer )
4409 0 : ct = ct_mypointer;
4410 : }
4411 0 : if ( ct!=-1 ) {
4412 0 : GDrawSetCursor(mv->gw,ct);
4413 0 : mv->cursor = ct;
4414 : }
4415 : }
4416 :
4417 0 : if ( event->type == et_mousemove && !mv->pressed ) {
4418 0 : if ( sc==NULL && within!=-1 )
4419 0 : sc = mv->glyphs[within].sc;
4420 0 : if ( sc!=NULL )
4421 0 : SCPreparePopup(mv->gw,sc,mv->fv->b.map->remap,mv->fv->b.map->backmap[sc->orig_pos],sc->unicodeenc);
4422 : /* Don't allow any editing when displaying a bitmap font */
4423 0 : } else if ( event->type == et_mousedown && mv->bdf==NULL ) {
4424 0 : CVPaletteDeactivate();
4425 0 : if ( sc!=NULL ) {
4426 0 : for ( j=0; j<mv->glyphcnt; ++j )
4427 0 : if ( j!=i && mv->perchar[j].selected )
4428 0 : MVDeselectChar(mv,j);
4429 0 : MVSelectChar(mv,i);
4430 0 : GWindowClearFocusGadgetOfWindow(mv->gw);
4431 0 : mv->pressed = true;
4432 0 : } else if ( within!=-1 ) {
4433 0 : mv->pressedwidth = onwidth;
4434 0 : mv->pressedkern = onkern;
4435 0 : if ( mv->pressedwidth || mv->pressedkern ) {
4436 0 : mv->pressed = true;
4437 0 : if ( !mv->perchar[within].selected ) {
4438 0 : MVDoSelect(mv,within);
4439 : }
4440 : }
4441 : }
4442 0 : mv->pressed_y = event->u.mouse.y;
4443 0 : } else if ( event->type == et_mousemove && mv->pressed ) {
4444 0 : for ( i=0; i<mv->glyphcnt && !mv->perchar[i].selected; ++i );
4445 0 : if ( mv->pressedwidth ) {
4446 0 : int ow = mv->perchar[i].dwidth;
4447 0 : mv->perchar[i].dwidth = rint(mv->glyphs[i].sc->vwidth*scale) + diff;
4448 0 : if ( ow!=mv->perchar[i].dwidth ) {
4449 0 : for ( j=i+1; j<mv->glyphcnt; ++j )
4450 0 : mv->perchar[j].dy = mv->perchar[j-1].dy+mv->perchar[j-1].dheight+
4451 0 : mv->perchar[j-1].kernafter;
4452 0 : GDrawRequestExpose(mv->v,NULL,false);
4453 : }
4454 0 : } else if ( mv->pressedkern ) {
4455 0 : int ow = mv->perchar[i-1].kernafter;
4456 : KernPair *kp;
4457 : int kpoff;
4458 : KernClass *kc;
4459 0 : kp = mv->glyphs[i-1].kp;
4460 0 : if ( kp!=NULL )
4461 0 : kpoff = kp->off;
4462 0 : else if ((kc=mv->glyphs[i-1].kc)!=NULL )
4463 0 : kpoff = kc->offsets[mv->glyphs[i-1].kc_index];
4464 : else
4465 0 : kpoff = 0;
4466 0 : kpoff = kpoff * mv->pixelsize*iscale /
4467 0 : (mv->sf->descent+mv->sf->ascent);
4468 0 : mv->perchar[i-1].kernafter = kpoff + diff;
4469 0 : if ( ow!=mv->perchar[i-1].kernafter ) {
4470 0 : for ( j=i; j<mv->glyphcnt; ++j )
4471 0 : mv->perchar[j].dy = mv->perchar[j-1].dy+mv->perchar[j-1].dheight+
4472 0 : mv->perchar[j-1].kernafter;
4473 0 : GDrawRequestExpose(mv->v,NULL,false);
4474 : }
4475 0 : } else if ( mv->type!=mv_kernonly ) {
4476 0 : int olda = mv->activeoff;
4477 0 : BDFChar *bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos);
4478 0 : mv->activeoff = diff;
4479 0 : MVRedrawI(mv,i,bdfc->xmin+olda,bdfc->xmax+olda);
4480 : }
4481 0 : } else if ( event->type == et_mouseup && event->u.mouse.clicks>1 &&
4482 0 : (within!=-1 || sc!=NULL)) {
4483 0 : mv->pressed = false; mv->activeoff = 0;
4484 0 : mv->pressedwidth = mv->pressedkern = false;
4485 0 : if ( within==-1 ) within = i;
4486 0 : if ( mv->bdf==NULL )
4487 0 : CharViewCreate(mv->glyphs[within].sc,mv->fv,-1);
4488 : else
4489 0 : BitmapViewCreate(mv->bdf->glyphs[mv->glyphs[within].sc->orig_pos],mv->bdf,mv->fv,-1);
4490 0 : if ( mv->showgrid==mv_hidemovinggrid )
4491 0 : GDrawRequestExpose(mv->v,NULL,false);
4492 0 : } else if ( event->type == et_mouseup && mv->pressed ) {
4493 0 : for ( i=0; i<mv->glyphcnt && !mv->perchar[i].selected; ++i );
4494 0 : mv->pressed = false;
4495 0 : mv->activeoff = 0;
4496 0 : sc = mv->glyphs[i].sc;
4497 0 : if ( mv->pressedwidth ) {
4498 0 : mv->pressedwidth = false;
4499 0 : diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale);
4500 0 : if ( diff!=0 ) {
4501 0 : SCPreserveWidth(sc);
4502 0 : sc->vwidth += diff;
4503 0 : SCCharChangedUpdate(sc,ly_none);
4504 0 : for ( ; i<mv->glyphcnt; ++i )
4505 0 : mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight +
4506 0 : mv->perchar[i-1].kernafter ;
4507 0 : GDrawRequestExpose(mv->v,NULL,false);
4508 0 : } else if ( mv->showgrid==mv_hidemovinggrid )
4509 0 : GDrawRequestExpose(mv->v,NULL,false);
4510 0 : } else if ( mv->pressedkern ) {
4511 0 : mv->pressedkern = false;
4512 0 : diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale);
4513 0 : if ( diff!=0 )
4514 0 : MV_ChangeKerning(mv, i, diff, true);
4515 0 : MVRefreshValues(mv,i-1);
4516 0 : } else if ( mv->type!=mv_kernonly ) {
4517 : real transform[6];
4518 : DBounds bb;
4519 0 : SplineCharFindBounds(sc,&bb);
4520 0 : transform[0] = transform[3] = 1.0;
4521 0 : transform[1] = transform[2] = transform[4] = 0;
4522 0 : transform[5] = -diff*
4523 0 : (mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale);
4524 0 : if ( transform[5]!=0 )
4525 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,false);
4526 : }
4527 0 : mv->pressedwidth = false;
4528 0 : mv->pressedkern = false;
4529 0 : } else if ( event->type == et_mouseup && mv->bdf!=NULL && within!=-1 ) {
4530 0 : for ( j=0; j<mv->glyphcnt; ++j )
4531 0 : if ( j!=within && mv->perchar[j].selected )
4532 0 : MVDeselectChar(mv,j);
4533 0 : MVSelectChar(mv,within);
4534 0 : if ( mv->showgrid==mv_hidemovinggrid )
4535 0 : GDrawRequestExpose(mv->v,NULL,false);
4536 : }
4537 0 : }
4538 :
4539 0 : static void MVSubMouse(MetricsView *mv,GEvent *event) {
4540 : // This handles mouse events in the preview area.
4541 : int i, x, y, j, within, ybase;
4542 : SplineChar *sc;
4543 : int diff;
4544 : int onwidth, onkern;
4545 : BDFChar *bdfc;
4546 0 : double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index];
4547 :
4548 0 : GGadgetEndPopup();
4549 :
4550 0 : if ( event->type==et_mouseup ) {
4551 0 : event->type = et_mousemove;
4552 0 : MVSubMouse(mv,event);
4553 0 : event->u.mouse.x -= mv->xoff;
4554 0 : event->u.mouse.y -= mv->yoff;
4555 0 : event->type = et_mouseup;
4556 : }
4557 :
4558 0 : event->u.mouse.x += mv->xoff;
4559 0 : event->u.mouse.y += mv->yoff;
4560 0 : if ( mv->vertical ) {
4561 0 : _MVSubVMouse(mv,event);
4562 0 : return;
4563 : }
4564 :
4565 0 : ybase = mv->ybaseline - mv->yoff;
4566 0 : within = -1;
4567 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
4568 0 : x = mv->perchar[i].dx + mv->perchar[i].xoff;
4569 0 : if ( mv->right_to_left )
4570 0 : x = mv->vwidth - x - mv->perchar[i].dwidth - mv->perchar[i].kernafter;
4571 0 : y = ybase - mv->perchar[i].yoff;
4572 0 : if ( mv->bdf==NULL ) {
4573 0 : bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos);
4574 0 : if ( event->u.mouse.x >= x+bdfc->xmin &&
4575 0 : event->u.mouse.x <= x+bdfc->xmax &&
4576 0 : event->u.mouse.y <= y-bdfc->ymin &&
4577 0 : event->u.mouse.y >= y-bdfc->ymax &&
4578 0 : hitsbit(bdfc,rint(iscale*(event->u.mouse.x-x-bdfc->xmin)),
4579 0 : rint(iscale*(bdfc->ymax-(y-event->u.mouse.y)))) )
4580 0 : break;
4581 : }
4582 0 : x += mv->right_to_left ? mv->perchar[i].xoff : -mv->perchar[i].xoff;
4583 0 : if ( event->u.mouse.x >= x && event->u.mouse.x < x+mv->perchar[i].dwidth+ mv->perchar[i].kernafter )
4584 0 : within = i;
4585 : }
4586 0 : if ( i==mv->glyphcnt )
4587 0 : sc = NULL;
4588 : else
4589 0 : sc = mv->glyphs[i].sc;
4590 :
4591 0 : diff = event->u.mouse.x-mv->pressed_x;
4592 : /*if ( mv->right_to_left ) diff = -diff;*/
4593 0 : onwidth = onkern = false;
4594 0 : if ( sc==NULL ) {
4595 0 : if ( !mv->right_to_left ) {
4596 0 : if ( mv->type == mv_kernonly ) {
4597 0 : if ( within>=0 && within+1<mv->glyphcnt &&
4598 0 : event->u.mouse.x>mv->perchar[within+1].dx-3 ) {
4599 0 : onkern = true; /* subsequent char */
4600 0 : ++within;
4601 0 : } else if ( within>0 &&
4602 0 : event->u.mouse.x<mv->perchar[within].dx+3 )
4603 0 : onkern = true;
4604 0 : } else if ( mv->type == mv_widthonly ) {
4605 0 : if ( within>=0 && within+1<mv->glyphcnt &&
4606 0 : event->u.mouse.x>mv->perchar[within+1].dx-3 )
4607 0 : onwidth = true; /* subsequent char */
4608 0 : else if ( within>=0 &&
4609 0 : event->u.mouse.x>mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3 ) {
4610 0 : onwidth = true;
4611 : }
4612 : } else {
4613 0 : if ( within>0 && mv->perchar[within-1].selected &&
4614 0 : event->u.mouse.x<mv->perchar[within].dx+3 )
4615 0 : onwidth = true; /* previous char */
4616 0 : else if ( within!=-1 && within+1<mv->glyphcnt &&
4617 0 : mv->perchar[within+1].selected &&
4618 0 : event->u.mouse.x>mv->perchar[within+1].dx-3 ) {
4619 0 : onkern = true; /* subsequent char */
4620 0 : ++within;
4621 0 : } else if ( within>0 && mv->perchar[within].selected &&
4622 0 : event->u.mouse.x<mv->perchar[within].dx+3 )
4623 0 : onkern = true;
4624 0 : else if ( within>=0 &&
4625 0 : event->u.mouse.x>mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3 ) {
4626 0 : onwidth = true;
4627 : }
4628 : }
4629 : } else {
4630 0 : if ( mv->type == mv_kernonly ) {
4631 0 : if ( within>=0 && within+1<mv->glyphcnt &&
4632 0 : event->u.mouse.x<mv->dwidth-(mv->perchar[within+1].dx-3) ) {
4633 0 : onkern = true; /* subsequent char */
4634 0 : ++within;
4635 0 : } else if ( within>0 &&
4636 0 : event->u.mouse.x>mv->dwidth-(mv->perchar[within].dx+3) )
4637 0 : onkern = true;
4638 0 : } else if ( mv->type == mv_widthonly ) {
4639 0 : if ( within>=0 && within+1<mv->glyphcnt &&
4640 0 : event->u.mouse.x<mv->dwidth-(mv->perchar[within+1].dx-3) )
4641 0 : onwidth = true; /* subsequent char */
4642 0 : else if ( within>=0 &&
4643 0 : event->u.mouse.x<mv->dwidth-(mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3) ) {
4644 0 : onwidth = true;
4645 : }
4646 : } else {
4647 0 : if ( within>0 && mv->perchar[within-1].selected &&
4648 0 : event->u.mouse.x>mv->dwidth-(mv->perchar[within].dx+3) )
4649 0 : onwidth = true; /* previous char */
4650 0 : else if ( within!=-1 && within+1<mv->glyphcnt &&
4651 0 : mv->perchar[within+1].selected &&
4652 0 : event->u.mouse.x<mv->dwidth-(mv->perchar[within+1].dx-3) ) {
4653 0 : onkern = true; /* subsequent char */
4654 0 : ++within;
4655 0 : } else if ( within>0 && mv->perchar[within].selected &&
4656 0 : event->u.mouse.x>mv->dwidth-(mv->perchar[within].dx+3) )
4657 0 : onkern = true;
4658 0 : else if ( within>=0 &&
4659 0 : event->u.mouse.x<mv->dwidth-(mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3) ) {
4660 0 : onwidth = true;
4661 : }
4662 : }
4663 : }
4664 : }
4665 :
4666 0 : if ( event->type != et_mousemove || !mv->pressed ) {
4667 0 : int ct = -1;
4668 0 : if ( mv->bdf!=NULL ||
4669 0 : ( mv->type==mv_kernonly && !onkern ) ||
4670 0 : ( mv->type==mv_widthonly && !onwidth )) {
4671 0 : if ( mv->cursor!=ct_mypointer )
4672 0 : ct = ct_mypointer;
4673 0 : } else if ( sc!=NULL ) {
4674 0 : if ( mv->cursor!=ct_lbearing )
4675 0 : ct = ct_lbearing;
4676 0 : } else if ( onwidth ) {
4677 0 : if ( mv->cursor!=ct_rbearing )
4678 0 : ct = ct_rbearing;
4679 0 : } else if ( onkern ) {
4680 0 : if ( mv->cursor!=ct_kerning )
4681 0 : ct = ct_kerning;
4682 : } else {
4683 0 : if ( mv->cursor!=ct_mypointer )
4684 0 : ct = ct_mypointer;
4685 : }
4686 0 : if ( ct!=-1 ) {
4687 0 : GDrawSetCursor(mv->gw,ct);
4688 0 : mv->cursor = ct;
4689 : }
4690 : }
4691 :
4692 0 : if ( event->type == et_mousemove && !mv->pressed ) {
4693 0 : if ( sc==NULL && within!=-1 )
4694 0 : sc = mv->glyphs[within].sc;
4695 0 : if ( sc!=NULL )
4696 0 : SCPreparePopup(mv->gw,sc,mv->fv->b.map->remap,mv->fv->b.map->backmap[sc->orig_pos],sc->unicodeenc);
4697 : /* Don't allow any editing when displaying a bitmap font */
4698 0 : } else if ( event->type == et_mousedown && mv->bdf==NULL ) {
4699 0 : CVPaletteDeactivate();
4700 0 : if ( sc!=NULL ) {
4701 0 : for ( j=0; j<mv->glyphcnt; ++j )
4702 0 : if ( j!=i && mv->perchar[j].selected )
4703 0 : MVDeselectChar(mv,j);
4704 0 : MVSelectChar(mv,i);
4705 0 : GWindowClearFocusGadgetOfWindow(mv->gw);
4706 0 : mv->pressed = true;
4707 0 : } else if ( within!=-1 ) {
4708 0 : mv->pressedwidth = onwidth;
4709 0 : mv->pressedkern = onkern;
4710 0 : if ( mv->pressedwidth || mv->pressedkern ) {
4711 0 : mv->pressed = true;
4712 0 : if ( !mv->perchar[within].selected ) {
4713 0 : MVDoSelect(mv,within);
4714 : }
4715 : }
4716 : }
4717 0 : mv->pressed_x = event->u.mouse.x;
4718 0 : } else if ( event->type == et_mousemove && mv->pressed ) {
4719 : // printf("move & pressed pressedwidth:%d pressedkern:%d type!=mv_kernonly:%d\n",mv->pressedwidth,mv->pressedkern,(mv->type!=mv_kernonly));
4720 :
4721 0 : for ( i=0; i<mv->glyphcnt && !mv->perchar[i].selected; ++i )
4722 : {
4723 : // nothing
4724 : }
4725 :
4726 0 : if ( mv->pressedwidth ) {
4727 0 : int ow = mv->perchar[i].dwidth;
4728 0 : if ( mv->right_to_left ) diff = -diff;
4729 0 : bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos);
4730 0 : mv->perchar[i].dwidth = bdfc->width + diff;
4731 0 : if ( ow!=mv->perchar[i].dwidth ) {
4732 0 : for ( j=i+1; j<mv->glyphcnt; ++j )
4733 0 : mv->perchar[j].dx = mv->perchar[j-1].dx+mv->perchar[j-1].dwidth+ mv->perchar[j-1].kernafter;
4734 0 : GDrawRequestExpose(mv->v,NULL,false);
4735 : }
4736 0 : } else if ( mv->pressedkern ) {
4737 0 : int ow = mv->perchar[i-1].kernafter;
4738 : KernPair *kp;
4739 : int kpoff;
4740 : KernClass *kc;
4741 : int index;
4742 0 : for ( kp = mv->glyphs[i-1].sc->kerns; kp!=NULL && kp->sc!=mv->glyphs[i].sc; kp = kp->next );
4743 0 : if ( kp!=NULL )
4744 0 : kpoff = kp->off;
4745 0 : else if ((kc=SFFindKernClass(mv->sf,mv->glyphs[i-1].sc,mv->glyphs[i].sc,&index,false))!=NULL )
4746 0 : kpoff = kc->offsets[index];
4747 : else
4748 0 : kpoff = 0;
4749 0 : kpoff = kpoff * mv->pixelsize*iscale /
4750 0 : (mv->sf->descent+mv->sf->ascent);
4751 0 : if ( mv->right_to_left ) diff = -diff;
4752 0 : mv->perchar[i-1].kernafter = kpoff + diff;
4753 0 : if ( ow!=mv->perchar[i-1].kernafter ) {
4754 0 : for ( j=i; j<mv->glyphcnt; ++j )
4755 0 : mv->perchar[j].dx = mv->perchar[j-1].dx+mv->perchar[j-1].dwidth+ mv->perchar[j-1].kernafter;
4756 0 : GDrawRequestExpose(mv->v,NULL,false);
4757 : }
4758 0 : } else if ( mv->type!=mv_kernonly ) {
4759 0 : int olda = mv->activeoff;
4760 0 : bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos);
4761 0 : mv->activeoff = diff;
4762 0 : MVRedrawI(mv,i,bdfc->xmin+olda,bdfc->xmax+olda);
4763 : }
4764 0 : } else if ( event->type == et_mouseup && event->u.mouse.clicks>1 &&
4765 0 : (within!=-1 || sc!=NULL)) {
4766 0 : mv->pressed = false; mv->activeoff = 0;
4767 0 : mv->pressedwidth = mv->pressedkern = false;
4768 0 : if ( within==-1 ) within = i;
4769 0 : if ( mv->bdf==NULL )
4770 0 : CharViewCreate(mv->glyphs[within].sc,mv->fv,-1);
4771 : else
4772 0 : BitmapViewCreate(mv->bdf->glyphs[mv->glyphs[within].sc->orig_pos],mv->bdf,mv->fv,-1);
4773 0 : if ( mv->showgrid==mv_hidemovinggrid )
4774 0 : GDrawRequestExpose(mv->v,NULL,false);
4775 0 : } else if ( event->type == et_mouseup && mv->pressed ) {
4776 0 : for ( i=0; i<mv->glyphcnt && !mv->perchar[i].selected; ++i )
4777 : {
4778 : // nothing
4779 : }
4780 :
4781 0 : printf("mvsubmouse() mv->pressedwidth:%d \n", mv->pressedwidth );
4782 0 : mv->pressed = false;
4783 0 : mv->activeoff = 0;
4784 0 : sc = mv->glyphs[i].sc;
4785 0 : if ( mv->pressedwidth ) {
4786 0 : mv->pressedwidth = false;
4787 0 : if ( mv->right_to_left ) diff = -diff;
4788 0 : diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale);
4789 0 : printf("mvsubmouse() diff:%d \n", diff );
4790 0 : if ( diff!=0 ) {
4791 0 : SCPreserveWidth(sc);
4792 0 : SCSynchronizeWidth(sc,sc->width+diff,sc->width,NULL);
4793 0 : SCCharChangedUpdate(sc,ly_none);
4794 0 : MV_handle_collabclient_sendRedo(mv,sc);
4795 : }
4796 0 : } else if ( mv->pressedkern ) {
4797 0 : mv->pressedkern = false;
4798 0 : diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale);
4799 0 : if ( diff!=0 ) {
4800 0 : if ( mv->right_to_left ) diff = -diff;
4801 0 : MV_ChangeKerning(mv, i, diff, true);
4802 0 : MVRefreshValues(mv,i-1);
4803 : }
4804 0 : } else if ( mv->type!=mv_kernonly ) {
4805 0 : printf("mvsubmouse() not kern only \n" );
4806 0 : MV_handle_collabclient_maybeSnapshot(mv,sc);
4807 : real transform[6];
4808 0 : transform[0] = transform[3] = 1.0;
4809 0 : transform[1] = transform[2] = transform[5] = 0;
4810 0 : transform[4] = diff*
4811 0 : (mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale);
4812 0 : if ( transform[4]!=0 )
4813 0 : FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL, 0 | fvt_alllayers );
4814 :
4815 0 : MV_handle_collabclient_sendRedo(mv,sc);
4816 : }
4817 0 : mv->pressedwidth = false;
4818 0 : mv->pressedkern = false;
4819 0 : if ( mv->showgrid==mv_hidemovinggrid )
4820 0 : GDrawRequestExpose(mv->v,NULL,false);
4821 0 : } else if ( event->type == et_mouseup && mv->bdf!=NULL && within!=-1 ) {
4822 0 : for ( j=0; j<mv->glyphcnt; ++j )
4823 0 : if ( j!=within && mv->perchar[j].selected )
4824 0 : MVDeselectChar(mv,j);
4825 0 : MVSelectChar(mv,within);
4826 0 : if ( mv->showgrid==mv_hidemovinggrid )
4827 0 : GDrawRequestExpose(mv->v,NULL,false);
4828 : }
4829 : }
4830 :
4831 0 : static void MVMouse(MetricsView *mv,GEvent *event) {
4832 : int i;
4833 :
4834 0 : if ( event->u.mouse.y< mv->topend || event->u.mouse.y >= mv->displayend ) {
4835 : // mv->displayend > mv->topend
4836 : // This triggers when the mouse is in the data entry grid.
4837 0 : if ( event->u.mouse.y >= mv->displayend &&
4838 0 : event->u.mouse.y<mv->height-mv->sbh ) {
4839 : // This excludes the scroll bar.
4840 0 : event->u.mouse.x += (mv->coff*mv->mwidth);
4841 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
4842 0 : if ( event->u.mouse.x >= mv->perchar[i].mx &&
4843 0 : event->u.mouse.x < mv->perchar[i].mx+mv->perchar[i].mwidth )
4844 0 : break; // This triggers only if the column has an associated character.
4845 : }
4846 0 : if ( i<mv->glyphcnt )
4847 0 : SCPreparePopup(mv->gw,mv->glyphs[i].sc,mv->fv->b.map->remap,
4848 0 : mv->fv->b.map->backmap[mv->glyphs[i].sc->orig_pos],
4849 0 : mv->glyphs[i].sc->unicodeenc);
4850 : }
4851 0 : if ( mv->cursor!=ct_mypointer ) {
4852 0 : GDrawSetCursor(mv->gw,ct_mypointer);
4853 0 : mv->cursor = ct_mypointer;
4854 : }
4855 0 : return;
4856 : }
4857 : }
4858 :
4859 0 : static void MVDrop(MetricsView *mv,GEvent *event) {
4860 0 : int x,ex = event->u.drag_drop.x + mv->xoff;
4861 0 : int y,ey = event->u.drag_drop.y + mv->yoff;
4862 : int within, i, cnt, ch;
4863 : int32 len;
4864 : char *cnames, *start, *pt;
4865 : unichar_t *newtext;
4866 : const unichar_t *oldtext;
4867 : SplineChar **founds;
4868 : /* We should get a list of character names. Add them before the character */
4869 : /* on which they are dropped */
4870 :
4871 0 : if ( !GDrawSelectionHasType(mv->gw,sn_drag_and_drop,"STRING"))
4872 0 : return;
4873 0 : cnames = GDrawRequestSelection(mv->gw,sn_drag_and_drop,"STRING",&len);
4874 0 : if ( cnames==NULL )
4875 0 : return;
4876 :
4877 0 : within = mv->glyphcnt;
4878 0 : if ( !mv->vertical ) {
4879 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
4880 0 : x = mv->perchar[i].dx;
4881 0 : if ( mv->right_to_left )
4882 0 : x = mv->dwidth - x - mv->perchar[i].dwidth - mv->perchar[i].kernafter ;
4883 0 : if ( ex >= x && ex < x+mv->perchar[i].dwidth+ mv->perchar[i].kernafter ) {
4884 0 : within = i;
4885 0 : break;
4886 : }
4887 : }
4888 : } else {
4889 0 : for ( i=0; i<mv->glyphcnt; ++i ) {
4890 0 : y = mv->perchar[i].dy;
4891 0 : if ( ey >= y && ey < y+mv->perchar[i].dheight+
4892 0 : mv->perchar[i].kernafter ) {
4893 0 : within = i;
4894 0 : break;
4895 : }
4896 : }
4897 : }
4898 :
4899 0 : founds = malloc(len*sizeof(SplineChar *)); /* Will be a vast over-estimate */
4900 0 : start = cnames;
4901 0 : for ( i=0; *start; ) {
4902 0 : while ( *start==' ' ) ++start;
4903 0 : if ( *start=='\0' )
4904 0 : break;
4905 0 : for ( pt=start; *pt && *pt!=' '; ++pt );
4906 0 : ch = *pt; *pt = '\0';
4907 0 : if ( (founds[i]=SFGetChar(mv->sf,-1,start))!=NULL )
4908 0 : ++i;
4909 0 : *pt = ch;
4910 0 : start = pt;
4911 : }
4912 0 : cnt = i;
4913 0 : free( cnames );
4914 0 : if ( cnt==0 ) {
4915 0 : free(founds);
4916 0 : return;
4917 : }
4918 0 : if ( within<mv->glyphcnt )
4919 0 : within = mv->glyphs[within].orig_index;
4920 : else
4921 0 : within = mv->clen;
4922 :
4923 0 : if ( mv->clen+cnt+1>=mv->cmax ) {
4924 0 : mv->cmax = mv->clen+cnt+10;
4925 0 : mv->chars = realloc(mv->chars,mv->cmax*sizeof(SplineChar *));
4926 : }
4927 0 : oldtext = _GGadgetGetTitle(mv->text);
4928 0 : newtext = malloc((mv->clen+cnt+1)*sizeof(unichar_t));
4929 0 : u_strcpy(newtext,oldtext);
4930 0 : newtext[mv->clen+cnt]='\0';
4931 0 : for ( i=mv->clen+cnt; i>=within+cnt; --i ) {
4932 0 : newtext[i] = newtext[i-cnt];
4933 0 : mv->chars[i] = mv->chars[i-cnt];
4934 : }
4935 0 : for ( i=within; i<within+cnt; ++i ) {
4936 0 : mv->chars[i] = founds[i-within];
4937 0 : newtext[i] = founds[i-within]->unicodeenc>=0 ?
4938 0 : founds[i-within]->unicodeenc : MVFakeUnicodeOfSc(mv,founds[i-within]);
4939 : }
4940 0 : mv->clen += cnt;
4941 0 : MVRemetric(mv);
4942 0 : free(founds);
4943 :
4944 0 : GGadgetSetTitle(mv->text,newtext);
4945 0 : free(newtext);
4946 :
4947 0 : GDrawRequestExpose(mv->v,NULL,false);
4948 : }
4949 :
4950 0 : static int mv_v_e_h(GWindow gw, GEvent *event) {
4951 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
4952 :
4953 0 : switch ( event->type ) {
4954 : case et_expose:
4955 0 : GDrawSetLineWidth(gw,0);
4956 0 : MVSubExpose(mv,gw,event);
4957 0 : break;
4958 : case et_char:
4959 0 : MVChar(mv,event);
4960 0 : break;
4961 : case et_charup:
4962 0 : if ( event->u.chr.keysym == GK_Left || event->u.chr.keysym==GK_KP_Left
4963 0 : || event->u.chr.keysym == GK_Right || event->u.chr.keysym==GK_KP_Right ) {
4964 0 : if( event->u.chr.state&ksm_meta ) {
4965 0 : MVChar(mv,event);
4966 : }
4967 : }
4968 0 : break;
4969 : case et_mouseup: case et_mousemove: case et_mousedown:
4970 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
4971 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
4972 0 : int ish = event->u.mouse.button>5;
4973 0 : if ( event->u.mouse.state&ksm_shift ) ish = !ish;
4974 0 : if ( event->u.mouse.state&ksm_control ) { /* bind control to magnify/minify */
4975 0 : if ( event->type==et_mousedown ) {
4976 0 : if ( event->u.mouse.button==4 || event->u.mouse.button==6 )
4977 0 : _MVMenuScale(mv,MID_ZoomIn);
4978 : else
4979 0 : _MVMenuScale(mv,MID_ZoomOut);
4980 : }
4981 0 : } else if ( ish ) { /* bind shift to horizontal scroll */
4982 0 : return( GGadgetDispatchEvent(mv->hsb,event));
4983 : } else {
4984 0 : return( GGadgetDispatchEvent(mv->vsb,event));
4985 : }
4986 0 : return( true );
4987 : }
4988 0 : if ( mv->gwgic!=NULL && event->type==et_mousedown)
4989 0 : GDrawSetGIC(mv->gw,mv->gwgic,0,20);
4990 0 : MVSubMouse(mv,event);
4991 0 : break;
4992 : case et_drop:
4993 0 : MVDrop(mv,event);
4994 0 : break;
4995 : }
4996 0 : return( true );
4997 : }
4998 :
4999 0 : static int mv_e_h(GWindow gw, GEvent *event) {
5000 0 : MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);
5001 : SplineFont *sf;
5002 0 : GGadget *active = 0;
5003 : // printf("mv_e_h() event->type:%d\n", event->type );
5004 :
5005 0 : switch ( event->type ) {
5006 : case et_selclear:
5007 0 : ClipboardClear();
5008 0 : break;
5009 : case et_expose:
5010 0 : GDrawSetLineWidth(gw,0);
5011 0 : MVExpose(mv,gw,event);
5012 0 : break;
5013 : case et_resize:
5014 0 : if ( event->u.resize.sized )
5015 0 : MVResize(mv);
5016 0 : break;
5017 : case et_char:
5018 0 : if ((event->u.chr.keysym == GK_Tab || event->u.chr.keysym == GK_BackTab) && (!(event->u.chr.state&ksm_meta))) {
5019 : // We want to allow somebody to move the cursor position
5020 : // forwards with tab and backwards with shift + tab.
5021 : // GGadget *active = GWindowGetFocusGadgetOfWindow(mv->gw); if (event->u.chr.state&ksm_shift) return 0;
5022 : // For now, we just return 0 so that the default event handler takes care.
5023 0 : return 0;
5024 : }
5025 : // MVChar(mv,event);
5026 0 : break;
5027 : case et_charup:
5028 0 : if ((event->u.chr.keysym == GK_Tab || event->u.chr.keysym == GK_BackTab) && (!(event->u.chr.state&ksm_meta))) {
5029 : // We want to allow somebody to move the cursor position
5030 : // forwards with tab and backwards with shift + tab.
5031 : // GGadget *active = GWindowGetFocusGadgetOfWindow(mv->gw); if (event->u.chr.state&ksm_shift) return 0;
5032 : // For now, we just return 0 so that the default event handler takes care.
5033 0 : return 0;
5034 0 : } else if ((event->u.chr.keysym == GK_Return) && (!(event->u.chr.state&ksm_meta))) {
5035 0 : MVMoveInTableByColumnByOffset(mv, (event->u.chr.state&ksm_shift) ? -1 : 1);
5036 : } else {
5037 0 : MVChar(mv,event);
5038 : }
5039 : #if 0
5040 : // It is unclear to Frank why we were being so selective.
5041 : if ( event->u.chr.keysym == GK_Left || event->u.chr.keysym==GK_KP_Left
5042 : || event->u.chr.keysym == GK_Right || event->u.chr.keysym==GK_KP_Right ) {
5043 : if( event->u.chr.state&ksm_meta ) {
5044 : MVChar(mv,event);
5045 : }
5046 : }
5047 : #endif // 0
5048 0 : break;
5049 : case et_mouseup: case et_mousemove: case et_mousedown:
5050 0 : active = GWindowGetFocusGadgetOfWindow(mv->gw);
5051 0 : if( GGadgetContainsEventLocation( mv->textPrev, event ))
5052 : {
5053 0 : GGadgetPreparePopup(mv->gw,c_to_u("Show the previous word in the current word list\n"
5054 : "Select the menu File / Load Word List... to load a wordlist."));
5055 : }
5056 0 : else if( GGadgetContainsEventLocation( mv->textNext, event ))
5057 : {
5058 0 : GGadgetPreparePopup(mv->gw,c_to_u("Show the next word in the current word list\n"
5059 : "Select the menu File / Load Word List... to load a wordlist."));
5060 : }
5061 0 : else if( GGadgetContainsEventLocation( mv->text, event ))
5062 : {
5063 0 : GGadgetPreparePopup(mv->gw,c_to_u("This is a word list that you can step through to quickly see your glyphs in context\n"
5064 : "Select the menu File / Load Word List... to load a wordlist."));
5065 : }
5066 : else
5067 : {
5068 0 : GGadgetPreparePopup(mv->gw, 0);
5069 : }
5070 :
5071 :
5072 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
5073 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
5074 0 : int ish = event->u.mouse.button>5;
5075 0 : if ( event->u.mouse.state&ksm_shift ) ish = !ish;
5076 0 : if ( event->u.mouse.state&ksm_control ) { /* bind control to magnify/minify */
5077 0 : if ( event->type==et_mousedown ) {
5078 0 : if ( event->u.mouse.button==4 || event->u.mouse.button==6 )
5079 0 : _MVMenuScale(mv,MID_ZoomIn);
5080 : else
5081 0 : _MVMenuScale(mv,MID_ZoomOut);
5082 : }
5083 0 : } else if ( ish ) { /* bind shift to horizontal scroll */
5084 0 : return( GGadgetDispatchEvent(mv->hsb,event));
5085 : } else {
5086 0 : return( GGadgetDispatchEvent(mv->vsb,event));
5087 : }
5088 0 : return( true );
5089 : }
5090 0 : if ( mv->gwgic!=NULL && event->type==et_mousedown)
5091 0 : GDrawSetGIC(mv->gw,mv->gwgic,0,20);
5092 0 : MVMouse(mv,event);
5093 0 : break;
5094 : case et_drop:
5095 0 : MVDrop(mv,event);
5096 0 : break;
5097 : case et_controlevent:
5098 0 : switch ( event->u.control.subtype ) {
5099 : case et_scrollbarchange:
5100 0 : if ( event->u.control.g==mv->hsb )
5101 0 : MVHScroll(mv,&event->u.control.u.sb);
5102 : else
5103 0 : MVVScroll(mv,&event->u.control.u.sb);
5104 0 : break;
5105 : }
5106 0 : break;
5107 : case et_close:
5108 0 : MVMenuClose(gw,NULL,NULL);
5109 0 : break;
5110 : case et_destroy:
5111 0 : sf = mv->sf;
5112 0 : if ( sf->cidmaster ) sf = sf->cidmaster;
5113 0 : if ( sf->metrics==mv )
5114 0 : sf->metrics = mv->next;
5115 : else {
5116 : MetricsView *n;
5117 0 : for ( n=sf->metrics; n->next!=mv; n=n->next );
5118 0 : n->next = mv->next;
5119 : }
5120 0 : KCLD_MvDetach(sf->kcld,mv);
5121 0 : MetricsViewFree(mv);
5122 0 : break;
5123 : case et_focus:
5124 0 : break;
5125 : }
5126 0 : return( true );
5127 : }
5128 :
5129 0 : GTextInfo *SLOfFont(SplineFont *sf) {
5130 : uint32 *scripttags, *langtags;
5131 : int s, l, i, k, cnt;
5132 : extern GTextInfo scripts[], languages[];
5133 0 : GTextInfo *ret = NULL;
5134 : char *sname, *lname, *temp;
5135 : char sbuf[8], lbuf[8];
5136 :
5137 0 : LookupUIInit();
5138 0 : scripttags = SFScriptsInLookups(sf,-1);
5139 0 : if ( scripttags==NULL )
5140 0 : return( NULL );
5141 :
5142 0 : for ( k=0; k<2; ++k ) {
5143 0 : cnt = 0;
5144 0 : for ( s=0; scripttags[s]!=0; ++s ) {
5145 0 : if ( k ) {
5146 0 : for ( i=0; scripts[i].text!=NULL; ++i )
5147 0 : if ( scripttags[s] == (intpt) (scripts[i].userdata))
5148 0 : break;
5149 0 : sname = (char *) (scripts[i].text);
5150 0 : sbuf[0] = scripttags[s]>>24;
5151 0 : sbuf[1] = scripttags[s]>>16;
5152 0 : sbuf[2] = scripttags[s]>>8;
5153 0 : sbuf[3] = scripttags[s];
5154 0 : sbuf[4] = 0;
5155 0 : if ( sname==NULL )
5156 0 : sname = sbuf;
5157 : }
5158 0 : langtags = SFLangsInScript(sf,-1,scripttags[s]);
5159 : /* This one can't be NULL */
5160 0 : for ( l=0; langtags[l]!=0; ++l ) {
5161 0 : if ( k ) {
5162 0 : for ( i=0; languages[i].text!=NULL; ++i )
5163 0 : if ( langtags[l] == (intpt) (languages[i].userdata))
5164 0 : break;
5165 0 : lname = (char *) (languages[i].text);
5166 0 : lbuf[0] = langtags[l]>>24;
5167 0 : lbuf[1] = langtags[l]>>16;
5168 0 : lbuf[2] = langtags[l]>>8;
5169 0 : lbuf[3] = langtags[l];
5170 0 : lbuf[4] = 0;
5171 0 : if ( lname==NULL )
5172 0 : lname = lbuf;
5173 0 : temp = malloc(strlen(sname)+strlen(lname)+3);
5174 0 : strcpy(temp,sname); strcat(temp,"{"); strcat(temp,lname); strcat(temp,"}");
5175 0 : ret[cnt].text = (unichar_t *) temp;
5176 0 : ret[cnt].text_is_1byte = true;
5177 0 : temp = malloc(11);
5178 0 : strcpy(temp,sbuf); temp[4] = '{'; strcpy(temp+5,lbuf); temp[9]='}'; temp[10] = 0;
5179 0 : ret[cnt].userdata = temp;
5180 : }
5181 0 : ++cnt;
5182 : }
5183 0 : free(langtags);
5184 : }
5185 0 : if ( !k )
5186 0 : ret = calloc((cnt+1),sizeof(GTextInfo));
5187 : }
5188 0 : free(scripttags);
5189 0 : return( ret );
5190 : }
5191 :
5192 : #define metricsicon_width 16
5193 : #define metricsicon_height 16
5194 : static unsigned char metricsicon_bits[] = {
5195 : 0x04, 0x10, 0xf0, 0x03, 0x24, 0x12, 0x20, 0x00, 0x24, 0x10, 0xe0, 0x00,
5196 : 0x24, 0x10, 0x20, 0x00, 0x24, 0x10, 0x20, 0x00, 0x74, 0x10, 0x00, 0x00,
5197 : 0x55, 0x55, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00};
5198 :
5199 : static int metricsview_ready = false;
5200 :
5201 0 : static void MetricsViewFinish() {
5202 0 : if (!metricsview_ready) return;
5203 0 : mb2FreeGetText(mblist);
5204 : }
5205 :
5206 0 : void MetricsViewFinishNonStatic() {
5207 0 : MetricsViewFinish();
5208 0 : }
5209 :
5210 0 : static void MetricsViewInit(void ) {
5211 : // static int inited = false; // superseded by metricsview_ready.
5212 0 : if (metricsview_ready) return;
5213 0 : mv_text_init[2].text = (unichar_t *) _((char *) mv_text_init[2].text);
5214 0 : mb2DoGetText(mblist);
5215 0 : MVColInit();
5216 0 : atexit(&MetricsViewFinishNonStatic);
5217 : }
5218 :
5219 0 : MetricsView *MetricsViewCreate(FontView *fv,SplineChar *sc,BDFFont *bdf) {
5220 : GRect pos;
5221 : GWindow gw;
5222 : GWindowAttrs wattrs;
5223 : GGadgetData gd;
5224 : GRect gsize;
5225 0 : MetricsView *mv = calloc(1,sizeof(MetricsView));
5226 : FontRequest rq;
5227 : static GWindow icon = NULL;
5228 : extern int _GScrollBar_Width;
5229 : // Max. glyphname length: 31, max. chars picked up: 15. 31*15 = 465
5230 : char buf[465], *pt;
5231 : GTextInfo label;
5232 : int i,j,cnt;
5233 : int as,ds,ld;
5234 : static GFont *mvfont=NULL;
5235 0 : SplineFont *master = fv->b.sf->cidmaster ? fv->b.sf->cidmaster : fv->b.sf;
5236 :
5237 0 : MetricsViewInit();
5238 :
5239 0 : if ( icon==NULL )
5240 0 : icon = GDrawCreateBitmap(NULL,metricsicon_width,metricsicon_height,metricsicon_bits);
5241 :
5242 0 : mv->fv = fv;
5243 0 : mv->sf = fv->b.sf;
5244 0 : mv->bdf = bdf;
5245 0 : mv->showgrid = mvshowgrid;
5246 0 : mv->antialias = mv_antialias;
5247 0 : mv->scale_index = SCALE_INDEX_NORMAL;
5248 0 : mv->next = master->metrics;
5249 0 : master->metrics = mv;
5250 0 : mv->layer = fv->b.active_layer;
5251 0 : mv->type = mv_type;
5252 0 : mv->pixelsize_set_by_window = true;
5253 0 : mv->dpi = 72;
5254 :
5255 0 : memset(&wattrs,0,sizeof(wattrs));
5256 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_icon;
5257 0 : wattrs.event_masks = ~(0);
5258 0 : wattrs.cursor = ct_mypointer;
5259 0 : MVWindowTitle(buf,sizeof(buf),mv);
5260 0 : wattrs.utf8_window_title = buf;
5261 0 : wattrs.icon = icon;
5262 0 : pos.x = pos.y = 0;
5263 0 : pos.width = mv_width;
5264 0 : pos.height = mv_height;
5265 0 : mv->gw = gw = GDrawCreateTopWindow(NULL,&pos,mv_e_h,mv,&wattrs);
5266 0 : mv->width = pos.width; mv->height = pos.height;
5267 0 : mv->gwgic = GDrawCreateInputContext(mv->gw,gic_root|gic_orlesser);
5268 0 : GDrawSetGIC(gw,mv->gwgic,0,20);
5269 0 : GDrawSetWindowTypeName(mv->gw, "MetricsView");
5270 :
5271 0 : memset(&gd,0,sizeof(gd));
5272 0 : gd.flags = gg_visible | gg_enabled;
5273 0 : helplist[0].invoke = MVMenuContextualHelp;
5274 0 : gd.u.menu2 = mblist;
5275 0 : mv->mb = GMenu2BarCreate( gw, &gd, NULL);
5276 0 : GGadgetGetSize(mv->mb,&gsize);
5277 0 : mv->mbh = gsize.height;
5278 :
5279 0 : gd.pos.height = GDrawPointsToPixels(gw,_GScrollBar_Width);
5280 0 : gd.pos.y = pos.height-gd.pos.height;
5281 0 : gd.pos.x = 0; gd.pos.width = pos.width;
5282 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
5283 0 : mv->hsb = GScrollBarCreate(gw,&gd,mv);
5284 0 : GGadgetGetSize(mv->hsb,&gsize);
5285 0 : mv->sbh = gsize.height;
5286 0 : mv->dwidth = mv->width-mv->sbh;
5287 :
5288 0 : gd.pos.width = mv->sbh;
5289 0 : gd.pos.y = 0; gd.pos.height = pos.height; /* we'll fix these later */
5290 0 : gd.pos.x = pos.width-gd.pos.width;
5291 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
5292 0 : mv->vsb = GScrollBarCreate(gw,&gd,mv);
5293 :
5294 0 : if ( mvfont==NULL ) {
5295 0 : memset(&rq,0,sizeof(rq));
5296 0 : rq.utf8_family_name = SANS_UI_FAMILIES;
5297 0 : rq.point_size = -12;
5298 0 : rq.weight = 400;
5299 0 : mvfont = GDrawInstanciateFont(gw,&rq);
5300 0 : mvfont = GResourceFindFont("MetricsView.Font",mvfont);
5301 : }
5302 0 : mv->font = mvfont;
5303 0 : GDrawWindowFontMetrics(gw,mv->font,&as,&ds,&ld);
5304 0 : mv->fh = as+ds; mv->as = as;
5305 :
5306 0 : pt = buf;
5307 0 : mv->chars = calloc(mv->cmax=20,sizeof(SplineChar *));
5308 0 : if ( sc!=NULL ) {
5309 0 : mv->chars[mv->clen++] = sc;
5310 : } else {
5311 0 : EncMap *map = fv->b.map;
5312 0 : for ( j=1; (j<=fv->sel_index || j<1) && mv->clen<15; ++j ) {
5313 0 : for ( i=0; i<map->enccount && mv->clen<15; ++i ) {
5314 0 : int gid = map->map[i];
5315 0 : if ( gid!=-1 && fv->b.selected[i]==j && fv->b.sf->glyphs[gid]!=NULL ) {
5316 0 : mv->chars[mv->clen++] = fv->b.sf->glyphs[gid];
5317 : }
5318 : }
5319 : }
5320 : }
5321 0 : mv->chars[mv->clen] = NULL;
5322 :
5323 0 : for ( cnt=0; cnt<mv->clen; ++cnt ) {
5324 0 : if ( mv->chars[cnt]->unicodeenc != -1 )
5325 0 : pt = utf8_idpb(pt,mv->chars[cnt]->unicodeenc,0);
5326 : else {
5327 0 : *pt = '/'; pt++;
5328 0 : strcpy(pt, mv->chars[cnt]->name);
5329 0 : pt += strlen(mv->chars[cnt]->name);
5330 0 : *pt = ' '; pt++;
5331 : }
5332 : }
5333 0 : *pt = '\0';
5334 :
5335 0 : memset(&gd,0,sizeof(gd));
5336 0 : memset(&label,0,sizeof(label));
5337 0 : gd.pos.y = mv->mbh+2; gd.pos.x = 10;
5338 0 : gd.pos.width = GDrawPointsToPixels(mv->gw,100);
5339 0 : gd.label = &label;
5340 0 : label.text = (unichar_t *) "DFLT{dflt}";
5341 0 : label.text_is_1byte = true;
5342 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
5343 0 : gd.u.list = mv->scriptlangs = SLOfFont(mv->sf);
5344 0 : gd.handle_controlevent = MV_ScriptLangChanged;
5345 0 : mv->script = GListFieldCreate(gw,&gd,mv);
5346 0 : GGadgetGetSize(mv->script,&gsize);
5347 0 : mv->topend = gsize.y + gsize.height + 2;
5348 :
5349 0 : gd.pos.x = gd.pos.x+gd.pos.width+10;
5350 0 : gd.pos.width = GDrawPointsToPixels(mv->gw,200);
5351 0 : gd.pos.height = gsize.height;
5352 0 : label.text = (unichar_t *) buf;
5353 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_text_xim;
5354 0 : gd.handle_controlevent = MV_TextChanged;
5355 0 : gd.u.list = mv_text_init;
5356 0 : mv->text = GListFieldCreate(gw,&gd,mv);
5357 :
5358 : // Up and Down buttons for moving through the word list.
5359 : {
5360 : GTextInfo label[9];
5361 0 : GGadgetData xgd = gd;
5362 0 : gd.pos.width += 2 * xgd.pos.height + 4;
5363 0 : memset(label, '\0', sizeof(GTextInfo));
5364 0 : xgd.pos.x += xgd.pos.width + 2;
5365 0 : xgd.pos.width = xgd.pos.height;
5366 0 : xgd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
5367 0 : xgd.handle_controlevent = MVMoveToPrevInWordList;
5368 0 : xgd.label = &label[0];
5369 0 : label[0].text = (unichar_t *) "⇞";
5370 0 : label[0].text_is_1byte = true;
5371 0 : mv->textPrev = GButtonCreate(mv->gw,&xgd,mv);
5372 0 : memset(label, '\0', sizeof(GTextInfo));
5373 0 : xgd.pos.x += xgd.pos.width + 2;
5374 0 : xgd.pos.width = xgd.pos.height;
5375 0 : xgd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
5376 0 : xgd.handle_controlevent = MVMoveToNextInWordList;
5377 0 : xgd.label = &label[0];
5378 0 : label[0].text = (unichar_t *) "⇟";
5379 0 : label[0].text_is_1byte = true;
5380 0 : mv->textNext = GButtonCreate(mv->gw,&xgd,mv);
5381 : }
5382 :
5383 :
5384 0 : gd.pos.x = gd.pos.x+gd.pos.width+10; --gd.pos.y;
5385 0 : gd.pos.width += 30;
5386 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
5387 0 : gd.handle_controlevent = MV_SubtableChanged;
5388 0 : gd.label = NULL;
5389 0 : gd.u.list = NULL;
5390 0 : mv->subtable_list = GListButtonCreate(gw,&gd,mv);
5391 0 : MVSetSubtables(master);
5392 :
5393 0 : gd.pos.y = mv->topend; gd.pos.x = 0;
5394 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_pos_use0|gg_list_multiplesel|gg_list_alphabetic;
5395 0 : gd.pos.width = GDrawPointsToPixels(mv->gw,50);
5396 0 : gd.handle_controlevent = MV_FeaturesChanged;
5397 0 : mv->features = GListCreate(gw,&gd,mv);
5398 0 : GListSetSBAlwaysVisible(mv->features,true);
5399 0 : GListSetPopupCallback(mv->features,MV_FriendlyFeatures);
5400 0 : mv->xstart = gd.pos.width;
5401 :
5402 0 : pos.x = mv->xstart; pos.width = mv->dwidth - mv->xstart;
5403 0 : pos.y = mv->topend+2; pos.height = mv->displayend - mv->topend - 2;
5404 0 : memset(&wattrs,0,sizeof(wattrs));
5405 0 : wattrs.mask = wam_events|wam_backcol;
5406 0 : wattrs.background_color = view_bgcol;
5407 0 : wattrs.event_masks = -1;
5408 0 : wattrs.cursor = ct_mypointer;
5409 0 : mv->v = GWidgetCreateSubWindow(mv->gw,&pos,mv_v_e_h,mv,&wattrs);
5410 0 : GDrawSetWindowTypeName(mv->v, "MetricsView");
5411 :
5412 0 : MVSetFeatures(mv);
5413 0 : MVMakeLabels(mv);
5414 0 : MVResize(mv);
5415 :
5416 0 : GDrawSetVisible(mv->v,true);
5417 0 : GDrawSetVisible(gw,true);
5418 : /*GWidgetHidePalettes();*/
5419 0 : return( mv );
5420 : }
5421 :
5422 0 : void MetricsViewFree(MetricsView *mv) {
5423 :
5424 0 : if ( mv->scriptlangs!=NULL ) {
5425 : int i;
5426 0 : for ( i=0; mv->scriptlangs[i].text!=NULL ; ++i )
5427 0 : free(mv->scriptlangs[i].userdata );
5428 0 : GTextInfoListFree(mv->scriptlangs);
5429 : }
5430 0 : BDFFontFree(mv->show);
5431 : /* the fields will free themselves */
5432 0 : free(mv->chars);
5433 0 : free(mv->glyphs);
5434 0 : free(mv->perchar);
5435 0 : free(mv);
5436 0 : }
5437 :
5438 0 : void MVRefreshAll(MetricsView *mv) {
5439 :
5440 0 : if ( mv!=NULL ) {
5441 0 : MVRemetric(mv);
5442 0 : GDrawRequestExpose(mv->v,NULL,false);
5443 : }
5444 0 : }
5445 :
5446 : /******************************************************************************/
5447 0 : static int MV_GlyphCnt(struct metricsview *mv) {
5448 0 : return( mv->glyphcnt );
5449 : }
5450 :
5451 0 : static SplineChar *MV_Glyph(struct metricsview *mv,int i) {
5452 0 : if ( i<0 || i>=mv->glyphcnt )
5453 0 : return( NULL );
5454 :
5455 0 : return( mv->glyphs[i].sc );
5456 : }
5457 :
5458 1 : static void MV_ReKernAll(struct splinefont *sf) {
5459 : MetricsView *mv;
5460 :
5461 1 : for ( mv=sf->metrics; mv!=NULL; mv=mv->next )
5462 0 : MVReKern(mv);
5463 1 : }
5464 :
5465 0 : static void MV_ReFeatureAll(struct splinefont *sf) {
5466 : MetricsView *mv;
5467 :
5468 0 : MVSetSubtables(sf);
5469 0 : for ( mv=sf->metrics; mv!=NULL; mv=mv->next )
5470 0 : MVSetFeatures(mv);
5471 0 : }
5472 :
5473 0 : static void MV_CloseAll(struct splinefont *sf) {
5474 : MetricsView *mv, *mvnext;
5475 0 : for ( mv=sf->metrics; mv!=NULL; mv=mvnext ) {
5476 0 : mvnext = mv->next;
5477 0 : GDrawDestroyWindow(mv->gw);
5478 : }
5479 0 : GDrawSync(NULL);
5480 0 : GDrawProcessPendingEvents(NULL);
5481 0 : }
5482 :
5483 : struct mv_interface gdraw_mv_interface = {
5484 : MV_GlyphCnt,
5485 : MV_Glyph,
5486 : MV_ReKernAll,
5487 : MV_ReFeatureAll,
5488 : MV_CloseAll
5489 : };
5490 :
5491 : static struct resed metricsview_re[] = {
5492 : {N_("Advance Width Col"), "AdvanceWidthColor", rt_color, &widthcol, N_("Color used to draw the advance width line of a glyph"), NULL, { 0 }, 0, 0 },
5493 : {N_("Italic Advance Col"), "ItalicAdvanceColor", rt_color, &widthcol, N_("Color used to draw the italic advance width line of a glyph"), NULL, { 0 }, 0, 0 },
5494 : {N_("Kern Line Color"), "KernLineColor", rt_color, &kernlinecol, N_("Color used to draw the kerning line"), NULL, { 0 }, 0, 0 },
5495 : {N_("Side Bearing Color"), "SideBearingLineColor", rt_color, &rbearinglinecol, N_("Color used to draw the left side bearing"), NULL, { 0 }, 0, 0 },
5496 : {N_("Selected Glyph Col"), "SelectedGlyphColor", rt_color, &selglyphcol, N_("Color used to mark the selected glyph"), NULL, { 0 }, 0, 0 },
5497 : RESED_EMPTY
5498 : };
5499 : extern GResInfo view_ri;
5500 : GResInfo metricsview_ri = {
5501 : &view_ri, NULL,NULL, NULL,
5502 : NULL,
5503 : NULL,
5504 : NULL,
5505 : metricsview_re,
5506 : N_("MetricsView"),
5507 : N_("This window displays metrics information about a font"),
5508 : "MetricsView",
5509 : "fontforge",
5510 : false,
5511 : 0,
5512 : NULL,
5513 : GBOX_EMPTY,
5514 : NULL,
5515 : NULL,
5516 : NULL
5517 : };
5518 :
5519 :
5520 0 : void MVSelectFirstKerningTable(struct metricsview *mv)
5521 : {
5522 : /* SplineFont *sf = mv->sf; */
5523 : /* printf("MVSelectFirstKerningTable() kerns:%p\n", sf->kerns ); */
5524 : /* if( sf->kerns ) */
5525 : /* { */
5526 : /* printf("MVSelectFirstKerningTable() kerns.next:%p\n", sf->kerns->next ); */
5527 : /* printf("MVSelectFirstKerningTable() kerns.subt:%p\n", sf->kerns->subtable ); */
5528 : /* } */
5529 :
5530 : //
5531 : // if nothing selected, then select the first entry.
5532 : //
5533 0 : if( GGadgetGetFirstListSelectedItem(mv->features) >= 0 )
5534 : {
5535 0 : return;
5536 : }
5537 :
5538 0 : GTextInfo **ti=NULL;
5539 : int32 len;
5540 0 : ti = GGadgetGetList(mv->features,&len);
5541 0 : GGadgetSelectOneListItem(mv->features,0);
5542 0 : MVRemetric(mv);
5543 0 : GDrawRequestExpose(mv->v,NULL,false);
5544 : }
5545 :
5546 :
|