LCOV - code coverage report
Current view: top level - fontforgeexe - bitmapview.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 1487 0.0 %
Date: 2017-08-04 Functions: 0 96 0.0 %

          Line data    Source code
       1             : /* -*- coding: utf-8 -*- */
       2             : /* Copyright (C) 2000-2012 by George Williams */
       3             : /*
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions are met:
       6             : 
       7             :  * Redistributions of source code must retain the above copyright notice, this
       8             :  * list of conditions and the following disclaimer.
       9             : 
      10             :  * Redistributions in binary form must reproduce the above copyright notice,
      11             :  * this list of conditions and the following disclaimer in the documentation
      12             :  * and/or other materials provided with the distribution.
      13             : 
      14             :  * The name of the author may not be used to endorse or promote products
      15             :  * derived from this software without specific prior written permission.
      16             : 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      18             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      19             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      20             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      22             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      23             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      24             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      25             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      26             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : #include "bitmapchar.h"
      29             : #include "bvedit.h"
      30             : #include "cvundoes.h"
      31             : #include "encoding.h"
      32             : #include "fontforgeui.h"
      33             : #include "fvfonts.h"
      34             : #include "splinefill.h"
      35             : #include "splinesaveafm.h"
      36             : #include <gkeysym.h>
      37             : #include <utype.h>
      38             : #include <ustring.h>
      39             : #include <math.h>
      40             : #include <locale.h>
      41             : #include <gresource.h>
      42             : #include <gresedit.h>
      43             : 
      44             : #include "gutils/unicodelibinfo.h"
      45             : 
      46             : int bv_width = 270, bv_height=250;
      47             : 
      48             : extern int _GScrollBar_Width;
      49             : extern struct lconv localeinfo;
      50             : extern char *coord_sep;
      51             : struct bvshows BVShows = { 1, 1, 1, 0 };
      52             : 
      53             : #define RPT_BASE        3               /* Place to draw the pointer icon */
      54             : #define RPT_DATA        24              /* x,y text after above */
      55             : #define RPT_COLOR       40              /* Blob showing the foreground color */
      56             : 
      57           0 : static void BVNewScale(BitmapView *bv) {
      58           0 :     int fh = bv->bdf->ascent+bv->bdf->descent;
      59             : 
      60           0 :     GScrollBarSetBounds(bv->vsb,-2*fh*bv->scale,4*fh*bv->scale,bv->height);
      61           0 :     GScrollBarSetBounds(bv->hsb,-3*fh*bv->scale,6*fh*bv->scale,bv->width);
      62           0 :     GScrollBarSetPos(bv->vsb,bv->yoff);
      63           0 :     GScrollBarSetPos(bv->hsb,bv->xoff);
      64             : 
      65           0 :     GDrawRequestExpose(bv->v,NULL,false);
      66           0 : }
      67             : 
      68           0 : static void BVFit(BitmapView *bv) {
      69             :     int left, right, top, bottom, hsc, wsc;
      70           0 :     int fh = bv->bdf->ascent+bv->bdf->descent;
      71             :     extern int palettes_docked;
      72           0 :     int offset = palettes_docked ? 80 : 0;
      73             : 
      74           0 :     if ( offset>bv->width ) offset = 0;
      75             : 
      76           0 :     bottom = bv->bc->ymin;
      77           0 :     top = bv->bc->ymax;
      78           0 :     left = bv->bc->xmin;
      79           0 :     right = bv->bc->xmax;
      80             : 
      81           0 :     if ( bottom>0 ) bottom = 0;
      82           0 :     if ( left>0 ) left = 0;
      83           0 :     if ( top==-1 && bottom==0 ) {       /* Empty */
      84           0 :         top = bv->bdf->ascent;
      85           0 :         bottom = -bv->bdf->descent;
      86           0 :         if ( right==-1 ) right = fh;
      87             :     }
      88           0 :     if ( top<bottom ) IError("Bottom bigger than top!");
      89           0 :     if ( right<left ) IError("Left bigger than right!");
      90           0 :     top -= bottom;
      91           0 :     right -= left;
      92           0 :     if ( top==0 ) top = bv->bdf->pixelsize;
      93           0 :     if ( right==0 ) right = bv->bdf->pixelsize;
      94           0 :     wsc = (8*(bv->width-offset)) / (10*right);
      95           0 :     hsc = (8*bv->height) / (10*top);
      96           0 :     if ( wsc<hsc ) hsc = wsc;
      97           0 :     if ( hsc<=0 ) hsc = 1;
      98           0 :     if ( hsc>32 ) hsc = 32;
      99             : 
     100           0 :     bv->scale = hsc;
     101             : 
     102           0 :     bv->xoff = left+(bv->width-offset-right*bv->scale)/2 + offset;
     103           0 :     bv->yoff = bottom + (bv->height-top*bv->scale)/2;
     104           0 :     if ( bv->xoff<-3*fh*bv->scale ) bv->xoff = -3*fh*bv->scale;
     105           0 :     if ( bv->yoff<-2*fh*bv->scale ) bv->yoff = -2*fh*bv->scale;
     106             : 
     107           0 :     BVNewScale(bv);
     108           0 : }
     109             : 
     110           0 : static void BVUnlinkView(BitmapView *bv ) {
     111             :     BitmapView *test;
     112             : 
     113           0 :     if ( bv->bc->views == bv ) {
     114           0 :         bv->bc->views = bv->next;
     115             :     } else {
     116           0 :         for ( test=bv->bc->views; test->next!=bv && test->next!=NULL; test=test->next );
     117           0 :         if ( test->next==bv )
     118           0 :             test->next = bv->next;
     119             :     }
     120           0 :     if ( bv->bc->views==NULL ) {
     121             :         /* We just got rid of the last view. Do a little clean up */
     122             :         /*  compress the bitmap, and get rid of the floating selection */
     123           0 :         BCCompressBitmap(bv->bc);
     124           0 :         BCFlattenFloat(bv->bc);
     125             :     }
     126           0 : }
     127             : 
     128           0 : static void BVRefreshImage(BitmapView *bv) {
     129             :     GRect box;
     130             : 
     131           0 :     box.x = 0; box.width = bv->infoh;
     132           0 :     box.y = bv->mbh; box.height = bv->infoh;
     133           0 :     GDrawRequestExpose(bv->gw,&box,false);
     134           0 : }
     135             : 
     136           0 : static void BCCharUpdate(BDFChar *bc) {
     137             :     BitmapView *bv;
     138             : 
     139           0 :     for ( bv = bc->views; bv!=NULL; bv=bv->next ) {
     140           0 :         GDrawRequestExpose(bv->v, NULL, false );
     141             :         /*BVRefreshImage(bv);*/         /* Select All gives us a blank image if we do this */
     142             :     }
     143           0 : }
     144             : 
     145           0 : static void BC_CharChangedUpdate(BDFChar *bc) {
     146             :     BDFFont *bdf;
     147             :     BitmapView *bv;
     148           0 :     int waschanged = bc->changed;
     149             :     FontView *fv;
     150             :     struct bdfcharlist *dlist;
     151             : 
     152           0 :     bc->changed = true;
     153           0 :     for ( bv = bc->views; bv!=NULL; bv=bv->next ) {
     154           0 :         GDrawRequestExpose(bv->v, NULL, false );
     155           0 :         BVRefreshImage(bv);
     156             :     }
     157             : 
     158           0 :     fv = (FontView *) (bc->sc->parent->fv);
     159           0 :     fv->b.sf->changed = true;
     160           0 :     if ( fv->show!=fv->filled ) {
     161           0 :         for ( bdf=fv->b.sf->bitmaps; bdf!=NULL && bdf->glyphs[bc->orig_pos]!=bc; bdf=bdf->next );
     162           0 :         if ( bdf!=NULL ) {
     163           0 :             FVRefreshChar(fv,bc->orig_pos);
     164           0 :             if ( fv->b.sf->onlybitmaps && !waschanged )
     165           0 :                 FVToggleCharChanged(fv->b.sf->glyphs[bc->orig_pos]);
     166             :         }
     167             :     }
     168           0 :     for ( dlist=bc->dependents; dlist!=NULL; dlist=dlist->next )
     169           0 :         BC_CharChangedUpdate(dlist->bc);
     170           0 : }
     171             : 
     172           0 : static char *BVMakeTitles(BitmapView *bv, BDFChar *bc,char *buf) {
     173             :     char *title;
     174             :     SplineChar *sc;
     175           0 :     BDFFont *bdf = bv->bdf;
     176             :     char *uniname;
     177             : 
     178           0 :     sc = bc->sc;
     179             : /* GT: This is the title for a window showing a bitmap character */
     180             : /* GT: It will look something like: */
     181             : /* GT:  exclam at 33 size 12 from Arial */
     182             : /* GT: $1 is the name of the glyph */
     183             : /* GT: $2 is the glyph's encoding */
     184             : /* GT: $3 is the pixel size of the bitmap font */
     185             : /* GT: $4 is the font name */
     186           0 :     sprintf(buf,_("%1$.80s at %2$d size %3$d from %4$.80s"),
     187           0 :             sc!=NULL ? sc->name : "<Nameless>", bv->enc, bdf->pixelsize, sc==NULL ? "" : sc->parent->fontname);
     188           0 :     title = copy(buf);
     189             : 
     190             :     /* Enhance 'buf' description with Nameslist.txt unicode name definition */
     191           0 :     if ( (uniname=unicode_name(sc->unicodeenc))!=NULL ) {
     192           0 :         strcat(buf, " ");
     193           0 :         strcpy(buf+strlen(buf), uniname);
     194           0 :         free(uniname);
     195             :     }
     196           0 :     return( title );
     197             : }
     198             : 
     199           0 : void BVChangeBC(BitmapView *bv, BDFChar *bc, int fitit ) {
     200             :     char *title;
     201             :     char buf[300];
     202             : 
     203           0 :     BVUnlinkView(bv);
     204           0 :     bv->bc = bc;
     205           0 :     bv->next = bc->views;
     206           0 :     bc->views = bv;
     207             : 
     208           0 :     if ( fitit )
     209           0 :         BVFit(bv);
     210             :     else
     211           0 :         BVNewScale(bv);
     212           0 :     BVRefreshImage(bv);
     213             : 
     214           0 :     title = BVMakeTitles(bv,bc,buf);
     215           0 :     GDrawSetWindowTitles8(bv->gw,buf,title);
     216           0 :     free(title);
     217             : 
     218           0 :     BVPaletteChangedChar(bv);
     219           0 : }
     220             : 
     221           0 : static void BVChangeChar(BitmapView *bv, int i, int fitit ) {
     222             :     BDFChar *bc;
     223           0 :     BDFFont *bdf = bv->bdf;
     224           0 :     EncMap *map = bv->fv->b.map;
     225             : 
     226           0 :     if ( bv->fv->b.cidmaster!=NULL && !map->enc->is_compact && i<bdf->glyphcnt &&
     227           0 :             (bc=bdf->glyphs[i])!=NULL ) {
     228             :         /* The attached bitmap fonts don't have the complexities of subfonts-- they are flat */
     229             :     } else {
     230           0 :         if ( i<0 || i>=map->enccount )
     231           0 : return;
     232           0 :         bc = BDFMakeChar(bdf,map,i);
     233             :     }
     234             : 
     235           0 :     if ( bc==NULL || bv->bc == bc )
     236           0 : return;
     237           0 :     bv->map_of_enc = map;
     238           0 :     bv->enc = i;
     239             : 
     240           0 :     BVChangeBC(bv,bc,fitit);
     241             : }
     242             : 
     243             : static void BVDoClear(BitmapView *bv);
     244             : static void BVHScroll(BitmapView *bv,struct sbevent *sb);
     245             : static void BVVScroll(BitmapView *bv,struct sbevent *sb);
     246             : 
     247           0 : void BVChar(BitmapView *bv, GEvent *event ) {
     248             :     BDFRefChar *head;
     249             :     extern int navigation_mask;
     250             : 
     251             : #if _ModKeysAutoRepeat
     252             :         /* Under cygwin these keys auto repeat, they don't under normal X */
     253             :         if ( bv->autorpt!=NULL ) {
     254             :             GDrawCancelTimer(bv->autorpt); bv->autorpt = NULL;
     255             :             if ( bv->keysym == event->u.chr.keysym )      /* It's an autorepeat, ignore it */
     256             : return;
     257             :             BVToolsSetCursor(bv,bv->oldstate,NULL);
     258             :         }
     259             : #endif
     260             : 
     261           0 :     BVPaletteActivate(bv);
     262           0 :     BVToolsSetCursor(bv,TrueCharState(event),NULL);
     263           0 :     if ( event->u.chr.keysym=='s' &&
     264           0 :             (event->u.chr.state&ksm_control) &&
     265           0 :             (event->u.chr.state&ksm_meta) )
     266           0 :         MenuSaveAll(NULL,NULL,NULL);
     267           0 :     else if ( !(event->u.chr.state&(ksm_control|ksm_meta)) &&
     268           0 :             event->u.chr.keysym == GK_BackSpace ) {
     269             :         /* Menu does delete */
     270           0 :         BVDoClear(bv);
     271           0 :     } else if ( event->u.chr.keysym == GK_Help ) {
     272           0 :         MenuHelp(NULL,NULL,NULL);       /* Menu does F1 */
     273           0 :     } else if ( event->u.chr.keysym == GK_Left ||
     274           0 :             event->u.chr.keysym == GK_Up ||
     275           0 :             event->u.chr.keysym == GK_Right ||
     276           0 :             event->u.chr.keysym == GK_Down ||
     277           0 :             event->u.chr.keysym == GK_KP_Left ||
     278           0 :             event->u.chr.keysym == GK_KP_Up ||
     279           0 :             event->u.chr.keysym == GK_KP_Right ||
     280           0 :             event->u.chr.keysym == GK_KP_Down ||
     281           0 :             event->u.chr.keysym == GK_KP_Home ||
     282           0 :             event->u.chr.keysym == GK_Home ) {
     283           0 :         int xoff=0, yoff=0;
     284           0 :         if ( event->u.chr.keysym == GK_Up || event->u.chr.keysym == GK_KP_Up )
     285           0 :             yoff = 1;
     286           0 :         else if ( event->u.chr.keysym == GK_Down || event->u.chr.keysym == GK_KP_Down )
     287           0 :             yoff = -1;
     288           0 :         else if ( event->u.chr.keysym == GK_Right || event->u.chr.keysym == GK_KP_Right )
     289           0 :             xoff = 1;
     290           0 :         else if ( event->u.chr.keysym == GK_Left || event->u.chr.keysym == GK_KP_Left )
     291           0 :             xoff = -1;
     292           0 :         else if ( event->u.chr.keysym == GK_Home || event->u.chr.keysym == GK_KP_Home ) {
     293           0 :             if ( bv->bc->selection==NULL ) {
     294           0 :                 xoff = -bv->bc->xmin;
     295           0 :                 yoff = -bv->bc->ymin;
     296             :             } else {
     297           0 :                 xoff = bv->bc->xmin-bv->bc->selection->xmin;
     298           0 :                 yoff = bv->bc->ymin-bv->bc->selection->ymin;
     299             :             }
     300             :         }
     301           0 :         if ( event->u.chr.state & (ksm_meta|ksm_control) ) {
     302             :             struct sbevent sb;
     303           0 :             sb.type = yoff>0 || xoff<0 ? et_sb_halfup : et_sb_halfdown;
     304           0 :             if ( xoff==0 )
     305           0 :                 BVVScroll(bv,&sb);
     306             :             else
     307           0 :                 BVHScroll(bv,&sb);
     308             :         } else {
     309           0 :             BCPreserveState(bv->bc);
     310           0 :             if ( bv->bc->selection==NULL ) {
     311           0 :                 bv->bc->xmin += xoff;  bv->bc->xmax += xoff;
     312           0 :                 bv->bc->ymin += yoff;  bv->bc->ymax += yoff;
     313           0 :                 for ( head=bv->bc->refs; head!=NULL; head=head->next ) {
     314           0 :                     if ( head->selected ) {
     315           0 :                         head->xoff += xoff;
     316           0 :                         head->yoff += yoff;
     317             :                     }
     318             :                 }
     319             :             } else {
     320           0 :                 bv->bc->selection->xmin += xoff;
     321           0 :                 bv->bc->selection->xmax += xoff;
     322           0 :                 bv->bc->selection->ymin += yoff;
     323           0 :                 bv->bc->selection->ymax += yoff;
     324             :             }
     325           0 :             BCCharChangedUpdate(bv->bc);
     326             :         }
     327           0 :     } else if ( (event->u.chr.state&((GMenuMask()|navigation_mask)&~(ksm_shift|ksm_capslock)))==navigation_mask &&
     328           0 :             event->type == et_char &&
     329           0 :             event->u.chr.keysym!=0 &&
     330           0 :             (event->u.chr.keysym<GK_Special /*|| event->u.chr.keysym>=0x10000*/)) {
     331           0 :         SplineFont *sf = bv->bc->sc->parent;
     332             :         int i;
     333           0 :         EncMap *map = bv->fv->b.map;
     334             :         extern int cv_auto_goto;
     335           0 :         if ( cv_auto_goto ) {
     336           0 :             i = SFFindSlot(sf,map,event->u.chr.keysym,NULL);
     337           0 :             if ( i!=-1 )
     338           0 :                 BVChangeChar(bv,i,false);
     339             :         }
     340             :     }
     341           0 : }
     342             : 
     343           0 : static int BVCurEnc(BitmapView *bv) {
     344           0 :     if ( bv->map_of_enc == bv->fv->b.map && bv->enc!=-1 )
     345           0 : return( bv->enc );
     346             : 
     347           0 : return( bv->fv->b.map->backmap[bv->bc->orig_pos] );
     348             : }
     349             : 
     350           0 : static void BVCharUp(BitmapView *bv, GEvent *event ) {
     351           0 :     if ( event->u.chr.keysym=='I' &&
     352           0 :             (event->u.chr.state&ksm_shift) &&
     353           0 :             (event->u.chr.state&ksm_meta) )
     354           0 :         SCCharInfo(bv->bc->sc,bv->fv->b.active_layer,bv->fv->b.map,BVCurEnc(bv));
     355             : #if _ModKeysAutoRepeat
     356             :     /* Under cygwin these keys auto repeat, they don't under normal X */
     357             :     else if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
     358             :             event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R ||
     359             :             event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R ||
     360             :             event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
     361             :             event->u.chr.keysym == GK_Super_L || event->u.chr.keysym == GK_Super_R ||
     362             :             event->u.chr.keysym == GK_Hyper_L || event->u.chr.keysym == GK_Hyper_R ) {
     363             :         if ( bv->autorpt!=NULL ) {
     364             :             GDrawCancelTimer(bv->autorpt);
     365             :             BVToolsSetCursor(bv,bv->oldstate,NULL);
     366             :         }
     367             :         bv->keysym = event->u.chr.keysym;
     368             :         bv->oldstate = TrueCharState(event);
     369             :         bv->autorpt = GDrawRequestTimer(bv->v,100,0,NULL);
     370             :     } else {
     371             :         if ( bv->autorpt!=NULL ) {
     372             :             GDrawCancelTimer(bv->autorpt); bv->autorpt=NULL;
     373             :             BVToolsSetCursor(bv,bv->oldstate,NULL);
     374             :         }
     375             :         BVToolsSetCursor(bv,TrueCharState(event),NULL);
     376             :     }
     377             : #else
     378           0 :     BVToolsSetCursor(bv,TrueCharState(event),NULL);
     379             : #endif
     380           0 : }
     381             : 
     382           0 : static void BVDrawTempPoint(BitmapView *bv,int x, int y,void *pixmap) {
     383             :     GRect pixel;
     384             : 
     385           0 :     pixel.width = pixel.height = bv->scale+1;
     386           0 :     pixel.x = bv->xoff + x*bv->scale;
     387           0 :     pixel.y = bv->height-bv->yoff-(y+1)*bv->scale;
     388           0 :     GDrawSetStippled(pixmap,1, 0,0);
     389           0 :     GDrawFillRect(pixmap,&pixel,0x909000);
     390           0 :     GDrawSetStippled(pixmap,0, 0,0);
     391           0 : }
     392             : 
     393           0 : static void BVDrawRefBorder(BitmapView *bv, BDFChar *bc, GWindow pixmap,
     394             :         uint8 selected, int8 xoff, int8 yoff) {
     395             :     int i, j;
     396             :     int isblack, lw, rw, tw, bw;
     397             :     int tx, ty;
     398           0 :     Color outcolor = selected ? 0x606000 : 0x606060;
     399             : 
     400           0 :     for ( i=bc->ymax-bc->ymin; i>=0; --i ) {
     401           0 :         for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
     402           0 :             tx = bv->xoff + (bc->xmin + xoff +j)*bv->scale;
     403           0 :             ty = bv->height-bv->yoff - (bc->ymax + yoff - i)*bv->scale;
     404             : 
     405           0 :             isblack = ( !bc->byte_data &&
     406           0 :                 ( bc->bitmap[i*bc->bytes_per_line+(j>>3)] & (1<<(7-(j&7))))) ||
     407           0 :                 ( bc->byte_data && bc->bitmap[i*bc->bytes_per_line+j] != 0 );
     408           0 :             if ( !isblack )
     409           0 :         continue;
     410           0 :             lw = ( j == 0 || ( !bc->byte_data &&
     411           0 :                 !( bc->bitmap[i*bc->bytes_per_line+((j-1)>>3)] & (1<<(7-((j-1)&7))))) ||
     412           0 :                 ( bc->byte_data && bc->bitmap[i*bc->bytes_per_line+j-1] == 0 ));
     413           0 :             rw = ( j == bc->xmax-bc->xmin || ( !bc->byte_data &&
     414           0 :                 !( bc->bitmap[i*bc->bytes_per_line+((j+1)>>3)] & (1<<(7-((j+1)&7))))) ||
     415           0 :                 ( bc->byte_data && bc->bitmap[i*bc->bytes_per_line+j+1] == 0 ));
     416           0 :             tw = ( i == bc->ymax-bc->ymin || ( !bc->byte_data &&
     417           0 :                 !( bc->bitmap[(i+1)*bc->bytes_per_line+(j>>3)] & (1<<(7-(j&7))))) ||
     418           0 :                 ( bc->byte_data && bc->bitmap[(i+1)*bc->bytes_per_line+j] == 0 ));
     419           0 :             bw = ( i == 0 || ( !bc->byte_data &&
     420           0 :                 !( bc->bitmap[(i-1)*bc->bytes_per_line+(j>>3)] & (1<<(7-(j&7))))) ||
     421           0 :                 ( bc->byte_data && bc->bitmap[(i-1)*bc->bytes_per_line+j] == 0 ));
     422             : 
     423           0 :             if ( lw )
     424           0 :                 GDrawDrawLine(pixmap,tx+1,ty, tx+1,ty-bv->scale,outcolor);
     425           0 :             if ( rw )
     426           0 :                 GDrawDrawLine(pixmap,tx+bv->scale-1,ty, tx+bv->scale-1,ty-bv->scale,outcolor);
     427           0 :             if ( tw )
     428           0 :                 GDrawDrawLine(pixmap,tx,ty-1, tx+bv->scale,ty-1,outcolor);
     429           0 :             if ( bw )
     430           0 :                 GDrawDrawLine(pixmap,tx,ty-bv->scale+1, tx+bv->scale,ty-bv->scale+1,outcolor);
     431             :         }
     432             :     }
     433           0 : }
     434             : 
     435           0 : static void BVDrawSelection(BitmapView *bv,void *pixmap) {
     436             :     GRect pixel, rect;
     437           0 :     BDFFloat *sel = bv->bc->selection;
     438           0 :     GClut *clut = bv->bdf->clut;
     439           0 :     Color bg = view_bgcol;
     440             :     int i,j;
     441             : 
     442           0 :     pixel.width = pixel.height = bv->scale+1;
     443           0 :     for ( i=sel->ymax-sel->ymin; i>=0; --i ) {
     444           0 :         for ( j=0; j<=sel->xmax-sel->xmin; ++j ) {
     445           0 :             pixel.x = bv->xoff + (sel->xmin+j)*bv->scale;
     446           0 :             pixel.y = bv->height-bv->yoff-(sel->ymax-i+1)*bv->scale;
     447           0 :             if ( clut==NULL ) {
     448           0 :                 if ( sel->bitmap[i*sel->bytes_per_line+(j>>3)] & (1<<(7-(j&7))) ) {
     449           0 :                     GDrawFillRect(pixmap,&pixel,0x808080);
     450             :                 } else {
     451           0 :                     GDrawFillRect(pixmap,&pixel,bg);
     452             :                 }
     453             :             } else
     454           0 :                 GDrawFillRect(pixmap,&pixel,
     455           0 :                         clut->clut[sel->bitmap[i*sel->bytes_per_line+j]]);
     456             :         }
     457             :     }
     458           0 :     GDrawSetStippled(pixmap,1, 0,0);
     459           0 :     rect.width = (sel->xmax-sel->xmin+1)*bv->scale;
     460           0 :     rect.height = (sel->ymax-sel->ymin+1)*bv->scale;
     461           0 :     rect.x = bv->xoff + sel->xmin*bv->scale;
     462           0 :     rect.y = bv->height-bv->yoff-(sel->ymax+1)*bv->scale;
     463           0 :     GDrawFillRect(pixmap,&rect,0x909000);
     464           0 :     GDrawSetStippled(pixmap,0, 0,0);
     465           0 : }
     466             : 
     467           0 : static void BCBresenhamLine(BitmapView *bv,
     468             :         void (*SetPoint)(BitmapView *,int x, int y, void *data),void *data) {
     469             :     /* Draw a line from (pressed_x,pressed_y) to (info_x,info_y) */
     470             :     /*  and call SetPoint for each point */
     471             :     int dx,dy,incr1,incr2,d,x,y,xend;
     472           0 :     int x1 = bv->pressed_x, y1 = bv->pressed_y;
     473           0 :     int x2 = bv->info_x, y2 = bv->info_y;
     474             :     int up;
     475             : 
     476           0 :     if ( y2<y1 ) {
     477           0 :         y2 ^= y1; y1 ^= y2; y2 ^= y1;
     478           0 :         x2 ^= x1; x1 ^= x2; x2 ^= x1;
     479             :     }
     480           0 :     dy = y2-y1;
     481           0 :     if (( dx = x2-x1)<0 ) dx=-dx;
     482             : 
     483           0 :     if ( dy<=dx ) {
     484           0 :         d = 2*dy-dx;
     485           0 :         incr1 = 2*dy;
     486           0 :         incr2 = 2*(dy-dx);
     487           0 :         if ( x1>x2 ) {
     488           0 :             x = x2; y = y2;
     489           0 :             xend = x1;
     490           0 :             up = -1;
     491             :         } else {
     492           0 :             x = x1; y = y1;
     493           0 :             xend = x2;
     494           0 :             up = 1;
     495             :         }
     496           0 :         (SetPoint)(bv,x,y,data);
     497           0 :         while ( x<xend ) {
     498           0 :             ++x;
     499           0 :             if ( d<0 ) d+=incr1;
     500             :             else {
     501           0 :                 y += up;
     502           0 :                 d += incr2;
     503             :             }
     504           0 :             (SetPoint)(bv,x,y,data);
     505             :         }
     506             :     } else {
     507           0 :         d = 2*dx-dy;
     508           0 :         incr1 = 2*dx;
     509           0 :         incr2 = 2*(dx-dy);
     510           0 :         x = x1; y = y1;
     511           0 :         if ( x1>x2 ) up = -1; else up = 1;
     512           0 :         (SetPoint)(bv,x,y,data);
     513           0 :         while ( y<y2 ) {
     514           0 :             ++y;
     515           0 :             if ( d<0 ) d+=incr1;
     516             :             else {
     517           0 :                 x += up;
     518           0 :                 d += incr2;
     519             :             }
     520           0 :             (SetPoint)(bv,x,y,data);
     521             :         }
     522             :     }
     523           0 : }
     524             : 
     525           0 : static void CirclePoints(BitmapView *bv,int x, int y, int ox, int oy, int xmod, int ymod,
     526             :         void (*SetPoint)(BitmapView *,int x, int y, void *data),void *data) {
     527             :     /* we draw the quadrant between Pi/2 and 0 */
     528           0 :     if ( bv->active_tool == bvt_filledelipse ) {
     529             :         int j;
     530           0 :         for ( j=2*oy+ymod-y; j<=y; ++j ) {
     531           0 :             SetPoint(bv,x,j,data);
     532           0 :             SetPoint(bv,2*ox+xmod-x,j,data);
     533             :         }
     534             :     } else {
     535           0 :         SetPoint(bv,x,y,data);
     536           0 :         SetPoint(bv,x,2*oy+ymod-y,data);
     537           0 :         SetPoint(bv,2*ox+xmod-x,y,data);
     538           0 :         SetPoint(bv,2*ox+xmod-x,2*oy+ymod-y,data);
     539             :     }
     540           0 : }
     541             : 
     542           0 : void BCGeneralFunction(BitmapView *bv,
     543             :         void (*SetPoint)(BitmapView *,int x, int y, void *data),void *data) {
     544             :     int i, j;
     545             :     int xmin, xmax, ymin, ymax;
     546             :     int ox, oy, modx, mody;
     547             :     int dx, dy, c,d,dx2,dy2,xp,yp;
     548             :     int x,y;
     549             : 
     550           0 :     if ( bv->pressed_x<bv->info_x ) {
     551           0 :         xmin = bv->pressed_x; xmax = bv->info_x;
     552             :     } else {
     553           0 :         xmin = bv->info_x; xmax = bv->pressed_x;
     554             :     }
     555           0 :     if ( bv->pressed_y<bv->info_y ) {
     556           0 :         ymin = bv->pressed_y; ymax = bv->info_y;
     557             :     } else {
     558           0 :         ymin = bv->info_y; ymax = bv->pressed_y;
     559             :     }
     560             : 
     561           0 :     switch ( bv->active_tool ) {
     562             :       case bvt_line:
     563           0 :         BCBresenhamLine(bv,SetPoint,data);
     564           0 :       break;
     565             :       case bvt_rect:
     566           0 :         for ( i=xmin; i<=xmax; ++i ) {
     567           0 :             SetPoint(bv,i,bv->pressed_y,data);
     568           0 :             SetPoint(bv,i,bv->info_y,data);
     569             :         }
     570           0 :         for ( i=ymin; i<=ymax; ++i ) {
     571           0 :             SetPoint(bv,bv->pressed_x,i,data);
     572           0 :             SetPoint(bv,bv->info_x,i,data);
     573             :         }
     574           0 :       break;
     575             :       case bvt_filledrect:
     576           0 :         for ( i=xmin; i<=xmax; ++i ) {
     577           0 :             for ( j=ymin; j<=ymax; ++j )
     578           0 :                 SetPoint(bv,i,j,data);
     579             :         }
     580           0 :       break;
     581             :       case bvt_elipse: case bvt_filledelipse:
     582           0 :         if ( xmax==xmin || ymax==ymin )         /* degenerate case */
     583           0 :             BCBresenhamLine(bv,SetPoint,data);
     584             :         else {
     585           0 :             ox = floor( (xmin+xmax)/2.0 );
     586           0 :             oy = floor( (ymin+ymax)/2.0 );
     587           0 :             modx = (xmax+xmin)&1; mody = (ymax+ymin)&1;
     588           0 :             dx = ox-xmin;
     589           0 :             dy = oy-ymin;
     590           0 :             dx2 = dx*dx; dy2 = dy*dy;
     591           0 :             xp = 0; yp = 4*dy*dx2;
     592           0 :             c = dy2+(2-4*dy)*dx2; d = 2*dy2 + (1-2*dy)*dx2;
     593           0 :             x = ox+modx; y = ymax;
     594           0 :             CirclePoints(bv,x,y,ox,oy,modx,mody,SetPoint,data);
     595           0 :             while ( x!=xmax ) {
     596             : #define move_right() (c += 4*dy2+xp, d += 6*dy2+xp, ++x, xp += 4*dy2 )
     597             : #define move_down() (c += 6*dx2-yp, d += 4*dx2-yp, --y, yp -= 4*dx2 )
     598           0 :                 if ( d<0 || y==0 )
     599           0 :                     move_right();
     600           0 :                 else if ( c > 0 )
     601           0 :                     move_down();
     602             :                 else {
     603           0 :                     move_right();
     604           0 :                     move_down();
     605             :                 }
     606             : #undef move_right
     607             : #undef move_down
     608           0 :                 if ( y<oy )          /* degenerate cases */
     609           0 :             break;
     610           0 :                 CirclePoints(bv,x,y,ox,oy,modx,mody,SetPoint,data);
     611             :             }
     612           0 :             if ( bv->active_tool==bvt_elipse ) {
     613             :                 /* there may be quite a gap between the two semi-circles */
     614             :                 /*  because the tangent is nearly vertical here. So just fill */
     615             :                 /*  it in */
     616             :                 int j;
     617           0 :                 for ( j=2*oy+mody-y; j<=y; ++j ) {
     618           0 :                     SetPoint(bv,x,j,data);
     619           0 :                     SetPoint(bv,2*ox+modx-x,j,data);
     620             :                 }
     621             :             }
     622             :         }
     623           0 :       break;
     624             :     }
     625           0 : }
     626             : 
     627           0 : static void BVDrawRefName(BitmapView *bv,GWindow pixmap,BDFRefChar *ref,int fg) {
     628             :     int x,y, len;
     629             :     GRect size;
     630             :     char *refinfo;
     631             :     IBounds bb;
     632             : 
     633           0 :     refinfo = malloc(strlen(ref->bdfc->sc->name) +  30);
     634           0 :     sprintf(refinfo,"%s XOff: %d YOff: %d", ref->bdfc->sc->name, ref->xoff, ref->yoff);
     635             : 
     636           0 :     bb.minx = ref->bdfc->xmin + ref->xoff;
     637           0 :     bb.maxx = ref->bdfc->xmax + ref->xoff;
     638           0 :     bb.miny = ref->bdfc->ymin + ref->yoff;
     639           0 :     bb.maxy = ref->bdfc->ymax + ref->yoff;
     640           0 :     BDFCharQuickBounds(ref->bdfc,&bb,ref->xoff,ref->yoff,false,true);
     641           0 :     x = bv->xoff + (bb.minx)*bv->scale;
     642           0 :     y = bv->height - bv->yoff - (bb.maxy + 1)*bv->scale;
     643           0 :     y -= 5;
     644           0 :     if ( x<-400 || y<-40 || x>bv->width+400 || y>bv->height )
     645             :     {
     646           0 :         free(refinfo);
     647           0 : return;
     648             :     }
     649             : 
     650           0 :     GDrawLayoutInit(pixmap,refinfo,-1,bv->small);
     651           0 :     GDrawLayoutExtents(pixmap,&size);
     652           0 :     GDrawLayoutDraw(pixmap,x-size.width/2,y,fg);
     653           0 :     len = size.width;
     654           0 :     free(refinfo);
     655             : }
     656             : 
     657           0 : static void BVDrawGlyph(BitmapView *bv, BDFChar *bc, GWindow pixmap, GRect *pixel,
     658             :         uint8 is_ref, uint8 selected, int8 xoff, int8 yoff) {
     659             :     int i, j;
     660           0 :     int color = 0x808080;
     661           0 :     BDFFont *bdf = bv->bdf;
     662             :     BDFRefChar *cur;
     663             : 
     664           0 :     if ( is_ref && !selected  )
     665           0 :         GDrawSetStippled(pixmap,1, 0,0);
     666           0 :     for ( i=bc->ymax-bc->ymin; i>=0; --i ) {
     667           0 :         for ( j=0; j<=bc->xmax-bc->xmin; ++j ) {
     668           0 :             pixel->x = bv->xoff + (bc->xmin + xoff +j)*bv->scale;
     669           0 :             pixel->y = bv->height-bv->yoff - (bc->ymax + yoff - i + 1)*bv->scale;
     670           0 :             if ( bdf->clut==NULL ) {
     671           0 :                 if ( bc->bitmap[i*bc->bytes_per_line+(j>>3)] & (1<<(7-(j&7))) ) {
     672           0 :                     GDrawFillRect(pixmap,pixel,color);
     673           0 :                     if ( selected ) {
     674           0 :                         GDrawSetStippled(pixmap,2, 0,0);
     675           0 :                         GDrawFillRect(pixmap,pixel,0x909000);
     676           0 :                         GDrawSetStippled(pixmap,0, 0,0);
     677             :                     }
     678             :                 }
     679             :             } else {
     680           0 :                 int index = bc->bitmap[i*bc->bytes_per_line+j];
     681           0 :                 if ( index!=0 ) {
     682           0 :                     GDrawFillRect(pixmap,pixel,bdf->clut->clut[index]);
     683           0 :                     if ( selected ) {
     684           0 :                         GDrawSetStippled(pixmap,2, 0,0);
     685           0 :                         GDrawFillRect(pixmap,pixel,0x909000);
     686           0 :                         GDrawSetStippled(pixmap,0, 0,0);
     687             :                     }
     688             :                 }
     689             :             }
     690             :         }
     691             :     }
     692           0 :     if ( is_ref ) {
     693           0 :         GDrawSetStippled(pixmap,0, 0,0);
     694           0 :         BVDrawRefBorder( bv,bc,pixmap,selected,xoff,yoff );
     695             :     }
     696           0 :     for ( cur=bc->refs; cur!=NULL; cur=cur->next ) if ( cur->bdfc != NULL ) {
     697           0 :         BVDrawGlyph( bv,cur->bdfc,pixmap,pixel,true,(cur->selected | selected),
     698           0 :             xoff+cur->xoff,yoff+cur->yoff );
     699             :     }
     700           0 : }
     701             : 
     702           0 : static void BVExpose(BitmapView *bv, GWindow pixmap, GEvent *event ) {
     703             :     CharView cvtemp;
     704             :     GRect old;
     705             :     DRect clip;
     706             :     int i;
     707             :     GRect pixel;
     708           0 :     BDFChar *bc = bv->bc;
     709             :     BDFRefChar *bref;
     710             :     RefChar *refs;
     711             :     extern Color widthcol;
     712             : 
     713           0 :     GDrawPushClip(pixmap,&event->u.expose.rect,&old);
     714           0 :     GDrawSetLineWidth(pixmap,0);
     715           0 :     if ( bv->showfore ) {
     716             :         /* fore ground is a misnomer. it's what we're interested in but we */
     717             :         /*  actually need to draw it first, otherwise it obscures everything */
     718           0 :         pixel.width = pixel.height = bv->scale+1;
     719           0 :         BVDrawGlyph( bv,bc,pixmap,&pixel,false,false,0,0 );
     720             : 
     721           0 :         if ( bv->active_tool!=bvt_none ) {
     722             :             /* This does nothing for many tools, but for lines, rects and circles */
     723             :             /*  it draws temporary points */
     724           0 :             BCGeneralFunction(bv,BVDrawTempPoint,pixmap);
     725             :         }
     726             :         /* Selected references are handled in BVDrawGlyph() */
     727           0 :         if ( bv->bc->selection )
     728           0 :             BVDrawSelection(bv,pixmap);
     729             :     }
     730           0 :     if ( bv->showgrid ) {
     731           0 :         if ( bv->scale>2 ) {
     732           0 :             for ( i=bv->xoff+bv->scale; i<bv->width; i += bv->scale )
     733           0 :                 GDrawDrawLine(pixmap,i,0, i,bv->height,0xa0a0a0);
     734           0 :             for ( i=bv->xoff-bv->scale; i>0; i -= bv->scale )
     735           0 :                 GDrawDrawLine(pixmap,i,0, i,bv->height,0xa0a0a0);
     736           0 :             for ( i=-bv->yoff+bv->height-bv->scale; i>0; i -= bv->scale )
     737           0 :                 GDrawDrawLine(pixmap,0,i,bv->width,i,0xa0a0a0);
     738           0 :             for ( i=-bv->yoff+bv->height+bv->scale; i<bv->height; i += bv->scale )
     739           0 :                 GDrawDrawLine(pixmap,0,i,bv->width,i,0xa0a0a0);
     740             :         }
     741           0 :         GDrawDrawLine(pixmap,0,-bv->yoff+bv->height-0*bv->scale,bv->width,-bv->yoff+bv->height-0*bv->scale,0x404040);
     742           0 :         GDrawDrawLine(pixmap,0,-bv->yoff+bv->height-bv->bdf->ascent*bv->scale,
     743           0 :                 bv->width,-bv->yoff+bv->height-bv->bdf->ascent*bv->scale,0x404040);
     744           0 :         GDrawDrawLine(pixmap,0,-bv->yoff+bv->height+bv->bdf->descent*bv->scale,
     745           0 :                 bv->width,-bv->yoff+bv->height+bv->bdf->descent*bv->scale,0x404040);
     746           0 :         GDrawDrawLine(pixmap,bv->xoff+0*bv->scale,0, bv->xoff+0*bv->scale,bv->height,0x404040);
     747           0 :         GDrawDrawLine(pixmap,bv->xoff+bv->bc->width*bv->scale,0, bv->xoff+bv->bc->width*bv->scale,bv->height,widthcol);
     748           0 :         if ( bv->bdf->sf->hasvmetrics )
     749           0 :             GDrawDrawLine(pixmap,0,-bv->yoff+bv->height-(bv->bdf->ascent-bc->vwidth)*bv->scale,
     750           0 :                     bv->width,-bv->yoff+bv->height-(bv->bdf->ascent-bc->vwidth)*bv->scale,widthcol);
     751             :     }
     752           0 :     if ( bv->showfore ) {
     753             :         /* Reference names are drawn after grid (otherwise some characters may get unreadable */
     754           0 :         for ( bref=bc->refs; bref!=NULL; bref=bref->next )
     755           0 :             BVDrawRefName( bv,pixmap,bref,0 );
     756             :     }
     757           0 :     if ( bv->showoutline ) {
     758           0 :         Color col = (view_bgcol<0x808080)
     759           0 :                 ? (bv->bc->byte_data ? 0x008800 : 0x004400 )
     760             :                 : 0x00ff00;
     761           0 :         memset(&cvtemp,'\0',sizeof(cvtemp));
     762           0 :         cvtemp.v = bv->v;
     763           0 :         cvtemp.width = bv->width;
     764           0 :         cvtemp.height = bv->height;
     765           0 :         cvtemp.scale = bv->scscale*bv->scale;
     766           0 :         cvtemp.xoff = bv->xoff/* *bv->scscale*/;
     767           0 :         cvtemp.yoff = bv->yoff/* *bv->scscale*/;
     768           0 :         cvtemp.b.sc = bv->bc->sc;
     769           0 :         cvtemp.b.drawmode = dm_fore;
     770             : 
     771           0 :         clip.width = event->u.expose.rect.width/cvtemp.scale;
     772           0 :         clip.height = event->u.expose.rect.height/cvtemp.scale;
     773           0 :         clip.x = (event->u.expose.rect.x-cvtemp.xoff)/cvtemp.scale;
     774           0 :         clip.y = (cvtemp.height-event->u.expose.rect.y-event->u.expose.rect.height-cvtemp.yoff)/cvtemp.scale;
     775           0 :         CVDrawSplineSet(&cvtemp,pixmap,cvtemp.b.sc->layers[ly_fore].splines,col,false,&clip);
     776           0 :         for ( refs = cvtemp.b.sc->layers[ly_fore].refs; refs!=NULL; refs = refs->next )
     777           0 :             CVDrawSplineSet(&cvtemp,pixmap,refs->layers[0].splines,col,false,&clip);
     778             :     }
     779           0 :     if ( bv->active_tool==bvt_pointer ) {
     780           0 :         if ( bv->bc->selection==NULL ) {
     781             :             int xmin, xmax, ymin, ymax;
     782           0 :             xmin = bv->pressed_x; xmax = bv->info_x;
     783           0 :             ymin = bv->info_y; ymax = bv->pressed_y;
     784           0 :             if ( ymin>ymax ) { ymax = ymin; ymin = bv->pressed_y; }
     785           0 :             if ( xmin>xmax ) { xmin = xmax; xmax = bv->pressed_x; }
     786           0 :             pixel.width = (xmax-xmin+1) * bv->scale;
     787           0 :             pixel.height = (ymax-ymin+1) * bv->scale;
     788           0 :             pixel.x =  bv->xoff + xmin*bv->scale;
     789           0 :             pixel.y = bv->height-bv->yoff-(ymax+1)*bv->scale;
     790           0 :             GDrawSetDashedLine(pixmap,3,3,0);
     791           0 :             GDrawDrawRect(pixmap,&pixel,0xffffff);
     792           0 :             GDrawSetDashedLine(pixmap,3,3,3);
     793           0 :             GDrawDrawRect(pixmap,&pixel,0x000000);
     794           0 :             GDrawSetDashedLine(pixmap,0,0,0);
     795             :         }
     796             :     }
     797           0 :     GDrawPopClip(pixmap,&old);
     798           0 : }
     799             : 
     800           0 : static void BVInfoDrawText(BitmapView *bv, GWindow pixmap ) {
     801             :     GRect r;
     802           0 :     Color bg = GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(pixmap));
     803             :     char buffer[50];
     804           0 :     int ybase = bv->mbh+10+bv->sas;
     805             : 
     806           0 :     GDrawSetFont(pixmap,bv->small);
     807           0 :     r.x = bv->infoh+RPT_DATA; r.width = 39;
     808           0 :     r.y = bv->mbh; r.height = 36 /* bv->infoh-1 */;
     809           0 :     GDrawFillRect(pixmap,&r,bg);
     810             : 
     811           0 :     sprintf(buffer,"%d%s%d", bv->info_x, coord_sep, bv->info_y );
     812           0 :     buffer[11] = '\0';
     813           0 :     GDrawDrawText8(pixmap,bv->infoh+RPT_DATA,ybase,buffer,-1,GDrawGetDefaultForeground(NULL));
     814             : 
     815           0 :     if ( bv->active_tool!=cvt_none ) {
     816           0 :         sprintf(buffer,"%d%s%d", bv->info_x-bv->pressed_x, coord_sep, bv->info_y-bv->pressed_y );
     817           0 :         buffer[11] = '\0';
     818           0 :         GDrawDrawText8(pixmap,bv->infoh+RPT_DATA,ybase+bv->sfh+10,buffer,-1,GDrawGetDefaultForeground(NULL));
     819             :     }
     820           0 : }
     821             : 
     822           0 : static void BVMainExpose(BitmapView *bv, GWindow pixmap, GEvent *event ) {
     823             :     GRect old, temp, box, old2, r;
     824             :     GImage gi;
     825             :     struct _GImage base;
     826             :     GClut clut;
     827           0 :     BDFChar *bdfc = BDFGetMergedChar( bv->bc );
     828             : 
     829           0 :     temp = event->u.expose.rect;
     830           0 :     if ( temp.y+temp.height < bv->mbh )
     831           0 : return;
     832           0 :     if ( temp.y <bv->mbh ) {
     833           0 :         temp.height -= (bv->mbh-temp.y);
     834           0 :         temp.y = bv->mbh;
     835             :     }
     836           0 :     GDrawPushClip(pixmap,&temp,&old);
     837           0 :     GDrawSetLineWidth(pixmap,0);
     838             : 
     839           0 :     if ( event->u.expose.rect.x<6+bdfc->xmax-bdfc->xmin ) {
     840           0 :         box.x = 0; box.width = bv->infoh;
     841           0 :         box.y = bv->mbh; box.height = bv->infoh;
     842           0 :         GDrawPushClip(pixmap,&box,&old2);
     843             : 
     844           0 :         memset(&gi,'\0',sizeof(gi));
     845           0 :         memset(&base,'\0',sizeof(base));
     846           0 :         memset(&clut,'\0',sizeof(clut));
     847           0 :         gi.u.image = &base;
     848           0 :         if ( bv->bdf->clut==NULL ) {
     849           0 :             base.image_type = it_mono;
     850           0 :             base.clut = &clut;
     851           0 :             clut.clut_len = 2;
     852           0 :             clut.clut[0] = GDrawGetDefaultBackground(NULL);
     853             :         } else {
     854           0 :             base.image_type = it_index;
     855           0 :             base.clut = bv->bdf->clut;
     856             :         }
     857           0 :         base.data = bdfc->bitmap;
     858           0 :         base.bytes_per_line = bdfc->bytes_per_line;
     859           0 :         base.width = bdfc->xmax-bdfc->xmin+1;
     860           0 :         base.height = bdfc->ymax-bdfc->ymin+1;
     861           0 :         GDrawDrawImage(pixmap,&gi,NULL, 5,bv->mbh+(bv->infoh-base.height)/2);
     862             : 
     863           0 :         GDrawPopClip(pixmap,&old2);
     864             : 
     865           0 :         GDrawDrawImage(pixmap,&GIcon_rightpointer,NULL,bv->infoh+RPT_BASE,bv->mbh+8);
     866           0 :         GDrawDrawImage(pixmap,&GIcon_press2ptr,NULL,bv->infoh+RPT_BASE,bv->mbh+18+bv->sfh);
     867           0 :         BVInfoDrawText(bv,pixmap );
     868             : 
     869           0 :         r.x = bv->infoh+RPT_DATA; r.y = bv->mbh+36;
     870           0 :         r.width = 20; r.height = 10;
     871           0 :         GDrawFillRect(pixmap,&r,
     872           0 :                 bv->bdf->clut==NULL ? GDrawGetDefaultBackground(NULL) :
     873           0 :                 bv->bdf->clut->clut[bv->color/( 255/((1<<BDFDepth(bv->bdf))-1) )] );
     874             : 
     875           0 :         GDrawDrawImage(pixmap,&GIcon_press2ptr,NULL,bv->infoh+RPT_BASE,bv->mbh+18+bv->sfh);
     876             :     }
     877           0 :     GDrawDrawLine(pixmap,0,bv->mbh+bv->infoh-1,bv->width+300,bv->mbh+bv->infoh-1,GDrawGetDefaultForeground(NULL));
     878             : 
     879           0 :     r.x = bv->width; r.y = bv->height+bv->infoh+bv->mbh;
     880           0 :     LogoExpose(pixmap,event,&r,dm_fore);
     881             : 
     882           0 :     GDrawPopClip(pixmap,&old);
     883           0 :     BDFCharFree( bdfc );
     884             : }
     885             : 
     886           0 : static void BVShowInfo(BitmapView *bv) {
     887           0 :     BVInfoDrawText(bv,bv->gw );
     888           0 : }
     889             : 
     890           0 : static void BVResize(BitmapView *bv, GEvent *event ) {
     891           0 :     int sbsize = GDrawPointsToPixels(bv->gw,_GScrollBar_Width);
     892           0 :     int newwidth = event->u.resize.size.width-sbsize,
     893           0 :         newheight = event->u.resize.size.height-sbsize - bv->mbh-bv->infoh;
     894             :     GRect size;
     895             : 
     896           0 :     if ( newwidth == bv->width && newheight == bv->height )
     897           0 : return;
     898             : 
     899             :     /* MenuBar takes care of itself */
     900           0 :     GDrawResize(bv->v,newwidth,newheight);
     901           0 :     GGadgetMove(bv->vsb,newwidth, bv->mbh+bv->infoh);
     902           0 :     GGadgetResize(bv->vsb,sbsize,newheight);
     903           0 :     GGadgetMove(bv->hsb,0,event->u.resize.size.height-sbsize);
     904           0 :     GGadgetResize(bv->hsb,newwidth,sbsize);
     905           0 :     bv->width = newwidth; bv->height = newheight;
     906           0 :     GGadgetGetSize(bv->recalc,&size);
     907           0 :     GGadgetMove(bv->recalc,event->u.resize.size.width - size.width - GDrawPointsToPixels(bv->gw,6),size.y);
     908           0 :     GDrawRequestExpose(bv->gw,NULL,false);
     909           0 :     BVFit(bv);
     910             : 
     911           0 :     bv_width  = event->u.resize.size.width;
     912           0 :     bv_height = event->u.resize.size.height;
     913           0 :     SavePrefs(true);
     914             : }
     915             : 
     916           0 : static void BVHScroll(BitmapView *bv,struct sbevent *sb) {
     917           0 :     int newpos = bv->xoff;
     918           0 :     int fh = bv->bdf->ascent+bv->bdf->descent;
     919             : 
     920           0 :     switch( sb->type ) {
     921             :       case et_sb_top:
     922           0 :         newpos = 0;
     923           0 :       break;
     924             :       case et_sb_uppage:
     925           0 :         newpos += 9*bv->width/10;
     926           0 :       break;
     927             :       case et_sb_up:
     928           0 :         newpos += bv->width/15;
     929           0 :       break;
     930             :       case et_sb_down:
     931           0 :         newpos -= bv->width/15;
     932           0 :       break;
     933             :       case et_sb_downpage:
     934           0 :         newpos -= 9*bv->width/10;
     935           0 :       break;
     936             :       case et_sb_bottom:
     937           0 :         newpos = 0;
     938           0 :       break;
     939             :       case et_sb_thumb:
     940             :       case et_sb_thumbrelease:
     941           0 :         newpos = -sb->pos;
     942           0 :       break;
     943             :       case et_sb_halfup:
     944           0 :         newpos += bv->width/30;
     945           0 :       break;
     946             :       case et_sb_halfdown:
     947           0 :         newpos -= bv->width/30;
     948           0 :       break;
     949             :     }
     950           0 :     if ( newpos>6*fh*bv->scale-bv->width )
     951           0 :         newpos = 6*fh*bv->scale-bv->width;
     952           0 :     if ( newpos<-3*fh*bv->scale ) newpos = -3*fh*bv->scale;
     953           0 :     if ( newpos!=bv->xoff ) {
     954           0 :         int diff = newpos-bv->xoff;
     955           0 :         bv->xoff = newpos;
     956           0 :         GScrollBarSetPos(bv->hsb,-newpos);
     957           0 :         GDrawScroll(bv->v,NULL,diff,0);
     958             :     }
     959           0 : }
     960             : 
     961           0 : static void BVVScroll(BitmapView *bv,struct sbevent *sb) {
     962           0 :     int newpos = bv->yoff;
     963           0 :     int fh = bv->bdf->ascent+bv->bdf->descent;
     964             : 
     965           0 :     switch( sb->type ) {
     966             :       case et_sb_top:
     967           0 :         newpos = 0;
     968           0 :       break;
     969             :       case et_sb_uppage:
     970           0 :         newpos -= 9*bv->width/10;
     971           0 :       break;
     972             :       case et_sb_up:
     973           0 :         newpos -= bv->width/15;
     974           0 :       break;
     975             :       case et_sb_down:
     976           0 :         newpos += bv->width/15;
     977           0 :       break;
     978             :       case et_sb_downpage:
     979           0 :         newpos += 9*bv->width/10;
     980           0 :       break;
     981             :       case et_sb_bottom:
     982           0 :         newpos = 0;
     983           0 :       break;
     984             :       case et_sb_thumb:
     985             :       case et_sb_thumbrelease:
     986           0 :         newpos = sb->pos;
     987           0 :       break;
     988             :       case et_sb_halfup:
     989           0 :         newpos -= bv->width/30;
     990           0 :       break;
     991             :       case et_sb_halfdown:
     992           0 :         newpos += bv->width/30;
     993           0 :       break;
     994             :     }
     995           0 :     if ( newpos>4*fh*bv->scale-bv->height )
     996           0 :         newpos = 4*fh*bv->scale-bv->height;
     997           0 :     if ( newpos<-2*fh*bv->scale ) newpos = -2*fh*bv->scale;
     998           0 :     if ( newpos!=bv->yoff ) {
     999           0 :         int diff = newpos-bv->yoff;
    1000           0 :         bv->yoff = newpos;
    1001           0 :         GScrollBarSetPos(bv->vsb,newpos);
    1002           0 :         GDrawScroll(bv->v,NULL,0,diff);
    1003             :     }
    1004           0 : }
    1005             : 
    1006           0 : static int BVRecalc(GGadget *g, GEvent *e) {
    1007             :     BitmapView *bv;
    1008             :     BDFChar *bdfc;
    1009           0 :     void *freetypecontext=NULL;
    1010             : 
    1011           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1012           0 :         bv = GDrawGetUserData(GGadgetGetWindow(g));
    1013           0 :         BCPreserveState(bv->bc);
    1014           0 :         BCFlattenFloat(bv->bc);
    1015           0 :         freetypecontext = FreeTypeFontContext(bv->bc->sc->parent,bv->bc->sc,NULL,ly_fore);
    1016           0 :         if ( freetypecontext!=NULL ) {
    1017           0 :             bdfc = SplineCharFreeTypeRasterize(freetypecontext,bv->bc->sc->orig_pos,bv->bdf->pixelsize,72,BDFDepth(bv->bdf));
    1018           0 :             FreeTypeFreeContext(freetypecontext);
    1019             :         } else
    1020           0 :             bdfc = SplineCharAntiAlias(bv->bc->sc,ly_fore,bv->bdf->pixelsize,(1<<(BDFDepth(bv->bdf)/2)));
    1021           0 :         free(bv->bc->bitmap);
    1022           0 :         bv->bc->bitmap = bdfc->bitmap; bdfc->bitmap = NULL;
    1023           0 :         bv->bc->width = bdfc->width;
    1024           0 :         bv->bc->xmin = bdfc->xmin;
    1025           0 :         bv->bc->xmax = bdfc->xmax;
    1026           0 :         bv->bc->ymin = bdfc->ymin;
    1027           0 :         bv->bc->ymax = bdfc->ymax;
    1028           0 :         bv->bc->bytes_per_line = bdfc->bytes_per_line;
    1029           0 :         BDFCharFree(bdfc);
    1030           0 :         BCCharChangedUpdate(bv->bc);
    1031             :     }
    1032           0 : return( true );
    1033             : }
    1034             : 
    1035           0 : static void BVSetWidth(BitmapView *bv, int x) {
    1036             :     int tot, cnt;
    1037             :     BDFFont *bdf;
    1038           0 :     BDFChar *bc = bv->bc;
    1039             : 
    1040           0 :     bc->width = x;
    1041           0 :     if ( bv->bdf->sf->onlybitmaps ) {
    1042           0 :         tot=0; cnt=0;
    1043           0 :         for ( bdf = bv->bdf->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
    1044           0 :             if ( bdf->glyphs[bc->orig_pos]) {
    1045           0 :                 tot += bdf->glyphs[bc->orig_pos]->width*1000/(bdf->ascent+bdf->descent);
    1046           0 :                 ++cnt;
    1047             :             }
    1048           0 :         if ( cnt!=0 ) {
    1049           0 :             bc->sc->width = tot/cnt;
    1050           0 :             bc->sc->widthset = true;
    1051             :         }
    1052             :     }
    1053           0 :     BCCharChangedUpdate(bc);
    1054           0 : }
    1055             : 
    1056           0 : static void BVSetVWidth(BitmapView *bv, int y) {
    1057             :     int tot, cnt;
    1058             :     BDFFont *bdf;
    1059           0 :     BDFChar *bc = bv->bc;
    1060             : 
    1061           0 :     if ( !bv->bdf->sf->hasvmetrics )
    1062           0 : return;
    1063           0 :     bc->vwidth = bv->bdf->ascent-y;
    1064           0 :     if ( bv->bdf->sf->onlybitmaps ) {
    1065           0 :         tot=0; cnt=0;
    1066           0 :         for ( bdf = bv->bdf->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
    1067           0 :             if ( bdf->glyphs[bc->orig_pos]) {
    1068           0 :                 tot += bdf->glyphs[bc->orig_pos]->vwidth*1000/(bdf->ascent+bdf->descent);
    1069           0 :                 ++cnt;
    1070             :             }
    1071           0 :         if ( cnt!=0 && bv->bdf->sf->onlybitmaps ) {
    1072           0 :             bc->sc->vwidth = tot/cnt;
    1073           0 :             bc->sc->widthset = true;
    1074             :         }
    1075             :     }
    1076           0 :     BCCharChangedUpdate(bc);
    1077             : }
    1078             : 
    1079           0 : int BVColor(BitmapView *bv) {
    1080           0 :     int div = 255/((1<<BDFDepth(bv->bdf))-1);
    1081           0 : return ( (bv->color+div/2)/div );
    1082             : }
    1083             : 
    1084           0 : static int IsReferenceTouched(BitmapView *bv, BDFRefChar *ref, int x, int y){
    1085             :     BDFRefChar *head;
    1086             :     BDFChar *rbc;
    1087             :     int nx, ny;
    1088             : 
    1089           0 :     if ( ref == NULL )
    1090           0 : return( false );
    1091             : 
    1092           0 :     rbc = ref->bdfc;
    1093           0 :     ny = rbc->ymax - y + ref->yoff;
    1094           0 :     nx = x - rbc->xmin - ref->xoff;
    1095           0 :     if (nx>=0 && nx<=( rbc->xmax - rbc->xmin ) &&
    1096           0 :         ny>=0 && ny<=( rbc->ymax - rbc->ymin ) &&
    1097           0 :         (( rbc->byte_data && rbc->bitmap[ny*rbc->bytes_per_line+nx] != 0 ) ||
    1098           0 :         (( !rbc->byte_data &&
    1099           0 :             rbc->bitmap[ny*rbc->bytes_per_line + (nx>>3)] & (1<<(7 - (nx&7)))))))
    1100           0 : return( true );
    1101             : 
    1102           0 :     for ( head = rbc->refs; head != NULL; head = head->next ) {
    1103           0 :         if ( IsReferenceTouched( bv,head,x,y))
    1104           0 : return( true );
    1105             :     }
    1106           0 : return( false );
    1107             : }
    1108             : 
    1109           0 : static void BVMouseDown(BitmapView *bv, GEvent *event) {
    1110           0 :     int x = floor( (event->u.mouse.x-bv->xoff)/ (real) bv->scale);
    1111           0 :     int y = floor( (bv->height-event->u.mouse.y-bv->yoff)/ (real) bv->scale);
    1112             :     int ny;
    1113           0 :     BDFChar *bc = bv->bc;
    1114             :     BDFFloat *sel;
    1115             :     int color_under_cursor;
    1116           0 :     BDFRefChar *refsel = NULL, *head;
    1117             : 
    1118           0 :     if ( event->u.mouse.button==2 && event->u.mouse.device!=NULL &&
    1119           0 :             strcmp(event->u.mouse.device,"stylus")==0 )
    1120           0 : return;         /* I treat this more like a modifier key change than a button press */
    1121             : 
    1122           0 :     if ( event->u.mouse.button==3 ) {
    1123           0 :         BVToolsPopup(bv,event);
    1124           0 : return;
    1125             :     }
    1126           0 :     BVToolsSetCursor(bv,event->u.mouse.state|(1<<(7+event->u.mouse.button)), event->u.mouse.device );
    1127           0 :     bv->active_tool = bv->showing_tool;
    1128           0 :     bv->pressed_x = x; bv->pressed_y = y;
    1129           0 :     bv->info_x = x; bv->info_y = y;
    1130           0 :     ny = bc->ymax-y;
    1131           0 :     if ( x<bc->xmin || x>bc->xmax || ny<0 || ny>bc->ymax-bc->ymin )
    1132           0 :         color_under_cursor = 0;
    1133           0 :     else if ( bc->byte_data )
    1134           0 :         color_under_cursor = bc->bitmap[(bc->ymax-y)*bc->bytes_per_line + x-bc->xmin] *
    1135           0 :                 255/((1<<BDFDepth(bv->bdf))-1);
    1136             :     else
    1137           0 :         color_under_cursor = bc->bitmap[(bc->ymax-y)*bc->bytes_per_line + (x-bc->xmin)/8]&(0x80>>((x-bc->xmin)&7)) *
    1138             :                 255;
    1139           0 :     BVPaletteColorUnderChange(bv,color_under_cursor);
    1140           0 :     bv->event_x = event->u.mouse.x; bv->event_y = event->u.mouse.y;
    1141           0 :     bv->recentchange = false;
    1142           0 :     for ( head = bc->refs; head != NULL; head = head->next ) {
    1143           0 :         if ( IsReferenceTouched( bv,head,x,y ))
    1144           0 :             refsel = head;
    1145             :     }
    1146           0 :     switch ( bv->active_tool ) {
    1147             :       case bvt_eyedropper:
    1148           0 :         bv->color = color_under_cursor;
    1149             :         /* Store color as a number between 0 and 255 no matter what the clut size is */
    1150           0 :         BVPaletteColorChange(bv);
    1151           0 :       break;
    1152             :       case bvt_pencil: case bvt_line:
    1153             :       case bvt_rect: case bvt_filledrect:
    1154           0 :         ny = bc->ymax-y;
    1155           0 :         bv->clearing = false;
    1156           0 :         if ( !bc->byte_data && x>=bc->xmin && x<=bc->xmax &&
    1157           0 :                 ny>=0 && ny<=bc->ymax-bc->ymin ) {
    1158           0 :             int nx = x-bc->xmin;
    1159           0 :             if ( bc->bitmap[ny*bc->bytes_per_line + (nx>>3)] &
    1160           0 :                 (1<<(7-(nx&7))) )
    1161           0 :             bv->clearing = true;
    1162             :         }
    1163           0 :         BCPreserveState(bc);
    1164           0 :         BCFlattenFloat(bc);
    1165           0 :         if ( bv->active_tool == bvt_pencil )
    1166           0 :             BCSetPoint(bc,x,y,bc->byte_data?BVColor(bv):!bv->clearing);
    1167           0 :         BCCharChangedUpdate(bc);
    1168           0 :       break;
    1169             :       case bvt_elipse: case bvt_filledelipse:
    1170           0 :         BCPreserveState(bc);
    1171           0 :         BCFlattenFloat(bc);
    1172           0 :         BCCharChangedUpdate(bc);
    1173           0 :       break;
    1174             :       case bvt_pointer:
    1175           0 :         if ( !( event->u.mouse.state&ksm_shift )) {
    1176           0 :             for ( head = bc->refs; head != NULL; head=head->next )
    1177           0 :                 head->selected = false;
    1178             :         }
    1179           0 :         if ( refsel != NULL ) {
    1180           0 :             BCFlattenFloat(bc);
    1181           0 :             refsel->selected = ( event->u.mouse.state&ksm_shift ) ?
    1182           0 :                 !(refsel->selected) : true;
    1183           0 :             GDrawSetCursor(bv->v,ct_shift);
    1184           0 :         } else if ( (sel = bc->selection)!=NULL ) {
    1185           0 :             if ( x<sel->xmin || x>sel->xmax || y<sel->ymin || y>sel->ymax )
    1186           0 :                 BCFlattenFloat(bc);
    1187             :             else {
    1188           0 :                 GDrawSetCursor(bv->v,ct_shift);
    1189             :                 /* otherwise we'll move the selection */
    1190             :             }
    1191           0 :         } else if ( /*bc->sc->parent->onlybitmaps &&*/
    1192           0 :                 event->u.mouse.x-bv->xoff > bc->width*bv->scale-3 &&
    1193           0 :                 event->u.mouse.x-bv->xoff < bc->width*bv->scale+3 ) {
    1194           0 :             bv->active_tool = bvt_setwidth;
    1195           0 :             BVToolsSetCursor(bv,event->u.mouse.state|(1<<(7+event->u.mouse.button)), event->u.mouse.device );
    1196           0 :         } else if ( /*bc->sc->parent->onlybitmaps &&*/ bc->sc->parent->hasvmetrics &&
    1197           0 :                 bv->height-event->u.mouse.y-bv->yoff > (bv->bdf->ascent-bc->vwidth)*bv->scale-3 &&
    1198           0 :                 bv->height-event->u.mouse.y-bv->yoff < (bv->bdf->ascent-bc->vwidth)*bv->scale+3 ) {
    1199           0 :             bv->active_tool = bvt_setvwidth;
    1200           0 :             BVToolsSetCursor(bv,event->u.mouse.state|(1<<(7+event->u.mouse.button)), event->u.mouse.device );
    1201             :         }
    1202           0 :         BCCharUpdate(bc);
    1203           0 :       break;
    1204             :       case bvt_setwidth:
    1205           0 :         BVSetWidth(bv,x);
    1206           0 :       break;
    1207             :       case bvt_setvwidth:
    1208           0 :         BVSetVWidth(bv,y);
    1209           0 :       break;
    1210             :     }
    1211             : }
    1212             : 
    1213           0 : static void BVMouseMove(BitmapView *bv, GEvent *event) {
    1214           0 :     int x = floor( (event->u.mouse.x-bv->xoff)/ (real) bv->scale);
    1215           0 :     int y = floor( (bv->height-event->u.mouse.y-bv->yoff)/ (real) bv->scale);
    1216             :     int newx, newy;
    1217           0 :     int fh = bv->bdf->ascent+bv->bdf->descent;
    1218           0 :     BDFChar *bc = bv->bc;
    1219           0 :     int color_under_cursor, ny, has_selected_refs = false;
    1220             :     BDFRefChar *head;
    1221             : 
    1222           0 :     bv->info_x = x; bv->info_y = y;
    1223           0 :     ny = bc->ymax-y;
    1224           0 :     if ( x<bc->xmin || x>bc->xmax || ny<0 || ny>bc->ymax-bc->ymin )
    1225           0 :         color_under_cursor = 0;
    1226           0 :     else if ( bc->byte_data )
    1227           0 :         color_under_cursor = bc->bitmap[(bc->ymax-y)*bc->bytes_per_line + x-bc->xmin] *
    1228           0 :                 255/((1<<BDFDepth(bv->bdf))-1);
    1229             :     else
    1230           0 :         color_under_cursor = bc->bitmap[(bc->ymax-y)*bc->bytes_per_line + (x-bc->xmin)/8]&(0x80>>((x-bc->xmin)&7)) *
    1231             :                 255;
    1232           0 :     BVShowInfo(bv);
    1233           0 :     BVPaletteColorUnderChange(bv,color_under_cursor);
    1234           0 :     if ( bv->active_tool==bvt_none )
    1235           0 : return;                 /* Not pressed */
    1236           0 :     switch ( bv->active_tool ) {
    1237             :       case bvt_pencil:
    1238           0 :         BCSetPoint(bc,x,y,bc->byte_data?BVColor(bv):!bv->clearing);
    1239           0 :         BCCharChangedUpdate(bc);
    1240           0 :       break;
    1241             :       case bvt_line: case bvt_rect: case bvt_filledrect:
    1242             :       case bvt_elipse: case bvt_filledelipse:
    1243           0 :         BCCharChangedUpdate(bc);
    1244           0 :       break;
    1245             :       case bvt_hand:
    1246           0 :         newx = bv->xoff + event->u.mouse.x-bv->event_x;
    1247           0 :         newy = bv->yoff + bv->event_y-event->u.mouse.y;
    1248           0 :         if ( newy>4*fh*bv->scale-bv->height )
    1249           0 :             newy = 4*fh*bv->scale-bv->height;
    1250           0 :         if ( newy<-2*fh*bv->scale ) newy = -2*fh*bv->scale;
    1251           0 :         if ( newx>6*fh*bv->scale-bv->width )
    1252           0 :             newx = 6*fh*bv->scale-bv->width;
    1253           0 :         if ( newx<-3*fh*bv->scale ) newx = -3*fh*bv->scale;
    1254           0 :         if ( newx!=bv->xoff || newy!=bv->yoff ) {
    1255           0 :             newx -= bv->xoff; bv->xoff += newx;
    1256           0 :             newy -= bv->yoff; bv->yoff += newy;
    1257           0 :             GScrollBarSetPos(bv->hsb,-bv->xoff);
    1258           0 :             GScrollBarSetPos(bv->vsb,-bv->yoff);
    1259           0 :             GDrawScroll(bv->v,NULL,newx,newy);
    1260             :         }
    1261           0 :         bv->event_x = event->u.mouse.x; bv->event_y = event->u.mouse.y;
    1262           0 :       break;
    1263             :       case bvt_shift:
    1264           0 :         if ( x!=bv->pressed_x || y!=bv->pressed_y ) {
    1265           0 :             if ( !bv->recentchange ) {
    1266           0 :                 BCPreserveState(bc);
    1267           0 :                 BCFlattenFloat(bc);
    1268           0 :                 bv->recentchange = true;
    1269             :             }
    1270           0 :             bc->xmin += x-bv->pressed_x;
    1271           0 :             bc->xmax += x-bv->pressed_x;
    1272           0 :             bc->ymin += y-bv->pressed_y;
    1273           0 :             bc->ymax += y-bv->pressed_y;
    1274             : 
    1275           0 :             for ( head=bc->refs; head!=NULL; head=head->next ) {
    1276           0 :                 if ( head->selected ) {
    1277           0 :                     head->xoff += x-bv->pressed_x;
    1278           0 :                     head->yoff += y-bv->pressed_y;
    1279             :                 }
    1280             :             }
    1281           0 :             BCCharChangedUpdate(bc);
    1282           0 :             bv->pressed_x = x; bv->pressed_y = y;
    1283             :         }
    1284           0 :       break;
    1285             :       case bvt_pointer:
    1286           0 :         for ( head=bc->refs; head!=NULL && !has_selected_refs; head=head->next ) {
    1287           0 :             if ( head->selected ) has_selected_refs = true;
    1288             :         }
    1289           0 :         if ( bc->selection!=NULL || has_selected_refs ) {
    1290           0 :             if ( x!=bv->pressed_x || y!=bv->pressed_y ) {
    1291           0 :                 if ( !bv->recentchange ) {
    1292           0 :                     BCPreserveState(bc);
    1293           0 :                     bv->recentchange = true;
    1294             :                 }
    1295           0 :                 if ( has_selected_refs ) {
    1296           0 :                     for ( head=bc->refs; head!=NULL; head=head->next ) {
    1297           0 :                         if ( head->selected ) {
    1298           0 :                             head->xoff += x-bv->pressed_x;
    1299           0 :                             head->yoff += y-bv->pressed_y;
    1300             :                         }
    1301             :                     }
    1302           0 :                 } else if ( bc->selection != NULL ) {
    1303           0 :                     bc->selection->xmin += x-bv->pressed_x;
    1304           0 :                     bc->selection->xmax += x-bv->pressed_x;
    1305           0 :                     bc->selection->ymin += y-bv->pressed_y;
    1306           0 :                     bc->selection->ymax += y-bv->pressed_y;
    1307             :                 }
    1308           0 :                 BCCharChangedUpdate(bc);
    1309           0 :                 bv->pressed_x = x; bv->pressed_y = y;
    1310             :             }
    1311             :         } else {
    1312           0 :             GDrawRequestExpose(bv->v,NULL,false);
    1313             :         }
    1314           0 :       break;
    1315             :       case bvt_setwidth:
    1316           0 :         BVSetWidth(bv,x);
    1317           0 :       break;
    1318             :       case bvt_setvwidth:
    1319           0 :         BVSetVWidth(bv,y);
    1320           0 :       break;
    1321             :     }
    1322             : }
    1323             : 
    1324           0 : static void BVSetPoint(BitmapView *bv, int x, int y, void *junk) {
    1325           0 :     BCSetPoint(bv->bc,x,y,bv->bc->byte_data?BVColor(bv):!bv->clearing);
    1326           0 : }
    1327             : 
    1328             : static void BVMagnify(BitmapView *bv, int midx, int midy, int bigger);
    1329             : 
    1330           0 : static void BVMouseUp(BitmapView *bv, GEvent *event) {
    1331           0 :     int x = floor( (event->u.mouse.x-bv->xoff)/ (real) bv->scale);
    1332           0 :     int y = floor( (bv->height-event->u.mouse.y-bv->yoff)/ (real) bv->scale);
    1333           0 :     BDFRefChar *refsel = NULL, *head;
    1334             : 
    1335           0 :     BVMouseMove(bv,event);
    1336           0 :     for ( head = bv->bc->refs; head != NULL; head = head->next ) {
    1337           0 :         if ( IsReferenceTouched( bv,head,x,y ))
    1338           0 :             refsel = head;
    1339             :     }
    1340           0 :     switch ( bv->active_tool ) {
    1341             :       case bvt_magnify: case bvt_minify:
    1342           0 :         BVMagnify(bv,x,y,bv->active_tool==bvt_magnify?1:-1);
    1343           0 :       break;
    1344             :       case bvt_line: case bvt_rect: case bvt_filledrect:
    1345             :       case bvt_elipse: case bvt_filledelipse:
    1346           0 :         if ( refsel == NULL ) {
    1347           0 :             BCGeneralFunction(bv,BVSetPoint,NULL);
    1348           0 :             bv->active_tool = bvt_none;
    1349           0 :             BCCharChangedUpdate(bv->bc);
    1350             :         }
    1351           0 :       break;
    1352             :       case bvt_pointer:
    1353           0 :         if ( bv->bc->selection!=NULL ) {
    1354             :             /* we've been moving it */
    1355           0 :             GDrawSetCursor(bv->v,ct_mypointer);
    1356           0 :             if ( !bv->recentchange ) {       /* Oh, we just clicked in it, get rid of it */
    1357           0 :                 BCFlattenFloat(bv->bc);
    1358           0 :                 BCCharChangedUpdate(bv->bc);
    1359             :             }
    1360           0 :         } else if ( refsel ) {
    1361           0 :             GDrawSetCursor(bv->v,ct_mypointer);
    1362           0 :             bv->active_tool = bvt_none;
    1363           0 :             BCCharChangedUpdate(bv->bc);
    1364             :         } else {
    1365             :             int dx,dy;
    1366           0 :             if ( (dx = event->u.mouse.x-bv->event_x)<0 ) dx = -dx;
    1367           0 :             if ( (dy = event->u.mouse.y-bv->event_y)<0 ) dy = -dy;
    1368           0 :             if ( dx+dy>4 ) {
    1369             :                 /* we've just dragged out a new one */
    1370           0 :                 BDFFloatCreate(bv->bc,bv->pressed_x,bv->info_x,bv->pressed_y,bv->info_y,true);
    1371             :             }
    1372           0 :             bv->active_tool = bvt_none;
    1373           0 :             BCCharChangedUpdate(bv->bc);
    1374             :         }
    1375           0 :       break;
    1376             :       case bvt_setwidth:
    1377           0 :         BVSetWidth(bv,x);
    1378           0 :       break;
    1379             :       case bvt_setvwidth:
    1380           0 :         BVSetVWidth(bv,y);
    1381           0 :       break;
    1382             :     }
    1383           0 :     bv->active_tool = bvt_none;
    1384           0 :     BVToolsSetCursor(bv,event->u.mouse.state&~(1<<(7+event->u.mouse.button)), event->u.mouse.device);                /* X still has the buttons set in the state, even though we just released them. I don't want em */
    1385           0 : }
    1386             : 
    1387           0 : static int v_e_h(GWindow gw, GEvent *event) {
    1388           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1389             : 
    1390           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    1391           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    1392           0 :         int ish = event->u.mouse.button>5;
    1393           0 :         if ( event->u.mouse.state&ksm_shift ) ish = !ish;
    1394           0 :         if ( ish ) /* bind shift to vertical scrolling */
    1395           0 : return( GGadgetDispatchEvent(bv->hsb,event));
    1396             :         else
    1397           0 : return( GGadgetDispatchEvent(bv->vsb,event));
    1398             :     }
    1399             : 
    1400           0 :     switch ( event->type ) {
    1401             :       case et_selclear:
    1402           0 :         ClipboardClear();
    1403           0 :       break;
    1404             :       case et_expose:
    1405           0 :         GDrawSetLineWidth(gw,0);
    1406           0 :         BVExpose(bv,gw,event);
    1407           0 :       break;
    1408             :       case et_crossing:
    1409           0 :         BVToolsSetCursor(bv,event->u.mouse.state, event->u.mouse.device);
    1410           0 :       break;
    1411             :       case et_mousedown:
    1412           0 :         BVPaletteActivate(bv);
    1413           0 :         BVMouseDown(bv,event);
    1414           0 :       break;
    1415             :       case et_mousemove:
    1416           0 :         BVMouseMove(bv,event);
    1417           0 :       break;
    1418             :       case et_mouseup:
    1419           0 :         BVMouseUp(bv,event);
    1420           0 :       break;
    1421             :       case et_char:
    1422           0 :         BVChar(bv,event);
    1423           0 :       break;
    1424             :       case et_charup:
    1425           0 :         BVCharUp(bv,event);
    1426           0 :       break;
    1427             :       case et_timer:
    1428             : #if _ModKeysAutoRepeat
    1429             :         /* Under cygwin the modifier keys auto repeat, they don't under normal X */
    1430             :         if ( bv->autorpt==event->u.timer.timer ) {
    1431             :             bv->autorpt = NULL;
    1432             :             BVToolsSetCursor(bv,bv->oldstate,NULL);
    1433             :         }
    1434             : #endif
    1435           0 :       break;
    1436             :       case et_focus:
    1437           0 :       break;
    1438             :       default:
    1439           0 :       break;
    1440             :     }
    1441           0 : return( true );
    1442             : }
    1443             : 
    1444           0 : static int bv_e_h(GWindow gw, GEvent *event) {
    1445           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1446             :     int enc;
    1447             : 
    1448           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    1449           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    1450           0 :         int ish = event->u.mouse.button>5;
    1451           0 :         if ( event->u.mouse.state&ksm_shift ) ish = !ish;
    1452           0 :         if ( ish ) /* bind shift to vertical scrolling */
    1453           0 : return( GGadgetDispatchEvent(bv->hsb,event));
    1454             :         else
    1455           0 : return( GGadgetDispatchEvent(bv->vsb,event));
    1456             :     }
    1457             : 
    1458           0 :     switch ( event->type ) {
    1459             :       case et_expose:
    1460           0 :         GDrawSetLineWidth(gw,0);
    1461           0 :         BVMainExpose(bv,gw,event);
    1462           0 :       break;
    1463             :       case et_char:
    1464           0 :         BVChar(bv,event);
    1465           0 :       break;
    1466             :       case et_charup:
    1467           0 :         BVCharUp(bv,event);
    1468           0 :       break;
    1469             :       case et_resize:
    1470           0 :         if ( event->u.resize.sized )
    1471           0 :             BVResize(bv,event);
    1472           0 :       break;
    1473             :       case et_controlevent:
    1474           0 :         switch ( event->u.control.subtype ) {
    1475             :           case et_scrollbarchange:
    1476           0 :             if ( event->u.control.g == bv->hsb )
    1477           0 :                 BVHScroll(bv,&event->u.control.u.sb);
    1478             :             else
    1479           0 :                 BVVScroll(bv,&event->u.control.u.sb);
    1480           0 :           break;
    1481             :         }
    1482           0 :       break;
    1483             :       case et_destroy:
    1484           0 :         BVUnlinkView(bv);
    1485           0 :         BVPalettesHideIfMine(bv);
    1486           0 :         BitmapViewFree(bv);
    1487           0 :       break;
    1488             :       case et_map:
    1489           0 :         if ( event->u.map.is_visible )
    1490           0 :             BVPaletteActivate(bv);
    1491             :         else
    1492           0 :             BVPalettesHideIfMine(bv);
    1493           0 :       break;
    1494             :       case et_close:
    1495           0 :         GDrawDestroyWindow(gw);
    1496           0 :       break;
    1497             :       case et_mouseup: case et_mousedown:
    1498           0 :         GGadgetEndPopup();
    1499           0 :         BVPaletteActivate(bv);
    1500           0 :       break;
    1501             :       case et_mousemove:
    1502           0 :         enc = BVCurEnc(bv);
    1503           0 :         SCPreparePopup(bv->gw,bv->bc->sc,bv->fv->b.map->remap,enc,
    1504           0 :                 UniFromEnc(enc,bv->fv->b.map->enc));
    1505           0 :       break;
    1506             :       case et_focus:
    1507           0 :       break;
    1508             :     }
    1509           0 : return( true );
    1510             : }
    1511             : 
    1512             : #define MID_Fit         2001
    1513             : #define MID_ZoomIn      2002
    1514             : #define MID_ZoomOut     2003
    1515             : #define MID_Next        2007
    1516             : #define MID_Prev        2008
    1517             : #define MID_Bigger      2009
    1518             : #define MID_Smaller     2010
    1519             : #define MID_NextDef     2012
    1520             : #define MID_PrevDef     2013
    1521             : #define MID_Cut         2101
    1522             : #define MID_Copy        2102
    1523             : #define MID_Paste       2103
    1524             : #define MID_Clear       2104
    1525             : #define MID_SelAll      2106
    1526             : #define MID_CopyRef     2107
    1527             : #define MID_UnlinkRef   2108
    1528             : #define MID_Undo        2109
    1529             : #define MID_Redo        2110
    1530             : #define MID_RemoveUndoes 2111
    1531             : #define MID_GetInfo     2203
    1532             : #define MID_AvailBitmaps        2210
    1533             : #define MID_RegenBitmaps        2211
    1534             : #define MID_Tools       2501
    1535             : #define MID_Layers      2502
    1536             : #define MID_Shades      2503
    1537             : #define MID_DockPalettes        2504
    1538             : #define MID_Revert      2702
    1539             : #define MID_Recent      2703
    1540             : #define MID_SetWidth    2601
    1541             : #define MID_SetVWidth   2602
    1542             : 
    1543             : #define MID_Warnings    3000
    1544             : 
    1545           0 : static void BVMenuOpen(GWindow gw, struct gmenuitem *mi, GEvent *g) {
    1546           0 :     BitmapView *d = (BitmapView*)GDrawGetUserData(gw);
    1547           0 :     FontView *fv = NULL;
    1548           0 :     if (d) {
    1549           0 :         fv = (FontView*)d->fv;
    1550             :     }
    1551           0 :     _FVMenuOpen(fv);
    1552           0 : }
    1553             : 
    1554           0 : static void BVMenuClose(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1555           0 :     GDrawDestroyWindow(gw);
    1556           0 : }
    1557             : 
    1558           0 : static void BVMenuOpenOutline(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1559           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1560             : 
    1561           0 :     CharViewCreate(bv->bc->sc,bv->fv,bv->map_of_enc==bv->fv->b.map?bv->enc:-1);
    1562           0 : }
    1563             : 
    1564           0 : static void BVMenuOpenMetrics(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1565           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1566           0 :     MetricsViewCreate(bv->fv,bv->bc->sc,bv->bdf);
    1567           0 : }
    1568             : 
    1569           0 : static void BVMenuSave(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1570           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1571           0 :     _FVMenuSave(bv->fv);
    1572           0 : }
    1573             : 
    1574           0 : static void BVMenuSaveAs(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1575           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1576           0 :     _FVMenuSaveAs(bv->fv);
    1577           0 : }
    1578             : 
    1579           0 : static void BVMenuGenerate(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1580           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1581           0 :     _FVMenuGenerate(bv->fv,false);
    1582           0 : }
    1583             : 
    1584           0 : static void BVMenuGenerateFamily(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1585           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1586           0 :     _FVMenuGenerate(bv->fv,gf_macfamily);
    1587           0 : }
    1588             : 
    1589           0 : static void BVMenuGenerateTTC(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1590           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1591           0 :     _FVMenuGenerate(bv->fv,gf_ttc);
    1592           0 : }
    1593             : 
    1594           0 : static void BVMenuExport(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1595           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1596           0 :     BVExport(bv);
    1597           0 : }
    1598             : 
    1599           0 : static void BVMenuImport(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1600           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1601           0 :     BVImport(bv);
    1602           0 : }
    1603             : 
    1604           0 : static void BVMenuRevert(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1605           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1606           0 :     FVDelay(bv->fv,(void (*)(FontView *)) FVRevert);
    1607             :                             /* The revert command can potentially */
    1608             :                             /* destroy our window (if the char weren't in the */
    1609             :                             /* old font). If that happens before the menu finishes */
    1610             :                             /* we get a crash. So delay till after the menu completes */
    1611           0 : }
    1612             : 
    1613           0 : static void fllistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1614           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1615             : 
    1616           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    1617           0 :         switch ( mi->mid ) {
    1618             :           case MID_Revert:
    1619           0 :             mi->ti.disabled = bv->bdf->sf->origname==NULL || bv->bdf->sf->new;
    1620           0 :           break;
    1621             :           case MID_Recent:
    1622           0 :             mi->ti.disabled = !RecentFilesAny();
    1623           0 :           break;
    1624             :         }
    1625             :     }
    1626           0 : }
    1627             : 
    1628           0 : static void BVMagnify(BitmapView *bv, int midx, int midy, int bigger) {
    1629             :     /* available sizes: 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 */
    1630             : 
    1631           0 :     if ( bigger>0 ) {
    1632           0 :         if ( bv->scale == 1 )
    1633           0 :             bv->scale = 2;
    1634           0 :         else if ( (bv->scale & (bv->scale - 1)) == 0 )         /* power of 2 */
    1635           0 :             bv->scale += bv->scale / 2;
    1636             :         else
    1637           0 :             bv->scale += bv->scale / 3;
    1638           0 :         if ( bv->scale > 32 ) bv->scale = 32;
    1639             :     } else {
    1640           0 :         if ( bv->scale <= 2 )
    1641           0 :             bv->scale = 1;
    1642           0 :         else if ( (bv->scale & (bv->scale - 1)) == 0 )
    1643           0 :             bv->scale -= bv->scale / 4;
    1644             :         else
    1645           0 :             bv->scale -= bv->scale / 3;
    1646             :     }
    1647           0 :     bv->xoff = -(midx*bv->scale - bv->width/2);
    1648           0 :     bv->yoff = -(midy*bv->scale - bv->height/2);
    1649           0 :     BVNewScale(bv);
    1650           0 : }
    1651             : 
    1652           0 : static void BVMenuScale(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1653           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1654             : 
    1655           0 :     if ( mi->mid == MID_Fit ) {
    1656           0 :         BVFit(bv);
    1657             :     } else {
    1658           0 :         real midx = (bv->width/2-bv->xoff)/bv->scale;
    1659           0 :         real midy = (bv->height/2-bv->yoff)/bv->scale;
    1660           0 :         BVMagnify(bv,midx,midy,mi->mid==MID_ZoomOut?-1:1);
    1661             :     }
    1662           0 : }
    1663             : 
    1664           0 : static void BVMenuChangeChar(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1665           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1666           0 :     SplineFont *sf = bv->bc->sc->parent;
    1667           0 :     EncMap *map = bv->fv->b.map;
    1668           0 :     int pos = -1, gid;
    1669             : 
    1670           0 :     if ( mi->mid == MID_Next ) {
    1671           0 :         pos = BVCurEnc(bv)+1;
    1672           0 :     } else if ( mi->mid == MID_Prev ) {
    1673           0 :         pos = BVCurEnc(bv)-1;
    1674           0 :     } else if ( mi->mid == MID_NextDef ) {
    1675           0 :         for ( pos = BVCurEnc(bv)+1; pos<map->enccount &&
    1676           0 :                     ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid]) ||
    1677           0 :                             bv->bdf->glyphs[gid]==NULL) ;
    1678           0 :                 ++pos );
    1679           0 :         if ( pos==map->enccount )
    1680           0 : return;
    1681           0 :     } else if ( mi->mid == MID_PrevDef ) {
    1682           0 :         for ( pos = BVCurEnc(bv)-1; pos>=0 &&
    1683           0 :                     ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid]) ||
    1684           0 :                             bv->bdf->glyphs[gid]==NULL) ;
    1685           0 :                     --pos );
    1686           0 :         if ( pos<0 )
    1687           0 : return;
    1688             :     }
    1689           0 :     if ( pos>=0 && pos<map->enccount )
    1690           0 :         BVChangeChar(bv,pos,false);
    1691             : }
    1692             : 
    1693           0 : static void BVMenuChangePixelSize(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1694           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1695           0 :     BDFFont *best=NULL, *bdf;
    1696             :     /* Bigger will find either a bigger pixelsize or a font with same pixelsize and greater depth */
    1697             : 
    1698           0 :     if ( mi->mid == MID_Bigger ) {
    1699           0 :         best = bv->bdf->next;             /* I rely on the bitmap list being ordered */
    1700             :     } else {
    1701           0 :         for ( bdf=bv->bdf->sf->bitmaps; bdf!=NULL && bdf->next!=bv->bdf; bdf=bdf->next );
    1702           0 :         best = bdf;
    1703             :     }
    1704           0 :     if ( best!=NULL && bv->bdf!=best ) {
    1705           0 :         bv->bdf = best;
    1706           0 :         bv->scscale = ((real) (best->pixelsize))/(best->sf->ascent+best->sf->descent);
    1707           0 :         BVChangeChar(bv,bv->enc,true);
    1708           0 :         BVShows.lastpixelsize = best->pixelsize;
    1709             :     }
    1710           0 : }
    1711             : 
    1712           0 : static void BVMenuGotoChar(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1713           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1714           0 :     int pos = GotoChar(bv->fv->b.sf,bv->fv->b.map,NULL);
    1715             : 
    1716           0 :     if ( pos!=-1 )
    1717           0 :         BVChangeChar(bv,pos,false);
    1718           0 : }
    1719             : 
    1720           0 : static void BVMenuFindInFontView(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1721           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1722             : 
    1723           0 :     FVChangeChar(bv->fv,bv->bc->sc->orig_pos);
    1724           0 :     GDrawSetVisible(bv->fv->gw,true);
    1725           0 :     GDrawRaise(bv->fv->gw);
    1726           0 : }
    1727             : 
    1728           0 : static void BVMenuPalettesDock(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1729           0 :     PalettesChangeDocking();
    1730           0 : }
    1731             : 
    1732           0 : static void BVMenuPaletteShow(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1733           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1734             : 
    1735           0 :     BVPaletteSetVisible(bv, mi->mid==MID_Tools?1:mi->mid==MID_Shades?2:0, !BVPaletteIsVisible(bv, mi->mid==MID_Tools?1:mi->mid==MID_Shades?2:0));
    1736           0 : }
    1737             : 
    1738           0 : static void BVUndo(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1739           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1740           0 :     if ( bv->bc->undoes==NULL )
    1741           0 : return;
    1742           0 :     BCDoUndo(bv->bc);
    1743             : }
    1744             : 
    1745           0 : static SplineChar *SCofBV(BitmapView *bv) {
    1746           0 :     SplineFont *sf = bv->bdf->sf;
    1747           0 :     int i, cid = bv->bc->orig_pos;
    1748             : 
    1749           0 :     if ( sf->subfonts ) {
    1750           0 :         for ( i=0; i<sf->subfontcnt; ++i )
    1751           0 :             if ( cid<sf->subfonts[i]->glyphcnt && sf->subfonts[i]->glyphs[cid]!=NULL )
    1752           0 : return( sf->subfonts[i]->glyphs[cid] );
    1753             : 
    1754           0 : return( NULL );
    1755             :     } else
    1756           0 : return( sf->glyphs[cid] );
    1757             : }
    1758             : 
    1759           0 : static void BVMenuSetWidth(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1760           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1761             :     char buffer[10];
    1762             :     char *ret;
    1763             :     BDFFont *bdf;
    1764           0 :     int mysize = bv->bdf->pixelsize;
    1765             :     SplineChar *sc;
    1766             :     int val;
    1767             : 
    1768           0 :     if ( !bv->bdf->sf->onlybitmaps )
    1769           0 : return;
    1770           0 :     if ( mi->mid==MID_SetWidth ) {
    1771           0 :         sprintf( buffer,"%d",bv->bc->width);
    1772           0 :         ret = gwwv_ask_string(_("Set Width..."),buffer,_("Set Width..."));
    1773             :     } else {
    1774           0 :         sprintf( buffer,"%d",bv->bc->vwidth);
    1775           0 :         ret = gwwv_ask_string(_("Set Vertical Width..."),buffer,_("Set Vertical Width..."));
    1776             :     }
    1777           0 :     if ( ret==NULL )
    1778           0 : return;
    1779           0 :     val = strtol(ret,NULL,10);
    1780           0 :     free(ret);
    1781           0 :     if ( val<0 )
    1782           0 : return;
    1783           0 :     if ( mi->mid==MID_SetWidth )
    1784           0 :         bv->bc->width = val;
    1785             :     else
    1786           0 :         bv->bc->vwidth = val;
    1787           0 :     BCCharChangedUpdate(bv->bc);
    1788           0 :     for ( bdf=bv->bdf->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
    1789           0 :         if ( bdf->pixelsize > mysize )
    1790           0 : return;
    1791           0 :     if ( (sc=SCofBV(bv))!=NULL ) {
    1792           0 :         if ( mi->mid==MID_SetWidth )
    1793           0 :             sc->width = val*(sc->parent->ascent+sc->parent->descent)/mysize;
    1794             :         else
    1795           0 :             sc->vwidth = val*(sc->parent->ascent+sc->parent->descent)/mysize;
    1796           0 :         SCCharChangedUpdate(sc,ly_none);
    1797             :     }
    1798             : }
    1799             : 
    1800           0 : static void BVRedo(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1801           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1802           0 :     if ( bv->bc->redoes==NULL )
    1803           0 : return;
    1804           0 :     BCDoRedo(bv->bc);
    1805             : }
    1806             : 
    1807           0 : static void _BVUnlinkRef(BitmapView *bv) {
    1808           0 :     int anyrefs = false;
    1809           0 :     BDFRefChar *ref, *next, *prev = NULL;
    1810             : 
    1811           0 :     if ( bv->bc->refs!=NULL ) {
    1812           0 :         BCPreserveState(bv->bc);
    1813           0 :         for ( ref=bv->bc->refs; ref!=NULL && !anyrefs; ref=ref->next )
    1814           0 :             if ( ref->selected ) anyrefs = true;
    1815           0 :         for ( ref=bv->bc->refs; ref!=NULL ; ref=next ) {
    1816           0 :             next = ref->next;
    1817           0 :             if ( ref->selected || !anyrefs) {
    1818           0 :                 BCPasteInto( bv->bc,ref->bdfc,ref->xoff,ref->yoff,false,false );
    1819           0 :                 BCMergeReferences( bv->bc,ref->bdfc,ref->xoff,ref->yoff );
    1820           0 :                 BCRemoveDependent( bv->bc,ref );
    1821             :             } else
    1822           0 :                 prev = ref;
    1823             :         }
    1824           0 :         BCCharChangedUpdate(bv->bc);
    1825             :     }
    1826           0 : }
    1827             : 
    1828           0 : static void BVUnlinkRef(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1829           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1830           0 :     _BVUnlinkRef(bv);
    1831           0 : }
    1832             : 
    1833           0 : static void BVRemoveUndoes(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1834           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1835           0 :     UndoesFree(bv->bc->undoes); bv->bc->undoes = NULL;
    1836           0 :     UndoesFree(bv->bc->redoes); bv->bc->redoes = NULL;
    1837           0 : }
    1838             : 
    1839           0 : static void BVCopy(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1840           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1841           0 :     BCCopySelected(bv->bc,bv->bdf->pixelsize,BDFDepth(bv->bdf));
    1842           0 : }
    1843             : 
    1844           0 : static void BVCopyRef(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1845           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1846           0 :     BCCopyReference(bv->bc,bv->bdf->pixelsize,BDFDepth(bv->bdf));
    1847           0 : }
    1848             : 
    1849           0 : static void BVDoClear(BitmapView *bv) {
    1850             :     BDFRefChar *head, *next;
    1851           0 :     BDFChar *bc = bv->bc;
    1852           0 :     int refs_changed = false;
    1853             : 
    1854           0 :     for ( head=bc->refs; head!=NULL; head=next ) {
    1855           0 :         next = head->next;
    1856           0 :         if ( head->selected ) {
    1857           0 :             if ( !refs_changed ) {
    1858           0 :                 BCPreserveState( bc );
    1859           0 :                 refs_changed = true;
    1860             :             }
    1861           0 :             BCRemoveDependent( bc,head );
    1862             :         }
    1863             :     }
    1864             : 
    1865           0 :     if ( bc->selection!=NULL ) {
    1866           0 :         BCPreserveState( bc );
    1867           0 :         BDFFloatFree( bc->selection );
    1868           0 :         bv->bc->selection = NULL;
    1869           0 :         BCCharChangedUpdate( bc );
    1870           0 :     } else if ( refs_changed ) {
    1871           0 :         BCCharChangedUpdate( bc );
    1872             :     }
    1873           0 : }
    1874             : 
    1875           0 : static void BVClear(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1876           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1877           0 :     BVDoClear(bv);
    1878           0 : }
    1879             : 
    1880           0 : static void BVPaste(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1881           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1882           0 :     if ( CopyContainsBitmap())
    1883           0 :         PasteToBC(bv->bc,bv->bdf->pixelsize,BDFDepth(bv->bdf));
    1884           0 : }
    1885             : 
    1886           0 : static void BVCut(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1887           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1888           0 :     BVCopy(gw,mi,e);
    1889           0 :     BVDoClear(bv);
    1890           0 : }
    1891             : 
    1892           0 : static void BVSelectAll(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1893           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1894           0 :     BDFChar *bc = bv->bc;
    1895             : 
    1896           0 :     BDFFloatCreate(bc,bc->xmin,bc->xmax,bc->ymin,bc->ymax, true);
    1897           0 :     BCCharUpdate(bc);
    1898           0 : }
    1899             : 
    1900           0 : static void BVMenuFontInfo(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1901           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1902           0 :     DelayEvent(FontMenuFontInfo,bv->fv);
    1903           0 : }
    1904             : 
    1905           0 : static void BVMenuBDFInfo(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1906           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1907           0 :     SFBdfProperties(bv->bdf->sf,bv->fv->b.map,bv->bdf);
    1908           0 : }
    1909             : 
    1910           0 : static void BVMenuGetInfo(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1911           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1912           0 :     SCCharInfo(bv->bc->sc,bv->fv->b.active_layer,bv->fv->b.map,BVCurEnc(bv));
    1913           0 : }
    1914             : 
    1915           0 : static void BVMenuBitmaps(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1916           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1917           0 :     BitmapDlg(bv->fv,bv->bc->sc,mi->mid==MID_AvailBitmaps );
    1918           0 : }
    1919             : 
    1920           0 : static void BVMenuRmGlyph(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1921           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1922             :     BitmapView *bvs, *bvnext;
    1923           0 :     BDFFont *bdf = bv->bdf;
    1924           0 :     BDFChar *bc = bv->bc;
    1925             :     FontView *fv;
    1926             : 
    1927           0 :     for ( bvs=bc->views; bvs!=NULL; bvs=bvnext ) {
    1928           0 :         bvnext = bvs->next;
    1929           0 :         GDrawDestroyWindow(bvs->gw);
    1930             :     }
    1931           0 :     bdf->glyphs[bc->orig_pos] = NULL;
    1932             :     /* Can't free the glyph yet, need to process all the destroy events */
    1933             :     /*  which touch bc->views first */
    1934           0 :     DelayEvent( (void (*)(void *))BDFCharFree,bc);
    1935           0 :     for ( fv = (FontView *) (bdf->sf->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) )
    1936           0 :         GDrawRequestExpose(fv->v,NULL,false);
    1937           0 : }
    1938             : 
    1939           0 : static int askfraction(int *xoff, int *yoff) {
    1940             :     static int lastx=1, lasty = 3;
    1941             :     char buffer[30];
    1942             :     char *ret, *end, *end2;
    1943             :     int xv, yv;
    1944             : 
    1945           0 :     sprintf( buffer, "%d:%d", lastx, lasty );
    1946           0 :     ret = ff_ask_string(_("Skew"),buffer,_("Skew Ratio"));
    1947           0 :     if ( ret==NULL )
    1948           0 : return( 0 );
    1949           0 :     xv = strtol(ret,&end,10);
    1950           0 :     yv = strtol(end+1,&end2,10);
    1951           0 :     if ( xv==0 || xv>10 || xv<-10 || yv<=0 || yv>10 || *end!=':' || *end2!='\0' ) {
    1952           0 :         ff_post_error( _("Bad Number"),_("Bad Number") );
    1953           0 :         free(ret);
    1954           0 : return( 0 );
    1955             :     }
    1956           0 :     free(ret);
    1957           0 :     *xoff = lastx = xv; *yoff = lasty = yv;
    1958           0 : return( 1 );
    1959             : }
    1960             : 
    1961           0 : void BVRotateBitmap(BitmapView *bv,enum bvtools type ) {
    1962           0 :     int xoff=0, yoff=0;
    1963             : 
    1964           0 :     if ( type==bvt_skew )
    1965           0 :         if ( !askfraction(&xoff,&yoff))
    1966           0 : return;
    1967           0 :     BCPreserveState(bv->bc);
    1968           0 :     BCTransFunc(bv->bc,type,xoff,yoff);
    1969           0 :     BCCharChangedUpdate(bv->bc);
    1970             : }
    1971             : 
    1972           0 : void BVMenuRotateInvoked(GWindow gw,struct gmenuitem *mi,GEvent *g) {
    1973           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1974           0 :     BVRotateBitmap(bv,mi->mid);
    1975           0 : }
    1976             : 
    1977           0 : static void ellistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1978           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1979             : 
    1980           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    1981           0 :         switch ( mi->mid ) {
    1982             :           case MID_RegenBitmaps:
    1983           0 :             mi->ti.disabled = bv->bdf->sf->onlybitmaps;
    1984           0 :           break;
    1985             :         }
    1986             :     }
    1987           0 : }
    1988             : 
    1989           0 : static void edlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1990           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    1991             :     BDFRefChar *cur;
    1992             : 
    1993           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    1994           0 :         switch ( mi->mid ) {
    1995             :           case MID_Cut: /*case MID_Copy:*/ case MID_Clear:
    1996             :             /* If nothing is selected, copy copies everything */
    1997           0 :             mi->ti.disabled = bv->bc->selection==NULL;
    1998           0 :             for ( cur=bv->bc->refs; cur!=NULL && mi->ti.disabled; cur=cur->next ) {
    1999           0 :                 if ( cur->selected )
    2000           0 :                     mi->ti.disabled = false;
    2001             :             }
    2002           0 :           break;
    2003             :           case MID_Paste:
    2004           0 :             mi->ti.disabled = !CopyContainsBitmap();
    2005           0 :           break;
    2006             :           case MID_Undo:
    2007           0 :             mi->ti.disabled = bv->bc->undoes==NULL;
    2008           0 :           break;
    2009             :           case MID_Redo:
    2010           0 :             mi->ti.disabled = bv->bc->redoes==NULL;
    2011           0 :           break;
    2012             :           case MID_RemoveUndoes:
    2013           0 :             mi->ti.disabled = bv->bc->redoes==NULL && bv->bc->undoes==NULL;
    2014           0 :           break;
    2015             :           case MID_UnlinkRef:
    2016           0 :             mi->ti.disabled = bv->bc->refs==NULL;
    2017           0 :           break;
    2018             :         }
    2019             :     }
    2020           0 : }
    2021             : 
    2022           0 : static void pllistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    2023           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    2024             :     extern int palettes_docked;
    2025             : 
    2026           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    2027           0 :         switch ( mi->mid ) {
    2028             :           case MID_Tools:
    2029           0 :             mi->ti.checked = BVPaletteIsVisible(bv,1);
    2030           0 :           break;
    2031             :           case MID_Layers:
    2032           0 :             mi->ti.checked = BVPaletteIsVisible(bv,0);
    2033           0 :           break;
    2034             :           case MID_Shades:
    2035           0 :             mi->ti.disabled = BDFDepth(bv->bdf)==1;
    2036           0 :             if ( !mi->ti.disabled )
    2037           0 :                 mi->ti.checked = BVPaletteIsVisible(bv,2);
    2038           0 :           break;
    2039             :           case MID_DockPalettes:
    2040           0 :             mi->ti.checked = palettes_docked;
    2041           0 :           break;
    2042             :         }
    2043             :     }
    2044           0 : }
    2045             : 
    2046           0 : static void vwlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    2047           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    2048             :     BDFFont *bdf;
    2049             : 
    2050           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    2051           0 :         switch ( mi->mid ) {
    2052             :           case MID_ZoomIn:
    2053           0 :             mi->ti.disabled = bv->scale==32;
    2054           0 :           break;
    2055             :           case MID_ZoomOut:
    2056           0 :             mi->ti.checked = bv->scale==1;
    2057           0 :           break;
    2058             :           case MID_Bigger:
    2059           0 :             mi->ti.disabled = bv->bdf->next==NULL;
    2060           0 :           break;
    2061             :           case MID_Smaller:
    2062           0 :             for ( bdf=bv->bdf->sf->bitmaps; bdf!=NULL && bdf->next!=bv->bdf; bdf=bdf->next );
    2063           0 :             mi->ti.disabled = bdf==NULL;
    2064           0 :           break;
    2065             :         }
    2066             :     }
    2067           0 : }
    2068             : 
    2069           0 : static void mtlistcheck(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    2070           0 :     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
    2071             : 
    2072           0 :     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
    2073           0 :         switch ( mi->mid ) {
    2074             :           case MID_SetWidth:
    2075           0 :             mi->ti.disabled = !bv->bdf->sf->onlybitmaps;
    2076           0 :           break;
    2077             :           case MID_SetVWidth:
    2078           0 :             mi->ti.disabled = !bv->bdf->sf->onlybitmaps || !bv->bdf->sf->hasvmetrics;
    2079           0 :           break;
    2080             :         }
    2081             :     }
    2082           0 : }
    2083             : 
    2084             : static GMenuItem2 wnmenu[] = {
    2085             :     { { (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, BVMenuOpenOutline, 0 },
    2086             :     { { (unichar_t *) N_("New _Bitmap Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("New Bitmap Window|Ctl+J"), NULL, NULL, /* No function, never avail */NULL, 0 },
    2087             :     { { (unichar_t *) N_("New _Metrics Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("New Metrics Window|Ctl+K"), NULL, NULL, BVMenuOpenMetrics, 0 },
    2088             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2089             :     { { (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 },
    2090             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2091             :     GMENUITEM2_EMPTY
    2092             : };
    2093             : 
    2094           0 : static void BVWindowMenuBuild(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    2095             :     struct gmenuitem *wmi;
    2096           0 :     WindowMenuBuild(gw,mi,e);
    2097           0 :     for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
    2098           0 :         switch ( wmi->mid ) {
    2099             :           case MID_Warnings:
    2100           0 :             wmi->ti.disabled = ErrorWindowExists();
    2101           0 :           break;
    2102             :         }
    2103             :     }
    2104           0 : }
    2105             : 
    2106           0 : static void BVMenuContextualHelp(GWindow base,struct gmenuitem *mi,GEvent *e) {
    2107           0 :     help("bitmapview.html");
    2108           0 : }
    2109             : 
    2110             : char *BVFlipNames[] = { N_("Flip Horizontally"), N_("Flip Vertically"),
    2111             : /* GT: "CW" means Clockwise */
    2112             :     NU_("Rotate 90° CW"),
    2113             : /* GT: "CW" means Counter-Clockwise */
    2114             :     NU_("Rotate 90° CCW"),
    2115             :     NU_("Rotate 180°"),
    2116             :     N_("Skew..."), NULL };
    2117             : 
    2118             : static GMenuItem2 dummyitem[] = {
    2119             :     { { (unichar_t *) N_("Font|_New"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, NULL, NULL, NULL, NULL, 0 },
    2120             :     GMENUITEM2_EMPTY
    2121             : };
    2122             : static GMenuItem2 fllist[] = {
    2123             :     { { (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, 0 },
    2124             :     { { (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, BVMenuOpen, 0 },
    2125             :     { { (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 },
    2126             :     { { (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, BVMenuClose, 0 },
    2127             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2128             :     { { (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, BVMenuSave, 0 },
    2129             :     { { (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, BVMenuSaveAs, 0 },
    2130             :     { { (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, BVMenuGenerate, 0 },
    2131             :     { { (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, BVMenuGenerateFamily, 0 },
    2132             :     { { (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, BVMenuGenerateTTC, 0 },
    2133             :     { { (unichar_t *) N_("Expor_t..."), (GImage *) "fileexport.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Export...|No Shortcut"), NULL, NULL, BVMenuExport, 0 },
    2134             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2135             :     { { (unichar_t *) N_("_Import..."), (GImage *) "fileimport.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Import...|Ctl+Shft+I"), NULL, NULL, BVMenuImport, 0 },
    2136             :     { { (unichar_t *) N_("_Revert File"), (GImage *) "filerevert.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Revert File|Ctl+Shft+R"), NULL, NULL, BVMenuRevert, MID_Revert },
    2137             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2138             :     { { (unichar_t *) N_("Pr_eferences..."), (GImage *) "fileprefs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Preferences...|No Shortcut"), NULL, NULL, MenuPrefs, 0 },
    2139             :     { { (unichar_t *) N_("_X Resource Editor..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("X Resource Editor...|No Shortcut"), NULL, NULL, MenuXRes, 0 },
    2140             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2141             :     { { (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, 0 },
    2142             :     GMENUITEM2_EMPTY
    2143             : };
    2144             : 
    2145             : static GMenuItem2 edlist[] = {
    2146             :     { { (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, BVUndo, MID_Undo },
    2147             :     { { (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, BVRedo, MID_Redo },
    2148             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2149             :     { { (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, BVCut, MID_Cut },
    2150             :     { { (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, BVCopy, MID_Copy },
    2151             :     { { (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, BVCopyRef, MID_CopyRef },
    2152             :     { { (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, BVPaste, MID_Paste },
    2153             :     { { (unichar_t *) N_("C_lear"), (GImage *) "editclear.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Clear|Delete"), NULL, NULL, BVClear, MID_Clear },
    2154             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2155             :     { { (unichar_t *) N_("Select _All"), (GImage *) "editselect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Select All|Ctl+A"), NULL, NULL, BVSelectAll, MID_SelAll },
    2156             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2157             :     { { (unichar_t *) N_("Remo_ve Undoes"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Remove Undoes|No Shortcut"), NULL, NULL, BVRemoveUndoes, MID_RemoveUndoes },
    2158             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2159             :     { { (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, BVUnlinkRef, MID_UnlinkRef },
    2160             :     GMENUITEM2_EMPTY
    2161             : };
    2162             : 
    2163             : static GMenuItem2 trlist[] = {
    2164             :     { { (unichar_t *) N_("Flip _Horizontally"), (GImage *) "transformfliphor.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Flip Horizontally|No Shortcut"), NULL, NULL, BVMenuRotateInvoked, bvt_fliph },
    2165             :     { { (unichar_t *) N_("Flip _Vertically"), (GImage *) "transformflipvert.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Flip Vertically|No Shortcut"), NULL, NULL, BVMenuRotateInvoked, bvt_flipv },
    2166             :     { { (unichar_t *) NU_("_Rotate 90° CW"), (GImage *) "transformrotatecw.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Rotate 90 CW|No Shortcut"), NULL, NULL, BVMenuRotateInvoked, bvt_rotate90cw },
    2167             :     { { (unichar_t *) NU_("Rotate _90° CCW"), (GImage *) "transformrotateccw.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '9' }, H_("Rotate 90 CCW|No Shortcut"), NULL, NULL, BVMenuRotateInvoked, bvt_rotate90ccw },
    2168             :     { { (unichar_t *) NU_("Rotate _180°"), (GImage *) "transformrotate180.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '1' }, H_("Rotate 180|No Shortcut"), NULL, NULL, BVMenuRotateInvoked, bvt_rotate180 },
    2169             :     { { (unichar_t *) N_("_Skew..."), (GImage *) "transformskew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Skew...|No Shortcut"), NULL, NULL, BVMenuRotateInvoked, bvt_skew },
    2170             :     GMENUITEM2_EMPTY
    2171             : };
    2172             : 
    2173             : static GMenuItem2 ellist[] = {
    2174             :     { { (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, BVMenuFontInfo, 0 },
    2175             :     { { (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, BVMenuGetInfo, MID_GetInfo },
    2176             :     { { (unichar_t *) N_("BDF Info..."), (GImage *) "elementbdfinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("BDF Info...|No Shortcut"), NULL, NULL, BVMenuBDFInfo, 0 },
    2177             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2178             :     { { (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, BVMenuBitmaps, MID_AvailBitmaps },
    2179             :     { { (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, BVMenuBitmaps, MID_RegenBitmaps },
    2180             :     { { (unichar_t *) N_("Remove This Glyph"), (GImage *) "elementremovebitmaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Remove This Glyph|No Shortcut"), NULL, NULL, BVMenuRmGlyph, 0 },
    2181             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2182             :     { { (unichar_t *) N_("_Transformations"), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, NULL, trlist, NULL, NULL, 0 },
    2183             :     GMENUITEM2_EMPTY
    2184             : };
    2185             : 
    2186             : static GMenuItem2 pllist[] = {
    2187             :     { { (unichar_t *) N_("_Tools"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Tools|No Shortcut"), NULL, NULL, BVMenuPaletteShow, MID_Tools },
    2188             :     { { (unichar_t *) N_("_Layers"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Layers|No Shortcut"), NULL, NULL, BVMenuPaletteShow, MID_Layers },
    2189             :     { { (unichar_t *) N_("_Shades"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'S' }, H_("Shades|No Shortcut"), NULL, NULL, BVMenuPaletteShow, MID_Shades },
    2190             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2191             :     { { (unichar_t *) N_("_Docked Palettes"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'D' }, H_("Docked Palettes|No Shortcut"), NULL, NULL, BVMenuPalettesDock, MID_DockPalettes },
    2192             :     GMENUITEM2_EMPTY
    2193             : };
    2194             : 
    2195             : static GMenuItem2 vwlist[] = {
    2196             :     { { (unichar_t *) N_("_Fit"), (GImage *) "viewfit.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Fit|Ctl+F"), NULL, NULL, BVMenuScale, MID_Fit },
    2197             :     { { (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, BVMenuScale, MID_ZoomOut },
    2198             :     { { (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, BVMenuScale, MID_ZoomIn },
    2199             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2200             :     { { (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, BVMenuChangeChar, MID_Next },
    2201             :     { { (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, BVMenuChangeChar, MID_Prev },
    2202             :     { { (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, BVMenuChangeChar, MID_NextDef },
    2203             :     { { (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, BVMenuChangeChar, MID_PrevDef },
    2204             :     { { (unichar_t *) N_("_Goto"), (GImage *) "viewgoto.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Goto|Ctl+Shft+>"), NULL, NULL, BVMenuGotoChar, 0 },
    2205             :     { { (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, BVMenuFindInFontView, 0 },
    2206             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2207             :     { { (unichar_t *) N_("_Bigger Pixel Size"), (GImage *) "viewbiggersize.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Bigger Pixel Size|Ctl+Shft++"), NULL, NULL, BVMenuChangePixelSize, MID_Bigger },
    2208             :     { { (unichar_t *) N_("_Smaller Pixel Size"), (GImage *) "viewsmallersize.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Smaller Pixel Size|Ctl+-"), NULL, NULL, BVMenuChangePixelSize, MID_Smaller },
    2209             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
    2210             :     { { (unichar_t *) N_("_Palettes"), (GImage *) "viewpalettes.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, NULL, pllist, pllistcheck, NULL, 0 },
    2211             :     GMENUITEM2_EMPTY
    2212             : };
    2213             : 
    2214             : static GMenuItem2 mtlist[] = {
    2215             :     { { (unichar_t *) N_("Set _Width..."), (GImage *) "metricssetwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Set Width...|Ctl+Shft+L"), NULL, NULL, BVMenuSetWidth, MID_SetWidth },
    2216             :     { { (unichar_t *) N_("Set _Vertical Width..."), (GImage *) "metricssetvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Set Vertical Width...|Ctl+Shft+L"), NULL, NULL, BVMenuSetWidth, MID_SetVWidth },
    2217             :     GMENUITEM2_EMPTY
    2218             : };
    2219             : 
    2220             : static GMenuItem2 mblist[] = {
    2221             :     { { (unichar_t *) N_("_File"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, NULL, fllist, fllistcheck, NULL, 0 },
    2222             :     { { (unichar_t *) N_("_Edit"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, NULL, edlist, edlistcheck, NULL, 0 },
    2223             :     { { (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, NULL, 0 },
    2224             :     { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, NULL, vwlist, vwlistcheck, NULL, 0 },
    2225             :     { { (unichar_t *) N_("_Metrics"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, NULL, mtlist, mtlistcheck, NULL, 0 },
    2226             :     { { (unichar_t *) N_("_Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, NULL, wnmenu, BVWindowMenuBuild, NULL, 0 },
    2227             :     { { (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, 0 },
    2228             :     GMENUITEM2_EMPTY
    2229             : };
    2230             : 
    2231             : #define bitmap_width 16
    2232             : #define bitmap_height 16
    2233             : static unsigned char bitmap_bits[] = {
    2234             :    0x00, 0x00, 0xfc, 0x03, 0xfc, 0x03, 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c,
    2235             :    0x30, 0x0c, 0xf0, 0x03, 0xf0, 0x03, 0x30, 0x0c, 0x30, 0x0c, 0x30, 0x0c,
    2236             :    0x30, 0x0c, 0xfc, 0x03, 0xfc, 0x03, 0x00, 0x00};
    2237             : 
    2238             : static int bitmapview_ready = false;
    2239             : 
    2240           0 : static void BitmapViewFinish() {
    2241           0 :   if ( !bitmapview_ready ) return;
    2242           0 :   bitmapview_ready = 0;
    2243           0 :   mb2FreeGetText(mblist);
    2244             : }
    2245             : 
    2246           0 : void BitmapViewFinishNonStatic() {
    2247           0 :   BitmapViewFinish();
    2248           0 : }
    2249             : 
    2250           0 : static void BitmapViewInit(void) {
    2251             :     // static int done = false; // superseded by bitmapview_ready.
    2252             :     int i;
    2253             : 
    2254           0 :     if ( bitmapview_ready )
    2255           0 : return;
    2256           0 :     bitmapview_ready = true;
    2257             : 
    2258           0 :     mb2DoGetText(mblist);
    2259           0 :     for ( i=0; BVFlipNames[i]!=NULL ; ++i )
    2260           0 :         BVFlipNames[i] = S_(BVFlipNames[i]);
    2261           0 :     atexit(&BitmapViewFinishNonStatic);
    2262             : }
    2263             : 
    2264           0 : BitmapView *BitmapViewCreate(BDFChar *bc, BDFFont *bdf, FontView *fv, int enc) {
    2265           0 :     BitmapView *bv = calloc(1,sizeof(BitmapView));
    2266             :     GRect pos, zoom, size;
    2267             :     GWindow gw;
    2268             :     GWindowAttrs wattrs;
    2269             :     GGadgetData gd;
    2270             :     GRect gsize;
    2271             :     int sbsize;
    2272             :     char buf[300];
    2273             :     static GWindow icon = NULL;
    2274             :     GTextInfo ti;
    2275             :     FontRequest rq;
    2276             :     int as, ds, ld;
    2277             :     static char *infofamily = NULL;
    2278             : 
    2279           0 :     BitmapViewInit();
    2280             : 
    2281           0 :     BVShows.lastpixelsize = bdf->pixelsize;
    2282             : 
    2283           0 :     if ( icon==NULL )
    2284           0 :         icon = GDrawCreateBitmap(NULL,bitmap_width,bitmap_height,bitmap_bits);
    2285             : 
    2286           0 :     bv->bc = bc;
    2287           0 :     bv->scale = 1;
    2288           0 :     bv->xoff = bv->yoff = 20;
    2289           0 :     bv->next = bc->views;
    2290           0 :     bc->views = bv;
    2291           0 :     bv->fv = fv;
    2292           0 :     bv->enc = enc;
    2293           0 :     bv->map_of_enc = fv->b.map;
    2294           0 :     bv->bdf = bdf;
    2295           0 :     bv->color = 255;
    2296           0 :     bv->shades_hidden = bdf->clut==NULL;
    2297             : 
    2298           0 :     bv->showfore = BVShows.showfore;
    2299           0 :     bv->showoutline = BVShows.showoutline;
    2300           0 :     bv->showgrid = BVShows.showgrid;
    2301           0 :     bv->scscale = ((real) (bdf->pixelsize))/(bdf->sf->ascent+bdf->sf->descent);
    2302             : 
    2303           0 :     memset(&wattrs,0,sizeof(wattrs));
    2304           0 :     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_utf8_ititle;
    2305           0 :     wattrs.event_masks = ~(1<<et_charup);
    2306           0 :     wattrs.cursor = ct_pointer;
    2307           0 :     wattrs.utf8_icon_title = BVMakeTitles(bv,bc,buf);
    2308           0 :     wattrs.utf8_window_title = buf;
    2309           0 :     wattrs.icon = icon;
    2310           0 :     if ( wattrs.icon )
    2311           0 :         wattrs.mask |= wam_icon;
    2312           0 :     pos.x = 8+9*16+10; pos.width=bv_width; pos.height = bv_height;
    2313           0 :     DefaultY(&pos);
    2314             : 
    2315           0 :     bv->gw = gw = GDrawCreateTopWindow(NULL,&pos,bv_e_h,bv,&wattrs);
    2316           0 :     free( (unichar_t *) wattrs.icon_title );
    2317             : 
    2318           0 :     GDrawGetSize(GDrawGetRoot(screen_display),&zoom);
    2319           0 :     zoom.x = BVPalettesWidth(); zoom.width -= zoom.x-10;
    2320           0 :     zoom.height -= 30;                  /* Room for title bar & such */
    2321           0 :     GDrawSetZoom(gw,&zoom,-1);
    2322             : 
    2323           0 :     memset(&gd,0,sizeof(gd));
    2324           0 :     gd.flags = gg_visible | gg_enabled;
    2325           0 :     helplist[0].invoke = BVMenuContextualHelp;
    2326           0 :     gd.u.menu2 = mblist;
    2327           0 :     bv->mb = GMenu2BarCreate( gw, &gd, NULL);
    2328           0 :     GGadgetGetSize(bv->mb,&gsize);
    2329           0 :     bv->mbh = gsize.height;
    2330           0 :     bv->infoh = GDrawPointsToPixels(gw,36);
    2331             : 
    2332           0 :     gd.pos.y = bv->mbh+bv->infoh;
    2333           0 :     gd.pos.width = sbsize = GDrawPointsToPixels(gw,_GScrollBar_Width);
    2334           0 :     gd.pos.height = pos.height-bv->mbh-bv->infoh - sbsize;
    2335           0 :     gd.pos.x = pos.width-sbsize;
    2336           0 :     gd.u.sbinit = NULL;
    2337           0 :     gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
    2338           0 :     bv->vsb = GScrollBarCreate(gw,&gd,bv);
    2339             : 
    2340           0 :     gd.pos.y = pos.height-sbsize; gd.pos.height = sbsize;
    2341           0 :     gd.pos.width = pos.width - sbsize;
    2342           0 :     gd.pos.x = 0;
    2343           0 :     gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
    2344           0 :     bv->hsb = GScrollBarCreate(gw,&gd,bv);
    2345             : 
    2346           0 :     memset(&gd, '\0', sizeof(gd));
    2347           0 :     memset(&ti, '\0', sizeof(ti));
    2348           0 :     gd.pos.x = pos.width - GDrawPointsToPixels(gw,111);
    2349           0 :     gd.pos.y = bv->mbh + GDrawPointsToPixels(gw,6);
    2350             :     /*gd.pos.width = GDrawPointsToPixels(gw,106);*/
    2351           0 :     gd.label = &ti;
    2352           0 :     ti.text = (unichar_t *) _("Recalculate Bitmaps");
    2353           0 :     ti.text_is_1byte = true;
    2354           0 :     gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
    2355           0 :     if ( fv->b.sf->onlybitmaps )
    2356           0 :         gd.flags = gg_pos_in_pixels;
    2357           0 :     gd.handle_controlevent = BVRecalc;
    2358           0 :     bv->recalc = GButtonCreate(gw,&gd,bv);
    2359           0 :     GGadgetGetSize(bv->recalc,&size);
    2360           0 :     GGadgetMove(bv->recalc,pos.width - size.width - GDrawPointsToPixels(gw,6),size.y);
    2361             : 
    2362           0 :     pos.y = bv->mbh+bv->infoh; pos.height -= bv->mbh + sbsize + bv->infoh;
    2363           0 :     pos.x = 0; pos.width -= sbsize;
    2364           0 :     wattrs.mask = wam_events|wam_cursor|wam_backcol;
    2365           0 :     wattrs.background_color = view_bgcol;
    2366           0 :     wattrs.event_masks = -1;
    2367           0 :     wattrs.cursor = ( bc->refs == NULL ) ? ct_pencil : ct_pointer;
    2368           0 :     bv->v = GWidgetCreateSubWindow(gw,&pos,v_e_h,bv,&wattrs);
    2369             : 
    2370           0 :     bv->height = pos.height; bv->width = pos.width;
    2371           0 :     bv->b1_tool = ( bc->refs == NULL ) ? bvt_pencil : bvt_pointer; bv->cb1_tool = bvt_pointer;
    2372           0 :     bv->b2_tool = bvt_magnify; bv->cb2_tool = bvt_shift;
    2373           0 :     bv->s1_tool = bv->s2_tool = bv->er_tool = bvt_pointer;
    2374           0 :     bv->showing_tool = ( bc->refs == NULL ) ? bvt_pencil : bvt_pointer;
    2375           0 :     bv->pressed_tool = bv->pressed_display = bv->active_tool = bvt_none;
    2376             : 
    2377             :     /*GWidgetHidePalettes();*/
    2378             :     /*bv->tools = BVMakeTools(bv);*/
    2379             :     /*bv->layers = BVMakeLayers(bv);*/
    2380             : 
    2381           0 :     if ( infofamily==NULL ) {   /* Yes, let's use the same resource name */
    2382           0 :         infofamily = copy(GResourceFindString("CharView.InfoFamily"));
    2383             :         /* FontConfig doesn't have access to all the X11 bitmap fonts */
    2384             :         /*  so the font I used to use isn't found, and a huge monster is */
    2385             :         /*  inserted instead */
    2386           0 :         if ( infofamily==NULL )
    2387           0 :             infofamily = SANS_UI_FAMILIES;
    2388             :     }
    2389             : 
    2390           0 :     memset(&rq,0,sizeof(rq));
    2391           0 :     rq.utf8_family_name = infofamily;
    2392           0 :     rq.point_size = -7;
    2393           0 :     rq.weight = 400;
    2394           0 :     bv->small = GDrawInstanciateFont(gw,&rq);
    2395           0 :     GDrawWindowFontMetrics(gw,bv->small,&as,&ds,&ld);
    2396           0 :     bv->sfh = as+ds; bv->sas = as;
    2397             : 
    2398           0 :     BVFit(bv);
    2399           0 :     GDrawSetVisible(bv->v,true);
    2400           0 :     GDrawSetVisible(gw,true);
    2401           0 : return( bv );
    2402             : }
    2403             : 
    2404           0 : BitmapView *BitmapViewCreatePick(int enc, FontView *fv) {
    2405             :     BDFFont *bdf;
    2406             :     SplineFont *sf;
    2407             :     EncMap *map;
    2408             : 
    2409           0 :     sf = fv->b.cidmaster ? fv->b.cidmaster : fv->b.sf;
    2410           0 :     map = fv->b.map;
    2411             : 
    2412           0 :     if ( fv->show!=fv->filled )
    2413           0 :         bdf = fv->show;
    2414             :     else
    2415           0 :         for ( bdf = sf->bitmaps; bdf!=NULL && bdf->pixelsize!=BVShows.lastpixelsize; bdf = bdf->next );
    2416           0 :     if ( bdf==NULL )
    2417           0 :         bdf = sf->bitmaps;
    2418             : 
    2419           0 : return( BitmapViewCreate(BDFMakeChar(bdf,map,enc),bdf,fv,enc));
    2420             : }
    2421             : 
    2422           0 : void BitmapViewFree(BitmapView *bv) {
    2423           0 :     free(bv);
    2424           0 : }
    2425             : 
    2426           0 : static void BC_RefreshAll(BDFChar *bc) {
    2427             :     BitmapView *bv;
    2428             : 
    2429           0 :     for ( bv = bc->views; bv!=NULL; bv = bv->next )
    2430           0 :         GDrawRequestExpose(bv->v,NULL,false);
    2431           0 : }
    2432             : 
    2433           0 : static void BC_DestroyAll(BDFChar *bc) {
    2434             :     BitmapView *bv, *next;
    2435             : 
    2436           0 :     for ( bv = bc->views; bv!=NULL; bv=next ) {
    2437           0 :         next = bv->next;
    2438           0 :         GDrawDestroyWindow(bv->gw);
    2439             :     }
    2440           0 : }
    2441             : 
    2442             : struct bc_interface gdraw_bc_interface = {
    2443             :     BC_CharChangedUpdate,
    2444             :     BC_RefreshAll,
    2445             :     BC_DestroyAll
    2446             : };

Generated by: LCOV version 1.10