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