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