/* Copyright (C) 2000-2011 by George Williams */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fontforgeui.h" #include #include #include #include #include #include #include int mv_width = 800, mv_height = 300; int mvshowgrid = mv_hidemovinggrid; int mv_type = mv_kernonly; static int mv_antialias = true; 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 }; #define SCALE_INDEX_NORMAL 4 static Color widthcol = 0x808080; static Color italicwidthcol = 0x909090; static Color selglyphcol = 0x909090; static Color kernlinecol = 0x008000; static Color rbearinglinecol = 0x000080; void MVColInit( void ) { static int cinit=false; GResStruct mvcolors[] = { { "AdvanceWidthColor", rt_color, &widthcol }, { "ItalicAdvanceColor", rt_color, &italicwidthcol }, { "SelectedGlyphColor", rt_color, &selglyphcol }, { "KernLineColor", rt_color, &kernlinecol }, { "SideBearingLineColor", rt_color, &rbearinglinecol }, { NULL } }; if ( !cinit ) { GResourceFind( mvcolors, "MetricsView."); cinit = true; } } static int MVSetVSb(MetricsView *mv); static int MVShowGrid(MetricsView *mv) { if ( mv->showgrid==mv_hidegrid || (mv->showgrid==mv_hidemovinggrid && mv->pressed )) return( false ); return( true ); } static void MVDrawLine(MetricsView *mv,GWindow pixmap, int xtop, int top,int xbot,int bot,Color col) { if ( mv->showgrid == mv_partialgrid ) { int y1, y2; int x1, x2; y1 = bot + ( top- bot)/4; x1 = xbot + (xtop-xbot)/4; y2 = bot + 4*( top- bot)/5; x2 = xbot + 4*(xtop-xbot)/5; GDrawDrawLine(pixmap,xtop,top,x2,y2,col); GDrawDrawLine(pixmap,x1,y1,xbot,bot,col); } else GDrawDrawLine(pixmap,xtop,top,xbot,bot,col); } static void MVSubVExpose(MetricsView *mv, GWindow pixmap, GEvent *event) { /* Expose routine for vertical metrics */ GRect *clip; int xbase, y, si, i, x, width, height; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; int as = rint(iscale*mv->pixelsize*mv->sf->ascent/(double) (mv->sf->ascent+mv->sf->descent)); BDFChar *bdfc; struct _GImage base; GImage gi; GClut clut; clip = &event->u.expose.rect; xbase = mv->vwidth/2; if ( mv->showgrid ) GDrawDrawLine(pixmap,xbase,0,xbase,mv->vheight,widthcol); if ( mv->bdf==NULL && MVShowGrid(mv) ) { y = mv->perchar[0].dy-mv->yoff; MVDrawLine(mv,pixmap,0,y,mv->vwidth,y,widthcol); } si = -1; for ( i=0; iglyphcnt; ++i ) { if ( mv->perchar[i].selected ) si = i; y = mv->perchar[i].dy-mv->yoff; if ( mv->bdf==NULL && MVShowGrid(mv)) { int yp = y+mv->perchar[i].dheight+mv->perchar[i].kernafter; MVDrawLine(mv,pixmap,0, yp,mv->vwidth,yp, mv->type==mv_kernonly && i!=mv->glyphcnt-1 ?kernlinecol : mv->type==mv_widthonly ?rbearinglinecol : widthcol); } y += mv->perchar[i].yoff; bdfc = mv->bdf==NULL ? BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos) : BDFGetMergedChar( mv->bdf->glyphs[mv->glyphs[i].sc->orig_pos]); if ( bdfc==NULL ) continue; y += as-rint(iscale * bdfc->ymax); if ( mv->perchar[i].selected ) y += mv->activeoff; x = xbase - rint(iscale * (mv->pixelsize/2 + bdfc->xmin) - mv->perchar[i].xoff); width = bdfc->xmax-bdfc->xmin+1; height = bdfc->ymax-bdfc->ymin+1; if ( clip->y+clip->height=clip->y && xx+clip->width && x+iscale*width >= clip->x ) { memset(&gi,'\0',sizeof(gi)); memset(&base,'\0',sizeof(base)); memset(&clut,'\0',sizeof(clut)); gi.u.image = &base; base.clut = &clut; if ( !bdfc->byte_data ) { base.image_type = it_mono; clut.clut_len = 2; clut.clut[0] = 0xffffff; if ( mv->perchar[i].selected ) clut.clut[1] = selglyphcol; } else { int scale, l; Color fg, bg; if ( mv->bdf!=NULL ) scale = BDFDepth(mv->bdf); else scale = BDFDepth(mv->show); base.image_type = it_index; clut.clut_len = 1<perchar[i].selected ) ? selglyphcol : 0x000000; for ( l=0; l<(1<bitmap; base.bytes_per_line = bdfc->bytes_per_line; base.width = width; base.height = height; if ( mv->pixelsize_set_by_window || mv->scale_index==SCALE_INDEX_NORMAL ) GDrawDrawGlyph(pixmap,&gi,NULL,x,y); else GDrawDrawImageMagnified(pixmap, &gi, NULL, x,y, (int) rint((width*mv_scales[mv->scale_index])), (int) rint((height*mv_scales[mv->scale_index]))); } if ( mv->bdf!=NULL ) BDFCharFree( bdfc ); } if ( si!=-1 && mv->bdf==NULL && MVShowGrid(mv) && mv->type==mv_kernwidth ) { y = mv->perchar[si].dy-mv->yoff; if ( si!=0 ) MVDrawLine(mv,pixmap,0,y,mv->vwidth,y,kernlinecol); y += mv->perchar[si].dheight+mv->perchar[si].kernafter; MVDrawLine(mv,pixmap,0,y,mv->vwidth,y,rbearinglinecol); } } static void MVSubExpose(MetricsView *mv, GWindow pixmap, GEvent *event) { GRect old, *clip; int x,y,ybase, width,height, i; BDFChar *bdfc; struct _GImage base; GImage gi; GClut clut; int si; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; double s = sin(-mv->sf->italicangle*3.1415926535897932/180.); int x_iaoffh = 0, x_iaoffl = 0; clip = &event->u.expose.rect; GDrawPushClip(pixmap,clip,&old); GDrawSetLineWidth(pixmap,0); if ( mv->vertical ) { MVSubVExpose(mv,pixmap,event); GDrawPopClip(pixmap,&old); return; } ybase = mv->ybaseline - mv->yoff; if ( mv->showgrid ) GDrawDrawLine(pixmap,0,ybase,mv->dwidth,ybase,widthcol); if ( mv->bdf==NULL && MVShowGrid(mv) ) { x = mv->perchar[0].dx-mv->xoff; if ( mv->right_to_left ) x = mv->vwidth - x - mv->perchar[0].dwidth - mv->perchar[0].kernafter; MVDrawLine(mv,pixmap,x,0,x,mv->vheight,widthcol); x_iaoffh = rint(ybase*s), x_iaoffl = rint((mv->vheight-ybase)*s); if ( ItalicConstrained && x_iaoffh!=0 ) { MVDrawLine(mv,pixmap,x+x_iaoffh,0,x-x_iaoffl,mv->vheight,italicwidthcol); } } si = -1; for ( i=0; iglyphcnt; ++i ) { if ( mv->perchar[i].selected ) si = i; x = mv->perchar[i].dx-mv->xoff; if ( mv->right_to_left ) x = mv->vwidth - x - mv->perchar[i].dwidth - mv->perchar[i].kernafter; if ( mv->bdf==NULL && MVShowGrid(mv) ) { int xp = x+mv->perchar[i].dwidth+mv->perchar[i].kernafter; MVDrawLine(mv,pixmap,xp, 0,xp,mv->vheight, mv->type==mv_kernonly && i!=mv->glyphcnt-1 ?kernlinecol : mv->type==mv_widthonly ?rbearinglinecol : widthcol); if ( ItalicConstrained && x_iaoffh!=0 ) { MVDrawLine(mv,pixmap,xp+x_iaoffh,0,xp-x_iaoffl,mv->vheight,italicwidthcol); } } if ( mv->right_to_left ) x += mv->perchar[i].kernafter-mv->perchar[i].xoff; else x += mv->perchar[i].xoff; bdfc = mv->bdf==NULL ? BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos) : BDFGetMergedChar( mv->bdf->glyphs[mv->glyphs[i].sc->orig_pos]); if ( bdfc==NULL ) continue; x += rint( iscale * bdfc->xmin ); if ( mv->perchar[i].selected ) x += mv->activeoff; y = ybase - rint( iscale * bdfc->ymax ) - (iscale-1) - mv->perchar[i].yoff; width = bdfc->xmax-bdfc->xmin+1; height = bdfc->ymax-bdfc->ymin+1; if ( !mv->right_to_left && clip->x+clip->width=clip->x && yy+clip->height && y+rint(iscale*height) >= clip->y ) { memset(&gi,'\0',sizeof(gi)); memset(&base,'\0',sizeof(base)); memset(&clut,'\0',sizeof(clut)); gi.u.image = &base; base.clut = &clut; if ( !bdfc->byte_data ) { base.image_type = it_mono; clut.clut_len = 2; clut.clut[0] = 0xffffff; if ( mv->perchar[i].selected ) clut.clut[1] = selglyphcol; } else { int lscale = 3000/mv->pixelsize, l; Color fg, bg; int scale; if ( mv->bdf!=NULL ) lscale = BDFDepth(mv->bdf); else lscale = BDFDepth(mv->show); base.image_type = it_index; scale = lscale==8?256:lscale==4?16:4; clut.clut_len = scale; bg = view_bgcol; fg = ( mv->perchar[i].selected ) ? selglyphcol : 0x000000; for ( l=0; lbitmap; base.bytes_per_line = bdfc->bytes_per_line; base.width = width; base.height = height; if ( mv->pixelsize_set_by_window || mv->scale_index==SCALE_INDEX_NORMAL ) GDrawDrawGlyph(pixmap,&gi,NULL,x,y); else GDrawDrawImageMagnified(pixmap, &gi, NULL, x,y, (int) rint((width*mv_scales[mv->scale_index])), (int) rint((height*mv_scales[mv->scale_index]))); } if ( mv->bdf!=NULL ) BDFCharFree( bdfc ); } if ( si!=-1 && mv->bdf==NULL && MVShowGrid(mv) && mv->type==mv_kernwidth ) { x = mv->perchar[si].dx-mv->xoff; if ( mv->right_to_left ) x = mv->vwidth - x; if ( si!=0 ) MVDrawLine(mv,pixmap,x,0,x,mv->vheight,kernlinecol); if ( mv->right_to_left ) x -= mv->perchar[si].dwidth+mv->perchar[si].kernafter; else x += mv->perchar[si].dwidth+mv->perchar[si].kernafter; MVDrawLine(mv,pixmap,x, 0,x,mv->vheight,rbearinglinecol); } GDrawPopClip(pixmap,&old); } static void MVExpose(MetricsView *mv, GWindow pixmap, GEvent *event) { GRect old, *clip; int x; int ke = mv->height-mv->sbh-(mv->fh+4); clip = &event->u.expose.rect; if ( clip->y+clip->height < mv->topend ) return; GDrawPushClip(pixmap,clip,&old); GDrawSetLineWidth(pixmap,0); for ( x=mv->mwidth; xwidth; x+=mv->mwidth ) { GDrawDrawLine(pixmap,x,mv->displayend,x,ke,0x000000); GDrawDrawLine(pixmap,x+mv->mwidth/2,ke,x+mv->mwidth/2,mv->height-mv->sbh,0x000000); } GDrawDrawLine(pixmap,0,mv->topend,mv->width,mv->topend,0x000000); GDrawDrawLine(pixmap,0,mv->displayend,mv->width,mv->displayend,0x000000); GDrawDrawLine(pixmap,0,mv->displayend+mv->fh+4,mv->width,mv->displayend+mv->fh+4,0x000000); GDrawDrawLine(pixmap,0,mv->displayend+2*(mv->fh+4),mv->width,mv->displayend+2*(mv->fh+4),0x000000); GDrawDrawLine(pixmap,0,mv->displayend+3*(mv->fh+4),mv->width,mv->displayend+3*(mv->fh+4),0x000000); GDrawDrawLine(pixmap,0,mv->displayend+4*(mv->fh+4),mv->width,mv->displayend+4*(mv->fh+4),0x000000); GDrawDrawLine(pixmap,0,mv->displayend+5*(mv->fh+4),mv->width,mv->displayend+5*(mv->fh+4),0x000000); } static void MVSetSubtables(SplineFont *sf) { GTextInfo **ti; OTLookup *otl; struct lookup_subtable *sub; int cnt, doit; MetricsView *mvs; int selected; if ( sf->cidmaster ) sf = sf->cidmaster; /* There might be more than one metricsview wandering around. Update them all */ for ( mvs = sf->metrics; mvs!=NULL; mvs=mvs->next ) { selected = false; for ( doit = 0; doit<2; ++doit ) { cnt = 0; for ( otl=sf->gpos_lookups; otl!=NULL; otl=otl->next ) { if ( otl->lookup_type == gpos_pair && FeatureTagInFeatureScriptList( mvs->vertical?CHR('v','k','r','n') : CHR('k','e','r','n'), otl->features)) { for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) { if ( doit ) { ti[cnt] = gcalloc(1,sizeof(GTextInfo)); ti[cnt]->text = utf82u_copy(sub->subtable_name); ti[cnt]->userdata = sub; if ( sub==mvs->cur_subtable ) ti[cnt]->selected = selected = true; ti[cnt]->disabled = sub->kc!=NULL; ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT; } ++cnt; } } } if ( !doit ) ti = gcalloc(cnt+3,sizeof(GTextInfo *)); else { if ( cnt!=0 ) { ti[cnt] = gcalloc(1,sizeof(GTextInfo)); ti[cnt]->line = true; ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT; ++cnt; } ti[cnt] = gcalloc(1,sizeof(GTextInfo)); ti[cnt]->text = utf82u_copy(_("New Lookup Subtable...")); ti[cnt]->userdata = NULL; ti[cnt]->fg = ti[cnt]->bg = COLOR_DEFAULT; ti[cnt]->selected = !selected; ++cnt; ti[cnt] = gcalloc(1,sizeof(GTextInfo)); } } if ( !selected ) mvs->cur_subtable = NULL; GGadgetSetList(mvs->subtable_list,ti,false); } } static void MVSetFeatures(MetricsView *mv) { SplineFont *sf = mv->sf; int i, j, cnt; GTextInfo **ti=NULL; uint32 *tags = NULL, script, lang; char buf[16]; uint32 *stds; const unichar_t *pt = _GGadgetGetTitle(mv->script); if ( sf->cidmaster ) sf=sf->cidmaster; script = DEFAULT_SCRIPT; lang = DEFAULT_LANG; if ( u_strlen(pt)>=4 ) script = (pt[0]<<24) | (pt[1]<<16) | (pt[2]<<8) | pt[3]; if ( pt[4]=='{' && u_strlen(pt)>=9 ) lang = (pt[5]<<24) | (pt[6]<<16) | (pt[7]<<8) | pt[8]; if ( mv->oldscript!=script || mv->oldlang!=lang ) stds = StdFeaturesOfScript(script); else { /* features list may have changed, but retain those set */ int32 len, sc; ti = GGadgetGetList(mv->features,&len); stds = galloc((len+1)*sizeof(uint32)); for ( i=sc=0; iselected ) stds[sc++] = (uint32) (intpt) ti[i]->userdata; stds[sc] = 0; } tags = SFFeaturesInScriptLang(sf,-2,script,lang); /* Never returns NULL */ for ( cnt=0; tags[cnt]!=0; ++cnt ); /*qsort(tags,cnt,sizeof(uint32),tag_comp);*/ /* The glist will do this for us */ ti = galloc((cnt+2)*sizeof(GTextInfo *)); for ( i=0; ifg = ti[i]->bg = COLOR_DEFAULT; if ( (tags[i]>>24)<' ' || (tags[i]>>24)>0x7e ) sprintf( buf, "<%d,%d>", tags[i]>>16, tags[i]&0xffff ); else { buf[0] = tags[i]>>24; buf[1] = tags[i]>>16; buf[2] = tags[i]>>8; buf[3] = tags[i]; buf[4] = 0; } ti[i]->text = uc_copy(buf); ti[i]->userdata = (void *) (intpt) tags[i]; for ( j=0; stds[j]!=0; ++j ) { if ( stds[j] == tags[i] ) { ti[i]->selected = true; break; } } } ti[i] = gcalloc(1,sizeof(GTextInfo)); GGadgetSetList(mv->features,ti,false); mv->oldscript = script; mv->oldlang = lang; } static void MVSelectSubtable(MetricsView *mv, struct lookup_subtable *sub) { int32 len; int i; GTextInfo **old = GGadgetGetList(mv->subtable_list,&len); for ( i=0; iuserdata!=sub || old[i]->line); ++i ); GGadgetSelectOneListItem(mv->subtable_list,i); if ( sub!=NULL ) mv->cur_subtable = sub; } static void MVRedrawI(MetricsView *mv,int i,int oldxmin,int oldxmax) { GRect r; BDFChar *bdfc; int off = 0; if ( mv->right_to_left || mv->vertical ) { /* right to left clipping is hard to think about, it doesn't happen */ /* often enough (I think) for me to put the effort to make it efficient */ GDrawRequestExpose(mv->v,NULL,false); return; } if ( mv->perchar[i].selected ) off = mv->activeoff; r.y = 0; r.height = mv->vheight; r.x = mv->perchar[i].dx-mv->xoff; r.width = mv->perchar[i].dwidth; if ( mv->perchar[i].kernafter>0 ) r.width += mv->perchar[i].kernafter; if ( mv->perchar[i].xoff<0 ) { r.x += mv->perchar[i].xoff; r.width -= mv->perchar[i].xoff; } else r.width += mv->perchar[i].xoff; bdfc = mv->bdf==NULL ? BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos) : mv->bdf->glyphs[mv->glyphs[i].sc->orig_pos]; if ( bdfc==NULL ) return; if ( bdfc->xmax+off+1>r.width ) r.width = bdfc->xmax+off+1; if ( oldxmax+1>r.width ) r.width = oldxmax+1; if ( bdfc->xmin+off<0 ) { r.x += bdfc->xmin+off; r.width -= bdfc->xmin+off; } if ( oldxminxmin ) { r.width += (bdfc->xmin+off-oldxmin); r.x -= (bdfc->xmin+off-oldxmin); } if ( mv->right_to_left ) r.x = mv->dwidth - r.x - r.width; GDrawRequestExpose(mv->v,&r,false); if ( mv->perchar[i].selected && i!=0 ) { struct lookup_subtable *sub = mv->glyphs[i].kp!=NULL ? mv->glyphs[i].kp->subtable : mv->glyphs[i].kc!=NULL ? mv->glyphs[i].kc->subtable : NULL; if ( sub!=NULL ) MVSelectSubtable(mv,sub); } } static void MVDeselectChar(MetricsView *mv, int i) { mv->perchar[i].selected = false; if ( mv->perchar[i].name!=NULL ) GGadgetSetEnabled(mv->perchar[i].name,mv->bdf==NULL); MVRedrawI(mv,i,0,0); } static void MVSelectSubtableForScript(MetricsView *mv,uint32 script) { int32 len; GTextInfo **ti = GGadgetGetList(mv->subtable_list,&len); struct lookup_subtable *sub; int i; sub = NULL; for ( i=0; iuserdata!=NULL && FeatureScriptTagInFeatureScriptList( mv->vertical?CHR('v','k','r','n') : CHR('k','e','r','n'), script,((struct lookup_subtable *) (ti[i]->userdata))->lookup->features)) { sub = ti[i]->userdata; break; } if ( sub!=NULL ) MVSelectSubtable(mv,sub); } static void MVSelectChar(MetricsView *mv, int i) { if ( i>=mv->glyphcnt || i<0 ) return; mv->perchar[i].selected = true; if ( mv->perchar[i].name!=NULL ) GGadgetSetEnabled(mv->perchar[i].name,false); if ( mv->glyphs[i].kp!=NULL ) MVSelectSubtable(mv,mv->glyphs[i].kp->subtable); else if ( mv->glyphs[i].kc!=NULL ) MVSelectSubtable(mv,mv->glyphs[i].kc->subtable); else MVSelectSubtableForScript(mv,SCScriptFromUnicode(mv->glyphs[i].sc)); MVRedrawI(mv,i,0,0); } static void MVDoSelect(MetricsView *mv, int i) { int j; for ( j=0; jglyphcnt; ++j ) if ( j!=i && mv->perchar[j].selected ) MVDeselectChar(mv,j); MVSelectChar(mv,i); } void MVRefreshChar(MetricsView *mv, SplineChar *sc) { int i; for ( i=0; iglyphcnt; ++i ) if ( mv->glyphs[i].sc == sc ) MVRedrawI(mv,i,0,0); } static void MVRefreshValues(MetricsView *mv, int i) { char buf[40]; DBounds bb; SplineChar *sc = mv->glyphs[i].sc; int kern_offset; SplineCharFindBounds(sc,&bb); GGadgetSetTitle8(mv->perchar[i].name,sc->name); sprintf(buf,"%d",mv->vertical ? sc->vwidth : sc->width); GGadgetSetTitle8(mv->perchar[i].width,buf); sprintf(buf,"%.2f",mv->vertical ? sc->parent->ascent-(double) bb.maxy : (double) bb.minx); if ( buf[strlen(buf)-1]=='0' ) { buf[strlen(buf)-1] = '\0'; if ( buf[strlen(buf)-1]=='0' ) { buf[strlen(buf)-1] = '\0'; if ( buf[strlen(buf)-1]=='.' ) buf[strlen(buf)-1] = '\0'; } } GGadgetSetTitle8(mv->perchar[i].lbearing,buf); sprintf(buf,"%.2f",(double) (mv->vertical ? sc->vwidth-(sc->parent->ascent-bb.miny) : sc->width-bb.maxx)); if ( buf[strlen(buf)-1]=='0' ) { buf[strlen(buf)-1] = '\0'; if ( buf[strlen(buf)-1]=='0' ) { buf[strlen(buf)-1] = '\0'; if ( buf[strlen(buf)-1]=='.' ) buf[strlen(buf)-1] = '\0'; } } GGadgetSetTitle8(mv->perchar[i].rbearing,buf); kern_offset = 0x7ffffff; if ( mv->glyphs[i].kp!=NULL ) kern_offset = mv->glyphs[i].kp->off; else if ( mv->glyphs[i].kc!=NULL ) kern_offset = mv->glyphs[i].kc->offsets[ mv->glyphs[i].kc_index ]; if ( kern_offset!=0x7ffffff && i!=mv->glyphcnt-1 ) { sprintf(buf,"%d",kern_offset); GGadgetSetTitle8(mv->perchar[i+1].kern,buf); } else if ( i!=mv->glyphcnt-1 ) GGadgetSetTitle8(mv->perchar[i+1].kern,""); } static void MVMakeLabels(MetricsView *mv) { static GBox small = { 0 }; GGadgetData gd; GTextInfo label; small.main_background = small.main_foreground = COLOR_DEFAULT; memset(&gd,'\0',sizeof(gd)); memset(&label,'\0',sizeof(label)); mv->mwidth = GGadgetScale(60); mv->displayend = mv->height- mv->sbh - 5*(mv->fh+4); /* We might not have set mv->vheight-2 yet */ if ( mv->pixelsize_set_by_window ) mv->pixelsize = mv_scales[mv->scale_index]*(mv->displayend - mv->topend - 4); label.text = (unichar_t *) _("Name:"); label.text_is_1byte = true; label.font = mv->font; gd.pos.x = 2; gd.pos.width = mv->mwidth-4; gd.pos.y = mv->displayend+2; gd.pos.height = mv->fh; gd.label = &label; gd.box = &small; gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels | gg_dontcopybox; mv->namelab = GLabelCreate(mv->gw,&gd,NULL); label.text = (unichar_t *) (mv->vertical ? _("Height:") : _("Width:") ); gd.pos.y += mv->fh+4; mv->widthlab = GLabelCreate(mv->gw,&gd,NULL); /* GT: Top/Left (side) bearing */ label.text = (unichar_t *) (mv->vertical ? _("TBearing:") : _("LBearing:") ); gd.pos.y += mv->fh+4; mv->lbearinglab = GLabelCreate(mv->gw,&gd,NULL); /* GT: Bottom/Right (side) bearing */ label.text = (unichar_t *) (mv->vertical ? _("BBearing:") : _("RBearing:") ); gd.pos.y += mv->fh+4; mv->rbearinglab = GLabelCreate(mv->gw,&gd,NULL); label.text = (unichar_t *) (mv->vertical ? _("VKern:") : _("Kern:")); gd.pos.y += mv->fh+4; mv->kernlab = GLabelCreate(mv->gw,&gd,NULL); } static int MV_KernChanged(GGadget *g, GEvent *e); static int MV_RBearingChanged(GGadget *g, GEvent *e); static int MV_LBearingChanged(GGadget *g, GEvent *e); static int MV_WidthChanged(GGadget *g, GEvent *e); static void MVCreateFields(MetricsView *mv,int i) { static GBox small = { 0 }; GGadgetData gd; GTextInfo label; static unichar_t nullstr[1] = { 0 }; int j; extern GBox _GGadget_gtextfield_box; small = _GGadget_gtextfield_box; small.flags = 0; small.border_type = bt_none; small.border_shape = bs_rect; small.border_width = 0; small.padding = 0; memset(&gd,'\0',sizeof(gd)); memset(&label,'\0',sizeof(label)); label.text = nullstr; label.font = mv->font; mv->perchar[i].mx = gd.pos.x = mv->mbase+(i+1-mv->coff)*mv->mwidth+2; mv->perchar[i].mwidth = gd.pos.width = mv->mwidth-4; gd.pos.y = mv->displayend+2; gd.pos.height = mv->fh; gd.label = &label; gd.box = &small; gd.flags = gg_visible | gg_pos_in_pixels | gg_dontcopybox; if ( mv->bdf==NULL ) gd.flags |= gg_enabled; mv->perchar[i].name = GLabelCreate(mv->gw,&gd,(void *) (intpt) i); if ( mv->perchar[i].selected ) GGadgetSetEnabled(mv->perchar[i].name,false); gd.pos.y += mv->fh+4; gd.handle_controlevent = MV_WidthChanged; mv->perchar[i].width = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i); gd.pos.y += mv->fh+4; gd.handle_controlevent = MV_LBearingChanged; mv->perchar[i].lbearing = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i); gd.pos.y += mv->fh+4; gd.handle_controlevent = MV_RBearingChanged; mv->perchar[i].rbearing = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i); if ( i!=0 ) { gd.pos.y += mv->fh+4; gd.pos.x -= mv->mwidth/2; gd.handle_controlevent = MV_KernChanged; mv->perchar[i].kern = GTextFieldCreate(mv->gw,&gd,(void *) (intpt) i); if ( i>=mv->glyphcnt ) { for ( j=mv->glyphcnt+1; j<=i ; ++ j ) mv->perchar[j].dx = mv->perchar[j-1].dx; mv->glyphcnt = i+1; } } GWidgetIndicateFocusGadget(mv->text); } static void MVSetSb(MetricsView *mv); static int MVSetVSb(MetricsView *mv); static void MVRemetric(MetricsView *mv) { SplineChar *anysc, *goodsc; int i, cnt, x, y, goodpos; const unichar_t *_script = _GGadgetGetTitle(mv->script); uint32 script, lang, *feats; char buf[20]; int32 len; GTextInfo **ti; SplineChar *sc; BDFChar *bdfc; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; double scale = iscale*mv->pixelsize/(double) (mv->sf->ascent+mv->sf->descent); SplineFont *sf; anysc = goodsc = NULL; goodpos = -1; for ( i=0; mv->chars[i] && iclen; ++i ) { if ( anysc==NULL ) anysc = mv->chars[i]; if ( SCScriptFromUnicode(mv->chars[i])!=DEFAULT_SCRIPT ) { goodsc = mv->chars[i]; goodpos = i; break; } } if ( _script[0]=='D' && _script[1]=='F' && _script[2]=='L' && _script[3]=='T' ) { if ( goodsc!=NULL ) { /* Set the script */ /* Remember if we get here the script is DFLT */ script = SCScriptFromUnicode(goodsc); buf[0] = script>>24; buf[1] = script>>16; buf[2] = script>>8; buf[3] = script; strcpy(buf+4,"{dflt}"); GGadgetSetTitle8(mv->script,buf); MVSelectSubtableForScript(mv,script); MVSetFeatures(mv); } } else { if ( anysc==NULL ) { /* If we get here the script is not DFLT */ GGadgetSetTitle8(mv->script,"DFLT{dflt}"); MVSetFeatures(mv); } } _script = _GGadgetGetTitle(mv->script); script = DEFAULT_SCRIPT; lang = DEFAULT_LANG; if ( u_strlen(_script)>=4 && (u_strchr(_script,'{')==NULL || u_strchr(_script,'{')-_script>=4)) { unichar_t *pt; script = (_script[0]<<24) | (_script[1]<<16) | (_script[2]<<8) | _script[3]; if ( (pt = u_strchr(_script,'{'))!=NULL && u_strlen(pt+1)>=4 && (u_strchr(pt+1,'}')==NULL || u_strchr(pt+1,'}')-(pt+1)>=4 )) lang = (pt[1]<<24) | (pt[2]<<16) | (pt[3]<<8) | pt[4]; } ti = GGadgetGetList(mv->features,&len); for ( i=cnt=0; iselected ) ++cnt; feats = gcalloc(cnt+1,sizeof(uint32)); for ( i=cnt=0; iselected ) feats[cnt++] = (intpt) ti[i]->userdata; free(mv->glyphs); sf = mv->sf; if ( sf->cidmaster ) sf = sf->cidmaster; mv->glyphs = ApplyTickedFeatures(sf,feats,script, lang, mv->pixelsize, mv->chars); free(feats); if ( goodsc!=NULL ) mv->right_to_left = SCRightToLeft(goodsc)?1:0; for ( cnt=0; mv->glyphs[cnt].sc!=NULL; ++cnt ); if ( cnt>=mv->max ) { int oldmax=mv->max; mv->max = cnt+10; mv->perchar = grealloc(mv->perchar,mv->max*sizeof(struct metricchar)); memset(mv->perchar+oldmax,'\0',(mv->max-oldmax)*sizeof(struct metricchar)); } for ( i=cnt; iglyphcnt; ++i ) { static unichar_t nullstr[] = { 0 }; GGadgetSetTitle(mv->perchar[i].name,nullstr); GGadgetSetTitle(mv->perchar[i].width,nullstr); GGadgetSetTitle(mv->perchar[i].lbearing,nullstr); GGadgetSetTitle(mv->perchar[i].rbearing,nullstr); if ( mv->perchar[i].kern!=NULL ) GGadgetSetTitle(mv->perchar[i].kern,nullstr); } mv->glyphcnt = cnt; for ( i=0; iperchar[i].width==NULL ) { MVCreateFields(mv,i); } } x = 10; y = 10; for ( i=0; iglyphs[i].sc; bdfc = mv->bdf!=NULL ? mv->bdf->glyphs[sc->orig_pos] : BDFPieceMealCheck(mv->show,sc->orig_pos); mv->perchar[i].dwidth = rint(iscale * bdfc->width); mv->perchar[i].dx = x; mv->perchar[i].xoff = rint(iscale * mv->glyphs[i].vr.xoff); mv->perchar[i].yoff = rint(iscale * mv->glyphs[i].vr.yoff); mv->perchar[i].kernafter = rint(iscale * mv->glyphs[i].vr.h_adv_off); x += mv->perchar[i].dwidth + mv->perchar[i].kernafter; mv->perchar[i].dheight = rint(sc->vwidth*scale); mv->perchar[i].dy = y; if ( mv->vertical ) { mv->perchar[i].kernafter = rint( iscale * mv->glyphs[i].vr.v_adv_off); y += mv->perchar[i].dheight + mv->perchar[i].kernafter; } } MVSetVSb(mv); MVSetSb(mv); } void MVReKern(MetricsView *mv) { MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } void MVRegenChar(MetricsView *mv, SplineChar *sc) { int i; if ( mv->bdf==NULL && sc->orig_posshow->glyphcnt ) { BDFCharFree(mv->show->glyphs[sc->orig_pos]); mv->show->glyphs[sc->orig_pos] = NULL; } for ( i=0; iglyphcnt; ++i ) { if ( mv->glyphs[i].sc == sc ) break; } if ( i>=mv->glyphcnt ) return; /* Not displayed */ MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } static void MVChangeDisplayFont(MetricsView *mv, BDFFont *bdf) { int i; if ( mv->bdf==bdf ) return; if ( (mv->bdf==NULL) != (bdf==NULL) ) { for ( i=0; imax; ++i ) if ( mv->perchar[i].width!=NULL ) { GGadgetSetEnabled(mv->perchar[i].width,bdf==NULL); GGadgetSetEnabled(mv->perchar[i].lbearing,bdf==NULL); GGadgetSetEnabled(mv->perchar[i].rbearing,bdf==NULL); if ( i!=0 ) GGadgetSetEnabled(mv->perchar[i].kern,bdf==NULL); } } if ( mv->bdf==NULL ) { BDFFontFree(mv->show); mv->show = NULL; } else if ( bdf==NULL ) { BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi, mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); } mv->bdf = bdf; MVRemetric(mv); } static int MV_WidthChanged(GGadget *g, GEvent *e) { MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g)); int which = (intpt) GGadgetGetUserData(g); int i; if ( e->type!=et_controlevent ) return( true ); if ( which>=mv->glyphcnt ) return( true ); if ( e->u.control.subtype == et_textchanged ) { unichar_t *end; int val = u_strtol(_GGadgetGetTitle(g),&end,10); SplineChar *sc = mv->glyphs[which].sc; if ( *end && !(*end=='-' && end[1]=='\0')) GDrawBeep(NULL); else if ( !mv->vertical && val!=sc->width ) { SCPreserveWidth(sc); SCSynchronizeWidth(sc,val,sc->width,NULL); SCCharChangedUpdate(sc,ly_none); } else if ( mv->vertical && val!=sc->vwidth ) { SCPreserveVWidth(sc); sc->vwidth = val; SCCharChangedUpdate(sc,ly_none); } } else if ( e->u.control.subtype == et_textfocuschanged && e->u.control.u.tf_focus.gained_focus ) { for ( i=0 ; iglyphcnt; ++i ) if ( i!=which && mv->perchar[i].selected ) MVDeselectChar(mv,i); MVSelectChar(mv,which); } return( true ); } static int MV_LBearingChanged(GGadget *g, GEvent *e) { MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g)); int which = (intpt) GGadgetGetUserData(g); int i; if ( e->type!=et_controlevent ) return( true ); if ( which>=mv->glyphcnt ) return( true ); if ( e->u.control.subtype == et_textchanged ) { unichar_t *end; double val = u_strtod(_GGadgetGetTitle(g),&end); SplineChar *sc = mv->glyphs[which].sc; DBounds bb; SplineCharFindBounds(sc,&bb); if ( *end && !(*end=='-' && end[1]=='\0')) GDrawBeep(NULL); else if ( !mv->vertical && val!=bb.minx ) { real transform[6]; transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; transform[4] = val-bb.minx; FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth); } else if ( mv->vertical && val!=sc->parent->ascent-bb.maxy ) { real transform[6]; transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[4] = 0; transform[5] = sc->parent->ascent-bb.maxy-val; FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth); } } else if ( e->u.control.subtype == et_textfocuschanged && e->u.control.u.tf_focus.gained_focus ) { for ( i=0 ; iglyphcnt; ++i ) if ( i!=which && mv->perchar[i].selected ) MVDeselectChar(mv,i); MVSelectChar(mv,which); } return( true ); } static int MV_RBearingChanged(GGadget *g, GEvent *e) { MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g)); int which = (intpt) GGadgetGetUserData(g); int i; if ( e->type!=et_controlevent ) return( true ); if ( which>=mv->glyphcnt ) return( true ); if ( e->u.control.subtype == et_textchanged ) { unichar_t *end; int val = u_strtod(_GGadgetGetTitle(g),&end); SplineChar *sc = mv->glyphs[which].sc; DBounds bb; SplineCharFindBounds(sc,&bb); if ( *end && !(*end=='-' && end[1]=='\0')) GDrawBeep(NULL); else if ( !mv->vertical && rint(val+bb.maxx)!=sc->width ) { int newwidth = rint(bb.maxx+val); SCPreserveWidth(sc); /* Width is an integer. Adjust the lbearing so that the rbearing */ /* remains what was just typed in */ if ( newwidth!=bb.maxx+val ) { real transform[6]; transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; transform[4] = newwidth-val-bb.maxx; FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth); } SCSynchronizeWidth(sc,newwidth,sc->width,NULL); SCCharChangedUpdate(sc,ly_none); } else if ( mv->vertical && val!=sc->vwidth-(sc->parent->ascent-bb.miny) ) { double vw = val+(sc->parent->ascent-bb.miny); SCPreserveWidth(sc); sc->vwidth = rint(vw); /* Width is an integer. Adjust the lbearing so that the rbearing */ /* remains what was just typed in */ if ( sc->width!=vw ) { real transform[6]; transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[4] = 0; transform[5] = vw-sc->vwidth; FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth); } SCCharChangedUpdate(sc,ly_none); } } else if ( e->u.control.subtype == et_textfocuschanged && e->u.control.u.tf_focus.gained_focus ) { for ( i=0 ; iglyphcnt; ++i ) if ( i!=which && mv->perchar[i].selected ) MVDeselectChar(mv,i); MVSelectChar(mv,which); } return( true ); } static int AskNewKernClassEntry(SplineChar *fsc,SplineChar *lsc,int first_is_0,int second_is_0) { char *yesno[3]; yesno[0] = _("_Alter Class"); yesno[1] = _("_Create Pair"); yesno[2] = NULL; return( gwwv_ask(_("Use Kerning Class?"),(const char **) yesno,0,1, _("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)?"), first_is_0 ? _("{Everything Else}") : fsc->name, second_is_0 ? _("{Everything Else}") : lsc->name)==0 ); } static int MV_ChangeKerning(MetricsView *mv, int which, int offset, int is_diff) { SplineChar *sc = mv->glyphs[which].sc; SplineChar *psc = mv->glyphs[which-1].sc; KernPair *kp; KernClass *kc; int index; int i; struct lookup_subtable *sub = GGadgetGetListItemSelected(mv->subtable_list)->userdata; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; kp = mv->glyphs[which-1].kp; kc = mv->glyphs[which-1].kc; index = mv->glyphs[which-1].kc_index; if ( kc!=NULL ) { if ( index==-1 ) kc = NULL; else if ( (!is_diff && offset==kc->offsets[index]) || ( is_diff && offset==0)) return( true ); /* No change, don't bother user */ else if ( kc->offsets[index]==0 && !AskNewKernClassEntry(psc,sc,mv->glyphs[which-1].prev_kc0,mv->glyphs[which-1].next_kc0)) kc=NULL; else offset = kc->offsets[index] = is_diff ? kc->offsets[index]+offset : offset; } if ( kc==NULL ) { if ( sub!=NULL && sub->kc!=NULL ) { /* If the subtable we were given contains a kern class, and for some reason */ /* we can't, or don't want to, use that kern class, then see */ /* if the lookup contains another subtable with no kern classes */ /* and use that */ struct lookup_subtable *s; for ( s = sub->lookup->subtables; s!=NULL && s->kc!=NULL; s=s->next ); sub = s; } if ( sub==NULL ) { struct subtable_data sd; memset(&sd,0,sizeof(sd)); sd.flags = (mv->vertical ? sdf_verticalkern : sdf_horizontalkern ) | sdf_kernpair; sub = SFNewLookupSubtableOfType(psc->parent,gpos_pair,&sd,mv->layer); if ( sub==NULL ) return( false ); mv->cur_subtable = sub; MVSetSubtables(mv->sf); MVSetFeatures(mv); } if ( kp==NULL ) { kp = chunkalloc(sizeof(KernPair)); kp->sc = sc; if ( !mv->vertical ) { kp->next = psc->kerns; psc->kerns = kp; } else { kp->next = psc->vkerns; psc->vkerns = kp; } mv->glyphs[which-1].kp = kp; } if ( !mv->vertical ) MMKern(sc->parent,psc,sc,kp==NULL?offset:is_diff?offset:offset-kp->off, sub,kp); #ifdef FONTFORGE_CONFIG_DEVICETABLES /* If we change the kerning offset, then any pixel corrections*/ /* will no longer apply (they only had meaning with the old */ /* offset) so free the device table, if any */ if ( (!is_diff && kp->off!=offset) || ( is_diff && offset!=0) ) { DeviceTableFree(kp->adjust); kp->adjust = NULL; } #endif offset = kp->off = is_diff ? kp->off+offset : offset; kp->subtable = sub; } mv->perchar[which-1].kernafter = iscale * (offset*mv->pixelsize)/ (mv->sf->ascent+mv->sf->descent); if ( mv->vertical ) { for ( i=which; iglyphcnt; ++i ) { mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight + mv->perchar[i-1].kernafter ; } } else { for ( i=which; iglyphcnt; ++i ) { mv->perchar[i].dx = mv->perchar[i-1].dx + mv->perchar[i-1].dwidth + mv->perchar[i-1].kernafter; } } mv->sf->changed = true; GDrawRequestExpose(mv->v,NULL,false); return( true ); } static int MV_KernChanged(GGadget *g, GEvent *e) { MetricsView *mv = GDrawGetUserData(GGadgetGetWindow(g)); int which = (intpt) GGadgetGetUserData(g); int i; if ( e->type!=et_controlevent ) return( true ); if ( which>mv->glyphcnt-1 || which==0 ) return( true ); if ( e->u.control.subtype == et_textchanged ) { unichar_t *end; int val = u_strtol(_GGadgetGetTitle(g),&end,10); if ( *end && !(*end=='-' && end[1]=='\0')) GDrawBeep(NULL); else { MV_ChangeKerning(mv,which,val, false); } } else if ( e->u.control.subtype == et_textfocuschanged && e->u.control.u.tf_focus.gained_focus ) { for ( i=0 ; iglyphcnt; ++i ) if ( i!=which && mv->perchar[i].selected ) MVDeselectChar(mv,i); MVSelectChar(mv,which); } return( true ); } static void MVToggleVertical(MetricsView *mv) { int size; mv->vertical = !mv->vertical; GGadgetSetTitle8( mv->widthlab, mv->vertical ? "Height:" : "Width:" ); GGadgetSetTitle8( mv->lbearinglab, mv->vertical ? "TBearing:" : "LBearing:" ); GGadgetSetTitle8( mv->rbearinglab, mv->vertical ? "BBearing:" : "RBearing:" ); GGadgetSetTitle8( mv->kernlab, mv->vertical ? "VKern:" : "Kern:" ); if ( mv->vertical ) if ( mv->scale_index<4 ) mv->scale_index = 4; if ( mv->pixelsize_set_by_window ) { size = (mv->displayend - mv->topend - 4); if ( mv->dwidth-20dwidth-20; size *= mv_scales[mv->scale_index]; if ( mv->pixelsize != size ) { mv->pixelsize = size; mv->dpi = 72; if ( mv->bdf==NULL ) { BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->pixelsize,72,mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); } MVRemetric(mv); } } } static SplineChar *MVSCFromUnicode(MetricsView *mv, SplineFont *sf, EncMap *map, int ch,BDFFont *bdf) { int i; SplineChar *sc; if ( mv->fake_unicode_base && ch>=mv->fake_unicode_base && ch<=mv->fake_unicode_base+mv->sf->glyphcnt ) return( mv->sf->glyphs[ch-mv->fake_unicode_base] ); i = SFFindSlot(sf,map,ch,NULL); if ( i==-1 ) return( NULL ); else { sc = SFMakeChar(sf,map,i); if ( bdf!=NULL ) BDFMakeChar(bdf,map,i); } return( sc ); } static void MVMoveFieldsBy(MetricsView *mv,int diff) { int i; int y,x; for ( i=0; imax && mv->perchar[i].width!=NULL; ++i ) { y = mv->displayend+2; x = mv->perchar[i].mx-diff; if ( xmbase+mv->mwidth ) x = -2*mv->mwidth; GGadgetMove(mv->perchar[i].name,x,y); y += mv->fh+4; GGadgetMove(mv->perchar[i].width,x,y); y += mv->fh+4; GGadgetMove(mv->perchar[i].lbearing,x,y); y += mv->fh+4; GGadgetMove(mv->perchar[i].rbearing,x,y); y += mv->fh+4; if ( i!=0 ) GGadgetMove(mv->perchar[i].kern,x-mv->mwidth/2,y); } } static int MVDisplayedCnt(MetricsView *mv) { int i, wid = mv->mbase; for ( i=mv->coff; iglyphcnt; ++i ) { wid += mv->perchar[i].dwidth; if ( wid>mv->dwidth ) return( i-mv->coff ); } return( i-mv->coff ); /* There's extra room. don't know exactly how much but allow for some */ } static void MVSetSb(MetricsView *mv) { int cnt = (mv->dwidth-mv->mbase-mv->mwidth)/mv->mwidth; int dcnt = MVDisplayedCnt(mv); if ( cnt>dcnt ) cnt = dcnt; if ( cnt==0 ) cnt = 1; GScrollBarSetBounds(mv->hsb,0,mv->glyphcnt,cnt); GScrollBarSetPos(mv->hsb,mv->coff); } static int MVSetVSb(MetricsView *mv) { int max, min, ret, yoff; int fudge; if ( mv->displayend==0 ) return(0); /* Setting the scroll bar is premature */ if ( mv->vertical ) { min = max = 0; if ( mv->glyphcnt!=0 ) max = mv->perchar[mv->glyphcnt-1].dy + mv->perchar[mv->glyphcnt-1].dheight; fudge = 10; } else { SplineFont *sf = mv->sf; int pixels = mv->pixelsize_set_by_window ? mv->vheight : mv->pixelsize; fudge = pixels/4; min = -(pixels*sf->descent)/(sf->ascent+sf->descent); max = pixels + min; min *= mv_scales[mv->scale_index]; max *= mv_scales[mv->scale_index]; } mv->ybaseline = max; max += fudge*mv_scales[mv->scale_index] + mv->vheight; min -= fudge*mv_scales[mv->scale_index]; GScrollBarSetBounds(mv->vsb,min,max,mv->vheight); yoff = mv->yoff; if ( yoff+mv->vheight > max ) yoff = max - mv->vheight; if ( yoffyoff; mv->yoff = yoff; GScrollBarSetPos(mv->vsb,yoff); return( ret ); } static void MVHScroll(MetricsView *mv,struct sbevent *sb) { int newpos = mv->coff; int cnt = (mv->dwidth-mv->mbase-mv->mwidth)/mv->mwidth; int dcnt = MVDisplayedCnt(mv); if ( cnt>dcnt ) cnt = dcnt; if ( cnt==0 ) cnt = 1; switch( sb->type ) { case et_sb_top: newpos = 0; break; case et_sb_uppage: newpos -= cnt; break; case et_sb_up: --newpos; break; case et_sb_down: ++newpos; break; case et_sb_downpage: newpos += cnt; break; case et_sb_bottom: newpos = mv->glyphcnt-cnt; break; case et_sb_thumb: case et_sb_thumbrelease: newpos = sb->pos; break; } if ( newpos>mv->glyphcnt-cnt ) newpos = mv->glyphcnt-cnt; if ( newpos<0 ) newpos =0; if ( newpos!=mv->coff ) { int old = mv->coff; int diff = newpos-mv->coff; int charsize = mv->perchar[newpos].dx-mv->perchar[old].dx; GRect fieldrect, charrect; mv->coff = newpos; charrect.x = 0; charrect.width = mv->vwidth; charrect.y = 0; charrect.height = mv->vheight; fieldrect.x = mv->mbase+mv->mwidth; fieldrect.width = mv->width-mv->mbase; fieldrect.y = mv->displayend; fieldrect.height = mv->height-mv->sbh-mv->displayend; GScrollBarSetBounds(mv->hsb,0,mv->glyphcnt,cnt); GScrollBarSetPos(mv->hsb,mv->coff); MVMoveFieldsBy(mv,newpos*mv->mwidth); GDrawScroll(mv->gw,&fieldrect,-diff*mv->mwidth,0); mv->xoff = mv->perchar[newpos].dx-mv->perchar[0].dx; if ( mv->right_to_left ) { charsize = -charsize; } GDrawScroll(mv->v,&charrect,-charsize,0); } } static void MVVScroll(MetricsView *mv,struct sbevent *sb) { int newpos = mv->yoff; int32 min, max, page; GScrollBarGetBounds(mv->vsb,&min,&max,&page); switch( sb->type ) { case et_sb_top: newpos = 0; break; case et_sb_uppage: newpos -= page; break; case et_sb_up: newpos -= (page)/15; break; case et_sb_down: newpos += (page)/15; break; case et_sb_downpage: newpos += page; break; case et_sb_bottom: newpos = max-page; break; case et_sb_thumb: case et_sb_thumbrelease: newpos = sb->pos; break; } if ( newpos>max-page ) newpos = max-page; if ( newposyoff ) { int diff = newpos-mv->yoff; GRect charrect; mv->yoff = newpos; charrect.x = 0; charrect.width = mv->vwidth; charrect.y = 0; charrect.height = mv->vheight; GScrollBarSetPos(mv->vsb,mv->yoff); GDrawScroll(mv->v,&charrect,0,diff); } } #ifdef UNICHAR_16 # define MVFakeUnicodeOfSc(mv,sc) 0xfffd # define MVOddMatch(mv,uni,sc) (uni==0xfffd && sc->unicodeenc==-1) #else static int MVFakeUnicodeOfSc(MetricsView *mv, SplineChar *sc) { if ( sc->unicodeenc!=-1 ) return( sc->unicodeenc ); if ( mv->fake_unicode_base==0 ) { /* Not set */ /* If they have nothing in Supplementary Private Use Area-A use it */ /* If they have nothing in Supplementary Private Use Area-B use it */ /* else just use 0xfffd */ int a, al, ah, b, bl, bh; int gid,k,max; SplineChar *test; SplineFont *_sf, *sf; sf = mv->sf; if ( sf->cidmaster ) sf = sf->cidmaster; k=0; a = al = ah = b = bl = bh = 0; max = 0; do { _sf = ( sf->subfontcnt==0 ) ? sf : sf->subfonts[k]; for ( gid=0; gid<_sf->glyphcnt; ++gid ) if ( (test=_sf->glyphs[gid])!=NULL ) { if ( test->unicodeenc>=0xf0000 && test->unicodeenc<=0xfffff ) { a = true; if ( test->unicodeenc<0xf8000 ) al = true; else ah = true; } else if ( test->unicodeenc>=0x100000 && test->unicodeenc<=0x10ffff ) { b = true; if ( test->unicodeenc<0x108000 ) bl = true; else bh = true; } } if ( gid>max ) max = gid; ++k; } while ( ksubfontcnt ); if ( !a ) /* Nothing in SPUA-A */ mv->fake_unicode_base = 0xf0000; else if ( !b ) mv->fake_unicode_base = 0x100000; else if ( max<0x8000 ) { if ( !al ) mv->fake_unicode_base = 0xf0000; else if ( !ah ) mv->fake_unicode_base = 0xf8000; else if ( !bl ) mv->fake_unicode_base = 0x100000; else if ( !bh ) mv->fake_unicode_base = 0x108000; } if ( mv->fake_unicode_base==0 ) mv->fake_unicode_base = -1; } if ( mv->fake_unicode_base==-1 ) return( 0xfffd ); else return( mv->fake_unicode_base+sc->orig_pos ); } static int MVOddMatch(MetricsView *mv,int uni,SplineChar *sc) { if ( sc->unicodeenc!=-1 ) return( false ); else if ( mv->fake_unicode_base<=0 ) return( uni==0xfffd ); else return( uni>=mv->fake_unicode_base && sc->orig_pos == uni-mv->fake_unicode_base ); } #endif void MVSetSCs(MetricsView *mv, SplineChar **scs) { /* set the list of characters being displayed to those in scs */ int len; unichar_t *ustr; for ( len=0; scs[len]!=NULL; ++len ); if ( len>=mv->cmax ) mv->chars = realloc(mv->chars,(mv->cmax=len+10)*sizeof(SplineChar *)); memcpy(mv->chars,scs,(len+1)*sizeof(SplineChar *)); mv->clen = len; ustr = galloc((len+1)*sizeof(unichar_t)); for ( len=0; scs[len]!=NULL; ++len ) #ifdef UNICHAR_16 if ( scs[len]->unicodeenc>0 && scs[len]->unicodeenc<0x10000 ) #else if ( scs[len]->unicodeenc>0 ) #endif ustr[len] = scs[len]->unicodeenc; else ustr[len] = MVFakeUnicodeOfSc(mv,scs[len]); ustr[len] = 0; GGadgetSetTitle(mv->text,ustr); free(ustr); MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } static void MVTextChanged(MetricsView *mv) { const unichar_t *ret, *pt, *ept, *tpt; int i,ei, j, start=0, end=0; int missing; int direction_change = false; SplineChar **hold = NULL; ret = _GGadgetGetTitle(mv->text); if (( ret[0]<0x10000 && isrighttoleft(ret[0]) && !mv->right_to_left ) || ( ret[0]<0x10000 && !isrighttoleft(ret[0]) && mv->right_to_left )) { direction_change = true; mv->right_to_left = !mv->right_to_left; } for ( pt=ret, i=0; iclen && *pt!='\0'; ++i, ++pt ) if ( *pt!=mv->chars[i]->unicodeenc && !MVOddMatch(mv,*pt,mv->chars[i])) break; if ( i==mv->clen && *pt=='\0' ) return; /* Nothing changed */ for ( ept=ret+u_strlen(ret)-1, ei=mv->clen-1; ; --ei, --ept ) if ( ei<0 || eptchars[ei]->unicodeenc && !MVOddMatch(mv,*ept,mv->chars[ei]))) { ++ei; ++ept; break; } else if ( ei=mv->cmax ) { int oldmax=mv->cmax; mv->cmax = u_strlen(ret)+10; mv->chars = grealloc(mv->chars,mv->cmax*sizeof(SplineChar *)); memset(mv->chars+oldmax,'\0',(mv->cmax-oldmax)*sizeof(SplineChar *)); } missing = 0; for ( tpt=pt; tptfake_unicode_base>0 && *tpt>=mv->fake_unicode_base && *tpt<=mv->fake_unicode_base+mv->sf->glyphcnt ) /* That's ok */; else if ( SFFindSlot(mv->sf,mv->fv->b.map,*tpt,NULL)==-1 ) ++missing; if ( ept-pt-missing > ei-i ) { if ( iclen ) { int diff = (ept-pt-missing) - (ei-i); hold = galloc((mv->clen+diff+6)*sizeof(SplineChar *)); for ( j=mv->clen-1; j>=ei; --j ) hold[j+diff] = mv->chars[j]; start = ei+diff; end = mv->clen+diff; } } else if ( ept-pt-missing != ei-i ) { int diff = (ept-pt-missing) - (ei-i); for ( j=ei; jclen; ++j ) if ( j+diff>=0 ) mv->chars[j+diff] = mv->chars[j]; } for ( j=i; ptsf,mv->fv->b.map,*pt,mv->bdf); if ( sc!=NULL ) mv->chars[j++] = sc; } if ( hold!=NULL ) { /* We had to figure out what sc's there were before we wrote over them*/ /* but we couldn't put them where they belonged until everything before*/ /* them was set properly */ for ( j=start; jchars[j] = hold[j]; free(hold); } mv->clen = u_strlen(ret)-missing; mv->chars[mv->clen] = NULL; MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } GTextInfo mv_text_init[] = { { (unichar_t *) "", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 1, 0, 1}, { NULL, NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 1}, { (unichar_t *) N_("Load Word List..."), NULL, 0, 0, (void *) -1, NULL, 0, 0, 0, 0, 0, 0, 1}, { (unichar_t *) N_("Load Glyph Name List..."), NULL, 0, 0, (void *) -2, NULL, 0, 0, 0, 0, 0, 0, 1}, { NULL } }; static void MVFigureGlyphNames(MetricsView *mv,const unichar_t *names) { char buffer[400], *pt, *start; SplineChar *founds[40]; int i,cnt,ch; unichar_t *newtext; u2utf8_strcpy(buffer,names); start = buffer; for ( i=0; *start; ) { while ( *start==' ' ) ++start; if ( *start=='\0' ) break; for ( pt=start; *pt && *pt!=' '; ++pt ); ch = *pt; *pt = '\0'; if ( i>=40 ) break; if ( (founds[i]=SFGetChar(mv->sf,-1,start))!=NULL ) ++i; *pt = ch; start = pt; } cnt = i; if ( cnt>=mv->cmax ) { mv->cmax = mv->clen+cnt+10; mv->chars = grealloc(mv->chars,mv->cmax*sizeof(SplineChar *)); } newtext = galloc((cnt+1)*sizeof(unichar_t)); for ( i=0; iunicodeenc==-1 || founds[i]->unicodeenc>=0x10000? #else newtext[i] = founds[i]->unicodeenc==-1 ? #endif MVFakeUnicodeOfSc(mv,founds[i]) : founds[i]->unicodeenc; mv->chars[i] = founds[i]; } newtext[i] = 0; mv->chars[i] = NULL; mv->clen = cnt; MVRemetric(mv); GGadgetSetTitle(mv->text,newtext); free(newtext); GDrawRequestExpose(mv->v,NULL,false); } static void MVLoadWordList(MetricsView *mv,int type) { GTextInfo **words; int cnt; char buffer[300], *pt; int ch; char *filename, *temp; FILE *file; filename = gwwv_open_filename(type==-1 ? "File of Kerning Words":"File of glyphname lists",NULL,"*.txt",NULL); if ( filename==NULL ) { GGadgetSetTitle8(mv->text,""); return; } temp = utf82def_copy(filename); file = fopen( temp,"r" ); free(temp); if ( file==NULL ) { ff_post_error("Could not open", "Could not open %s", filename ); GGadgetSetTitle8(mv->text,""); return; } free(filename); words = galloc(1002*sizeof(GTextInfo *)); cnt = 0; if ( type==-1 ) { ch = getc(file); while ( ch!=EOF ) { while ( isspace(ch) && ch<0x80 ) ch=getc(file); for ( pt = buffer; ch!=EOF && !(isspace(ch) && ch<0x80) ; ch=getc(file)) if ( pt1000-3 ) break; words[cnt] = gcalloc(1,sizeof(GTextInfo)); words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT; words[cnt]->text = (unichar_t *) utf82def_copy( buffer ); words[cnt++]->text_is_1byte = true; } } else { strcpy(buffer,"​"); /* Zero width space: 0x200b, I use as a flag */ while ( fgets(buffer+3,sizeof(buffer)-3,file)!=NULL ) { if ( buffer[3]=='\n' || buffer[3]=='#' ) continue; if ( cnt>1000-3 ) break; if ( buffer[strlen(buffer)-1]=='\n' ) buffer[strlen(buffer)-1] = '\0'; words[cnt] = gcalloc(1,sizeof(GTextInfo)); words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT; words[cnt]->text = (unichar_t *) copy( buffer ); words[cnt++]->text_is_1byte = true; } } fclose(file); if ( cnt!=0 ) { words[cnt] = gcalloc(1,sizeof(GTextInfo)); words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT; words[cnt++]->line = true; words[cnt] = gcalloc(1,sizeof(GTextInfo)); words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT; words[cnt]->text = (unichar_t *) copy( _("Load Word List...") ); words[cnt]->text_is_1byte = true; words[cnt++]->userdata = (void *) -1; words[cnt] = gcalloc(1,sizeof(GTextInfo)); words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT; words[cnt]->text = (unichar_t *) copy( _("Load Glyph Name List...") ); words[cnt]->text_is_1byte = true; words[cnt++]->userdata = (void *) -2; words[cnt] = gcalloc(1,sizeof(GTextInfo)); GGadgetSetList(mv->text,words,true); GGadgetSetTitle8(mv->text,(char *) (words[0]->text)); if ( type==-2 ) MVFigureGlyphNames(mv,_GGadgetGetTitle(mv->text)+1); GTextInfoArrayFree(words); mv->word_index = 0; } else { GGadgetSetTitle8(mv->text,""); free(words); } } static int MV_TextChanged(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) { MetricsView *mv = GGadgetGetUserData(g); int pos = e->u.control.u.tf_changed.from_pulldown; if ( pos!=-1 ) { int32 len; GTextInfo **ti = GGadgetGetList(g,&len); GTextInfo *cur = ti[pos]; int type = (intpt) cur->userdata; if ( type < 0 ) MVLoadWordList(mv,type); else if ( cur->text!=NULL ) { mv->word_index = pos; if ( cur->text[0]==0x200b ) /* Zero width space, flag for glyph names */ MVFigureGlyphNames(mv,cur->text+1); } } MVTextChanged(mv); } return( true ); } static int MV_ScriptLangChanged(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) { const unichar_t *sstr = _GGadgetGetTitle(g); MetricsView *mv = GGadgetGetUserData(g); if ( e->u.control.u.tf_changed.from_pulldown!=-1 ) { GGadgetSetTitle8(g,mv->scriptlangs[e->u.control.u.tf_changed.from_pulldown].userdata ); sstr = _GGadgetGetTitle(g); } else { if ( u_strlen(sstr)<4 || !isalpha(sstr[0]) || !isalnum(sstr[1]) /*|| !isalnum(sstr[2]) || !isalnum(sstr[3])*/ ) return( true ); if ( u_strlen(sstr)==4 ) /* No language, we'll use default */; else if ( u_strlen(sstr)!=10 || sstr[4]!='{' || sstr[9]!='}' || !isalpha(sstr[5]) || !isalpha(sstr[6]) || !isalpha(sstr[7]) ) return( true ); } MVSetFeatures(mv); if ( mv->clen!=0 )/* if there are no chars, remetricking will set the script field to DFLT */ MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } return( true ); } static int MV_FeaturesChanged(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) { MetricsView *mv = GGadgetGetUserData(g); MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } return( true ); } void MV_FriendlyFeatures(GGadget *g, int pos) { int32 len; GTextInfo **ti = GGadgetGetList(g,&len); if ( pos<0 || pos>=len ) GGadgetEndPopup(); else { const unichar_t *pt = ti[pos]->text; uint32 tag; int i; tag = (pt[0]<<24) | (pt[1]<<16) | (pt[2]<<8) | pt[3]; LookupUIInit(); for ( i=0; friendlies[i].friendlyname!=NULL; ++i ) if ( friendlies[i].tag==tag ) break; if ( friendlies[i].friendlyname!=NULL ) GGadgetPreparePopup8(GGadgetGetWindow(g),friendlies[i].friendlyname); } } static int MV_SubtableChanged(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) { MetricsView *mv = GGadgetGetUserData(g); int32 len; GTextInfo **ti = GGadgetGetList(g,&len); int i; KernPair *kp; struct lookup_subtable *sub; SplineFont *sf = mv->sf; if ( sf->cidmaster!=NULL ) sf = sf->cidmaster; if ( ti[len-1]->selected ) {/* New lookup subtable */ struct subtable_data sd; memset(&sd,0,sizeof(sd)); sd.flags = (mv->vertical ? sdf_verticalkern : sdf_horizontalkern ) | sdf_kernpair | sdf_dontedit; sub = SFNewLookupSubtableOfType(sf,gpos_pair,&sd,mv->layer); if ( sub==NULL ) return( true ); mv->cur_subtable = sub; MVSetSubtables(mv->sf); MVSetFeatures(mv); /* Is this needed? */ } else if ( ti[len-2]->selected ) { /* Idiots. They selected the line, can't have that */ MVSetSubtables(mv->sf); sub = mv->cur_subtable; } else mv->cur_subtable = GGadgetGetListItemSelected(mv->subtable_list)->userdata; for ( i=0; iglyphcnt; ++i ) { if ( mv->perchar[i].selected ) break; } kp = mv->glyphs[i].kp; if ( kp!=NULL ) kp->subtable = mv->cur_subtable; } return( true ); } #define MID_ZoomIn 2002 #define MID_ZoomOut 2003 #define MID_Next 2005 #define MID_Prev 2006 #define MID_Outline 2007 #define MID_ShowGrid 2008 #define MID_HideGrid 2009 #define MID_PartialGrid 2010 #define MID_HideGridWhenMoving 2011 #define MID_NextDef 2012 #define MID_PrevDef 2013 #define MID_AntiAlias 2014 #define MID_FindInFontView 2015 #define MID_Ligatures 2020 #define MID_KernPairs 2021 #define MID_AnchorPairs 2022 #define MID_Vertical 2023 #define MID_ReplaceChar 2024 #define MID_InsertCharB 2025 #define MID_InsertCharA 2026 #define MID_Layers 2027 #define MID_PointSize 2028 #define MID_Bigger 2029 #define MID_Smaller 2030 #define MID_SizeWindow 2031 #define MID_CharInfo 2201 #define MID_FindProblems 2216 #define MID_Transform 2202 #define MID_Stroke 2203 #define MID_RmOverlap 2204 #define MID_Simplify 2205 #define MID_Correct 2206 #define MID_BuildAccent 2208 #define MID_AvailBitmaps 2210 #define MID_RegenBitmaps 2211 #define MID_Autotrace 2212 #define MID_Round 2213 #define MID_ShowDependents 2222 #define MID_AddExtrema 2224 #define MID_CleanupGlyph 2225 #define MID_TilePath 2226 #define MID_BuildComposite 2227 #define MID_Intersection 2229 #define MID_FindInter 2230 #define MID_Effects 2231 #define MID_SimplifyMore 2232 #define MID_Center 2600 #define MID_OpenBitmap 2700 #define MID_OpenOutline 2701 #define MID_Cut 2101 #define MID_Copy 2102 #define MID_Paste 2103 #define MID_Clear 2104 #define MID_SelAll 2106 #define MID_ClearSel 2105 #define MID_UnlinkRef 2108 #define MID_Undo 2109 #define MID_Redo 2110 #define MID_CopyRef 2107 #define MID_CopyWidth 2111 #define MID_CopyLBearing 2125 #define MID_CopyRBearing 2126 #define MID_CopyVWidth 2127 #define MID_Join 2128 #define MID_Center 2600 #define MID_Thirds 2604 #define MID_VKernClass 2605 #define MID_VKernFromHKern 2606 #define MID_KernOnly 2607 #define MID_WidthOnly 2608 #define MID_BothKernWidth 2609 #define MID_Recent 2703 #define MID_Warnings 3000 static void MVMenuClose(GWindow gw,struct gmenuitem *mi,GEvent *e) { GDrawDestroyWindow(gw); } static void MVMenuOpenBitmap(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); EncMap *map; int i; if ( mv->sf->bitmaps==NULL ) return; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) break; map = mv->fv->b.map; if ( i!=mv->glyphcnt ) BitmapViewCreatePick(map->backmap[mv->glyphs[i].sc->orig_pos],mv->fv); } static void MVMenuMergeKern(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); MergeKernInfo(mv->sf,mv->fv->b.map); } static void MVMenuOpenOutline(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) break; if ( i!=mv->glyphcnt ) CharViewCreate(mv->glyphs[i].sc,mv->fv,-1); } static void MVMenuSave(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _FVMenuSave(mv->fv); } static void MVMenuSaveAs(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _FVMenuSaveAs(mv->fv); } static void MVMenuGenerate(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _FVMenuGenerate(mv->fv,false); } static void MVMenuGenerateFamily(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _FVMenuGenerate(mv->fv,gf_macfamily); } static void MVMenuGenerateTTC(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _FVMenuGenerate(mv->fv,gf_ttc); } static void MVMenuPrint(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); PrintDlg(NULL,NULL,mv); } static void MVUndo(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_undo) ) /* MVTextChanged(mv) */; else { for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; if ( mv->glyphs[i].sc->layers[mv->layer].undoes!=NULL ) SCDoUndo(mv->glyphs[i].sc,mv->layer); } } static void MVRedo(GWindow gw,struct gmenuitem *mi, GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_redo) ) /* MVTextChanged(mv) */; else { for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; if ( mv->glyphs[i].sc->layers[mv->layer].redoes!=NULL ) SCDoRedo(mv->glyphs[i].sc,mv->layer); } } static void MVClear(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; SplineChar *sc; BDFFont *bdf; extern int onlycopydisplayed; if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_clear) ) /* MVTextChanged(mv) */; else { for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; sc = mv->glyphs[i].sc; if ( sc->dependents!=NULL ) { int yes; char *buts[4]; buts[1] = _("_Unlink"); buts[0] = _("_Yes"); buts[2] = _("_Cancel"); buts[3] = NULL; 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); if ( yes==2 ) return; if ( yes==1 ) UnlinkThisReference(NULL,sc,mv->layer); } if ( onlycopydisplayed && mv->bdf==NULL ) { SCClearAll(sc,mv->layer); } else if ( onlycopydisplayed ) { BCClearAll(mv->bdf->glyphs[sc->orig_pos]); } else { SCClearAll(sc,mv->layer); for ( bdf=mv->sf->bitmaps; bdf!=NULL; bdf = bdf->next ) BCClearAll(bdf->glyphs[sc->orig_pos]); } } } static void MVCut(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_cut) ) /* MVTextChanged(mv) */; else { for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; MVCopyChar(&mv->fv->b,mv->bdf,mv->glyphs[i].sc,ct_fullcopy); MVClear(gw,mi,e); } } static void MVCopy(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_copy) ) /* MVTextChanged(mv) */; else { for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; MVCopyChar(&mv->fv->b,mv->bdf,mv->glyphs[i].sc,ct_fullcopy); } } static void MVMenuCopyRef(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL ) return; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; MVCopyChar(&mv->fv->b,mv->bdf,mv->glyphs[i].sc,ct_reference); } static void MVMenuCopyWidth(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL ) return; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; SCCopyWidth(mv->glyphs[i].sc, mi->mid==MID_CopyWidth?ut_width: mi->mid==MID_CopyVWidth?ut_vwidth: mi->mid==MID_CopyLBearing?ut_lbearing: ut_rbearing); } static void MVMenuJoin(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i, changed; extern float joinsnap; if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL ) return; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; SCPreserveLayer(mv->glyphs[i].sc,mv->layer,false); mv->glyphs[i].sc->layers[mv->layer].splines = SplineSetJoin(mv->glyphs[i].sc->layers[mv->layer].splines,true,joinsnap,&changed); if ( changed ) SCCharChangedUpdate(mv->glyphs[i].sc,mv->layer); } static void MVPaste(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GGadgetActiveGadgetEditCmd(mv->gw,ec_paste) ) /*MVTextChanged(mv)*/; /* Should get an event now */ else { for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; PasteIntoMV(&mv->fv->b,mv->bdf,mv->glyphs[i].sc,true); } } static void MVUnlinkRef(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; SplineChar *sc; RefChar *rf, *next; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) return; sc = mv->glyphs[i].sc; SCPreserveLayer(sc,mv->layer,false); for ( rf=sc->layers[mv->layer].refs; rf!=NULL ; rf=next ) { next = rf->next; SCRefToSplines(sc,rf,mv->layer); } SCCharChangedUpdate(sc,mv->layer); } static void MVSelectAll(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); GGadgetActiveGadgetEditCmd(mv->gw,ec_selectall); } static void MVClearSelection(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; GWindowClearFocusGadgetOfWindow(mv->gw); for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) MVDeselectChar(mv,i); } static void MVMenuFontInfo(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); DelayEvent(FontMenuFontInfo,mv->fv); } static void MVMenuCharInfo(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) SCCharInfo(mv->glyphs[i].sc,mv->layer,mv->fv->b.map,-1); } static void MVMenuShowDependents(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) return; if ( mv->glyphs[i].sc->dependents==NULL ) return; SCRefBy(mv->glyphs[i].sc); } static void MVMenuFindProblems(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) FindProblems(mv->fv,NULL,mv->glyphs[i].sc); } static void MVMenuBitmaps(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) break; if ( i!=mv->glyphcnt ) BitmapDlg(mv->fv,mv->glyphs[i].sc,mi->mid==MID_AvailBitmaps ); else if ( mi->mid==MID_AvailBitmaps ) BitmapDlg(mv->fv,NULL,true ); } static int getorigin(void *d,BasePoint *base,int index) { SplineChar *sc = (SplineChar *) d; DBounds bb; base->x = base->y = 0; switch ( index ) { case 0: /* Character origin */ /* all done */ break; case 1: /* Center of selection */ SplineCharFindBounds(sc,&bb); base->x = (bb.minx+bb.maxx)/2; base->y = (bb.miny+bb.maxy)/2; break; default: return( false ); } return( true ); } static void MVTransFunc(void *_sc,real transform[6],int otype, BVTFunc *bvts, enum fvtrans_flags flags ) { SplineChar *sc = _sc; FVTrans( (FontViewBase *)sc->parent->fv,sc,transform, NULL,flags); } static void MVMenuTransform(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) TransformDlgCreate( mv->glyphs[i].sc,MVTransFunc,getorigin,true,cvt_none ); } #ifdef FONTFORGE_CONFIG_TILEPATH static void MVMenuTilePath(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) SCTile(mv->glyphs[i].sc,mv->layer); } #endif static void _MVMenuOverlap(MetricsView *mv,enum overlap_type ot) { int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; if ( !SCRoundToCluster(sc,mv->layer,false,.03,.12)) SCPreserveLayer(sc,mv->layer,false); MinimumDistancesFree(sc->md); sc->md = NULL; sc->layers[mv->layer].splines = SplineSetRemoveOverlap(sc,sc->layers[mv->layer].splines,ot); SCCharChangedUpdate(sc,mv->layer); } } static void MVMenuOverlap(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _MVMenuOverlap(mv,mi->mid==MID_RmOverlap ? over_remove : mi->mid==MID_Intersection ? over_intersect : over_findinter); } static void MVMenuInline(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); OutlineDlg(NULL,NULL,mv,true); } static void MVMenuOutline(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); OutlineDlg(NULL,NULL,mv,false); } static void MVMenuShadow(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); ShadowDlg(NULL,NULL,mv,false); } static void MVMenuWireframe(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); ShadowDlg(NULL,NULL,mv,true); } static void MVSimplify( MetricsView *mv,int type ) { int i; static struct simplifyinfo smpls[] = { { sf_normal }, { sf_normal,.75,.05,0,-1 }, { sf_normal,.75,.05,0,-1 }}; struct simplifyinfo *smpl = &smpls[type+1]; if ( smpl->linelenmax==-1 ) { smpl->err = (mv->sf->ascent+mv->sf->descent)/1000.; smpl->linelenmax = (mv->sf->ascent+mv->sf->descent)/100.; } if ( type==1 ) { if ( !SimplifyDlg(mv->sf,smpl)) return; if ( smpl->set_as_default ) smpls[1] = *smpl; } for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; SCPreserveLayer(sc,mv->layer,false); sc->layers[mv->layer].splines = SplineCharSimplify(sc,sc->layers[mv->layer].splines,smpl); SCCharChangedUpdate(sc,mv->layer); } } static void MVMenuSimplify(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); MVSimplify(mv,false); } static void MVMenuSimplifyMore(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); MVSimplify(mv,true); } static void MVMenuCleanup(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); MVSimplify(mv,-1); } static void MVMenuAddExtrema(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; SplineFont *sf = mv->sf; int emsize = sf->ascent+sf->descent; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; SCPreserveLayer(sc,mv->layer,false); SplineCharAddExtrema(sc,sc->layers[mv->layer].splines,ae_only_good,emsize); SCCharChangedUpdate(sc,mv->layer); } } static void MVMenuRound2Int(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SCPreserveLayer(mv->glyphs[i].sc,mv->layer,false); SCRound2Int( mv->glyphs[i].sc,mv->layer,1.0); } } static void MVMenuAutotrace(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; GCursor ct; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { ct = GDrawGetCursor(mv->gw); GDrawSetCursor(mv->gw,ct_watch); ff_progress_allow_events(); SCAutoTrace(mv->glyphs[i].sc,mv->layer,e!=NULL && (e->u.mouse.state&ksm_shift)); GDrawSetCursor(mv->gw,ct); } } static void MVMenuCorrectDir(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; int changed = false, refchanged=false; RefChar *ref; int asked=-1; for ( ref=sc->layers[mv->layer].refs; ref!=NULL; ref=ref->next ) { if ( ref->transform[0]*ref->transform[3]<0 || (ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) { if ( asked==-1 ) { char *buts[4]; buts[0] = _("_Unlink"); buts[1] = _("_No"); buts[2] = _("_Cancel"); buts[3] = NULL; 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 ); if ( asked==2 ) return; else if ( asked==1 ) break; } if ( asked==0 ) { if ( !refchanged ) { refchanged = true; SCPreserveLayer(sc,mv->layer,false); } SCRefToSplines(sc,ref,mv->layer); } } } if ( !refchanged ) SCPreserveLayer(sc,mv->layer,false); sc->layers[mv->layer].splines = SplineSetsCorrect(sc->layers[mv->layer].splines,&changed); if ( changed || refchanged ) SCCharChangedUpdate(sc,mv->layer); } } static void _MVMenuBuildAccent(MetricsView *mv,int onlyaccents) { int i; extern int onlycopydisplayed; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i!=-1 ) { SplineChar *sc = mv->glyphs[i].sc; if ( SFIsSomethingBuildable(mv->sf,sc,mv->layer,onlyaccents) ) SCBuildComposit(mv->sf,sc,mv->layer,NULL,onlycopydisplayed); } } static void MVMenuBuildAccent(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _MVMenuBuildAccent(mv,false); } static void MVMenuBuildComposite(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _MVMenuBuildAccent(mv,true); } static void MVResetText(MetricsView *mv) { unichar_t *new, *pt; int i; new = galloc((mv->clen+1)*sizeof(unichar_t)); for ( pt=new, i=0; iclen; ++i ) { #ifdef UNICHAR_16 if ( mv->chars[i]->unicodeenc==-1 || mv->chars[i]->unicodeenc>=0x10000 ) #else if ( mv->chars[i]->unicodeenc==-1 ) #endif *pt++ = MVFakeUnicodeOfSc(mv,mv->chars[i]); else *pt++ = mv->chars[i]->unicodeenc; } *pt = '\0'; GGadgetSetTitle(mv->text,new); free(new ); } static void MVMenuLigatures(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SFShowLigatures(mv->sf,NULL); } static void MVMenuKernPairs(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SFShowKernPairs(mv->sf,NULL,NULL,mv->layer); } static void MVMenuAnchorPairs(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SFShowKernPairs(mv->sf,NULL,mi->ti.userdata,mv->layer); } static void _MVMenuScale( MetricsView *mv, int mid ) { if ( mid==MID_ZoomIn ) { if ( --mv->scale_index<0 ) mv->scale_index = 0; } else { if ( ++mv->scale_index >= sizeof(mv_scales)/sizeof(mv_scales[0]) ) mv->scale_index = sizeof(mv_scales)/sizeof(mv_scales[0])-1; } if ( mv->pixelsize_set_by_window ) { mv->pixelsize = mv_scales[mv->scale_index]*(mv->vheight - 2); if ( mv->bdf==NULL ) { BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->pixelsize,72,mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); } else mv->pixelsize_set_by_window = false; } MVReKern(mv); MVSetVSb(mv); } static void MVMenuScale(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); _MVMenuScale(mv,mi->mid); } static void MVMenuInsertChar(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SplineFont *sf = mv->sf; int i, j, pos = GotoChar(sf,mv->fv->b.map,NULL); if ( pos==-1 || pos>=mv->fv->b.map->enccount ) return; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) break; if ( i!=mv->glyphcnt ) /* Something selected */ /* Ok... */; else if ( mi->mid==MID_InsertCharA ) i = mv->glyphcnt; else i = 0; if ( mi->mid==MID_InsertCharA ) { if ( i!=mv->glyphcnt ) ++i; } else { if ( i==mv->glyphcnt ) i = 0; } if ( i==mv->glyphcnt ) i = mv->clen; else i = mv->glyphs[i].orig_index; /* Index in the string of chars, not glyphs */ if ( mv->clen+1>=mv->cmax ) { int oldmax=mv->cmax; mv->cmax = mv->clen+10; mv->chars = grealloc(mv->chars,mv->cmax*sizeof(SplineChar *)); memset(mv->chars+oldmax,'\0',(mv->cmax-oldmax)*sizeof(SplineChar *)); } for ( j=mv->clen; j>i; --j ) mv->chars[j] = mv->chars[j-1]; mv->chars[i] = SFMakeChar(sf,mv->fv->b.map,pos); ++mv->clen; MVRemetric(mv); for ( j=0; jglyphcnt; ++j ) if ( mv->glyphs[j].orig_index==i ) { MVDoSelect(mv,j); break; } GDrawRequestExpose(mv->v,NULL,false); MVResetText(mv); } static void MVMenuChangeChar(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SplineFont *sf = mv->sf; SplineChar *sc; EncMap *map = mv->fv->b.map; int i, pos, gid; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) break; if ( i!=mv->glyphcnt ) { pos = -1; i = mv->glyphs[i].orig_index; sc = mv->chars[ i ]; if ( mi->mid == MID_Next ) { pos = map->backmap[sc->orig_pos]+1; } else if ( mi->mid==MID_Prev ) { pos = map->backmap[sc->orig_pos]-1; } else if ( mi->mid==MID_NextDef ) { for ( pos = map->backmap[sc->orig_pos]+1; posenccount && ((gid=map->map[pos])==-1 || sf->glyphs[gid]==NULL); ++pos ); if ( pos>=map->enccount ) return; } else if ( mi->mid==MID_PrevDef ) { for ( pos = map->backmap[sc->orig_pos]-1; posenccount && ((gid=map->map[pos])==-1 || sf->glyphs[gid]==NULL); --pos ); if ( pos<0 ) return; } else if ( mi->mid==MID_ReplaceChar ) { pos = GotoChar(sf,mv->fv->b.map,NULL); if ( pos<0 || pos>=mv->fv->b.map->enccount) return; } if ( pos>=0 && posenccount ) { mv->chars[i] = SFMakeChar(sf,mv->fv->b.map,pos); MVRemetric(mv); MVResetText(mv); GDrawRequestExpose(mv->v,NULL,false); } } } static void MVMenuFindInFontView(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; for ( i=0; iglyphcnt; ++i ) { if ( mv->perchar[i].selected ) { FVChangeChar(mv->fv,mv->fv->b.map->backmap[mv->glyphs[i].sc->orig_pos]); GDrawSetVisible(mv->fv->gw,true); GDrawRaise(mv->fv->gw); break; } } } static void MVMenuShowGrid(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); if ( mi->mid == MID_ShowGrid ) mv->showgrid = mv_showgrid; else if ( mi->mid == MID_HideGrid ) mv->showgrid = mv_hidegrid; else if ( mi->mid == MID_PartialGrid ) mv->showgrid = mv_partialgrid; else if ( mi->mid == MID_HideGridWhenMoving ) mv->showgrid = mv_hidemovinggrid; mvshowgrid = mv->showgrid; SavePrefs(true); GDrawRequestExpose(mv->v,NULL,false); } static void MVMenuAA(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); mv_antialias = mv->antialias = !mv->antialias; mv->bdf = NULL; BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi, mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); GDrawRequestExpose(mv->v,NULL,false); } static void MVWindowTitle(char *buffer, int bufsize, MetricsView *mv) { snprintf(buffer,bufsize, mv->type == mv_kernonly ? _("Kerning Metrics For %.50s") : mv->type == mv_widthonly ? _("Advance Width Metrics For %.50s") : _("Metrics For %.50s"), mv->sf->fontname); } static void MVMenuWindowType(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); char buf[120]; mv_type = mv->type = mi->mid==MID_KernOnly ? mv_kernonly : mi->mid==MID_WidthOnly ? mv_widthonly : mv_kernwidth; MVWindowTitle(buf,sizeof(buf),mv); GDrawSetWindowTitles8(mv->gw, buf, buf); GDrawRequestExpose(mv->v,NULL,false); GDrawRequestExpose(mv->gw,NULL,false); } static void MVMenuVertical(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); if ( !mv->sf->hasvmetrics ) { if ( mv->vertical ) MVToggleVertical(mv); } else MVToggleVertical(mv); GDrawRequestExpose(mv->gw,NULL,false); GDrawRequestExpose(mv->v,NULL,false); } static void MVMenuShowBitmap(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); BDFFont *bdf = mi->ti.userdata; if ( mv->bdf!=bdf ) { mv->pixelsize_set_by_window = bdf==NULL; if ( bdf!=NULL ) { mv->pixelsize = mv->ptsize = bdf->pixelsize; mv->dpi = 72; } MVChangeDisplayFont(mv,bdf); GDrawRequestExpose(mv->v,NULL,false); } } #define CID_DPI 1002 #define CID_Size 1003 struct pxsz { MetricsView *mv; GWindow gw; int done; }; static int PXSZ_OK(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) { struct pxsz *pxsz = GDrawGetUserData(GGadgetGetWindow(g)); MetricsView *mv = pxsz->mv; int ptsize, dpi, err=0; ptsize = GetInt8( pxsz->gw, CID_Size, _("Point Size"), &err ); dpi = GetInt8( pxsz->gw, CID_DPI, _("DPI"), &err ); if ( err ) return(true); if ( ptsize<3 || ptsize>300 || dpi<10 || dpi > 2000 ) { ff_post_error(_("Number out of range"),_("Number out of range")); return( true ); } mv->pixelsize_set_by_window = false; mv->ptsize = ptsize; mv->dpi = dpi; mv->pixelsize = rint( (ptsize*dpi)/72.0 ); if ( mv->bdf==NULL ) BDFFontFree(mv->show); mv->bdf = NULL; mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi, mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); MVReKern(mv); MVSetVSb(mv); pxsz->done = 2; } return( true ); } static int PXSZ_Cancel(GGadget *g, GEvent *e) { if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) { struct pxsz *pxsz = GDrawGetUserData(GGadgetGetWindow(g)); pxsz->done = true; } return( true ); } static int pxsz_e_h(GWindow gw, GEvent *event) { struct pxsz *pxsz = GDrawGetUserData(gw); switch ( event->type ) { case et_char: return( false ); case et_close: pxsz->done = true; break; } return( true ); } static void MVMenuPointSize(GWindow mgw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(mgw); struct pxsz pxsz; GRect pos; GWindow gw; GWindowAttrs wattrs; GGadgetCreateData gcd[7], *hvarray[5][3], *barray[8], boxes[3]; GTextInfo label[7]; int i,k; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; char buffer[20], dbuffer[20]; memset(&pxsz,0,sizeof(pxsz)); pxsz.mv = mv; memset(&wattrs,0,sizeof(wattrs)); memset(&gcd,0,sizeof(gcd)); memset(&label,0,sizeof(label)); memset(&boxes,0,sizeof(boxes)); wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict; wattrs.event_masks = ~(1<ptsize/iscale )); label[k].text = (unichar_t *) buffer; label[k].text_is_1byte = true; gcd[k].gd.label = &label[k]; gcd[k].gd.flags = gg_visible|gg_enabled; gcd[k].gd.cid = CID_Size; gcd[k++].creator = GTextFieldCreate; hvarray[i][1] = &gcd[k-1]; hvarray[i++][2] = NULL; label[k].text = (unichar_t *) _("DPI:"); label[k].text_is_1byte = true; gcd[k].gd.label = &label[k]; gcd[k].gd.flags = gg_visible|gg_enabled ; /*gcd[k].gd.handle_controlevent = SS_ScriptChanged;*/ gcd[k++].creator = GLabelCreate; hvarray[i][0] = &gcd[k-1]; sprintf( dbuffer, "%d", mv->dpi ); label[k].text = (unichar_t *) dbuffer; label[k].text_is_1byte = true; gcd[k].gd.label = &label[k]; gcd[k].gd.flags = gg_visible|gg_enabled; gcd[k].gd.cid = CID_DPI; gcd[k++].creator = GTextFieldCreate; hvarray[i][1] = &gcd[k-1]; hvarray[i++][2] = NULL; label[k].text = (unichar_t *) _("_OK"); label[k].text_is_1byte = true; label[k].text_in_resource = true; gcd[k].gd.label = &label[k]; gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_default; gcd[k].gd.handle_controlevent = PXSZ_OK; gcd[k++].creator = GButtonCreate; label[k].text = (unichar_t *) _("_Cancel"); label[k].text_is_1byte = true; label[k].text_in_resource = true; gcd[k].gd.label = &label[k]; gcd[k].gd.flags = gg_visible|gg_enabled | gg_but_cancel; gcd[k].gd.handle_controlevent = PXSZ_Cancel; gcd[k++].creator = GButtonCreate; barray[0] = barray[2] = barray[3] = barray[4] = barray[6] = GCD_Glue; barray[7] = NULL; barray[1] = &gcd[k-2]; barray[5] = &gcd[k-1]; hvarray[i][0] = &boxes[2]; hvarray[i][1] = GCD_ColSpan; hvarray[i++][2] = NULL; hvarray[i][0] = NULL; memset(boxes,0,sizeof(boxes)); boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2; boxes[0].gd.flags = gg_enabled|gg_visible; boxes[0].gd.u.boxelements = hvarray[0]; boxes[0].creator = GHVGroupCreate; boxes[2].gd.flags = gg_enabled|gg_visible; boxes[2].gd.u.boxelements = barray; boxes[2].creator = GHBoxCreate; GGadgetsCreate(gw,boxes); GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame); GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue); GHVBoxFitWindow(boxes[0].ret); GDrawSetVisible(gw,true); while ( !pxsz.done ) GDrawProcessOneEvent(NULL); GDrawDestroyWindow(gw); } static void MVMenuSizeWindow(GWindow mgw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(mgw); mv->pixelsize_set_by_window = true; mv->pixelsize = mv_scales[mv->scale_index]*(mv->vheight - 2); mv->dpi = 72; mv->ptsize = mv->pixelsize; if ( mv->bdf==NULL ) { BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->pixelsize,72,mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); } MVReKern(mv); MVSetVSb(mv); } static void MVMenuChangePointSize(GWindow mgw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(mgw); if ( mv->pixelsize_set_by_window ) return; if ( mi->mid==MID_Bigger ) ++(mv->ptsize); else --(mv->ptsize); mv->pixelsize = rint( (mv->ptsize*mv->dpi)/72.0 ); if ( mv->bdf==NULL ) BDFFontFree(mv->show); mv->bdf = NULL; mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi, mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); MVReKern(mv); MVSetVSb(mv); } static void MVMenuChangeLayer(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); mv->layer = mi->mid; BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi, mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } static void MVMenuCenter(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; DBounds bb; real transform[6]; SplineChar *sc; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) break; if ( i!=mv->glyphcnt ) { sc = mv->glyphs[i].sc; transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0.0; SplineCharFindBounds(sc,&bb); if ( mi->mid==MID_Center ) transform[4] = (sc->width-(bb.maxx-bb.minx))/2 - bb.minx; else transform[4] = (sc->width-(bb.maxx-bb.minx))/3 - bb.minx; if ( transform[4]!=0 ) FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,fvt_dontmovewidth); } } static void MVMenuKernByClasses(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); ShowKernClasses(mv->sf,mv,mv->layer,false); } static void MVMenuVKernByClasses(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); ShowKernClasses(mv->sf,mv,mv->layer,true); } static void MVMenuVKernFromHKern(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); FVVKernFromHKern((FontViewBase *) mv->fv); } static void MVMenuKPCloseup(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SplineChar *sc1=NULL, *sc2=NULL; int i; for ( i=0; iglyphcnt; ++i ) if ( mv->perchar[i].selected ) { sc1 = mv->glyphs[i].sc; if ( i+1glyphcnt ) sc2 = mv->glyphs[i+1].sc; break; } KernPairD(mv->sf,sc1,sc2,mv->layer,mv->vertical); } static GMenuItem2 wnmenu[] = { { { (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|Ctl+H"), NULL, NULL, MVMenuOpenOutline, MID_OpenOutline }, { { (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|Ctl+J"), NULL, NULL, MVMenuOpenBitmap, MID_OpenBitmap }, { { (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|Ctl+K"), NULL, NULL, /* No function, never avail */NULL }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { NULL } }; static void MVWindowMenuBuild(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; SplineChar *sc; struct gmenuitem *wmi; WindowMenuBuild(gw,mi,e); for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) sc = NULL; else sc = mv->glyphs[i].sc; for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) { switch ( wmi->mid ) { case MID_OpenOutline: wmi->ti.disabled = sc==NULL; break; case MID_OpenBitmap: mi->ti.disabled = mv->sf->bitmaps==NULL || sc==NULL; break; case MID_Warnings: wmi->ti.disabled = ErrorWindowExists(); break; } } } static GMenuItem2 dummyitem[] = { { (unichar_t *) N_("Font|_New"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, NULL }; static GMenuItem2 fllist[] = { { { (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|Ctl+N"), NULL, NULL, MenuNew }, { { (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|Ctl+O"), NULL, NULL, MenuOpen }, { { (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 }, { { (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|Ctl+Shft+Q"), NULL, NULL, MVMenuClose }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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|Ctl+S"), NULL, NULL, MVMenuSave }, { { (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...|Ctl+Shft+S"), NULL, NULL, MVMenuSaveAs }, { { (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...|Ctl+Shft+G"), NULL, NULL, MVMenuGenerate }, { { (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...|Alt+Ctl+G"), NULL, NULL, MVMenuGenerateFamily }, { { (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 }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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...|Ctl+Shft+K"), NULL, NULL, MVMenuMergeKern }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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...|Ctl+P"), NULL, NULL, MVMenuPrint }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { { (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 }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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|Ctl+Q"), NULL, NULL, MenuExit }, { NULL } }; static GMenuItem2 edlist[] = { { { (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|Ctl+Z"), NULL, NULL, MVUndo, MID_Undo }, { { (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|Ctl+Y"), NULL, NULL, MVRedo, MID_Redo }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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|Ctl+X"), NULL, NULL, MVCut, MID_Cut }, { { (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|Ctl+C"), NULL, NULL, MVCopy, MID_Copy }, { { (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|Ctl+G"), NULL, NULL, MVMenuCopyRef, MID_CopyRef }, { { (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|Ctl+W"), NULL, NULL, MVMenuCopyWidth, MID_CopyWidth }, { { (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 }, { { (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 }, { { (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 }, { { (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|Ctl+V"), NULL, NULL, MVPaste, MID_Paste }, { { (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 }, { { (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|Ctl+Shft+J"), NULL, NULL, MVMenuJoin, MID_Join }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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|Ctl+A"), NULL, NULL, MVSelectAll, MID_SelAll }, { { (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 }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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|Ctl+U"), NULL, NULL, MVUnlinkRef, MID_UnlinkRef }, { NULL } }; static GMenuItem2 smlist[] = { { { (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|Ctl+Shft+M"), NULL, NULL, MVMenuSimplify, MID_Simplify }, { { (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...|Alt+Ctl+Shft+M"), NULL, NULL, MVMenuSimplifyMore, MID_SimplifyMore }, { { (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 }, { NULL } }; static GMenuItem2 rmlist[] = { { { (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|Ctl+Shft+O"), NULL, NULL, MVMenuOverlap, MID_RmOverlap }, { { (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 }, { { (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 }, { NULL } }; static GMenuItem2 eflist[] = { { { (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 }, { { (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 }, { { (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 }, { { (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 }, { NULL } }; static GMenuItem2 balist[] = { { { (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|Ctl+Shft+A"), NULL, NULL, MVMenuBuildAccent, MID_BuildAccent }, { { (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 }, { NULL } }; static void balistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; SplineChar *sc; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) sc = NULL; else sc = mv->glyphs[i].sc; for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_BuildAccent: mi->ti.disabled = sc==NULL || !SFIsSomethingBuildable(sc->parent,sc,mv->layer,true); break; case MID_BuildComposite: mi->ti.disabled = sc==NULL || !SFIsSomethingBuildable(sc->parent,sc,mv->layer,false); break; } } } static GMenuItem2 ellist[] = { { { (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...|Ctl+Shft+F"), NULL, NULL, MVMenuFontInfo }, { { (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...|Ctl+I"), NULL, NULL, MVMenuCharInfo, MID_CharInfo }, { { (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|Alt+Ctl+I"), NULL, NULL, MVMenuShowDependents, MID_ShowDependents }, { { (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...|Ctl+E"), NULL, NULL, MVMenuFindProblems, MID_FindProblems }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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...|Ctl+Shft+B"), NULL, NULL, MVMenuBitmaps, MID_AvailBitmaps }, { { (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...|Ctl+B"), NULL, NULL, MVMenuBitmaps, MID_RegenBitmaps }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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...|Ctl+\\"), NULL, NULL, MVMenuTransform, MID_Transform }, #ifdef FONTFORGE_CONFIG_TILEPATH { { (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 }, #endif { { (unichar_t *) N_("_Remove Overlap"), (GImage *) "rmoverlap.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'O' }, NULL, rmlist, NULL, NULL, MID_RmOverlap }, { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, NULL, smlist, NULL, NULL, MID_Simplify }, { { (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|Ctl+Shft+X"), NULL, NULL, MVMenuAddExtrema, MID_AddExtrema }, { { (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|Ctl+Shft+_"), NULL, NULL, MVMenuRound2Int, MID_Round }, { { (unichar_t *) N_("Effects"), (GImage *) "elementstyles.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, NULL, eflist, NULL, NULL, MID_Effects }, { { (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|Ctl+Shft+T"), NULL, NULL, MVMenuAutotrace, MID_Autotrace }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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|Ctl+Shft+D"), NULL, NULL, MVMenuCorrectDir, MID_Correct }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (unichar_t *) N_("B_uild"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, NULL, balist, balistcheck, NULL, MID_BuildAccent }, { NULL } }; static GMenuItem2 dummyall[] = { { { (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 }, NULL }; /* Builds up a menu containing all the anchor classes */ static void aplistbuild(GWindow base,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(base); extern void GMenuItemArrayFree(GMenuItem *mi); GMenuItemArrayFree(mi->sub); mi->sub = NULL; _aplistbuild(mi,mv->sf,MVMenuAnchorPairs); } static GMenuItem2 cblist[] = { { { (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 }, { { (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 }, { { (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 }, NULL }; static void cblistcheck(GWindow gw,struct gmenuitem *mi, GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SplineFont *sf = mv->sf; int i, anyligs=0, anykerns=0; PST *pst; for ( i=0; iglyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { for ( pst=sf->glyphs[i]->possub; pst!=NULL; pst=pst->next ) { if ( pst->type==pst_ligature ) { anyligs = true; if ( anykerns ) break; } } if ( (mv->vertical ? sf->glyphs[i]->vkerns : sf->glyphs[i]->kerns)!=NULL ) { anykerns = true; if ( anyligs ) break; } } for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_Ligatures: mi->ti.disabled = !anyligs; break; case MID_KernPairs: mi->ti.disabled = !anykerns; break; case MID_AnchorPairs: mi->ti.disabled = sf->anchor==NULL; break; } } } static GMenuItem2 lylist[] = { { { (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 }, NULL }; static void lylistcheck(GWindow gw,struct gmenuitem *mi, GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SplineFont *sf = mv->fv->b.sf; extern void GMenuItemArrayFree(GMenuItem *mi); int ly; GMenuItem *sub; sub = gcalloc(sf->layer_cnt+1,sizeof(GMenuItem)); for ( ly=ly_fore; lylayer_cnt; ++ly ) { sub[ly-1].ti.text = utf82u_copy(sf->layers[ly].name); sub[ly-1].ti.checkable = true; sub[ly-1].ti.checked = ly == mv->layer; sub[ly-1].invoke = MVMenuChangeLayer; sub[ly-1].mid = ly; sub[ly-1].ti.fg = sub[ly-1].ti.bg = COLOR_DEFAULT; } GMenuItemArrayFree(mi->sub); mi->sub = sub; } static GMenuItem2 gdlist[] = { { { (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 }, { { (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 }, { { (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 }, { { (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 }, { NULL } }; static void gdlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_ShowGrid: mi->ti.checked = mv->showgrid == mv_showgrid; break; case MID_HideGrid: mi->ti.checked = mv->showgrid == mv_hidegrid; break; case MID_PartialGrid: mi->ti.checked = mv->showgrid == mv_partialgrid; break; case MID_HideGridWhenMoving: mi->ti.checked = mv->showgrid == mv_hidemovinggrid; break; } } } static GMenuItem2 vwlist[] = { { { (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|Alt+Ctl+-"), NULL, NULL, MVMenuScale, MID_ZoomOut }, { { (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|Alt+Ctl+Shft++"), NULL, NULL, MVMenuScale, MID_ZoomIn }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { { (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 }, { { (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...|Ctl+G"), NULL, NULL, MVMenuChangeChar, MID_ReplaceChar }, { { (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|Ctl+]"), NULL, NULL, MVMenuChangeChar, MID_Next }, { { (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|Ctl+["), NULL, NULL, MVMenuChangeChar, MID_Prev }, { { (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|Alt+Ctl+]"), NULL, NULL, MVMenuChangeChar, MID_NextDef }, { { (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|Alt+Ctl+["), NULL, NULL, MVMenuChangeChar, MID_PrevDef }, { { (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|Ctl+Shft+<"), NULL, NULL, MVMenuFindInFontView, MID_FindInFontView }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (unichar_t *) N_("_Layers"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, NULL, lylist, lylistcheck }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (unichar_t *) N_("Com_binations"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'b' }, NULL, cblist, cblistcheck }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (unichar_t *) N_("Show _Grid"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, NULL, gdlist, gdlistcheck, MVMenuShowGrid, MID_ShowGrid }, { { (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|Ctl+="), NULL, NULL, MVMenuAA, MID_AntiAlias }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { { (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 }, { { (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|Ctl+Shft++"), NULL, NULL, MVMenuChangePointSize, MID_Bigger }, { { (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|Ctl+-"), NULL, NULL, MVMenuChangePointSize, MID_Smaller }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { NULL }, /* Some extra room to show bitmaps */ { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL }, { NULL } }; static void MVMenuContextualHelp(GWindow base,struct gmenuitem *mi,GEvent *e) { help("metricsview.html"); } static GMenuItem2 tylist[] = { { { (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 }, { { (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 }, { { (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 }, { NULL } }; static void tylistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_KernOnly: mi->ti.checked = mv->type == mv_kernonly; break; case MID_WidthOnly: mi->ti.checked = mv->type == mv_widthonly; break; case MID_BothKernWidth: mi->ti.checked = mv->type == mv_kernwidth; break; } } } static GMenuItem2 mtlist[] = { { { (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 }, { { (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 }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (unichar_t *) N_("_Window Type"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, NULL, tylist, tylistcheck }, { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, }}, { { (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 }, { { (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 }, { { (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 }, { { (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 }, { NULL } }; static void fllistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { /*MetricsView *mv = (MetricsView *) GDrawGetUserData(gw);*/ for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_Recent: mi->ti.disabled = !RecentFilesAny(); break; } } } static void edlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i; if ( GWindowGetFocusGadgetOfWindow(gw)!=NULL ) i = -1; else for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_Cut: case MID_Copy: #if 0 /* Copy/Cut should always be enabled so textfields will get the event */ mi->ti.disabled = i==-1; #endif break; case MID_Join: case MID_CopyRef: case MID_CopyWidth: case MID_CopyLBearing: case MID_CopyRBearing: case MID_Clear: mi->ti.disabled = i==-1; break; case MID_CopyVWidth: mi->ti.disabled = i==-1 || !mv->sf->hasvmetrics; break; #if 0 /* Undo/Redo should always be enabled so textfields will get the event */ case MID_Undo: mi->ti.disabled = i==-1 || mv->glyphs[i].sc->layers[mv->layer].undoes==NULL; break; case MID_Redo: mi->ti.disabled = i==-1 || mv->glyphs[i].sc->layers[mv->layer].redoes==NULL; break; #endif case MID_UnlinkRef: mi->ti.disabled = i==-1 || mv->glyphs[i].sc->layers[mv->layer].refs==NULL; break; case MID_Paste: #if 0 /* Paste should always be enabled so textfields will get the event */ mi->ti.disabled = i==-1 || (!CopyContainsSomething() && #ifndef _NO_LIBPNG !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/png") && #endif #ifndef _NO_LIBXML !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/svg+xml") && !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/svg-xml") && !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/svg") && #endif !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/bmp") && !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/ps") && !GDrawSelectionHasType(mv->gw,sn_clipboard,"image/eps")); #endif break; } } } static void ellistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i, anybuildable; SplineChar *sc; int order2 = mv->sf->layers[mv->layer].order2; for ( i=mv->glyphcnt-1; i>=0; --i ) if ( mv->perchar[i].selected ) break; if ( i==-1 ) sc = NULL; else sc = mv->glyphs[i].sc; for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_RegenBitmaps: mi->ti.disabled = mv->sf->bitmaps==NULL; break; case MID_CharInfo: mi->ti.disabled = sc==NULL /*|| mv->fv->b.cidmaster!=NULL*/; break; case MID_ShowDependents: mi->ti.disabled = sc==NULL || sc->dependents == NULL; break; case MID_FindProblems: case MID_Transform: mi->ti.disabled = sc==NULL; break; case MID_Effects: mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps || order2; break; case MID_RmOverlap: case MID_Stroke: mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps; break; case MID_AddExtrema: case MID_Round: case MID_Correct: mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps; break; #ifdef FONTFORGE_CONFIG_TILEPATH case MID_TilePath: mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps || ClipBoardToSplineSet()==NULL || order2; break; #endif case MID_Simplify: mi->ti.disabled = sc==NULL || mv->sf->onlybitmaps; break; case MID_BuildAccent: anybuildable = false; if ( sc!=NULL && SFIsSomethingBuildable(mv->sf,sc,mv->layer,false) ) anybuildable = true; mi->ti.disabled = !anybuildable; break; case MID_Autotrace: mi->ti.disabled = !(FindAutoTraceName()!=NULL && sc!=NULL && sc->layers[ly_back].images!=NULL ); break; } } } static void vwlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); int i, j, base, aselection; BDFFont *bdf; char buffer[60]; extern void GMenuItemArrayFree(GMenuItem *mi); extern GMenuItem *GMenuItem2ArrayCopy(GMenuItem2 *mi, uint16 *cnt); aselection = false; for ( j=0; jglyphcnt; ++j ) if ( mv->perchar[j].selected ) { aselection = true; break; } for ( i=0; vwlist[i].mid!=MID_Outline; ++i ) switch ( vwlist[i].mid ) { case MID_ZoomIn: vwlist[i].ti.disabled = mv->scale_index==0; break; case MID_ZoomOut: vwlist[i].ti.disabled = mv->scale_index>=sizeof(mv_scales)/sizeof(mv_scales[0])-1; break; case MID_AntiAlias: vwlist[i].ti.checked = mv->antialias; vwlist[i].ti.disabled = mv->bdf!=NULL; break; case MID_SizeWindow: vwlist[i].ti.disabled = mv->pixelsize_set_by_window; vwlist[i].ti.checked = mv->pixelsize_set_by_window; break; case MID_Bigger: case MID_Smaller: vwlist[i].ti.disabled = mv->pixelsize_set_by_window; break; case MID_ReplaceChar: case MID_FindInFontView: case MID_Next: case MID_Prev: case MID_NextDef: case MID_PrevDef: vwlist[i].ti.disabled = !aselection; break; case MID_Vertical: vwlist[i].ti.checked = mv->vertical; vwlist[i].ti.disabled = !mv->sf->hasvmetrics; break; case MID_Layers: vwlist[i].ti.disabled = mv->sf->layer_cnt<=2 || mv->sf->multilayer; break; } vwlist[i].ti.checked = mv->bdf==NULL; base = i+1; for ( i=base; vwlist[i].ti.text!=NULL || vwlist[i].ti.line; ++i ) { free( vwlist[i].ti.text); vwlist[i].ti.text = NULL; } if ( mv->sf->bitmaps!=NULL ) { for ( bdf = mv->sf->bitmaps, i=base; inext ) { if ( BDFDepth(bdf)==1 ) sprintf( buffer, _("%d pixel bitmap"), bdf->pixelsize ); else sprintf( buffer, _("%d@%d pixel bitmap"), bdf->pixelsize, BDFDepth(bdf) ); vwlist[i].ti.text = utf82u_copy(buffer); vwlist[i].ti.checkable = true; vwlist[i].ti.checked = bdf==mv->bdf; vwlist[i].ti.userdata = bdf; vwlist[i].invoke = MVMenuShowBitmap; vwlist[i].ti.fg = vwlist[i].ti.bg = COLOR_DEFAULT; } } GMenuItemArrayFree(mi->sub); mi->sub = GMenuItem2ArrayCopy(vwlist,NULL); } static void mtlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) { switch ( mi->mid ) { case MID_VKernClass: case MID_VKernFromHKern: mi->ti.disabled = !mv->sf->hasvmetrics; break; } } } static GMenuItem2 mblist[] = { { { (unichar_t *) N_("_File"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, NULL, fllist, fllistcheck }, { { (unichar_t *) N_("_Edit"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, NULL, edlist, edlistcheck }, { { (unichar_t *) N_("E_lement"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, NULL, ellist, ellistcheck }, { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, NULL, vwlist, vwlistcheck }, { { (unichar_t *) N_("_Metrics"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, NULL, mtlist, mtlistcheck }, { { (unichar_t *) N_("_Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, NULL, wnmenu, MVWindowMenuBuild, NULL }, { { (unichar_t *) N_("_Help"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, NULL, helplist, NULL }, { NULL } }; static void MVResize(MetricsView *mv) { GRect pos, wsize; int i; int size; GDrawGetSize(mv->gw,&wsize); if ( wsize.height < mv->topend+20 + mv->height-mv->displayend || wsize.width < 30 ) { int width= wsize.width < 30 ? 30 : wsize.width; int height; if ( wsize.height < mv->topend+20 + mv->height-mv->displayend ) height = mv->topend+20 + mv->height-mv->displayend; else height = wsize.height; GDrawResize(mv->gw,width,height); return; } mv->width = wsize.width; mv->displayend = wsize.height - (mv->height-mv->displayend); mv->height = wsize.height; mv_width = wsize.width; mv_height = wsize.height; SavePrefs(true); pos.width = wsize.width; pos.height = mv->sbh; pos.y = wsize.height - pos.height; pos.x = 0; GGadgetResize(mv->hsb,pos.width,pos.height); GGadgetMove(mv->hsb,pos.x,pos.y); mv->dwidth = mv->width - mv->sbh; GGadgetResize(mv->vsb,mv->sbh,mv->displayend-mv->topend); GGadgetMove(mv->vsb,wsize.width-mv->sbh,mv->topend); GGadgetResize(mv->features,mv->xstart,mv->displayend - mv->topend); size = (mv->displayend - mv->topend - 4); if ( mv->dwidth-20dwidth-20; if ( mv->pixelsize_set_by_window ) { mv->ptsize = mv->pixelsize = mv_scales[mv->scale_index]*size; mv->dpi = 72; if ( mv->bdf==NULL ) { BDFFontFree(mv->show); mv->show = SplineFontPieceMeal(mv->sf,mv->layer,mv->ptsize,mv->dpi, mv->antialias?(pf_antialias|pf_ft_recontext):pf_ft_recontext,NULL); } } for ( i=0; imax; ++i ) if ( mv->perchar[i].width!=NULL ) { GGadgetMove(mv->perchar[i].name,mv->perchar[i].mx,mv->displayend+2); GGadgetMove(mv->perchar[i].width,mv->perchar[i].mx,mv->displayend+2+mv->fh+4); GGadgetMove(mv->perchar[i].lbearing,mv->perchar[i].mx,mv->displayend+2+2*(mv->fh+4)); GGadgetMove(mv->perchar[i].rbearing,mv->perchar[i].mx,mv->displayend+2+3*(mv->fh+4)); if ( mv->perchar[i].kern!=NULL ) GGadgetMove(mv->perchar[i].kern,mv->perchar[i].mx-mv->perchar[i].mwidth/2,mv->displayend+2+4*(mv->fh+4)); } GGadgetMove(mv->namelab,2,mv->displayend+2); GGadgetMove(mv->widthlab,2,mv->displayend+2+mv->fh+4); GGadgetMove(mv->lbearinglab,2,mv->displayend+2+2*(mv->fh+4)); GGadgetMove(mv->rbearinglab,2,mv->displayend+2+3*(mv->fh+4)); GGadgetMove(mv->kernlab,2,mv->displayend+2+4*(mv->fh+4)); mv->vwidth = mv->dwidth-mv->xstart; mv->vheight = mv->displayend-mv->topend-2; GDrawResize(mv->v,mv->vwidth, mv->vheight); MVRemetric(mv); GDrawRequestExpose(mv->gw,NULL,true); GDrawRequestExpose(mv->v,NULL,true); } static void MVChar(MetricsView *mv,GEvent *event) { if ( event->u.chr.keysym=='s' && (event->u.chr.state&ksm_control) && (event->u.chr.state&ksm_meta) ) MenuSaveAll(NULL,NULL,NULL); else if ( event->u.chr.keysym=='I' && (event->u.chr.state&ksm_shift) && (event->u.chr.state&ksm_meta) ) MVMenuCharInfo(mv->gw,NULL,NULL); else if ( event->u.chr.keysym == GK_Help ) { MenuHelp(NULL,NULL,NULL); /* Menu does F1 */ } else if ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up || event->u.chr.keysym == GK_Down || event->u.chr.keysym==GK_KP_Down ) { int dir = ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ) ? -1 : 1; if ( mv->word_index!=-1 ) { int32 len; GTextInfo **ti = GGadgetGetList(mv->text,&len); /* We subtract 3 because: There are two lines saying "load * list" */ /* and then a line with a rule on it which we don't want access to */ if ( mv->word_index+dir >=0 && mv->word_index+dirword_index += dir; GGadgetSelectOneListItem(mv->text,mv->word_index); tit = _GGadgetGetTitle(mv->text); if ( tit!=NULL && tit[0]==0x200b ) MVFigureGlyphNames(mv,tit+1); else MVTextChanged(mv); ti = NULL; } } } } static int hitsbit(BDFChar *bc, int x, int y) { if ( bc->byte_data ) return( bc->bitmap[y*bc->bytes_per_line+x] ); else return( bc->bitmap[y*bc->bytes_per_line+(x>>3)]&(1<<(7-(x&7))) ); } static void _MVSubVMouse(MetricsView *mv,GEvent *event) { int i, x, y, j, within, xbase; SplineChar *sc; int diff; int onwidth, onkern; SplineFont *sf = mv->sf; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; double scale = iscale*mv->pixelsize/(double) (sf->ascent+sf->descent); int as = rint(sf->ascent*scale); xbase = mv->vwidth/2; within = -1; for ( i=0; iglyphcnt; ++i ) { y = mv->perchar[i].dy + mv->perchar[i].yoff; x = xbase - mv->pixelsize*iscale/2 - mv->perchar[i].xoff; if ( mv->bdf==NULL ) { BDFChar *bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos); if ( event->u.mouse.x >= x+bdfc->xmin && event->u.mouse.x <= x+bdfc->xmax && event->u.mouse.y <= (y+as)-bdfc->ymin && event->u.mouse.y >= (y+as)-bdfc->ymax && hitsbit(bdfc,rint(iscale*(event->u.mouse.x-x-bdfc->xmin)), rint(iscale*(event->u.mouse.y-(y+as-bdfc->ymax)))) ) break; } y += -mv->perchar[i].yoff; if ( event->u.mouse.y >= y && event->u.mouse.y < y+mv->perchar[i].dheight+ mv->perchar[i].kernafter ) within = i; } if ( i==mv->glyphcnt ) sc = NULL; else sc = mv->glyphs[i].sc; diff = event->u.mouse.y-mv->pressed_y; onwidth = onkern = false; if ( sc==NULL ) { if ( mv->type == mv_kernonly ) { if ( within!=-1 && within+1glyphcnt && event->u.mouse.y>mv->perchar[within+1].dy-3 ) { onkern = true; /* subsequent char */ ++within; } else if ( within>0 && event->u.mouse.yperchar[within].dy+3 ) onkern = true; } else if ( mv->type == mv_widthonly ) { if ( within!=-1 && within+1glyphcnt && event->u.mouse.y>mv->perchar[within+1].dy-3 ) onwidth = true; /* subsequent char */ else if ( within>=0 && event->u.mouse.y>mv->perchar[within].dy+mv->perchar[within].dheight+mv->perchar[within].kernafter-3 ) { onwidth = true; } } else { if ( within>0 && mv->perchar[within-1].selected && event->u.mouse.yperchar[within].dy+3 ) onwidth = true; /* previous char */ else if ( within!=-1 && within+1glyphcnt && mv->perchar[within+1].selected && event->u.mouse.y>mv->perchar[within+1].dy-3 ) { onkern = true; /* subsequent char */ ++within; } else if ( within>0 && mv->perchar[within].selected && event->u.mouse.yperchar[within].dy+3 ) onkern = true; else if ( within>=0 && event->u.mouse.y>mv->perchar[within].dy+mv->perchar[within].dheight+mv->perchar[within].kernafter-3 ) { onwidth = true; } } } if ( event->type != et_mousemove || !mv->pressed ) { int ct = -1; if ( mv->bdf!=NULL || ( mv->type==mv_kernonly && !onkern ) || ( mv->type==mv_widthonly && !onwidth )) { if ( mv->cursor!=ct_mypointer ) ct = ct_mypointer; } else if ( sc!=NULL ) { if ( mv->cursor!=ct_lbearing ) ct = ct_lbearing; } else if ( onwidth ) { if ( mv->cursor!=ct_rbearing ) ct = ct_rbearing; } else if ( onkern ) { if ( mv->cursor!=ct_kerning ) ct = ct_kerning; } else { if ( mv->cursor!=ct_mypointer ) ct = ct_mypointer; } if ( ct!=-1 ) { GDrawSetCursor(mv->gw,ct); mv->cursor = ct; } } if ( event->type == et_mousemove && !mv->pressed ) { if ( sc==NULL && within!=-1 ) sc = mv->glyphs[within].sc; if ( sc!=NULL ) SCPreparePopup(mv->gw,sc,mv->fv->b.map->remap,mv->fv->b.map->backmap[sc->orig_pos],sc->unicodeenc); /* Don't allow any editing when displaying a bitmap font */ } else if ( event->type == et_mousedown && mv->bdf==NULL ) { CVPaletteDeactivate(); if ( sc!=NULL ) { for ( j=0; jglyphcnt; ++j ) if ( j!=i && mv->perchar[j].selected ) MVDeselectChar(mv,j); MVSelectChar(mv,i); GWindowClearFocusGadgetOfWindow(mv->gw); mv->pressed = true; } else if ( within!=-1 ) { mv->pressedwidth = onwidth; mv->pressedkern = onkern; if ( mv->pressedwidth || mv->pressedkern ) { mv->pressed = true; if ( !mv->perchar[within].selected ) { MVDoSelect(mv,within); } } #if 0 } else if ( event->u.mouse.yperchar[mv->glyphcnt-1].dy+ mv->perchar[mv->glyphcnt-1].dheight+ mv->perchar[mv->glyphcnt-1].kernafter+3 && mv->type!=mv_kernonly ) { mv->pressed = mv->pressedwidth = true; GDrawSetCursor(mv->gw,ct_rbearing); mv->cursor = ct_rbearing; if ( !mv->perchar[mv->glyphcnt-1].selected ) MVDoSelect(mv,mv->glyphcnt-1); #endif } mv->pressed_y = event->u.mouse.y; } else if ( event->type == et_mousemove && mv->pressed ) { for ( i=0; iglyphcnt && !mv->perchar[i].selected; ++i ); if ( mv->pressedwidth ) { int ow = mv->perchar[i].dwidth; mv->perchar[i].dwidth = rint(mv->glyphs[i].sc->vwidth*scale) + diff; if ( ow!=mv->perchar[i].dwidth ) { for ( j=i+1; jglyphcnt; ++j ) mv->perchar[j].dy = mv->perchar[j-1].dy+mv->perchar[j-1].dheight+ mv->perchar[j-1].kernafter; GDrawRequestExpose(mv->v,NULL,false); } } else if ( mv->pressedkern ) { int ow = mv->perchar[i-1].kernafter; KernPair *kp; int kpoff; KernClass *kc; kp = mv->glyphs[i-1].kp; if ( kp!=NULL ) kpoff = kp->off; else if ((kc=mv->glyphs[i-1].kc)!=NULL ) kpoff = kc->offsets[mv->glyphs[i-1].kc_index]; else kpoff = 0; kpoff = kpoff * mv->pixelsize*iscale / (mv->sf->descent+mv->sf->ascent); mv->perchar[i-1].kernafter = kpoff + diff; if ( ow!=mv->perchar[i-1].kernafter ) { for ( j=i; jglyphcnt; ++j ) mv->perchar[j].dy = mv->perchar[j-1].dy+mv->perchar[j-1].dheight+ mv->perchar[j-1].kernafter; GDrawRequestExpose(mv->v,NULL,false); } } else if ( mv->type!=mv_kernonly ) { int olda = mv->activeoff; BDFChar *bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos); mv->activeoff = diff; MVRedrawI(mv,i,bdfc->xmin+olda,bdfc->xmax+olda); } } else if ( event->type == et_mouseup && event->u.mouse.clicks>1 && (within!=-1 || sc!=NULL)) { mv->pressed = false; mv->activeoff = 0; mv->pressedwidth = mv->pressedkern = false; if ( within==-1 ) within = i; if ( mv->bdf==NULL ) CharViewCreate(mv->glyphs[within].sc,mv->fv,-1); else BitmapViewCreate(mv->bdf->glyphs[mv->glyphs[within].sc->orig_pos],mv->bdf,mv->fv,-1); if ( mv->showgrid==mv_hidemovinggrid ) GDrawRequestExpose(mv->v,NULL,false); } else if ( event->type == et_mouseup && mv->pressed ) { for ( i=0; iglyphcnt && !mv->perchar[i].selected; ++i ); mv->pressed = false; mv->activeoff = 0; sc = mv->glyphs[i].sc; if ( mv->pressedwidth ) { mv->pressedwidth = false; diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale); if ( diff!=0 ) { SCPreserveWidth(sc); sc->vwidth += diff; SCCharChangedUpdate(sc,ly_none); for ( ; iglyphcnt; ++i ) mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight + mv->perchar[i-1].kernafter ; GDrawRequestExpose(mv->v,NULL,false); } else if ( mv->showgrid==mv_hidemovinggrid ) GDrawRequestExpose(mv->v,NULL,false); } else if ( mv->pressedkern ) { mv->pressedkern = false; diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale); if ( diff!=0 ) MV_ChangeKerning(mv, i, diff, true); MVRefreshValues(mv,i-1); } else if ( mv->type!=mv_kernonly ) { real transform[6]; DBounds bb; SplineCharFindBounds(sc,&bb); transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[4] = 0; transform[5] = -diff* (mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale); if ( transform[5]!=0 ) FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,false); } mv->pressedwidth = false; mv->pressedkern = false; } else if ( event->type == et_mouseup && mv->bdf!=NULL && within!=-1 ) { for ( j=0; jglyphcnt; ++j ) if ( j!=within && mv->perchar[j].selected ) MVDeselectChar(mv,j); MVSelectChar(mv,within); if ( mv->showgrid==mv_hidemovinggrid ) GDrawRequestExpose(mv->v,NULL,false); } } static void MVSubMouse(MetricsView *mv,GEvent *event) { int i, x, y, j, within, ybase; SplineChar *sc; int diff; int onwidth, onkern; BDFChar *bdfc; double iscale = mv->pixelsize_set_by_window ? 1.0 : mv_scales[mv->scale_index]; GGadgetEndPopup(); if ( event->type==et_mouseup ) { event->type = et_mousemove; MVSubMouse(mv,event); event->u.mouse.x -= mv->xoff; event->u.mouse.y -= mv->yoff; event->type = et_mouseup; } event->u.mouse.x += mv->xoff; event->u.mouse.y += mv->yoff; if ( mv->vertical ) { _MVSubVMouse(mv,event); return; } ybase = mv->ybaseline - mv->yoff; within = -1; for ( i=0; iglyphcnt; ++i ) { x = mv->perchar[i].dx + mv->perchar[i].xoff; if ( mv->right_to_left ) x = mv->vwidth - x - mv->perchar[i].dwidth - mv->perchar[i].kernafter; y = ybase - mv->perchar[i].yoff; if ( mv->bdf==NULL ) { bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos); if ( event->u.mouse.x >= x+bdfc->xmin && event->u.mouse.x <= x+bdfc->xmax && event->u.mouse.y <= y-bdfc->ymin && event->u.mouse.y >= y-bdfc->ymax && hitsbit(bdfc,rint(iscale*(event->u.mouse.x-x-bdfc->xmin)), rint(iscale*(bdfc->ymax-(y-event->u.mouse.y)))) ) break; } x += mv->right_to_left ? mv->perchar[i].xoff : -mv->perchar[i].xoff; if ( event->u.mouse.x >= x && event->u.mouse.x < x+mv->perchar[i].dwidth+ mv->perchar[i].kernafter ) within = i; } if ( i==mv->glyphcnt ) sc = NULL; else sc = mv->glyphs[i].sc; diff = event->u.mouse.x-mv->pressed_x; /*if ( mv->right_to_left ) diff = -diff;*/ onwidth = onkern = false; if ( sc==NULL ) { if ( !mv->right_to_left ) { if ( mv->type == mv_kernonly ) { if ( within>=0 && within+1glyphcnt && event->u.mouse.x>mv->perchar[within+1].dx-3 ) { onkern = true; /* subsequent char */ ++within; } else if ( within>0 && event->u.mouse.xperchar[within].dx+3 ) onkern = true; } else if ( mv->type == mv_widthonly ) { if ( within>=0 && within+1glyphcnt && event->u.mouse.x>mv->perchar[within+1].dx-3 ) onwidth = true; /* subsequent char */ else if ( within>=0 && event->u.mouse.x>mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3 ) { onwidth = true; } } else { if ( within>0 && mv->perchar[within-1].selected && event->u.mouse.xperchar[within].dx+3 ) onwidth = true; /* previous char */ else if ( within!=-1 && within+1glyphcnt && mv->perchar[within+1].selected && event->u.mouse.x>mv->perchar[within+1].dx-3 ) { onkern = true; /* subsequent char */ ++within; } else if ( within>0 && mv->perchar[within].selected && event->u.mouse.xperchar[within].dx+3 ) onkern = true; else if ( within>=0 && event->u.mouse.x>mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3 ) { onwidth = true; } } } else { if ( mv->type == mv_kernonly ) { if ( within>=0 && within+1glyphcnt && event->u.mouse.xdwidth-(mv->perchar[within+1].dx-3) ) { onkern = true; /* subsequent char */ ++within; } else if ( within>0 && event->u.mouse.x>mv->dwidth-(mv->perchar[within].dx+3) ) onkern = true; } else if ( mv->type == mv_widthonly ) { if ( within>=0 && within+1glyphcnt && event->u.mouse.xdwidth-(mv->perchar[within+1].dx-3) ) onwidth = true; /* subsequent char */ else if ( within>=0 && event->u.mouse.xdwidth-(mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3) ) { onwidth = true; } } else { if ( within>0 && mv->perchar[within-1].selected && event->u.mouse.x>mv->dwidth-(mv->perchar[within].dx+3) ) onwidth = true; /* previous char */ else if ( within!=-1 && within+1glyphcnt && mv->perchar[within+1].selected && event->u.mouse.xdwidth-(mv->perchar[within+1].dx-3) ) { onkern = true; /* subsequent char */ ++within; } else if ( within>0 && mv->perchar[within].selected && event->u.mouse.x>mv->dwidth-(mv->perchar[within].dx+3) ) onkern = true; else if ( within>=0 && event->u.mouse.xdwidth-(mv->perchar[within].dx+mv->perchar[within].dwidth+mv->perchar[within].kernafter-3) ) { onwidth = true; } } } } if ( event->type != et_mousemove || !mv->pressed ) { int ct = -1; if ( mv->bdf!=NULL || ( mv->type==mv_kernonly && !onkern ) || ( mv->type==mv_widthonly && !onwidth )) { if ( mv->cursor!=ct_mypointer ) ct = ct_mypointer; } else if ( sc!=NULL ) { if ( mv->cursor!=ct_lbearing ) ct = ct_lbearing; } else if ( onwidth ) { if ( mv->cursor!=ct_rbearing ) ct = ct_rbearing; } else if ( onkern ) { if ( mv->cursor!=ct_kerning ) ct = ct_kerning; } else { if ( mv->cursor!=ct_mypointer ) ct = ct_mypointer; } if ( ct!=-1 ) { GDrawSetCursor(mv->gw,ct); mv->cursor = ct; } } if ( event->type == et_mousemove && !mv->pressed ) { if ( sc==NULL && within!=-1 ) sc = mv->glyphs[within].sc; if ( sc!=NULL ) SCPreparePopup(mv->gw,sc,mv->fv->b.map->remap,mv->fv->b.map->backmap[sc->orig_pos],sc->unicodeenc); /* Don't allow any editing when displaying a bitmap font */ } else if ( event->type == et_mousedown && mv->bdf==NULL ) { CVPaletteDeactivate(); if ( sc!=NULL ) { for ( j=0; jglyphcnt; ++j ) if ( j!=i && mv->perchar[j].selected ) MVDeselectChar(mv,j); MVSelectChar(mv,i); GWindowClearFocusGadgetOfWindow(mv->gw); mv->pressed = true; } else if ( within!=-1 ) { mv->pressedwidth = onwidth; mv->pressedkern = onkern; if ( mv->pressedwidth || mv->pressedkern ) { mv->pressed = true; if ( !mv->perchar[within].selected ) { MVDoSelect(mv,within); } } #if 0 } else if ( !mv->right_to_left && mv->glyphcnt>=1 && event->u.mouse.xperchar[mv->glyphcnt-1].dx+mv->perchar[mv->glyphcnt-1].dwidth+mv->perchar[mv->glyphcnt-1].kernafter+3 && mv->type!=mv_kernonly ) { mv->pressed = mv->pressedwidth = true; GDrawSetCursor(mv->gw,ct_rbearing); mv->cursor = ct_rbearing; if ( !mv->perchar[mv->glyphcnt-1].selected ) MVDoSelect(mv,mv->glyphcnt-1); } else if ( mv->right_to_left && mv->glyphcnt>=1 && event->u.mouse.x>mv->dwidth - (mv->perchar[mv->glyphcnt-1].dx+mv->perchar[mv->glyphcnt-1].dwidth+mv->perchar[mv->glyphcnt-1].kernafter+3) && mv->type!=mv_kernonly ) { mv->pressed = mv->pressedwidth = true; GDrawSetCursor(mv->gw,ct_rbearing); mv->cursor = ct_rbearing; if ( !mv->perchar[mv->glyphcnt-1].selected ) MVDoSelect(mv,mv->glyphcnt-1); #endif } mv->pressed_x = event->u.mouse.x; } else if ( event->type == et_mousemove && mv->pressed ) { for ( i=0; iglyphcnt && !mv->perchar[i].selected; ++i ); if ( mv->pressedwidth ) { int ow = mv->perchar[i].dwidth; if ( mv->right_to_left ) diff = -diff; bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos); mv->perchar[i].dwidth = bdfc->width + diff; if ( ow!=mv->perchar[i].dwidth ) { for ( j=i+1; jglyphcnt; ++j ) mv->perchar[j].dx = mv->perchar[j-1].dx+mv->perchar[j-1].dwidth+ mv->perchar[j-1].kernafter; GDrawRequestExpose(mv->v,NULL,false); } } else if ( mv->pressedkern ) { int ow = mv->perchar[i-1].kernafter; KernPair *kp; int kpoff; KernClass *kc; int index; for ( kp = mv->glyphs[i-1].sc->kerns; kp!=NULL && kp->sc!=mv->glyphs[i].sc; kp = kp->next ); if ( kp!=NULL ) kpoff = kp->off; else if ((kc=SFFindKernClass(mv->sf,mv->glyphs[i-1].sc,mv->glyphs[i].sc,&index,false))!=NULL ) kpoff = kc->offsets[index]; else kpoff = 0; kpoff = kpoff * mv->pixelsize*iscale / (mv->sf->descent+mv->sf->ascent); if ( mv->right_to_left ) diff = -diff; mv->perchar[i-1].kernafter = kpoff + diff; if ( ow!=mv->perchar[i-1].kernafter ) { for ( j=i; jglyphcnt; ++j ) mv->perchar[j].dx = mv->perchar[j-1].dx+mv->perchar[j-1].dwidth+ mv->perchar[j-1].kernafter; GDrawRequestExpose(mv->v,NULL,false); } } else if ( mv->type!=mv_kernonly ) { int olda = mv->activeoff; bdfc = BDFPieceMealCheck(mv->show,mv->glyphs[i].sc->orig_pos); mv->activeoff = diff; MVRedrawI(mv,i,bdfc->xmin+olda,bdfc->xmax+olda); } } else if ( event->type == et_mouseup && event->u.mouse.clicks>1 && (within!=-1 || sc!=NULL)) { mv->pressed = false; mv->activeoff = 0; mv->pressedwidth = mv->pressedkern = false; if ( within==-1 ) within = i; if ( mv->bdf==NULL ) CharViewCreate(mv->glyphs[within].sc,mv->fv,-1); else BitmapViewCreate(mv->bdf->glyphs[mv->glyphs[within].sc->orig_pos],mv->bdf,mv->fv,-1); if ( mv->showgrid==mv_hidemovinggrid ) GDrawRequestExpose(mv->v,NULL,false); } else if ( event->type == et_mouseup && mv->pressed ) { for ( i=0; iglyphcnt && !mv->perchar[i].selected; ++i ); mv->pressed = false; mv->activeoff = 0; sc = mv->glyphs[i].sc; if ( mv->pressedwidth ) { mv->pressedwidth = false; if ( mv->right_to_left ) diff = -diff; diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale); if ( diff!=0 ) { SCPreserveWidth(sc); SCSynchronizeWidth(sc,sc->width+diff,sc->width,NULL); SCCharChangedUpdate(sc,ly_none); } } else if ( mv->pressedkern ) { mv->pressedkern = false; diff = diff*(mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale); if ( diff!=0 ) { if ( mv->right_to_left ) diff = -diff; MV_ChangeKerning(mv, i, diff, true); MVRefreshValues(mv,i-1); } } else if ( mv->type!=mv_kernonly ) { real transform[6]; transform[0] = transform[3] = 1.0; transform[1] = transform[2] = transform[5] = 0; transform[4] = diff* (mv->sf->ascent+mv->sf->descent)/(mv->pixelsize*iscale); if ( transform[4]!=0 ) FVTrans( (FontViewBase *)mv->fv,sc,transform,NULL,false); } mv->pressedwidth = false; mv->pressedkern = false; if ( mv->showgrid==mv_hidemovinggrid ) GDrawRequestExpose(mv->v,NULL,false); } else if ( event->type == et_mouseup && mv->bdf!=NULL && within!=-1 ) { for ( j=0; jglyphcnt; ++j ) if ( j!=within && mv->perchar[j].selected ) MVDeselectChar(mv,j); MVSelectChar(mv,within); if ( mv->showgrid==mv_hidemovinggrid ) GDrawRequestExpose(mv->v,NULL,false); } } static void MVMouse(MetricsView *mv,GEvent *event) { int i; if ( event->u.mouse.y< mv->topend || event->u.mouse.y >= mv->displayend ) { if ( event->u.mouse.y >= mv->displayend && event->u.mouse.yheight-mv->sbh ) { event->u.mouse.x += (mv->coff*mv->mwidth); for ( i=0; iglyphcnt; ++i ) { if ( event->u.mouse.x >= mv->perchar[i].mx && event->u.mouse.x < mv->perchar[i].mx+mv->perchar[i].mwidth ) break; } if ( iglyphcnt ) SCPreparePopup(mv->gw,mv->glyphs[i].sc,mv->fv->b.map->remap, mv->fv->b.map->backmap[mv->glyphs[i].sc->orig_pos], mv->glyphs[i].sc->unicodeenc); } if ( mv->cursor!=ct_mypointer ) { GDrawSetCursor(mv->gw,ct_mypointer); mv->cursor = ct_mypointer; } return; } } static void MVDrop(MetricsView *mv,GEvent *event) { int x,ex = event->u.drag_drop.x + mv->xoff; int y,ey = event->u.drag_drop.y + mv->yoff; int within, i, cnt, ch; int32 len; char *cnames, *start, *pt; unichar_t *newtext; const unichar_t *oldtext; SplineChar **founds; /* We should get a list of character names. Add them before the character */ /* on which they are dropped */ if ( !GDrawSelectionHasType(mv->gw,sn_drag_and_drop,"STRING")) return; cnames = GDrawRequestSelection(mv->gw,sn_drag_and_drop,"STRING",&len); if ( cnames==NULL ) return; within = mv->glyphcnt; if ( !mv->vertical ) { for ( i=0; iglyphcnt; ++i ) { x = mv->perchar[i].dx; if ( mv->right_to_left ) x = mv->dwidth - x - mv->perchar[i].dwidth - mv->perchar[i].kernafter ; if ( ex >= x && ex < x+mv->perchar[i].dwidth+ mv->perchar[i].kernafter ) { within = i; break; } } } else { for ( i=0; iglyphcnt; ++i ) { y = mv->perchar[i].dy; if ( ey >= y && ey < y+mv->perchar[i].dheight+ mv->perchar[i].kernafter ) { within = i; break; } } } founds = galloc(len*sizeof(SplineChar *)); /* Will be a vast over-estimate */ start = cnames; for ( i=0; *start; ) { while ( *start==' ' ) ++start; if ( *start=='\0' ) break; for ( pt=start; *pt && *pt!=' '; ++pt ); ch = *pt; *pt = '\0'; if ( (founds[i]=SFGetChar(mv->sf,-1,start))!=NULL ) ++i; *pt = ch; start = pt; } cnt = i; free( cnames ); if ( cnt==0 ) return; if ( withinglyphcnt ) within = mv->glyphs[within].orig_index; else within = mv->clen; if ( mv->clen+cnt+1>=mv->cmax ) { mv->cmax = mv->clen+cnt+10; mv->chars = grealloc(mv->chars,mv->cmax*sizeof(SplineChar *)); } oldtext = _GGadgetGetTitle(mv->text); newtext = galloc((mv->clen+cnt+1)*sizeof(unichar_t)); u_strcpy(newtext,oldtext); newtext[mv->clen+cnt]='\0'; for ( i=mv->clen+cnt; i>=within+cnt; --i ) { newtext[i] = newtext[i-cnt]; mv->chars[i] = mv->chars[i-cnt]; } for ( i=within; ichars[i] = founds[i-within]; #ifdef UNICHAR_16 newtext[i] = (founds[i-within]->unicodeenc>=0 && founds[i-within]->unicodeenc<0x10000)? #else newtext[i] = founds[i-within]->unicodeenc>=0 ? #endif founds[i-within]->unicodeenc : MVFakeUnicodeOfSc(mv,founds[i-within]); } mv->clen += cnt; MVRemetric(mv); free(founds); GGadgetSetTitle(mv->text,newtext); free(newtext); GDrawRequestExpose(mv->v,NULL,false); } static int mv_v_e_h(GWindow gw, GEvent *event) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); switch ( event->type ) { case et_expose: GDrawSetLineWidth(gw,0); MVSubExpose(mv,gw,event); break; case et_char: MVChar(mv,event); break; case et_mouseup: case et_mousemove: case et_mousedown: if (( event->type==et_mouseup || event->type==et_mousedown ) && (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) { int ish = event->u.mouse.button>5; if ( event->u.mouse.state&ksm_shift ) ish = !ish; if ( event->u.mouse.state&ksm_control ) { /* bind control to magnify/minify */ if ( event->type==et_mousedown ) { if ( event->u.mouse.button==4 || event->u.mouse.button==6 ) _MVMenuScale(mv,MID_ZoomIn); else _MVMenuScale(mv,MID_ZoomOut); } } else if ( ish ) { /* bind shift to horizontal scroll */ return( GGadgetDispatchEvent(mv->hsb,event)); } else { return( GGadgetDispatchEvent(mv->vsb,event)); } return( true ); } if ( mv->gwgic!=NULL && event->type==et_mousedown) GDrawSetGIC(mv->gw,mv->gwgic,0,20); MVSubMouse(mv,event); break; case et_drop: MVDrop(mv,event); break; } return( true ); } static int mv_e_h(GWindow gw, GEvent *event) { MetricsView *mv = (MetricsView *) GDrawGetUserData(gw); SplineFont *sf; switch ( event->type ) { case et_selclear: ClipboardClear(); break; case et_expose: GDrawSetLineWidth(gw,0); MVExpose(mv,gw,event); break; case et_resize: if ( event->u.resize.sized ) MVResize(mv); break; case et_char: MVChar(mv,event); break; case et_mouseup: case et_mousemove: case et_mousedown: if (( event->type==et_mouseup || event->type==et_mousedown ) && (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) { int ish = event->u.mouse.button>5; if ( event->u.mouse.state&ksm_shift ) ish = !ish; if ( event->u.mouse.state&ksm_control ) { /* bind control to magnify/minify */ if ( event->type==et_mousedown ) { if ( event->u.mouse.button==4 || event->u.mouse.button==6 ) _MVMenuScale(mv,MID_ZoomIn); else _MVMenuScale(mv,MID_ZoomOut); } } else if ( ish ) { /* bind shift to horizontal scroll */ return( GGadgetDispatchEvent(mv->hsb,event)); } else { return( GGadgetDispatchEvent(mv->vsb,event)); } return( true ); } if ( mv->gwgic!=NULL && event->type==et_mousedown) GDrawSetGIC(mv->gw,mv->gwgic,0,20); MVMouse(mv,event); break; case et_drop: MVDrop(mv,event); break; case et_controlevent: switch ( event->u.control.subtype ) { case et_scrollbarchange: if ( event->u.control.g==mv->hsb ) MVHScroll(mv,&event->u.control.u.sb); else MVVScroll(mv,&event->u.control.u.sb); break; } break; case et_close: MVMenuClose(gw,NULL,NULL); break; case et_destroy: sf = mv->sf; if ( sf->cidmaster ) sf = sf->cidmaster; if ( sf->metrics==mv ) sf->metrics = mv->next; else { MetricsView *n; for ( n=sf->metrics; n->next!=mv; n=n->next ); n->next = mv->next; } KCLD_MvDetach(sf->kcld,mv); MetricsViewFree(mv); break; case et_focus: #if 0 if ( event->u.focus.gained_focus ) CVPaletteDeactivate(); #endif break; } return( true ); } GTextInfo *SLOfFont(SplineFont *sf) { uint32 *scripttags, *langtags; int s, l, i, k, cnt; extern GTextInfo scripts[], languages[]; GTextInfo *ret = NULL; char *sname, *lname, *temp; char sbuf[8], lbuf[8]; LookupUIInit(); scripttags = SFScriptsInLookups(sf,-1); if ( scripttags==NULL ) return( NULL ); for ( k=0; k<2; ++k ) { cnt = 0; for ( s=0; scripttags[s]!=0; ++s ) { if ( k ) { for ( i=0; scripts[i].text!=NULL; ++i ) if ( scripttags[s] == (intpt) (scripts[i].userdata)) break; sname = (char *) (scripts[i].text); sbuf[0] = scripttags[s]>>24; sbuf[1] = scripttags[s]>>16; sbuf[2] = scripttags[s]>>8; sbuf[3] = scripttags[s]; sbuf[4] = 0; if ( sname==NULL ) sname = sbuf; } langtags = SFLangsInScript(sf,-1,scripttags[s]); /* This one can't be NULL */ for ( l=0; langtags[l]!=0; ++l ) { if ( k ) { for ( i=0; languages[i].text!=NULL; ++i ) if ( langtags[l] == (intpt) (languages[i].userdata)) break; lname = (char *) (languages[i].text); lbuf[0] = langtags[l]>>24; lbuf[1] = langtags[l]>>16; lbuf[2] = langtags[l]>>8; lbuf[3] = langtags[l]; lbuf[4] = 0; if ( lname==NULL ) lname = lbuf; temp = galloc(strlen(sname)+strlen(lname)+3); strcpy(temp,sname); strcat(temp,"{"); strcat(temp,lname); strcat(temp,"}"); ret[cnt].text = (unichar_t *) temp; ret[cnt].text_is_1byte = true; temp = galloc(11); strcpy(temp,sbuf); temp[4] = '{'; strcpy(temp+5,lbuf); temp[9]='}'; temp[10] = 0; ret[cnt].userdata = temp; } ++cnt; } free(langtags); } if ( !k ) ret = gcalloc((cnt+1),sizeof(GTextInfo)); } free(scripttags); return( ret ); } #define metricsicon_width 16 #define metricsicon_height 16 static unsigned char metricsicon_bits[] = { 0x04, 0x10, 0xf0, 0x03, 0x24, 0x12, 0x20, 0x00, 0x24, 0x10, 0xe0, 0x00, 0x24, 0x10, 0x20, 0x00, 0x24, 0x10, 0x20, 0x00, 0x74, 0x10, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00}; static void MetricsViewInit(void ) { static int inited = false; if ( !inited ) { mv_text_init[2].text = (unichar_t *) _((char *) mv_text_init[2].text); mb2DoGetText(mblist); MVColInit(); } } MetricsView *MetricsViewCreate(FontView *fv,SplineChar *sc,BDFFont *bdf) { GRect pos; GWindow gw; GWindowAttrs wattrs; GGadgetData gd; GRect gsize; MetricsView *mv = gcalloc(1,sizeof(MetricsView)); FontRequest rq; static GWindow icon = NULL; extern int _GScrollBar_Width; char buf[120], *pt; GTextInfo label; int i,j,cnt; int as,ds,ld; static GFont *mvfont=NULL; SplineFont *master = fv->b.sf->cidmaster ? fv->b.sf->cidmaster : fv->b.sf; MetricsViewInit(); if ( icon==NULL ) icon = GDrawCreateBitmap(NULL,metricsicon_width,metricsicon_height,metricsicon_bits); mv->fv = fv; mv->sf = fv->b.sf; mv->bdf = bdf; mv->showgrid = mvshowgrid; mv->antialias = mv_antialias; mv->scale_index = SCALE_INDEX_NORMAL; mv->next = master->metrics; master->metrics = mv; mv->layer = fv->b.active_layer; mv->type = mv_type; mv->pixelsize_set_by_window = true; mv->dpi = 72; memset(&wattrs,0,sizeof(wattrs)); wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_icon; wattrs.event_masks = ~(1<gw = gw = GDrawCreateTopWindow(NULL,&pos,mv_e_h,mv,&wattrs); mv->width = pos.width; mv->height = pos.height; mv->gwgic = GDrawCreateInputContext(mv->gw,gic_root|gic_orlesser); GDrawSetGIC(gw,mv->gwgic,0,20); memset(&gd,0,sizeof(gd)); gd.flags = gg_visible | gg_enabled; helplist[0].invoke = MVMenuContextualHelp; gd.u.menu2 = mblist; mv->mb = GMenu2BarCreate( gw, &gd, NULL); GGadgetGetSize(mv->mb,&gsize); mv->mbh = gsize.height; gd.pos.height = GDrawPointsToPixels(gw,_GScrollBar_Width); gd.pos.y = pos.height-gd.pos.height; gd.pos.x = 0; gd.pos.width = pos.width; gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels; mv->hsb = GScrollBarCreate(gw,&gd,mv); GGadgetGetSize(mv->hsb,&gsize); mv->sbh = gsize.height; mv->dwidth = mv->width-mv->sbh; gd.pos.width = mv->sbh; gd.pos.y = 0; gd.pos.height = pos.height; /* we'll fix these later */ gd.pos.x = pos.width-gd.pos.width; gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert; mv->vsb = GScrollBarCreate(gw,&gd,mv); if ( mvfont==NULL ) { memset(&rq,0,sizeof(rq)); rq.utf8_family_name = SANS_UI_FAMILIES; rq.point_size = -12; rq.weight = 400; mvfont = GDrawInstanciateFont(GDrawGetDisplayOfWindow(gw),&rq); mvfont = GResourceFindFont("MetricsView.Font",mvfont); } mv->font = mvfont; GDrawFontMetrics(mv->font,&as,&ds,&ld); mv->fh = as+ds; mv->as = as; pt = buf; mv->chars = gcalloc(mv->cmax=20,sizeof(SplineChar *)); if ( sc!=NULL ) { mv->chars[mv->clen++] = sc; } else { EncMap *map = fv->b.map; for ( j=1; (j<=fv->sel_index || j<1) && mv->clen<15; ++j ) { for ( i=0; ienccount && mv->clen<15; ++i ) { int gid = map->map[i]; if ( gid!=-1 && fv->b.selected[i]==j && fv->b.sf->glyphs[gid]!=NULL ) { mv->chars[mv->clen++] = fv->b.sf->glyphs[gid]; } } } } mv->chars[mv->clen] = NULL; for ( cnt=0; cntclen; ++cnt ) pt = utf8_idpb(pt, #ifdef UNICHAR_16 mv->chars[cnt]->unicodeenc==-1 || mv->chars[cnt]->unicodeenc>=0x10000? #else mv->chars[cnt]->unicodeenc==-1? #endif MVFakeUnicodeOfSc(mv,mv->chars[cnt]): mv->chars[cnt]->unicodeenc); *pt = '\0'; memset(&gd,0,sizeof(gd)); memset(&label,0,sizeof(label)); gd.pos.y = mv->mbh+2; gd.pos.x = 10; gd.pos.width = GDrawPointsToPixels(mv->gw,100); gd.label = &label; label.text = (unichar_t *) "DFLT{dflt}"; label.text_is_1byte = true; gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels; gd.u.list = mv->scriptlangs = SLOfFont(mv->sf); gd.handle_controlevent = MV_ScriptLangChanged; mv->script = GListFieldCreate(gw,&gd,mv); GGadgetGetSize(mv->script,&gsize); mv->topend = gsize.y + gsize.height + 2; gd.pos.x = gd.pos.x+gd.pos.width+10; gd.pos.width = GDrawPointsToPixels(mv->gw,200); gd.pos.height = gsize.height; label.text = (unichar_t *) buf; gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_text_xim; gd.handle_controlevent = MV_TextChanged; gd.u.list = mv_text_init; mv->text = GListFieldCreate(gw,&gd,mv); gd.pos.x = gd.pos.x+gd.pos.width+10; --gd.pos.y; gd.pos.width += 30; gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels; gd.handle_controlevent = MV_SubtableChanged; gd.label = NULL; gd.u.list = NULL; mv->subtable_list = GListButtonCreate(gw,&gd,mv); MVSetSubtables(master); gd.pos.y = mv->topend; gd.pos.x = 0; gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_pos_use0|gg_list_multiplesel|gg_list_alphabetic; gd.pos.width = GDrawPointsToPixels(mv->gw,50); gd.handle_controlevent = MV_FeaturesChanged; mv->features = GListCreate(gw,&gd,mv); GListSetSBAlwaysVisible(mv->features,true); GListSetPopupCallback(mv->features,MV_FriendlyFeatures); mv->xstart = gd.pos.width; pos.x = mv->xstart; pos.width = mv->dwidth - mv->xstart; pos.y = mv->topend+2; pos.height = mv->displayend - mv->topend - 2; memset(&wattrs,0,sizeof(wattrs)); wattrs.mask = wam_events|wam_backcol; wattrs.background_color = view_bgcol; wattrs.event_masks = -1; wattrs.cursor = ct_mypointer; mv->v = GWidgetCreateSubWindow(mv->gw,&pos,mv_v_e_h,mv,&wattrs); MVSetFeatures(mv); MVMakeLabels(mv); MVResize(mv); GDrawSetVisible(mv->v,true); GDrawSetVisible(gw,true); /*GWidgetHidePalettes();*/ return( mv ); } void MetricsViewFree(MetricsView *mv) { if ( mv->scriptlangs!=NULL ) { int i; for ( i=0; mv->scriptlangs[i].text!=NULL ; ++i ) free(mv->scriptlangs[i].userdata ); GTextInfoListFree(mv->scriptlangs); } BDFFontFree(mv->show); /* the fields will free themselves */ free(mv->chars); free(mv->glyphs); free(mv->perchar); free(mv); } void MVRefreshAll(MetricsView *mv) { if ( mv!=NULL ) { MVRemetric(mv); GDrawRequestExpose(mv->v,NULL,false); } } /******************************************************************************/ static int MV_GlyphCnt(struct metricsview *mv) { return( mv->glyphcnt ); } static SplineChar *MV_Glyph(struct metricsview *mv,int i) { if ( i<0 || i>=mv->glyphcnt ) return( NULL ); return( mv->glyphs[i].sc ); } static void MV_ReKernAll(struct splinefont *sf) { MetricsView *mv; for ( mv=sf->metrics; mv!=NULL; mv=mv->next ) MVReKern(mv); } static void MV_ReFeatureAll(struct splinefont *sf) { MetricsView *mv; MVSetSubtables(sf); for ( mv=sf->metrics; mv!=NULL; mv=mv->next ) MVSetFeatures(mv); } static void MV_CloseAll(struct splinefont *sf) { MetricsView *mv, *mvnext; for ( mv=sf->metrics; mv!=NULL; mv=mvnext ) { mvnext = mv->next; GDrawDestroyWindow(mv->gw); } GDrawSync(NULL); GDrawProcessPendingEvents(NULL); } struct mv_interface gdraw_mv_interface = { MV_GlyphCnt, MV_Glyph, MV_ReKernAll, MV_ReFeatureAll, MV_CloseAll }; static struct resed metricsview_re[] = { {N_("Advance Width Col"), "AdvanceWidthColor", rt_color, &widthcol, N_("Color used to draw the advance width line of a glyph")}, {N_("Italic Advance Col"), "ItalicAdvanceColor", rt_color, &widthcol, N_("Color used to draw the italic advance width line of a glyph")}, {N_("Kern Line Color"), "KernLineColor", rt_color, &kernlinecol, N_("Color used to draw the kerning line")}, {N_("Side Bearing Color"), "SideBearingLineColor", rt_color, &rbearinglinecol, N_("Color used to draw the left side bearing")}, {N_("Selected Glyph Col"), "SelectedGlyphColor", rt_color, &selglyphcol, N_("Color used to mark the selected glyph")}, NULL }; extern GResInfo view_ri; GResInfo metricsview_ri = { &view_ri, NULL,NULL, NULL, NULL, NULL, NULL, metricsview_re, N_("MetricsView"), N_("This window displays metrics information about a font"), "MetricsView", "fontforge", false };