Line data Source code
1 : /* -*- coding: utf-8 -*- */
2 : /* Copyright (C) 2000-2012 by George Williams */
3 : /*
4 : * Redistribution and use in source and binary forms, with or without
5 : * modification, are permitted provided that the following conditions are met:
6 :
7 : * Redistributions of source code must retain the above copyright notice, this
8 : * list of conditions and the following disclaimer.
9 :
10 : * Redistributions in binary form must reproduce the above copyright notice,
11 : * this list of conditions and the following disclaimer in the documentation
12 : * and/or other materials provided with the distribution.
13 :
14 : * The name of the author may not be used to endorse or promote products
15 : * derived from this software without specific prior written permission.
16 :
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : */
28 :
29 : /* Routines to handle bdf properties, and a dialog to set them */
30 : #include "bitmapchar.h"
31 : #include "fontforgeui.h"
32 : #include "splinefont.h"
33 : #include "splinefill.h"
34 : #include <string.h>
35 : #include <ustring.h>
36 : #include <utype.h>
37 : #include <math.h>
38 : #include <gkeysym.h>
39 :
40 : extern GBox _ggadget_Default_Box;
41 : #define ACTIVE_BORDER (_ggadget_Default_Box.active_border)
42 : #define MAIN_FOREGROUND (_ggadget_Default_Box.main_foreground)
43 :
44 : struct bdf_dlg_font {
45 : int old_prop_cnt;
46 : BDFProperties *old_props;
47 : BDFFont *bdf;
48 : int top_prop; /* for the scrollbar */
49 : int sel_prop;
50 : };
51 :
52 : struct bdf_dlg {
53 : int fcnt;
54 : struct bdf_dlg_font *fonts;
55 : struct bdf_dlg_font *cur;
56 : EncMap *map;
57 : SplineFont *sf;
58 : GWindow gw, v;
59 : GGadget *vsb;
60 : GGadget *tf;
61 : GFont *font;
62 : int value_x;
63 : int vheight;
64 : int vwidth;
65 : int height,width;
66 : int fh, as;
67 : int done;
68 : int active;
69 : int press_pos;
70 : };
71 :
72 : extern struct std_bdf_props StandardProps[];
73 :
74 0 : static int NumericKey(char *key) {
75 : int i;
76 :
77 0 : for ( i=0; StandardProps[i].name!=NULL; ++i )
78 0 : if ( strcmp(key,StandardProps[i].name)==0 )
79 0 : return(( StandardProps[i].type&~prt_property)==prt_uint || ( StandardProps[i].type&~prt_property)==prt_int );
80 :
81 0 : return( false );
82 : }
83 :
84 0 : static int KnownProp(char *keyword) { /* We can generate default values for these */
85 : int i;
86 :
87 0 : for ( i=0; StandardProps[i].name!=NULL; ++i )
88 0 : if ( strcmp(keyword,StandardProps[i].name)==0 )
89 0 : return( StandardProps[i].defaultable );
90 :
91 0 : return( false );
92 : }
93 :
94 0 : static int KeyType(char *keyword) {
95 : int i;
96 :
97 0 : for ( i=0; StandardProps[i].name!=NULL; ++i )
98 0 : if ( strcmp(keyword,StandardProps[i].name)==0 )
99 0 : return( StandardProps[i].type );
100 :
101 0 : return( -1 );
102 : }
103 :
104 0 : static int UnknownKey(char *keyword) {
105 : int i;
106 :
107 0 : for ( i=0; StandardProps[i].name!=NULL; ++i )
108 0 : if ( strcmp(keyword,StandardProps[i].name)==0 )
109 0 : return( false );
110 :
111 0 : return( true );
112 : }
113 :
114 : /* ************************************************************************** */
115 : /* ************ Dialog **************** */
116 : /* ************************************************************************** */
117 :
118 : #define CID_Delete 1001
119 : #define CID_DefAll 1002
120 : #define CID_DefCur 1003
121 : #define CID_Up 1004
122 : #define CID_Down 1005
123 :
124 : #define CID_OK 1010
125 : #define CID_Cancel 1011
126 :
127 0 : static void BdfP_RefigureScrollbar(struct bdf_dlg *bd) {
128 0 : struct bdf_dlg_font *cur = bd->cur;
129 0 : int lines = bd->vheight/(bd->fh+1);
130 :
131 : /* allow for one extra line which will display "New" */
132 0 : GScrollBarSetBounds(bd->vsb,0,cur->bdf->prop_cnt+1,lines);
133 0 : if ( cur->top_prop+lines>cur->bdf->prop_cnt+1 )
134 0 : cur->top_prop = cur->bdf->prop_cnt+1-lines;
135 0 : if ( cur->top_prop < 0 )
136 0 : cur->top_prop = 0;
137 0 : GScrollBarSetPos(bd->vsb,cur->top_prop);
138 0 : }
139 :
140 0 : static void BdfP_EnableButtons(struct bdf_dlg *bd) {
141 0 : struct bdf_dlg_font *cur = bd->cur;
142 :
143 0 : if ( cur->sel_prop<0 || cur->sel_prop>=cur->bdf->prop_cnt ) {
144 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_Delete),false);
145 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_DefCur),false);
146 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_Up),false);
147 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_Down),false);
148 : } else {
149 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_Delete),true);
150 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_DefCur),KnownProp(cur->bdf->props[cur->sel_prop].name));
151 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_Up),cur->sel_prop>0);
152 0 : GGadgetSetEnabled(GWidgetGetControl(bd->gw,CID_Down),cur->sel_prop<cur->bdf->prop_cnt-1);
153 : }
154 0 : }
155 :
156 0 : static void BdfP_HideTextField(struct bdf_dlg *bd) {
157 0 : if ( bd->active ) {
158 0 : bd->active = false;
159 0 : GGadgetSetVisible(bd->tf,false);
160 : }
161 0 : }
162 :
163 0 : static int BdfP_FinishTextField(struct bdf_dlg *bd) {
164 0 : if ( bd->active ) {
165 0 : char *text = GGadgetGetTitle8(bd->tf);
166 : char *pt, *end;
167 : int val;
168 0 : struct bdf_dlg_font *cur = bd->cur;
169 0 : BDFFont *bdf = cur->bdf;
170 :
171 0 : for ( pt=text; *pt; ++pt )
172 0 : if ( *pt&0x80 ) {
173 0 : ff_post_error(_("Not ASCII"),_("All characters in the value must be in ASCII"));
174 0 : free(text);
175 0 : return( false );
176 : }
177 0 : val = strtol(text,&end,10);
178 0 : if ( NumericKey(bdf->props[cur->sel_prop].name) ) {
179 0 : if ( *end!='\0' ) {
180 0 : ff_post_error(_("Bad Number"),_("Must be a number"));
181 0 : free(text);
182 0 : return( false );
183 : }
184 : }
185 0 : if ( (bdf->props[cur->sel_prop].type&~prt_property)==prt_string ||
186 0 : (bdf->props[cur->sel_prop].type&~prt_property)==prt_atom )
187 0 : free(bdf->props[cur->sel_prop].u.str);
188 0 : if ( UnknownKey(bdf->props[cur->sel_prop].name) ) {
189 0 : if ( *end!='\0' ) {
190 0 : bdf->props[cur->sel_prop].type = prt_string | prt_property;
191 0 : bdf->props[cur->sel_prop].u.str = copy(text);
192 : } else {
193 0 : if ( bdf->props[cur->sel_prop].type != (prt_uint | prt_property ))
194 0 : bdf->props[cur->sel_prop].type = prt_int | prt_property;
195 0 : bdf->props[cur->sel_prop].u.val = val;
196 : }
197 0 : } else if ( NumericKey(bdf->props[cur->sel_prop].name) ) {
198 0 : bdf->props[cur->sel_prop].type = KeyType(bdf->props[cur->sel_prop].name);
199 0 : bdf->props[cur->sel_prop].u.val = val;
200 : } else {
201 0 : bdf->props[cur->sel_prop].type = KeyType(bdf->props[cur->sel_prop].name);
202 0 : bdf->props[cur->sel_prop].u.str = copy(text);
203 : }
204 0 : free(text);
205 0 : bd->active = false;
206 0 : GGadgetSetVisible(bd->tf,false);
207 : }
208 0 : return( true );
209 : }
210 :
211 0 : static int BdfP_DefaultAll(GGadget *g, GEvent *e) {
212 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
213 0 : struct bdf_dlg *bd = GDrawGetUserData(GGadgetGetWindow(g));
214 0 : int res = BdfPropHasInt(bd->cur->bdf,"RESOLUTION_Y",-1);
215 0 : if ( res!=-1 )
216 0 : bd->cur->bdf->res = res;
217 0 : BdfP_HideTextField(bd);
218 0 : BDFPropsFree(bd->cur->bdf);
219 0 : bd->cur->bdf->prop_cnt = bd->cur->bdf->prop_max = 0;
220 0 : bd->cur->bdf->props = NULL;
221 0 : BDFDefaultProps(bd->cur->bdf, bd->map, -1);
222 0 : bd->cur->top_prop = 0; bd->cur->sel_prop = -1;
223 0 : BdfP_RefigureScrollbar(bd);
224 0 : BdfP_EnableButtons(bd);
225 0 : GDrawRequestExpose(bd->v,NULL,false);
226 : }
227 0 : return( true );
228 : }
229 :
230 0 : static void _BdfP_DefaultCurrent(struct bdf_dlg *bd) {
231 0 : struct bdf_dlg_font *cur = bd->cur;
232 0 : BDFFont *bdf = cur->bdf;
233 0 : if ( cur->sel_prop<0 || cur->sel_prop>=bdf->prop_cnt )
234 0 : return;
235 0 : BdfP_HideTextField(bd);
236 0 : if ( strcmp(bdf->props[cur->sel_prop].name,"FONT")==0 ) {
237 0 : Default_XLFD(bdf,bd->map,-1);
238 0 : } else if ( strcmp(bdf->props[cur->sel_prop].name,"COMMENT")==0 )
239 0 : return;
240 : else
241 0 : Default_Properties(bdf,bd->map,bdf->props[cur->sel_prop].name);
242 0 : GDrawRequestExpose(bd->v,NULL,false);
243 0 : return;
244 : }
245 :
246 0 : static int BdfP_DefaultCurrent(GGadget *g, GEvent *e) {
247 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
248 0 : struct bdf_dlg *bd = GDrawGetUserData(GGadgetGetWindow(g));
249 0 : _BdfP_DefaultCurrent(bd);
250 : }
251 0 : return( true );
252 : }
253 :
254 0 : static int BdfP_DeleteCurrent(GGadget *g, GEvent *e) {
255 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
256 0 : struct bdf_dlg *bd = GDrawGetUserData(GGadgetGetWindow(g));
257 0 : struct bdf_dlg_font *cur = bd->cur;
258 0 : BDFFont *bdf = cur->bdf;
259 : int i;
260 0 : if ( cur->sel_prop<0 || cur->sel_prop>=bdf->prop_cnt )
261 0 : return( true );
262 0 : BdfP_HideTextField(bd);
263 0 : if ( (bdf->props[cur->sel_prop].type&~prt_property)==prt_string ||
264 0 : (bdf->props[cur->sel_prop].type&~prt_property)==prt_atom )
265 0 : free(bdf->props[cur->sel_prop].u.str);
266 0 : free(bdf->props[cur->sel_prop].name);
267 0 : --bdf->prop_cnt;
268 0 : for ( i=cur->sel_prop; i<bdf->prop_cnt; ++i )
269 0 : bdf->props[i] = bdf->props[i+1];
270 0 : if ( cur->sel_prop >= bdf->prop_cnt )
271 0 : --cur->sel_prop;
272 0 : BdfP_RefigureScrollbar(bd);
273 0 : BdfP_EnableButtons(bd);
274 0 : GDrawRequestExpose(bd->v,NULL,false);
275 : }
276 0 : return( true );
277 : }
278 :
279 0 : static void _BdfP_Up(struct bdf_dlg *bd) {
280 0 : struct bdf_dlg_font *cur = bd->cur;
281 0 : BDFFont *bdf = cur->bdf;
282 : GRect r;
283 : BDFProperties prop;
284 0 : if ( cur->sel_prop<1 || cur->sel_prop>=bdf->prop_cnt )
285 0 : return;
286 0 : prop = bdf->props[cur->sel_prop];
287 0 : bdf->props[cur->sel_prop] = bdf->props[cur->sel_prop-1];
288 0 : bdf->props[cur->sel_prop-1] = prop;
289 0 : --cur->sel_prop;
290 0 : GGadgetGetSize(bd->tf,&r);
291 0 : GGadgetMove(bd->tf,r.x,r.y-(bd->fh+1));
292 0 : BdfP_EnableButtons(bd);
293 0 : GDrawRequestExpose(bd->v,NULL,false);
294 : }
295 :
296 0 : static int BdfP_Up(GGadget *g, GEvent *e) {
297 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
298 0 : _BdfP_Up( GDrawGetUserData(GGadgetGetWindow(g)));
299 : }
300 0 : return( true );
301 : }
302 :
303 0 : static void _BdfP_Down(struct bdf_dlg *bd) {
304 0 : struct bdf_dlg_font *cur = bd->cur;
305 0 : BDFFont *bdf = cur->bdf;
306 : GRect r;
307 : BDFProperties prop;
308 0 : if ( cur->sel_prop<0 || cur->sel_prop>=bdf->prop_cnt-1 )
309 0 : return;
310 0 : prop = bdf->props[cur->sel_prop];
311 0 : bdf->props[cur->sel_prop] = bdf->props[cur->sel_prop+1];
312 0 : bdf->props[cur->sel_prop+1] = prop;
313 0 : ++cur->sel_prop;
314 0 : GGadgetGetSize(bd->tf,&r);
315 0 : GGadgetMove(bd->tf,r.x,r.y+(bd->fh+1));
316 0 : BdfP_EnableButtons(bd);
317 0 : GDrawRequestExpose(bd->v,NULL,false);
318 0 : return;
319 : }
320 :
321 0 : static int BdfP_Down(GGadget *g, GEvent *e) {
322 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
323 0 : _BdfP_Down((struct bdf_dlg *) GDrawGetUserData(GGadgetGetWindow(g)));
324 : }
325 0 : return( true );
326 : }
327 :
328 0 : static int BdfP_ChangeBDF(GGadget *g, GEvent *e) {
329 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
330 0 : struct bdf_dlg *bd = GDrawGetUserData(GGadgetGetWindow(g));
331 0 : int sel = GGadgetGetFirstListSelectedItem(g);
332 0 : if ( sel<0 || sel>=bd->fcnt )
333 0 : return( true );
334 0 : if ( !BdfP_FinishTextField(bd)) {
335 0 : sel = bd->cur-bd->fonts;
336 0 : GGadgetSelectListItem(g,sel,true);
337 0 : return( true );
338 : }
339 0 : bd->cur = &bd->fonts[sel];
340 0 : BdfP_RefigureScrollbar(bd);
341 0 : BdfP_EnableButtons(bd);
342 0 : GDrawRequestExpose(bd->v,NULL,false);
343 : }
344 0 : return( true );
345 : }
346 :
347 0 : static void BdfP_DoCancel(struct bdf_dlg *bd) {
348 : int i;
349 0 : for ( i=0; i<bd->fcnt; ++i ) {
350 0 : BDFFont *bdf = bd->fonts[i].bdf;
351 0 : BDFPropsFree(bdf);
352 0 : bdf->props = bd->fonts[i].old_props;
353 0 : bdf->prop_cnt = bd->fonts[i].old_prop_cnt;
354 : }
355 0 : free(bd->fonts);
356 0 : bd->done = true;
357 0 : }
358 :
359 0 : static int BdfP_Cancel(GGadget *g, GEvent *e) {
360 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
361 0 : struct bdf_dlg *bd = GDrawGetUserData(GGadgetGetWindow(g));
362 0 : BdfP_DoCancel(bd);
363 : }
364 0 : return( true );
365 : }
366 :
367 0 : static int BdfP_OK(GGadget *g, GEvent *e) {
368 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
369 0 : struct bdf_dlg *bd = GDrawGetUserData(GGadgetGetWindow(g));
370 : int i;
371 : struct xlfd_components components;
372 : const char *xlfd;
373 :
374 0 : if ( !BdfP_FinishTextField(bd))
375 0 : return( true );
376 0 : for ( i=0; i<bd->fcnt; ++i ) {
377 0 : BDFFont *bdf = bd->fonts[i].bdf;
378 0 : BDFProperties *temp = bdf->props;
379 0 : int pc = bdf->prop_cnt;
380 0 : bdf->props = bd->fonts[i].old_props;
381 0 : bdf->prop_cnt = bd->fonts[i].old_prop_cnt;
382 0 : BDFPropsFree(bdf);
383 0 : bdf->props = temp;
384 0 : bdf->prop_cnt = pc;
385 :
386 0 : xlfd = BdfPropHasString(bdf,"FONT",NULL);
387 0 : if ( xlfd!=NULL )
388 0 : XLFD_GetComponents(xlfd,&components);
389 : else
390 0 : XLFD_CreateComponents(bdf,bd->map, -1, &components);
391 0 : bdf->res = components.res_y;
392 : }
393 0 : free(bd->fonts);
394 0 : bd->sf->changed = true;
395 0 : bd->done = true;
396 : }
397 0 : return( true );
398 : }
399 :
400 0 : static void BdfP_VScroll(struct bdf_dlg *bd,struct sbevent *sb) {
401 0 : int newpos = bd->cur->top_prop;
402 0 : int page = bd->vheight/(bd->fh+1);
403 :
404 0 : switch( sb->type ) {
405 : case et_sb_top:
406 0 : newpos = 0;
407 0 : break;
408 : case et_sb_uppage:
409 0 : newpos -= 9*page/10;
410 0 : break;
411 : case et_sb_up:
412 0 : newpos--;
413 0 : break;
414 : case et_sb_down:
415 0 : newpos++;
416 0 : break;
417 : case et_sb_downpage:
418 0 : newpos += 9*page/10;
419 0 : break;
420 : case et_sb_bottom:
421 0 : newpos = bd->cur->bdf->prop_cnt+1;
422 0 : break;
423 : case et_sb_thumb:
424 : case et_sb_thumbrelease:
425 0 : newpos = sb->pos;
426 0 : break;
427 : }
428 0 : if ( newpos + page > bd->cur->bdf->prop_cnt+1 )
429 0 : newpos = bd->cur->bdf->prop_cnt+1 - page;
430 0 : if ( newpos<0 )
431 0 : newpos = 0;
432 0 : if ( newpos!=bd->cur->top_prop ) {
433 0 : int diff = (newpos-bd->cur->top_prop)*(bd->fh+1);
434 : GRect r;
435 0 : bd->cur->top_prop = newpos;
436 0 : GScrollBarSetPos(bd->vsb,newpos);
437 0 : GGadgetGetSize(bd->tf,&r);
438 0 : GGadgetMove(bd->tf,r.x,r.y+diff);
439 0 : r.x = 0; r.y = 0; r.width = bd->vwidth; r.height = (bd->vheight/(bd->fh+1))*(bd->fh+1);
440 0 : GDrawScroll(bd->v,&r,0,diff);
441 : }
442 0 : }
443 :
444 0 : static int _BdfP_VScroll(GGadget *g, GEvent *e) {
445 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_scrollbarchange ) {
446 0 : struct bdf_dlg *bd = (struct bdf_dlg *) GDrawGetUserData(GGadgetGetWindow(g));
447 0 : BdfP_VScroll(bd,&e->u.control.u.sb);
448 : }
449 0 : return( true );
450 : }
451 :
452 0 : static void BdfP_Resize(struct bdf_dlg *bd) {
453 : extern int _GScrollBar_Width;
454 0 : int sbwidth = GDrawPointsToPixels(bd->gw,_GScrollBar_Width);
455 : GRect size, pos;
456 : static int cids[] = { CID_Delete, CID_DefAll, CID_DefCur, CID_Up,
457 : CID_Down, CID_OK, CID_Cancel, 0 };
458 : int i;
459 :
460 0 : GDrawGetSize(bd->gw,&size);
461 0 : GDrawGetSize(bd->v,&pos);
462 0 : if ( size.width!=bd->width || size.height!=bd->height ) {
463 0 : int yoff = size.height-bd->height;
464 0 : int xoff = size.width-bd->width;
465 0 : bd->width = size.width; bd->height = size.height;
466 0 : bd->vwidth += xoff; bd->vheight += yoff;
467 0 : GDrawResize(bd->v,bd->vwidth,bd->vheight);
468 :
469 0 : GGadgetMove(bd->vsb,size.width-sbwidth,pos.y-1);
470 0 : GGadgetResize(bd->vsb,sbwidth,bd->vheight+2);
471 :
472 0 : GGadgetGetSize(bd->tf,&pos);
473 0 : GGadgetResize(bd->tf,pos.width+xoff,pos.height);
474 :
475 0 : for ( i=0; cids[i]!=0; ++i ) {
476 0 : GGadgetGetSize(GWidgetGetControl(bd->gw,cids[i]),&pos);
477 0 : GGadgetMove(GWidgetGetControl(bd->gw,cids[i]),pos.x,pos.y+yoff);
478 : }
479 : }
480 0 : BdfP_RefigureScrollbar(bd);
481 0 : GDrawRequestExpose(bd->v,NULL,false);
482 0 : GDrawRequestExpose(bd->gw,NULL,true);
483 0 : }
484 :
485 0 : static void BdfP_Expose(struct bdf_dlg *bd, GWindow pixmap) {
486 0 : struct bdf_dlg_font *cur = bd->cur;
487 0 : BDFFont *bdf = cur->bdf;
488 : int i;
489 0 : int page = bd->vheight/(bd->fh+1);
490 : GRect clip, old, r;
491 : char buffer[40];
492 : extern GBox _ggadget_Default_Box;
493 :
494 0 : GDrawSetFont(pixmap,bd->font);
495 0 : clip.x = 4; clip.width = bd->value_x-4-2; clip.height = bd->fh;
496 0 : for ( i=0; i<page && i+cur->top_prop<bdf->prop_cnt; ++i ) {
497 0 : int sel = i+cur->top_prop==cur->sel_prop;
498 0 : clip.y = i*(bd->fh+1);
499 0 : if ( sel ) {
500 0 : r.x = 0; r.width = bd->width;
501 0 : r.y = clip.y; r.height = clip.height;
502 0 : GDrawFillRect(pixmap,&r,ACTIVE_BORDER);
503 : }
504 0 : GDrawPushClip(pixmap,&clip,&old);
505 0 : GDrawDrawText8(pixmap,4,i*(bd->fh+1)+bd->as,bdf->props[i+cur->top_prop].name,-1,MAIN_FOREGROUND);
506 0 : GDrawPopClip(pixmap,&old);
507 0 : switch ( bdf->props[i+cur->top_prop].type&~prt_property ) {
508 : case prt_string: case prt_atom:
509 0 : GDrawDrawText8(pixmap,bd->value_x+2,i*(bd->fh+1)+bd->as,bdf->props[i+cur->top_prop].u.str,-1,MAIN_FOREGROUND);
510 0 : break;
511 : case prt_int:
512 0 : sprintf( buffer, "%d", bdf->props[i+cur->top_prop].u.val );
513 0 : GDrawDrawText8(pixmap,bd->value_x+2,i*(bd->fh+1)+bd->as,buffer,-1,MAIN_FOREGROUND);
514 0 : break;
515 : case prt_uint:
516 0 : sprintf( buffer, "%u", (unsigned) bdf->props[i+cur->top_prop].u.val );
517 0 : GDrawDrawText8(pixmap,bd->value_x+2,i*(bd->fh+1)+bd->as,buffer,-1,MAIN_FOREGROUND);
518 0 : break;
519 : }
520 0 : GDrawDrawLine(pixmap,0,i*(bd->fh+1)+bd->fh,bd->vwidth,i*(bd->fh+1)+bd->fh,0x808080);
521 : }
522 0 : if ( i<page ) {
523 : /* GT: I am told that the use of "|" to provide contextual information in a */
524 : /* GT: gettext string is non-standard. However it is documented in section */
525 : /* GT: 10.2.6 of http://www.gnu.org/software/gettext/manual/html_mono/gettext.html */
526 : /* GT: */
527 : /* GT: Anyway here the word "Property" is used to provide context for "New..." and */
528 : /* GT: the translator should only translate "New...". This is necessary because in */
529 : /* GT: French (or any language where adjectives agree in gender/number with their */
530 : /* GT: nouns) there are several different forms of "New" and the one chose depends */
531 : /* GT: on the noun in question. */
532 : /* GT: A french translation might be either msgstr "Nouveau..." or msgstr "Nouvelle..." */
533 : /* GT: */
534 : /* GT: I expect there are more cases where one english word needs to be translated */
535 : /* GT: by several different words in different languages (in Japanese a different */
536 : /* GT: word is used for the latin script and the latin language) and that you, as */
537 : /* GT: a translator may need to ask me to disambiguate more strings. Please do so: */
538 : /* GT: <pfaedit@users.sourceforge.net> */
539 0 : GDrawDrawText8(pixmap,4,i*(bd->fh+1)+bd->as,S_("Property|New..."),-1,0xff0000);
540 0 : GDrawDrawLine(pixmap,0,i*(bd->fh+1)+bd->fh,bd->vwidth,i*(bd->fh+1)+bd->fh, _ggadget_Default_Box.border_darker);
541 : }
542 0 : GDrawDrawLine(pixmap,bd->value_x,0,bd->value_x,bd->vheight, _ggadget_Default_Box.border_darker);
543 0 : }
544 :
545 0 : static void BdfP_Invoked(GWindow v, GMenuItem *mi, GEvent *e) {
546 0 : struct bdf_dlg *bd = (struct bdf_dlg *) GDrawGetUserData(v);
547 0 : BDFFont *bdf = bd->cur->bdf;
548 0 : char *prop_name = cu_copy(mi->ti.text);
549 0 : int sel = bd->cur->sel_prop;
550 : int i;
551 :
552 0 : if ( sel>=bdf->prop_cnt ) {
553 : /* Create a new one */
554 0 : if ( bdf->prop_cnt>=bdf->prop_max )
555 0 : bdf->props = realloc(bdf->props,(bdf->prop_max+=10)*sizeof(BDFProperties));
556 0 : sel = bd->cur->sel_prop = bdf->prop_cnt++;
557 0 : bdf->props[sel].name = prop_name;
558 0 : for ( i=0; StandardProps[i].name!=NULL; ++i )
559 0 : if ( strcmp(prop_name,StandardProps[i].name)==0 )
560 0 : break;
561 0 : if ( StandardProps[i].name!=NULL ) {
562 0 : bdf->props[sel].type = StandardProps[i].type;
563 0 : if ( (bdf->props[sel].type&~prt_property)==prt_string ||
564 0 : (bdf->props[sel].type&~prt_property)==prt_atom)
565 0 : bdf->props[sel].u.str = NULL;
566 : else
567 0 : bdf->props[sel].u.val = 0;
568 0 : if ( StandardProps[i].defaultable )
569 0 : _BdfP_DefaultCurrent(bd);
570 0 : else if ( (bdf->props[sel].type&~prt_property)==prt_string ||
571 0 : (bdf->props[sel].type&~prt_property)==prt_atom)
572 0 : bdf->props[sel].u.str = copy("");
573 : } else {
574 0 : bdf->props[sel].type = prt_property|prt_string;
575 0 : bdf->props[sel].u.str = copy("");
576 : }
577 : } else {
578 0 : free(bdf->props[sel].name);
579 0 : bdf->props[sel].name = prop_name;
580 : }
581 0 : GDrawRequestExpose(bd->v,NULL,false);
582 0 : }
583 :
584 0 : static void BdfP_PopupMenuProps(struct bdf_dlg *bd, GEvent *e) {
585 : GMenuItem *mi;
586 : int i;
587 :
588 0 : for ( i=0 ; StandardProps[i].name!=NULL; ++i );
589 0 : mi = calloc(i+3,sizeof(GMenuItem));
590 0 : mi[0].ti.text = (unichar_t *) _("No Change");
591 0 : mi[0].ti.text_is_1byte = true;
592 0 : mi[0].ti.fg = COLOR_DEFAULT;
593 0 : mi[0].ti.bg = COLOR_DEFAULT;
594 :
595 0 : mi[1].ti.line = true;
596 0 : mi[1].ti.fg = COLOR_DEFAULT;
597 0 : mi[1].ti.bg = COLOR_DEFAULT;
598 :
599 0 : for ( i=0 ; StandardProps[i].name!=NULL; ++i ) {
600 0 : mi[i+2].ti.text = (unichar_t *) StandardProps[i].name; /* These do not translate!!! */
601 0 : mi[i+2].ti.text_is_1byte = true;
602 0 : mi[i+2].ti.fg = COLOR_DEFAULT;
603 0 : mi[i+2].ti.bg = COLOR_DEFAULT;
604 0 : mi[i+2].invoke = BdfP_Invoked;
605 : }
606 :
607 0 : GMenuCreatePopupMenu(bd->v,e,mi);
608 0 : free(mi);
609 0 : }
610 :
611 0 : static void BdfP_Mouse(struct bdf_dlg *bd, GEvent *e) {
612 0 : int line = e->u.mouse.y/(bd->fh+1) + bd->cur->top_prop;
613 :
614 0 : if ( line<0 || line>bd->cur->bdf->prop_cnt )
615 0 : return; /* "New" happens when line==bd->cur->bdf->prop_cnt */
616 0 : if ( e->type == et_mousedown ) {
617 0 : if ( !BdfP_FinishTextField(bd) ) {
618 0 : bd->press_pos = -1;
619 0 : return;
620 : }
621 0 : if ( e->u.mouse.x>=4 && e->u.mouse.x<= bd->value_x ) {
622 0 : bd->cur->sel_prop = line;
623 0 : BdfP_PopupMenuProps(bd,e);
624 0 : BdfP_EnableButtons(bd);
625 0 : } else if ( line>=bd->cur->bdf->prop_cnt )
626 0 : return;
627 : else {
628 0 : bd->press_pos = line;
629 0 : bd->cur->sel_prop = -1;
630 0 : GDrawRequestExpose(bd->v,NULL,false );
631 : }
632 0 : } else if ( e->type == et_mouseup ) {
633 0 : int pos = bd->press_pos;
634 0 : bd->press_pos = -1;
635 0 : if ( line>=bd->cur->bdf->prop_cnt || line!=pos )
636 0 : return;
637 0 : if ( bd->active ) /* Should never happen */
638 0 : return;
639 0 : bd->cur->sel_prop = line;
640 0 : if ( e->u.mouse.x > bd->value_x ) {
641 0 : BDFFont *bdf = bd->cur->bdf;
642 0 : GGadgetMove(bd->tf,bd->value_x+2,(line-bd->cur->top_prop)*(bd->fh+1));
643 0 : if ( (bdf->props[line].type&~prt_property) == prt_int ||
644 0 : (bdf->props[line].type&~prt_property) == prt_uint ) {
645 : char buffer[40];
646 0 : sprintf( buffer,"%d",bdf->props[line].u.val );
647 0 : GGadgetSetTitle8(bd->tf,buffer);
648 : } else
649 0 : GGadgetSetTitle8(bd->tf,bdf->props[line].u.str );
650 0 : GGadgetSetVisible(bd->tf,true);
651 0 : bd->active = true;
652 : }
653 0 : GDrawRequestExpose(bd->v,NULL,false );
654 : }
655 : }
656 :
657 0 : static int BdfP_Char(struct bdf_dlg *bd, GEvent *e) {
658 0 : if ( bd->active || bd->cur->sel_prop==-1 )
659 0 : return( false );
660 0 : switch ( e->u.chr.keysym ) {
661 : case GK_Up: case GK_KP_Up:
662 0 : _BdfP_Up(bd);
663 0 : return( true );
664 : case GK_Down: case GK_KP_Down:
665 0 : _BdfP_Down(bd);
666 0 : return( true );
667 : default:
668 0 : return( false );
669 : }
670 : }
671 :
672 0 : static int bdfpv_e_h(GWindow gw, GEvent *event) {
673 0 : struct bdf_dlg *bd = GDrawGetUserData(gw);
674 0 : if ( event->type==et_expose ) {
675 0 : BdfP_Expose(bd,gw);
676 0 : } else if ( event->type == et_char ) {
677 0 : return( BdfP_Char(bd,event));
678 0 : } else if ( event->type == et_mousedown || event->type == et_mouseup || event->type==et_mousemove ) {
679 0 : BdfP_Mouse(bd,event);
680 0 : if ( event->type == et_mouseup )
681 0 : BdfP_EnableButtons(bd);
682 : }
683 0 : return( true );
684 : }
685 :
686 0 : static int bdfp_e_h(GWindow gw, GEvent *event) {
687 0 : struct bdf_dlg *bd = GDrawGetUserData(gw);
688 0 : if ( event->type==et_close ) {
689 0 : BdfP_DoCancel(bd);
690 0 : } else if ( event->type == et_expose ) {
691 : GRect r;
692 0 : GDrawGetSize(bd->v,&r);
693 0 : GDrawDrawLine(gw,0,r.y-1,bd->width,r.y-1,0x808080);
694 0 : GDrawDrawLine(gw,0,r.y+r.height,bd->width,r.y+r.height,0x808080);
695 0 : } else if ( event->type == et_char ) {
696 0 : return( BdfP_Char(bd,event));
697 0 : } else if ( event->type == et_resize ) {
698 0 : BdfP_Resize(bd);
699 : }
700 0 : return( true );
701 : }
702 :
703 0 : void SFBdfProperties(SplineFont *sf, EncMap *map, BDFFont *thisone) {
704 : struct bdf_dlg bd;
705 : int i;
706 : BDFFont *bdf;
707 : GTextInfo *ti;
708 : char buffer[40];
709 : char title[130];
710 : GRect pos, subpos;
711 : GWindow gw;
712 : GWindowAttrs wattrs;
713 : GGadgetCreateData gcd[10];
714 : GTextInfo label[9];
715 : FontRequest rq;
716 : static GFont *font = NULL;
717 : extern int _GScrollBar_Width;
718 : int sbwidth;
719 : static unichar_t sans[] = { 'h','e','l','v','e','t','i','c','a',',','c','l','e','a','r','l','y','u',',','u','n','i','f','o','n','t', '\0' };
720 : static GBox small = GBOX_EMPTY;
721 : GGadgetData gd;
722 : /* I don't use a MatrixEdit here because I want to be able to display */
723 : /* non-standard properties. And a MatrixEdit can only disply things in */
724 : /* its pull-down list */
725 :
726 0 : memset(&bd,0,sizeof(bd));
727 0 : bd.map = map;
728 0 : bd.sf = sf;
729 0 : for ( bdf = sf->bitmaps, i=0; bdf!=NULL; bdf=bdf->next, ++i );
730 0 : if ( i==0 )
731 0 : return;
732 0 : bd.fcnt = i;
733 0 : bd.fonts = calloc(i,sizeof(struct bdf_dlg_font));
734 0 : bd.cur = &bd.fonts[0];
735 0 : for ( bdf = sf->bitmaps, i=0; bdf!=NULL; bdf=bdf->next, ++i ) {
736 0 : bd.fonts[i].bdf = bdf;
737 0 : bd.fonts[i].old_prop_cnt = bdf->prop_cnt;
738 0 : bd.fonts[i].old_props = BdfPropsCopy(bdf->props,bdf->prop_cnt);
739 0 : bd.fonts[i].sel_prop = -1;
740 0 : bdf->prop_max = bdf->prop_cnt;
741 0 : if ( bdf==thisone )
742 0 : bd.cur = &bd.fonts[i];
743 : }
744 :
745 0 : ti = calloc((i+1),sizeof(GTextInfo));
746 0 : for ( bdf = sf->bitmaps, i=0; bdf!=NULL; bdf=bdf->next, ++i ) {
747 0 : if ( bdf->clut==NULL )
748 0 : sprintf( buffer, "%d", bdf->pixelsize );
749 : else
750 0 : sprintf( buffer, "%d@%d", bdf->pixelsize, BDFDepth(bdf));
751 0 : ti[i].text = (unichar_t *) copy(buffer);
752 0 : ti[i].text_is_1byte = true;
753 : }
754 0 : ti[bd.cur-bd.fonts].selected = true;
755 :
756 0 : memset(&wattrs,0,sizeof(wattrs));
757 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
758 0 : wattrs.event_masks = ~(1<<et_charup);
759 0 : wattrs.is_dlg = true;
760 0 : wattrs.restrict_input_to_me = 1;
761 0 : wattrs.undercursor = 1;
762 0 : wattrs.cursor = ct_pointer;
763 0 : snprintf(title,sizeof(title),_("Strike Information for %.90s"),
764 : sf->fontname);
765 0 : wattrs.utf8_window_title = title;
766 0 : pos.x = pos.y = 0;
767 0 : pos.width = GDrawPointsToPixels(NULL,GGadgetScale(268));
768 0 : pos.height = GDrawPointsToPixels(NULL,375);
769 0 : bd.gw = gw = GDrawCreateTopWindow(NULL,&pos,bdfp_e_h,&bd,&wattrs);
770 :
771 0 : sbwidth = GDrawPointsToPixels(bd.gw,_GScrollBar_Width);
772 0 : subpos.x = 0; subpos.y = GDrawPointsToPixels(NULL,28);
773 0 : subpos.width = pos.width-sbwidth;
774 0 : subpos.height = pos.height - subpos.y - GDrawPointsToPixels(NULL,70);
775 0 : wattrs.mask = wam_events;
776 0 : bd.v = GWidgetCreateSubWindow(gw,&subpos,bdfpv_e_h,&bd,&wattrs);
777 0 : bd.vwidth = subpos.width; bd.vheight = subpos.height;
778 0 : bd.width = pos.width; bd.height = pos.height;
779 0 : bd.value_x = GDrawPointsToPixels(bd.gw,135);
780 :
781 0 : if ( font==NULL ) {
782 0 : memset(&rq,0,sizeof(rq));
783 0 : rq.family_name = sans;
784 0 : rq.point_size = 10;
785 0 : rq.weight = 400;
786 0 : font = GDrawInstanciateFont(gw,&rq);
787 0 : font = GResourceFindFont("BDFProperties.Font",font);
788 : }
789 0 : bd.font = font;
790 : {
791 : int as, ds, ld;
792 0 : GDrawWindowFontMetrics(gw,bd.font,&as,&ds,&ld);
793 0 : bd.as = as; bd.fh = as+ds;
794 : }
795 :
796 0 : memset(gcd,0,sizeof(gcd));
797 0 : memset(label,0,sizeof(label));
798 :
799 0 : i=0;
800 0 : gcd[i].gd.pos.x = 10; gcd[i].gd.pos.y = 3;
801 0 : gcd[i].gd.flags = gg_visible | gg_enabled;
802 0 : gcd[i].gd.u.list = ti;
803 0 : gcd[i].gd.handle_controlevent = BdfP_ChangeBDF;
804 0 : gcd[i++].creator = GListButtonCreate;
805 :
806 0 : gcd[i].gd.pos.x = bd.vwidth; gcd[i].gd.pos.y = subpos.y-1;
807 0 : gcd[i].gd.pos.width = sbwidth; gcd[i].gd.pos.height = subpos.height+2;
808 0 : gcd[i].gd.flags = gg_visible | gg_enabled | gg_sb_vert | gg_pos_in_pixels;
809 0 : gcd[i].gd.handle_controlevent = _BdfP_VScroll;
810 0 : gcd[i++].creator = GScrollBarCreate;
811 :
812 0 : label[i].text = (unichar_t *) _("Delete");
813 0 : label[i].text_is_1byte = true;
814 0 : gcd[i].gd.label = &label[i];
815 0 : gcd[i].gd.pos.x = 4; gcd[i].gd.pos.y = GDrawPixelsToPoints(gw,subpos.y+subpos.height)+6;
816 0 : gcd[i].gd.flags = gg_visible | gg_enabled ;
817 0 : gcd[i].gd.handle_controlevent = BdfP_DeleteCurrent;
818 0 : gcd[i].gd.cid = CID_Delete;
819 0 : gcd[i++].creator = GButtonCreate;
820 :
821 0 : label[i].text = (unichar_t *) _("Default All");
822 0 : label[i].text_is_1byte = true;
823 0 : gcd[i].gd.label = &label[i];
824 0 : gcd[i].gd.pos.x = 80; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y;
825 0 : gcd[i].gd.flags = gg_visible | gg_enabled ;
826 0 : gcd[i].gd.handle_controlevent = BdfP_DefaultAll;
827 0 : gcd[i].gd.cid = CID_DefAll;
828 0 : gcd[i++].creator = GButtonCreate;
829 :
830 0 : label[i].text = (unichar_t *) _("Default This");
831 0 : label[i].text_is_1byte = true;
832 0 : gcd[i].gd.label = &label[i];
833 0 : gcd[i].gd.pos.y = gcd[i-1].gd.pos.y;
834 0 : gcd[i].gd.flags = gg_visible | gg_enabled ;
835 0 : gcd[i].gd.handle_controlevent = BdfP_DefaultCurrent;
836 0 : gcd[i].gd.cid = CID_DefCur;
837 0 : gcd[i++].creator = GButtonCreate;
838 :
839 : /* I want the 2 pronged arrow, but gdraw can't find a nice one */
840 : /* label[i].text = (unichar_t *) "⇑"; *//* Up Arrow */
841 0 : label[i].text = (unichar_t *) "↑"; /* Up Arrow */
842 0 : label[i].text_is_1byte = true;
843 0 : gcd[i].gd.label = &label[i];
844 0 : gcd[i].gd.pos.y = gcd[i-1].gd.pos.y;
845 0 : gcd[i].gd.flags = gg_visible | gg_enabled ;
846 0 : gcd[i].gd.handle_controlevent = BdfP_Up;
847 0 : gcd[i].gd.cid = CID_Up;
848 0 : gcd[i++].creator = GButtonCreate;
849 :
850 : /* I want the 2 pronged arrow, but gdraw can't find a nice one */
851 : /* label[i].text = (unichar_t *) "⇓"; *//* Down Arrow */
852 0 : label[i].text = (unichar_t *) "↓"; /* Down Arrow */
853 0 : label[i].text_is_1byte = true;
854 0 : gcd[i].gd.label = &label[i];
855 0 : gcd[i].gd.pos.y = gcd[i-1].gd.pos.y;
856 0 : gcd[i].gd.flags = gg_visible | gg_enabled ;
857 0 : gcd[i].gd.handle_controlevent = BdfP_Down;
858 0 : gcd[i].gd.cid = CID_Down;
859 0 : gcd[i++].creator = GButtonCreate;
860 :
861 :
862 0 : gcd[i].gd.pos.x = 30-3; gcd[i].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-32-3;
863 0 : gcd[i].gd.pos.width = -1; gcd[i].gd.pos.height = 0;
864 0 : gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
865 0 : label[i].text = (unichar_t *) _("_OK");
866 0 : label[i].text_is_1byte = true;
867 0 : label[i].text_in_resource = true;
868 0 : gcd[i].gd.label = &label[i];
869 0 : gcd[i].gd.handle_controlevent = BdfP_OK;
870 0 : gcd[i].gd.cid = CID_OK;
871 0 : gcd[i++].creator = GButtonCreate;
872 :
873 0 : gcd[i].gd.pos.x = -30; gcd[i].gd.pos.y = gcd[i-1].gd.pos.y+3;
874 0 : gcd[i].gd.pos.width = -1; gcd[i].gd.pos.height = 0;
875 0 : gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
876 0 : label[i].text = (unichar_t *) _("_Cancel");
877 0 : label[i].text_is_1byte = true;
878 0 : label[i].text_in_resource = true;
879 0 : gcd[i].gd.label = &label[i];
880 0 : gcd[i].gd.handle_controlevent = BdfP_Cancel;
881 0 : gcd[i].gd.cid = CID_Cancel;
882 0 : gcd[i++].creator = GButtonCreate;
883 :
884 0 : GGadgetsCreate(gw,gcd);
885 0 : GTextInfoListFree(gcd[0].gd.u.list);
886 0 : bd.vsb = gcd[1].ret;
887 :
888 0 : small.main_background = small.main_foreground = COLOR_DEFAULT;
889 0 : small.main_foreground = 0x0000ff;
890 0 : memset(&gd,'\0',sizeof(gd));
891 0 : memset(&label[0],'\0',sizeof(label[0]));
892 :
893 0 : label[0].text = (unichar_t *) "\0\0\0\0";
894 0 : label[0].font = bd.font;
895 0 : gd.pos.height = bd.fh;
896 0 : gd.pos.width = bd.vwidth-bd.value_x;
897 0 : gd.label = &label[0];
898 0 : gd.box = &small;
899 0 : gd.flags = gg_enabled | gg_pos_in_pixels | gg_dontcopybox | gg_text_xim;
900 0 : bd.tf = GTextFieldCreate(bd.v,&gd,&bd);
901 :
902 0 : bd.press_pos = -1;
903 0 : BdfP_EnableButtons(&bd);
904 0 : BdfP_RefigureScrollbar(&bd);
905 :
906 0 : GDrawSetVisible(bd.v,true);
907 0 : GDrawSetVisible(gw,true);
908 0 : while ( !bd.done )
909 0 : GDrawProcessOneEvent(NULL);
910 0 : GDrawDestroyWindow(gw);
911 : }
|