1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "basics.h"
31 #include "gdraw.h"
32 #include "ggadgetP.h"
33 #include "gkeysym.h"
34 #include "gresource.h"
35 #include "gwidget.h"
36 #include "ustring.h"
37 #include "utype.h"
38 
39 GBox _ggadget_Default_Box = { bt_raised, bs_rect, 2, 2, 0, 0,
40     COLOR_CREATE(0xd8,0xd8,0xd8),		/* border left */ /* brightest */
41     COLOR_CREATE(0xd0,0xd0,0xd0),		/* border top */
42     COLOR_CREATE(0x80,0x80,0x80),		/* border right */
43     COLOR_CREATE(0x66,0x66,0x66),		/* border bottom */ /* darkest */
44     COLOR_DEFAULT,				/* normal background */
45     COLOR_DEFAULT,				/* normal foreground */
46     COLOR_CREATE(0xd8,0xd8,0xd8),		/* disabled background */
47     COLOR_CREATE(0x66,0x66,0x66),		/* disabled foreground */
48     COLOR_CREATE(0xff,0xff,0x00),		/* active border */
49     COLOR_CREATE(0xa0,0xa0,0xa0),		/* pressed background */
50     COLOR_CREATE(0x00,0x00,0x00),		/* gradient bg end */
51     COLOR_CREATE(0x00,0x00,0x00),		/* border inner */
52     COLOR_CREATE(0x00,0x00,0x00),		/* border outer */
53 };
54 GBox _GListMark_Box = GBOX_EMPTY; /* Don't initialize here */
55 FontInstance *_ggadget_default_font = NULL;
56 static FontInstance *popup_font = NULL;
57 int _GListMarkSize = 12;
58 GResImage *_GListMark_Image = NULL, *_GListMark_DisImage;
59 static int _GGadget_FirstLine = 6;
60 static int _GGadget_LeftMargin = 6;
61 static int _GGadget_LineSkip = 3;
62 int _GGadget_Skip = 6;
63 int _GGadget_TextImageSkip = 4;
64 char *_GGadget_ImagePath = NULL;
65 static int _ggadget_inited=0;
66 static Color popup_foreground=0, popup_background=COLOR_CREATE(0xff,0xff,0xc0);
67 static int popup_delay=1000, popup_lifetime=20000;
68 
69 static GResInfo popup_ri;
70 static struct resed ggadget_re[] = {
71     {N_("Text Image Skip"), "TextImageSkip", rt_int, &_GGadget_TextImageSkip, N_("Space (in points) left between images and text in labels, buttons, menu items, etc. which have both"), NULL, { 0 }, 0, 0 },
72     {N_("Image Path"), "ImagePath", rt_stringlong, &_GGadget_ImagePath, N_("List of directories to search for images, separated by colons"), NULL, { 0 }, 0, 0 },
73     RESED_EMPTY
74 };
75 GResInfo ggadget_ri = {
76     &listmark_ri, NULL,NULL, NULL,
77     &_ggadget_Default_Box,
78     &_ggadget_default_font,
79     NULL,
80     ggadget_re,
81     N_("GGadget"),
82     N_("This is an \"abstract\" gadget. It will never appear on the screen\nbut it is the root of gadget tree from which all others inherit"),
83     "GGadget",
84     "Gdraw",
85     false,
86     0,
87     NULL,
88     GBOX_EMPTY,
89     NULL,
90     NULL,
91     NULL
92 };
93 static struct resed popup_re[] = {
94     {N_("Color|Foreground"), "Foreground", rt_color, &popup_foreground, N_("Text color for popup windows"), NULL, { 0 }, 0, 0 },
95     {N_("Color|Background"), "Background", rt_color, &popup_background, N_("Background color for popup windows"), NULL, { 0 }, 0, 0 },
96     {N_("Delay"), "Delay", rt_int, &popup_delay, N_("Delay (in milliseconds) before popup windows appear"), NULL, { 0 }, 0, 0 },
97     {N_("Life Time"), "LifeTime", rt_int, &popup_lifetime, N_("Time (in milliseconds) that popup windows remain visible"), NULL, { 0 }, 0, 0 },
98     RESED_EMPTY
99 };
100 static void popup_refresh(void);
101 static GResInfo popup_ri = {
102     &ggadget_ri, NULL, NULL,NULL,
103     NULL,	/* No box */
104     &popup_font,
105     NULL,
106     popup_re,
107     N_("Popup"),
108     N_("Popup windows"),
109     "GGadget.Popup",
110     "Gdraw",
111     false,
112     omf_refresh,
113     NULL,
114     GBOX_EMPTY,
115     popup_refresh,
116     NULL,
117     NULL
118 };
119 static struct resed listmark_re[] = {
120     { N_("Image"), "Image", rt_image, &_GListMark_Image, N_("Image used for enabled listmarks (overrides the box)"), NULL, { 0 }, 0, 0 },
121     { N_("Disabled Image"), "DisabledImage", rt_image, &_GListMark_DisImage, N_("Image used for disabled listmarks (overrides the box)"), NULL, { 0 }, 0, 0 },
122     { N_("Width"), "Width", rt_int, &_GListMarkSize, N_("Size of the list mark"), NULL, { 0 }, 0, 0 },
123     RESED_EMPTY
124 };
125 static GTextInfo list_choices[] = {
126     { (unichar_t *) "1", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
127     { (unichar_t *) "2", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
128     { (unichar_t *) "3", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
129     GTEXTINFO_EMPTY
130 };
131 static GGadgetCreateData droplist_gcd[] = {
132     { GListFieldCreate, { {0, 0, 80, 0 }, NULL, 0, 0, 0, 0, 0, &list_choices[0], { list_choices }, gg_visible, NULL, NULL }, NULL, NULL },
133     { GListFieldCreate, { {0, 0, 80, 0 }, NULL, 0, 0, 0, 0, 0, &list_choices[1], { list_choices }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL }
134 };
135 static GGadgetCreateData *dlarray[] = { GCD_Glue, &droplist_gcd[0], GCD_Glue, &droplist_gcd[1], GCD_Glue, NULL, NULL };
136 static GGadgetCreateData droplistbox =
137     { GHVGroupCreate, { { 2, 2, 0, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) dlarray }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL };
138 GResInfo listmark_ri = {
139     NULL, &ggadget_ri, NULL,NULL,
140     &_GListMark_Box,	/* No box */
141     NULL,
142     &droplistbox,
143     listmark_re,
144     N_("List Mark"),
145     N_("This is the mark that differentiates ComboBoxes and ListButtons\n"
146 	"from TextFields and normal Buttons." ),
147     "GListMark",
148     "Gdraw",
149     false,
150     omf_border_width|omf_padding,
151     NULL,
152     GBOX_EMPTY,
153     NULL,
154     NULL,
155     NULL
156 };
157 
158 
159 static GWindow popup;
160 static GTimer *popup_timer, *popup_vanish_timer;
161 static int popup_visible = false;
162 
match(char ** list,char * val)163 static int match(char **list, char *val) {
164     int i;
165 
166     for ( i=0; list[i]!=NULL; ++i )
167 	if ( strmatch(val,list[i])==0 )
168 return( i );
169 
170 return( -1 );
171 }
172 
border_type_cvt(char * val,void * def)173 static void *border_type_cvt(char *val, void *def) {
174     static char *types[] = { "none", "box", "raised", "lowered", "engraved",
175 	    "embossed", "double", NULL };
176     int ret = match(types,val);
177     if ( ret== -1 )
178 return( def );
179 return( (void *) (intpt) ret );
180 }
181 
border_shape_cvt(char * val,void * def)182 static void *border_shape_cvt(char *val, void *def) {
183     static char *shapes[] = { "rect", "roundrect", "elipse", "diamond", NULL };
184     int ret = match(shapes,val);
185     if ( ret== -1 )
186 return( def );
187 return( (void *) (intpt) ret );
188 }
189 
190 /* font name may be something like:
191 	bold italic extended 12pt courier
192 	400 10pt small-caps
193     family name comes at the end, size must have "pt" after it
194 */
GResource_font_cvt(char * val,void * def)195 void *GResource_font_cvt(char *val, void *def) {
196     static char *styles[] = { "normal", "italic", "oblique", "small-caps",
197 	    "bold", "light", "extended", "condensed", NULL };
198     FontRequest rq;
199     FontInstance *fi;
200     char *pt, *end, ch;
201     int ret;
202     char *freeme=NULL;
203 
204     memset(&rq,0,sizeof(rq));
205     rq.utf8_family_name = SANS_UI_FAMILIES;
206     rq.point_size = 10;
207     rq.weight = 400;
208     rq.style = 0;
209     if ( def!=NULL )
210 	GDrawDecomposeFont((FontInstance *)def, &rq);
211     else if ( _ggadget_default_font!=NULL )
212 	GDrawDecomposeFont(_ggadget_default_font, &rq);
213 
214     for ( pt=val; *pt && *pt!='"'; ) {
215 	for ( end=pt; *end!=' ' && *end!='\0'; ++end );
216 	ch = *end; *end = '\0';
217 	ret = match(styles,pt);
218 	if ( ret==-1 && isdigit(*pt)) {
219 	    char *e;
220 	    ret = strtol(pt,&e,10);
221 	    if ( strmatch(e,"pt")==0 )
222 		rq.point_size = ret;
223 	    else if ( *e=='\0' )
224 		rq.weight = ret;
225 	    else {
226 		*end = ch;
227     break;
228 	    }
229 	} else if ( ret==-1 ) {
230 	    *end = ch;
231     break;
232 	} else if ( ret==0 )
233 	    /* Do Nothing */;
234 	else if ( ret==1 || ret==2 )
235 	    rq.style |= fs_italic;
236 	else if ( ret==3 )
237 	    rq.style |= fs_smallcaps;
238 	else if ( ret==4 )
239 	    rq.weight = 700;
240 	else if ( ret==5 )
241 	    rq.weight = 300;
242 	else if ( ret==6 )
243 	    rq.style |= fs_extended;
244 	else
245 	    rq.style |= fs_condensed;
246 	*end = ch;
247 	pt = end;
248 	while ( *pt==' ' ) ++pt;
249     }
250 
251     if ( *pt!='\0' )
252 	rq.utf8_family_name = freeme = copy(pt);
253 
254     fi = GDrawInstanciateFont(NULL,&rq);
255 
256     free(freeme);
257 
258     if ( fi==NULL )
259 return( def );
260 return( (void *) fi );
261 }
262 
GResourceFindFont(char * resourcename,FontInstance * deffont)263 FontInstance *GResourceFindFont(char *resourcename,FontInstance *deffont) {
264     char *val = GResourceFindString(resourcename);
265     if ( val==NULL )
266 return( deffont );
267 
268 return( GResource_font_cvt(val,deffont));
269 }
270 
_GGadgetCopyDefaultBox(GBox * box)271 void _GGadgetCopyDefaultBox(GBox *box) {
272     *box = _ggadget_Default_Box;
273 }
274 
_GGadgetInitDefaultBox(char * class,GBox * box,FontInstance * deffont)275 FontInstance *_GGadgetInitDefaultBox(char *class,GBox *box, FontInstance *deffont) {
276     GResStruct bordertype[] = {
277 	{ "Box.BorderType", rt_string, NULL, border_type_cvt, 0 },
278 	GRESSTRUCT_EMPTY
279     };
280     GResStruct boxtypes[] = {
281 	{ "Box.BorderType", rt_string, NULL, border_type_cvt, 0 },
282 	{ "Box.BorderShape", rt_string, NULL, border_shape_cvt, 0 },
283 	{ "Box.BorderWidth", rt_int, NULL, NULL, 0 },
284 	{ "Box.Padding", rt_int, NULL, NULL, 0 },
285 	{ "Box.Radius", rt_int, NULL, NULL, 0 },
286 	{ "Box.BorderInner", rt_bool, NULL, NULL, 0 },
287 	{ "Box.BorderOuter", rt_bool, NULL, NULL, 0 },
288 	{ "Box.ActiveInner", rt_bool, NULL, NULL, 0 },
289 	{ "Box.DoDepressedBackground", rt_bool, NULL, NULL, 0 },
290 	{ "Box.DrawDefault", rt_bool, NULL, NULL, 0 },
291 	{ "Box.BorderBrightest", rt_color, NULL, NULL, 0 },
292 	{ "Box.BorderBrighter", rt_color, NULL, NULL, 0 },
293 	{ "Box.BorderDarkest", rt_color, NULL, NULL, 0 },
294 	{ "Box.BorderDarker", rt_color, NULL, NULL, 0 },
295 	{ "Box.NormalBackground", rt_color, NULL, NULL, 0 },
296 	{ "Box.NormalForeground", rt_color, NULL, NULL, 0 },
297 	{ "Box.DisabledBackground", rt_color, NULL, NULL, 0 },
298 	{ "Box.DisabledForeground", rt_color, NULL, NULL, 0 },
299 	{ "Box.ActiveBorder", rt_color, NULL, NULL, 0 },
300 	{ "Box.PressedBackground", rt_color, NULL, NULL, 0 },
301 	{ "Box.BorderLeft", rt_color, NULL, NULL, 0 },
302 	{ "Box.BorderTop", rt_color, NULL, NULL, 0 },
303 	{ "Box.BorderRight", rt_color, NULL, NULL, 0 },
304 	{ "Box.BorderBottom", rt_color, NULL, NULL, 0 },
305 	{ "Font", rt_string, NULL, GResource_font_cvt, 0 },
306 	{ "Box.GradientBG", rt_bool, NULL, NULL, 0 },
307 	{ "Box.GradientStartCol", rt_color, NULL, NULL, 0 },
308 	{ "Box.ShadowOuter", rt_bool, NULL, NULL, 0 },
309 	{ "Box.BorderInnerCol", rt_color, NULL, NULL, 0 },
310 	{ "Box.BorderOuterCol", rt_color, NULL, NULL, 0 },
311 	GRESSTRUCT_EMPTY
312     };
313     intpt bt, bs;
314     int bw, pad, rr, inner, outer, active, depressed, def, grad, shadow;
315     FontInstance *fi=deffont;
316 
317     if ( !_ggadget_inited )
318 	GGadgetInit();
319     if ( fi==NULL )
320 	fi = _ggadget_default_font;
321     bt = box->border_type;
322     bs = box->border_shape;
323     bw = box->border_width;
324     pad = box->padding;
325     rr = box->rr_radius;
326     inner = box->flags & box_foreground_border_inner;
327     outer = box->flags & box_foreground_border_outer;
328     active = box->flags & box_active_border_inner;
329     depressed = box->flags & box_do_depressed_background;
330     def = box->flags & box_draw_default;
331     grad = box->flags & box_gradient_bg;
332     shadow = box->flags & box_foreground_shadow_outer;
333 
334     bordertype[0].val = &bt;
335     boxtypes[0].val = &bt;
336     boxtypes[1].val = &bs;
337     boxtypes[2].val = &bw;
338     boxtypes[3].val = &pad;
339     boxtypes[4].val = &rr;
340     boxtypes[5].val = &inner;
341     boxtypes[6].val = &outer;
342     boxtypes[7].val = &active;
343     boxtypes[8].val = &depressed;
344     boxtypes[9].val = &def;
345     boxtypes[10].val = &box->border_brightest;
346     boxtypes[11].val = &box->border_brighter;
347     boxtypes[12].val = &box->border_darkest;
348     boxtypes[13].val = &box->border_darker;
349     boxtypes[14].val = &box->main_background;
350     boxtypes[15].val = &box->main_foreground;
351     boxtypes[16].val = &box->disabled_background;
352     boxtypes[17].val = &box->disabled_foreground;
353     boxtypes[18].val = &box->active_border;
354     boxtypes[19].val = &box->depressed_background;
355     boxtypes[20].val = &box->border_brightest;
356     boxtypes[21].val = &box->border_brighter;
357     boxtypes[22].val = &box->border_darkest;
358     boxtypes[23].val = &box->border_darker;
359     boxtypes[24].val = &fi;
360     boxtypes[25].val = &grad;
361     boxtypes[26].val = &box->gradient_bg_end;
362     boxtypes[27].val = &shadow;
363     boxtypes[28].val = &box->border_inner;
364     boxtypes[29].val = &box->border_outer;
365 
366     GResourceFind( bordertype, class);
367     /* for a plain box, default to all borders being the same. they must change*/
368     /*  explicitly */
369     if ( bt==bt_box || bt==bt_double )
370 	box->border_brightest = box->border_brighter = box->border_darker = box->border_darkest;
371     GResourceFind( boxtypes, class);
372 
373     box->border_type = bt;
374     box->border_shape = bs;
375     box->border_width = bw;
376     box->padding = pad;
377     box->rr_radius = rr;
378     box->flags=0;
379     if ( inner )
380 	box->flags |= box_foreground_border_inner;
381     if ( outer )
382 	box->flags |= box_foreground_border_outer;
383     if ( active )
384 	box->flags |= box_active_border_inner;
385     if ( depressed )
386 	box->flags |= box_do_depressed_background;
387     if ( def )
388 	box->flags |= box_draw_default;
389     if ( grad )
390 	box->flags |= box_gradient_bg;
391     if ( shadow )
392 	box->flags |= box_foreground_shadow_outer;
393 
394     if ( fi==NULL ) {
395 	FontRequest rq;
396 	memset(&rq,0,sizeof(rq));
397 	rq.utf8_family_name = SANS_UI_FAMILIES;
398 	rq.point_size = 10;
399 	rq.weight = 400;
400 	rq.style = 0;
401 	fi = GDrawInstanciateFont(NULL,&rq);
402 	if ( fi==NULL )
403 	    GDrawFatalError("Cannot find a default font for gadgets");
404     }
405 return( fi );
406 }
407 
localeptsize(void)408 static int localeptsize(void) {
409 /* smaller point size to squeeze these languages in */
410     const char *loc = getenv("LC_ALL");
411     if ( loc==NULL ) loc = getenv("LC_CTYPE");
412     if ( loc==NULL ) loc = getenv("LANG");
413     /* if ( loc==NULL ) loc = getenv("LC_MESSAGES"); */
414 
415     if ( loc!=NULL && ( \
416 		strncmp(loc,"ja",2)==0 || \
417 		strncmp(loc,"zh",2)==0 || \
418 		strncmp(loc,"ko",2)==0) )
419 	return( -16 );
420 
421     return( -10 );
422 }
423 
GGadgetInit(void)424 void GGadgetInit(void) {
425     static GResStruct res[] = {
426 	{ "Font", rt_string, NULL, GResource_font_cvt, 0 },
427 	GRESSTRUCT_EMPTY
428     };
429     if ( !_ggadget_inited ) {
430 	_ggadget_inited = true;
431 	GGadgetSetImagePath(GResourceFindString("GGadget.ImagePath"));
432 	_ggadget_Default_Box.main_background = GDrawGetDefaultBackground(NULL);
433 	_ggadget_Default_Box.main_foreground = GDrawGetDefaultForeground(NULL);
434 	_ggadget_default_font = _GGadgetInitDefaultBox("GGadget.",&_ggadget_Default_Box,NULL);
435 	_GGadgetCopyDefaultBox(&_GListMark_Box);
436 	_GListMark_Box.border_width = _GListMark_Box.padding = 1;
437 	/*_GListMark_Box.flags = 0;*/
438 	_GGadgetInitDefaultBox("GListMark.",&_GListMark_Box,NULL);
439 	_GListMarkSize = GResourceFindInt("GListMark.Width", _GListMarkSize);
440 	_GListMark_Image = GGadgetResourceFindImage("GListMark.Image", NULL);
441 	_GListMark_DisImage = GGadgetResourceFindImage("GListMark.DisabledImage", NULL);
442 	if ( _GListMark_Image!=NULL && _GListMark_Image->image!=NULL ) {
443 	    int size = GDrawPixelsToPoints(NULL,GImageGetWidth(_GListMark_Image->image));
444 	    if ( size>_GListMarkSize )
445 		_GListMarkSize=size;
446 	}
447 	_GGadget_FirstLine = GResourceFindInt("GGadget.FirstLine", _GGadget_FirstLine);
448 	_GGadget_LeftMargin = GResourceFindInt("GGadget.LeftMargin", _GGadget_LeftMargin);
449 	_GGadget_LineSkip = GResourceFindInt("GGadget.LineSkip", _GGadget_LineSkip);
450 	_GGadget_Skip = GResourceFindInt("GGadget.Skip", _GGadget_Skip);
451 	_GGadget_TextImageSkip = GResourceFindInt("GGadget.TextImageSkip", _GGadget_TextImageSkip);
452 
453 	popup_foreground = GResourceFindColor("GGadget.Popup.Foreground",popup_foreground);
454 	popup_background = GResourceFindColor("GGadget.Popup.Background",popup_background);
455 	popup_delay = GResourceFindInt("GGadget.Popup.Delay",popup_delay);
456 	popup_lifetime = GResourceFindInt("GGadget.Popup.LifeTime",popup_lifetime);
457 	res[0].val = &popup_font;
458 	GResourceFind( res, "GGadget.Popup.");
459 	if ( popup_font==NULL ) {
460 	    FontRequest rq;
461 	    memset(&rq,0,sizeof(rq));
462 	    rq.utf8_family_name = SANS_UI_FAMILIES;
463 	    rq.point_size = localeptsize();
464 	    rq.weight = 400;
465 	    rq.style = 0;
466 	    popup_font = GDrawInstanciateFont(NULL,&rq);
467 	    if ( popup_font==NULL )
468 		popup_font = _ggadget_default_font;
469 	}
470     }
471 }
472 
GListMarkDraw(GWindow pixmap,int x,int y,int height,enum gadget_state state)473 void GListMarkDraw(GWindow pixmap,int x, int y, int height, enum gadget_state state ) {
474     GRect r, old;
475     int marklen = GDrawPointsToPixels(pixmap,_GListMarkSize);
476 
477     if ( state == gs_disabled &&
478            _GListMark_DisImage!=NULL && _GListMark_DisImage->image!=NULL) {
479 	GDrawDrawScaledImage(pixmap,_GListMark_DisImage->image,x,
480 		y + (height-GImageGetScaledHeight(pixmap,_GListMark_DisImage->image))/2);
481     } else if ( _GListMark_Image!=NULL && _GListMark_Image->image!=NULL ) {
482 	GDrawDrawScaledImage(pixmap,_GListMark_Image->image,x,
483 		y + (height-GImageGetScaledHeight(pixmap,_GListMark_Image->image))/2);
484     } else {
485 	r.x = x; r.width = marklen;
486 	r.height = 2*GDrawPointsToPixels(pixmap,_GListMark_Box.border_width) +
487 		    GDrawPointsToPixels(pixmap,3);
488 	r.y = y + (height-r.height)/2;
489 	GDrawPushClip(pixmap,&r,&old);
490 
491 	GBoxDrawBackground(pixmap,&r,&_GListMark_Box, state,false);
492 	GBoxDrawBorder(pixmap,&r,&_GListMark_Box,state,false);
493 	GDrawPopClip(pixmap,&old);
494     }
495 }
496 
497 static struct popup_info {
498     const unichar_t *msg;
499     GImage *img;
500     const void *data;
501     GImage *(*get_image)(const void *data);
502     void (*free_image)(const void *data,GImage *img);
503     GWindow gw;
504 } popup_info;
505 
GGadgetEndPopup()506 void GGadgetEndPopup() {
507     if ( popup_visible ) {
508 	GDrawSetVisible(popup,false);
509 	popup_visible = false;
510     }
511     if ( popup_timer!=NULL ) {
512 	GDrawCancelTimer(popup_timer);
513 	popup_timer = NULL;
514     }
515     if ( popup_vanish_timer!=NULL ) {
516 	GDrawCancelTimer(popup_vanish_timer);
517 	popup_vanish_timer = NULL;
518     }
519     if ( popup_info.img!=NULL ) {
520 	if ( popup_info.free_image!=NULL )
521 	    (popup_info.free_image)(popup_info.data,popup_info.img);
522 	else
523 	    GImageDestroy(popup_info.img);
524     }
525 
526     memset(&popup_info,0,sizeof(popup_info));
527 }
528 
GGadgetPopupExternalEvent(GEvent * e)529 void GGadgetPopupExternalEvent(GEvent *e) {
530     /* Depress control key to keep popup alive */
531     if ( e->type == et_char &&
532 	    ( e->u.chr.keysym == GK_Control_L || e->u.chr.keysym == GK_Control_R )) {
533 	if ( popup_vanish_timer!=NULL ) {
534 	    GDrawCancelTimer(popup_vanish_timer);
535 	    popup_vanish_timer = NULL;
536 	}
537 return;
538     }
539     if ( e->type==et_char || e->type==et_charup || e->type==et_mousemove ||
540 	    e->type == et_mousedown || e->type==et_mouseup ||
541 	    e->type==et_destroy || (e->type==et_create && popup!=e->w))
542 	GGadgetEndPopup();
543 }
544 
GGadgetPopupTest(GEvent * e)545 static int GGadgetPopupTest(GEvent *e) {
546     unichar_t *msg;
547     int lines, temp, width;
548     GWindow root = GDrawGetRoot(GDrawGetDisplayOfWindow(popup));
549     GRect pos, size;
550     unichar_t *pt, *ept;
551     int as, ds, ld, img_height=0;
552     GEvent where;
553 
554     if ( e->type!=et_timer || e->u.timer.timer!=popup_timer || popup==NULL )
555 return( false );
556     popup_timer = NULL;
557 
558     /* Is the cursor still in the original window? */
559     if (!GDrawWindowIsAncestor(popup_info.gw, GDrawGetPointerWindow(popup_info.gw)))
560         return true;
561 
562     lines = 0; width = 1;
563     if ( popup_info.img==NULL && popup_info.get_image!=NULL ) {
564 	popup_info.img = (popup_info.get_image)(popup_info.data);
565 	popup_info.get_image = NULL;
566     }
567     if ( popup_info.img!=NULL ) {
568 	img_height = GImageGetHeight(popup_info.img);
569 	width = GImageGetWidth(popup_info.img);
570     }
571     pt = msg = (unichar_t *) popup_info.msg;
572     if ( msg!=NULL ) {
573 	GDrawSetFont(popup,popup_font);
574 	do {
575 	    temp = -1;
576 	    if (( ept = u_strchr(pt,'\n'))!=NULL )
577 		temp = ept-pt;
578 	    temp = GDrawGetTextWidth(popup,pt,temp);
579 	    if ( temp>width ) width = temp;
580 	    ++lines;
581 	    pt = ept+1;
582 	} while ( ept!=NULL && *pt!='\0' );
583     }
584     GDrawWindowFontMetrics(popup,popup_font,&as, &ds, &ld);
585     pos.width = width+2*GDrawPointsToPixels(popup,2);
586     pos.height = lines*(as+ds) + img_height + 2*GDrawPointsToPixels(popup,2);
587 
588     GDrawGetPointerPosition(root,&where);
589     pos.x = where.u.mouse.x+10; pos.y = where.u.mouse.y+10;
590     GDrawGetSize(root,&size);
591     if ( pos.x + pos.width > size.width )
592 	pos.x = (pos.x - 20 - pos.width );
593     if ( pos.x<0 ) pos.x = 0;
594     if ( pos.y + pos.height > size.height )
595 	pos.y = (pos.y - 20 - pos.height );
596     if ( pos.y<0 ) pos.y = 0;
597     GDrawMoveResize(popup,pos.x,pos.y,pos.width,pos.height);
598     GDrawSetVisible(popup,true);
599     GDrawRaise(popup);
600     GDrawSetUserData(popup,msg);
601     popup_vanish_timer = GDrawRequestTimer(popup,popup_lifetime,0,NULL);
602 return( true );
603 }
604 
msgpopup_eh(GWindow popup,GEvent * event)605 static int msgpopup_eh(GWindow popup,GEvent *event) {
606     if ( event->type == et_expose ) {
607 	unichar_t *msg, *pt, *ept;
608 	int x,y, fh, temp;
609 	int as, ds, ld;
610 
611 	popup_visible = true;
612 	pt = msg = (unichar_t *) popup_info.msg;
613 	if ( (pt==NULL || *pt=='\0') && popup_info.img==NULL ) {
614 	    GGadgetEndPopup();
615 return( true );
616 	}
617 	y = x = GDrawPointsToPixels(popup,2);
618 	if ( popup_info.img!=NULL ) {
619 	    GDrawDrawImage(popup,popup_info.img,NULL,x,y);
620 	    y += GImageGetHeight(popup_info.img);
621 	}
622 	if ( pt!=NULL ) {
623 	    GDrawWindowFontMetrics(popup,popup_font,&as, &ds, &ld);
624 	    fh = as+ds;
625 	    y += as;
626 	    while ( *pt!='\0' ) {
627                 /* Find end of this line, if multiline text */
628 		if (( ept = u_strchr(pt,'\n'))!=NULL )
629 		    temp = ept-pt;  /* display next segment of multiline text */
630                 else
631                     temp = -1;     /* last line, so display remainder of text */
632 		GDrawDrawText(popup,x,y,pt,temp,popup_foreground);
633 		y += fh;
634 		pt = ept+1;
635                 if ( ept==NULL )
636                     break;
637 	    }
638 	}
639     } else if ( event->type == et_timer && event->u.timer.timer==popup_timer ) {
640 	GGadgetPopupTest(event);
641     } else if ( event->type == et_mousemove || event->type == et_mouseup ||
642 	    event->type == et_mousedown || event->type == et_char ||
643 	    event->type == et_timer || event->type == et_crossing ) {
644 	GGadgetEndPopup();
645     }
646 return( true );
647 }
648 
GGadgetPreparePopupImage(GWindow base,const unichar_t * msg,const void * data,GImage * (* get_image)(const void * data),void (* free_image)(const void * data,GImage * img))649 void GGadgetPreparePopupImage(GWindow base,const unichar_t *msg, const void *data,
650 	GImage *(*get_image)(const void *data),
651 	void (*free_image)(const void *data,GImage *img)) {
652 
653     GGadgetEndPopup();
654     if ( msg==NULL && get_image==NULL )
655 return;
656 
657     memset(&popup_info,0,sizeof(popup_info));
658     popup_info.msg = msg;
659     popup_info.data = data;
660     popup_info.get_image = get_image;
661     popup_info.free_image = free_image;
662     popup_info.gw = base;
663 
664     if ( popup==NULL ) {
665 	GWindowAttrs pattrs;
666 	GRect pos;
667 
668 	pattrs.mask = wam_events|wam_nodecor|wam_positioned|wam_cursor|wam_backcol/*|wam_transient*/;
669 	pattrs.event_masks = -1;
670 	pattrs.nodecoration = true;
671 	pattrs.positioned = true;
672 	pattrs.cursor = ct_pointer;
673 	pattrs.background_color = popup_background;
674 	/*pattrs.transient = GWidgetGetTopWidget(base);*/
675 	pos.x = pos.y = 0; pos.width = pos.height = 1;
676 	popup = GDrawCreateTopWindow(GDrawGetDisplayOfWindow(base),&pos,
677 		msgpopup_eh,NULL,&pattrs);
678 	GDrawSetFont(popup,popup_font);
679     }
680     popup_timer = GDrawRequestTimer(popup,popup_delay,0,(void *) msg);
681 }
682 
popup_refresh(void)683 static void popup_refresh(void) {
684     if ( popup!=NULL ) {
685 	GDrawSetWindowBackground(popup,popup_background);
686     }
687 }
688 
GGadgetPreparePopup(GWindow base,const unichar_t * msg)689 void GGadgetPreparePopup(GWindow base,const unichar_t *msg) {
690     GGadgetPreparePopupImage(base,msg,NULL,NULL,NULL);
691 }
692 
GGadgetPreparePopupR(GWindow base,int msg)693 void GGadgetPreparePopupR(GWindow base,int msg) {
694     GGadgetPreparePopupImage(base,GStringGetResource(msg,NULL),NULL,NULL,NULL);
695 }
696 
GGadgetPreparePopup8(GWindow base,const char * msg)697 void GGadgetPreparePopup8(GWindow base, const char *msg) {
698     static unichar_t popup_msg[500];
699     utf82u_strncpy(popup_msg,msg,sizeof(popup_msg)/sizeof(popup_msg[0]));
700     popup_msg[sizeof(popup_msg)/sizeof(popup_msg[0])-1]=0;
701     GGadgetPreparePopupImage(base,popup_msg,NULL,NULL,NULL);
702 }
703 
_ggadget_redraw(GGadget * g)704 void _ggadget_redraw(GGadget *g) {
705     GDrawRequestExpose(g->base, &g->r, false);
706 }
707 
_ggadget_noop(GGadget * g,GEvent * event)708 int _ggadget_noop(GGadget *g, GEvent *event) {
709 return( false );
710 }
711 
GBoxFigureRect(GWindow gw,GBox * design,GRect * r,int isdef)712 static void GBoxFigureRect(GWindow gw, GBox *design, GRect *r, int isdef) {
713     int scale = GDrawPointsToPixels(gw,1);
714     int bp = GDrawPointsToPixels(gw,design->border_width)+
715 	     GDrawPointsToPixels(gw,design->padding)+
716 	     ((design->flags & box_foreground_border_outer)?scale:0)+
717 	     ((design->flags &
718 		 (box_foreground_border_inner|box_active_border_inner))?scale:0)+
719 	     (isdef && (design->flags & box_draw_default)?scale+GDrawPointsToPixels(gw,2):0);
720     r->width += 2*bp;
721     r->height += 2*bp;
722 }
723 
GBoxFigureDiamond(GWindow gw,GBox * design,GRect * r,int isdef)724 static void GBoxFigureDiamond(GWindow gw, GBox *design, GRect *r, int isdef) {
725     int scale = GDrawPointsToPixels(gw,1);
726     int p = GDrawPointsToPixels(gw,design->padding);
727     int b = GDrawPointsToPixels(gw,design->border_width)+
728 	     ((design->flags & box_foreground_border_outer)?scale:0)+
729 	     ((design->flags &
730 		 (box_foreground_border_inner|box_active_border_inner))?scale:0)+
731 	     (isdef && (design->flags & box_draw_default)?scale+GDrawPointsToPixels(gw,2):0);
732     int xoff = r->width/2, yoff = r->height/2;
733 
734     if ( xoff<2*p ) xoff = 2*p;
735     if ( yoff<2*p ) yoff = 2*p;
736      r->width += 2*b+xoff;
737      r->height += 2*b+yoff;
738 }
739 
_ggadgetFigureSize(GWindow gw,GBox * design,GRect * r,int isdef)740 void _ggadgetFigureSize(GWindow gw, GBox *design, GRect *r, int isdef) {
741     /* given that we want something with a client rectangle as big as r */
742     /*  Then given the box shape, figure out how much of a rectangle we */
743     /*  need around it */
744 
745     if ( r->width<=0 ) r->width = 1;
746     if ( r->height<=0 ) r->height = 1;
747 
748     switch ( design->border_shape ) {
749       case bs_rect:
750 	GBoxFigureRect(gw,design,r,isdef);
751       break;
752       case bs_roundrect:
753 	GBoxFigureRect(gw,design,r,isdef);
754       break;
755       case bs_elipse:
756 	GBoxFigureDiamond(gw,design,r,isdef);
757       break;
758       case bs_diamond:
759 	GBoxFigureDiamond(gw,design,r,isdef);
760       break;
761     }
762 }
763 
_ggadgetSetRects(GGadget * g,GRect * outer,GRect * inner,int xjust,int yjust)764 void _ggadgetSetRects(GGadget *g, GRect *outer, GRect *inner, int xjust, int yjust) {
765     int bp = GBoxBorderWidth(g->base,g->box);
766 
767 
768     if ( g->r.width==0 )
769 	g->r.width = outer->width;
770     if ( g->r.height==0 )
771 	g->r.height = outer->height;
772 
773     if ( g->inner.width==0 ) {
774 	if ( inner->width<g->r.width ) {
775 	    g->inner.width = g->r.width - 2*bp;
776 	    if ( xjust==-1 )
777 		g->inner.x = g->r.x + bp;
778 	    else if ( xjust==0 ) {
779 		g->inner.x = g->r.x + (g->r.width-inner->width)/2;
780 		g->inner.width = inner->width;
781 	    } else
782 		g->inner.x = g->r.x + (g->r.width-bp-g->inner.width);
783 	} else {
784 	    g->inner.x = g->r.x;
785 	    g->inner.width = g->r.width;
786 	}
787     }
788     if ( g->inner.height==0 ) {
789 	if ( inner->height<g->r.height ) {
790 	    if ( yjust==-1 )
791 		g->inner.y = g->r.y + bp;
792 	    else if ( yjust==0 )
793 		g->inner.y = g->r.y + (g->r.height-inner->height)/2;
794 	    else
795 		g->inner.y = g->r.y + (g->r.height-bp-inner->height);
796 	    g->inner.height = inner->height;
797 	} else {
798 	    g->inner.y = g->r.y;
799 	    g->inner.height = g->r.height;
800 	}
801     }
802 }
803 
GGadgetFindLastOpenGroup(GGadget * g)804 static GGadget *GGadgetFindLastOpenGroup(GGadget *g) {
805     for ( g=g->prev; g!=NULL && !g->opengroup; g = g->prev );
806 return( g );
807 }
808 
GGadgetLMargin(GGadget * sigh,GGadget * lastOpenGroup)809 static int GGadgetLMargin(GGadget *sigh, GGadget *lastOpenGroup) {
810     if ( lastOpenGroup==NULL )
811 return( GDrawPointsToPixels(sigh->base,_GGadget_LeftMargin));
812     else
813 return( lastOpenGroup->r.x + GDrawPointsToPixels(lastOpenGroup->base,_GGadget_Skip));
814 }
815 
GGadgetScale(int xpos)816 int GGadgetScale(int xpos) {
817 return( xpos*GIntGetResource(_NUM_ScaleFactor)/100 );
818 }
819 
_GGadget_Create(GGadget * g,struct gwindow * base,GGadgetData * gd,void * data,GBox * def)820 GGadget *_GGadget_Create(GGadget *g, struct gwindow *base, GGadgetData *gd,void *data, GBox *def) {
821     GGadget *last, *lastopengroup;
822 
823     g->desired_width = g->desired_height = -1;
824     _GWidget_AddGGadget(base,g);
825     g->r = gd->pos;
826     if ( !(gd->flags&gg_pos_in_pixels) ) {
827 	g->r.x = GDrawPointsToPixels(base,g->r.x);
828 	g->r.y = GDrawPointsToPixels(base,g->r.y);
829 	if ( g->r.width!=-1 )
830 	    g->r.width = GDrawPointsToPixels(base,g->r.width);
831 	if ( !(gd->flags&gg_pos_use0)) {
832 	    g->r.x = GGadgetScale(g->r.x);
833 	    if ( g->r.width!=-1 )
834 		g->r.width = GGadgetScale(g->r.width);
835 	}
836 	g->r.height = GDrawPointsToPixels(base,g->r.height);
837     }
838     if ( gd->pos.width>0 ) g->desired_width = g->r.width;
839     if ( gd->pos.height>0 ) g->desired_height = g->r.height;
840     last = g->prev;
841     lastopengroup = GGadgetFindLastOpenGroup(g);
842     if ( g->r.y==0 && !(gd->flags & gg_pos_use0)) {
843 	if ( last==NULL ) {
844 	    g->r.y = GDrawPointsToPixels(base,_GGadget_FirstLine);
845 	    if ( g->r.x==0 )
846 		g->r.x = GGadgetLMargin(g,lastopengroup);
847 	} else if ( gd->flags & gg_pos_newline ) {
848 	    int temp, y = last->r.y, nexty = last->r.y+last->r.height;
849 	    while ( last!=NULL && last->r.y==y ) {
850 		temp = last->r.y+last->r.height;
851 		if ( temp>nexty ) nexty = temp;
852 		last = last->prev;
853 	    }
854 	    g->r.y = nexty + GDrawPointsToPixels(base,_GGadget_LineSkip);
855 	    if ( g->r.x==0 )
856 		g->r.x = GGadgetLMargin(g,lastopengroup);
857 	} else {
858 	    g->r.y = last->r.y;
859 	}
860     }
861     if ( g->r.x == 0 && !(gd->flags & gg_pos_use0)) {
862 	last = g->prev;
863 	if ( last==NULL )
864 	    g->r.x = GGadgetLMargin(g,lastopengroup);
865 	else if ( gd->flags & gg_pos_under ) {
866 	    int onthisline=0, onprev=0, i;
867 	    GGadget *prev, *prevline;
868 	    /* see if we can find a gadget on the previous line that has the */
869 	    /*  same number of gadgets between it and the start of the line  */
870 	    /*  as this one has from the start of its line, then put at the  */
871 	    /*  same x offset */
872 	    for ( prev = last; prev!=NULL && prev->r.y==g->r.y; prev = prev->prev )
873 		++onthisline;
874 	    prevline = prev;
875 	    for ( ; prev!=NULL && prev->r.y==prevline->r.y ; prev = prev->prev )
876 		onprev++;
877 	    for ( prev = prevline, i=0; prev!=NULL && i<onprev-onthisline; prev = prev->prev);
878 	    if ( prev!=NULL )
879 		g->r.x = prev->r.x;
880 	}
881 	if ( g->r.x==0 )
882 	    g->r.x = last->r.x + last->r.width + GDrawPointsToPixels(base,_GGadget_Skip);
883     }
884 
885     g->mnemonic = islower(gd->mnemonic)?toupper(gd->mnemonic):gd->mnemonic;
886     g->shortcut = islower(gd->shortcut)?toupper(gd->shortcut):gd->shortcut;
887     g->short_mask = gd->short_mask;
888     g->cid = gd->cid;
889     g->data = data;
890     g->popup_msg = utf82u_copy(gd->popup_msg);
891     g->handle_controlevent = gd->handle_controlevent;
892     if ( gd->box == NULL )
893 	g->box = def;
894     else if ( gd->flags & gg_dontcopybox )
895 	g->box = gd->box;
896     else {
897 	g->free_box = true;
898 	g->box = malloc(sizeof(GBox));
899 	*g->box = *gd->box;
900     }
901     g->state = !(gd->flags&gg_visible) ? gs_invisible :
902 		  !(gd->flags&gg_enabled) ? gs_disabled :
903 		  gs_enabled;
904     if ( !(gd->flags&gg_enabled) ) g->was_disabled = true;
905 return( g );
906 }
907 
_GGadget_FinalPosition(GGadget * g,struct gwindow * base,GGadgetData * gd)908 void _GGadget_FinalPosition(GGadget *g, struct gwindow *base, GGadgetData *gd) {
909     if ( g->r.x<0 && !(gd->flags&gg_pos_use0)) {
910 	GRect size;
911 	GDrawGetSize(base,&size);
912 	g->r.x += size.width-g->r.width;
913 	g->inner.x += size.width-g->r.width;
914     }
915 }
916 
_ggadget_destroy(GGadget * g)917 void _ggadget_destroy(GGadget *g) {
918     if ( g==NULL )
919 return;
920     _GWidget_RemoveGadget(g);
921     GGadgetEndPopup();
922     if ( g->free_box )
923 	free( g->box );
924     free(g->popup_msg);
925     free(g);
926 }
927 
_GGadgetCloseGroup(GGadget * g)928 void _GGadgetCloseGroup(GGadget *g) {
929     GGadget *group = GGadgetFindLastOpenGroup(g);
930     GGadget *prev;
931     int maxx=0, maxy=0, temp;
932     int bp = GBoxBorderWidth(g->base,g->box);
933 
934     if ( group==NULL )
935 return;
936     for ( prev=g ; prev!=group; prev = prev->prev ) {
937 	temp = prev->r.x + prev->r.width;
938 	if ( temp>maxx ) maxx = temp;
939 	temp = prev->r.y + prev->r.height;
940 	if ( temp>maxy ) maxy = temp;
941     }
942     if ( group->prevlabel ) {
943 	prev = group->prev;
944 	temp = prev->r.x + prev->r.width;
945 	if ( temp>maxx ) maxx = temp;
946 	temp = prev->r.y + prev->r.height/2 ;
947 	if ( temp>maxy ) maxy = temp;
948     }
949     maxx += GDrawPointsToPixels(g->base,_GGadget_Skip);
950     maxy += GDrawPointsToPixels(g->base,_GGadget_LineSkip);
951 
952     if ( group->r.width==0 ) {
953 	group->r.width = maxx - group->r.x;
954 	group->inner.width = group->r.width - 2*bp;
955     }
956     if ( group->r.height==0 ) {
957 	group->r.height = maxy - group->r.y;
958 	group->inner.height = group->r.y + group->r.height - bp -
959 		group->inner.y;
960     }
961     group->opengroup = false;
962 }
963 
GGadgetWithin(GGadget * g,int x,int y)964 int GGadgetWithin(GGadget *g, int x, int y) {
965     register GRect *r = &g->r;
966 
967     if ( x<r->x || y<r->y || x>=r->x+r->width || y>=r->y+r->height )
968 return( false );
969 
970 return( true );
971 }
972 
GGadgetInnerWithin(GGadget * g,int x,int y)973 int GGadgetInnerWithin(GGadget *g, int x, int y) {
974     register GRect *r = &g->inner;
975 
976     if ( x<r->x || y<r->y || x>=r->x+r->width || y>=r->y+r->height )
977 return( false );
978 
979 return( true );
980 }
981 
_ggadget_underlineMnemonic(GWindow gw,int32 x,int32 y,unichar_t * label,unichar_t mnemonic,Color fg,int maxy)982 void _ggadget_underlineMnemonic(GWindow gw,int32 x,int32 y,unichar_t *label,
983 	unichar_t mnemonic, Color fg, int maxy) {
984     int point = GDrawPointsToPixels(gw,1);
985     int width;
986     /*GRect clip;*/
987 
988     if ( mnemonic=='\0' )
989 return;
990     char *ctext = u2utf8_copy(label);
991     char *cpt = utf8_strchr(ctext,mnemonic);
992     GRect space;
993     if ( cpt==NULL && isupper(mnemonic))
994 	cpt = strchr(ctext,tolower(mnemonic));
995     if ( cpt==NULL )
996 return;
997     GDrawLayoutInit(gw,ctext,-1,NULL);
998     GDrawLayoutIndexToPos(gw, cpt-ctext, &space);
999     free(ctext);
1000     x += space.x;
1001     width = space.width;
1002     GDrawSetLineWidth(gw,point);
1003     y += 2*point;
1004     if ( y+point-1 >= maxy )
1005 	y = maxy-point;
1006     GDrawDrawLine(gw,x,y,x+width,y,fg);
1007     GDrawSetLineWidth(gw,0);
1008 }
1009 
_ggadget_move(GGadget * g,int32 x,int32 y)1010 void _ggadget_move(GGadget *g, int32 x, int32 y ) {
1011     g->inner.x = x+(g->inner.x-g->r.x);
1012     g->inner.y = y+(g->inner.y-g->r.y);
1013     g->r.x = x;
1014     g->r.y = y;
1015 }
1016 
_ggadget_resize(GGadget * g,int32 width,int32 height)1017 void _ggadget_resize(GGadget *g, int32 width, int32 height ) {
1018     g->inner.width = width-(g->r.width-g->inner.width);
1019     g->inner.height = height-(g->r.height-g->inner.height);
1020     g->r.width = width;
1021     g->r.height = height;
1022 }
1023 
_ggadget_getDesiredSize(GGadget * g,GRect * outer,GRect * inner)1024 void _ggadget_getDesiredSize(GGadget *g, GRect *outer, GRect *inner) {
1025 
1026     if ( inner!=NULL ) {
1027 	inner->x = inner->y = 0;
1028 	inner->width = g->desired_width;
1029 	inner->height = g->desired_height;
1030     }
1031     if ( outer!=NULL ) {
1032 	outer->x = outer->y = 0;
1033 	outer->width = g->desired_width;
1034 	outer->height = g->desired_height;
1035     }
1036 }
1037 
_ggadget_setDesiredSize(GGadget * g,GRect * outer,GRect * inner)1038 void _ggadget_setDesiredSize(GGadget *g,GRect *outer, GRect *inner) {
1039     int bp = GBoxBorderWidth(g->base,g->box);
1040 
1041     if ( outer!=NULL ) {
1042 	g->desired_width = outer->width;
1043 	g->desired_height = outer->height;
1044     } else if ( inner!=NULL ) {
1045 	g->desired_width = inner->width<=0 ? -1 : inner->width+2*bp;
1046 	g->desired_height = inner->height<=0 ? -1 : inner->height+2*bp;
1047     }
1048 }
1049 
_ggadget_getsize(GGadget * g,GRect * rct)1050 GRect *_ggadget_getsize(GGadget *g,GRect *rct) {
1051     *rct = g->r;
1052 return( rct );
1053 }
1054 
_ggadget_getinnersize(GGadget * g,GRect * rct)1055 GRect *_ggadget_getinnersize(GGadget *g,GRect *rct) {
1056     *rct = g->inner;
1057 return( rct );
1058 }
1059 
_ggadget_setvisible(GGadget * g,int visible)1060 void _ggadget_setvisible(GGadget *g,int visible) {
1061     g->state = !visible ? gs_invisible :
1062 		g->was_disabled ? gs_disabled :
1063 		gs_enabled;
1064     /* Make sure it isn't the focused _ggadget in the container !!!! */
1065     _ggadget_redraw(g);
1066 }
1067 
_ggadget_setenabled(GGadget * g,int enabled)1068 void _ggadget_setenabled(GGadget *g,int enabled) {
1069     g->was_disabled = !enabled;
1070     if ( g->state!=gs_invisible ) {
1071 	g->state = enabled? gs_enabled : gs_disabled;
1072 	_ggadget_redraw(g);
1073     }
1074     /* Make sure it isn't the focused _ggadget in the container !!!! */
1075 }
1076 
GGadgetDestroy(GGadget * g)1077 void GGadgetDestroy(GGadget *g) {
1078     (g->funcs->destroy)(g);
1079 }
1080 
GGadgetRedraw(GGadget * g)1081 void GGadgetRedraw(GGadget *g) {
1082     (g->funcs->redraw)(g);
1083 }
1084 
GGadgetMove(GGadget * g,int32 x,int32 y)1085 void GGadgetMove(GGadget *g,int32 x, int32 y ) {
1086     (g->funcs->move)(g,x,y);
1087 }
1088 
GGadgetMoveAddToY(GGadget * g,int32 yoffset)1089 void GGadgetMoveAddToY(GGadget *g, int32 yoffset )
1090 {
1091     GRect sz;
1092     GGadgetGetSize( g, &sz );
1093     GGadgetMove( g, sz.x, sz.y + yoffset );
1094 }
1095 
1096 
1097 
GGadgetGetX(GGadget * g)1098 int32 GGadgetGetX(GGadget *g)
1099 {
1100     return g->r.x;
1101 }
1102 
GGadgetGetY(GGadget * g)1103 int32 GGadgetGetY(GGadget *g)
1104 {
1105     return g->r.y;
1106 }
1107 
GGadgetSetY(GGadget * g,int32 y)1108 void  GGadgetSetY(GGadget *g, int32 y )
1109 {
1110     int32 x = GGadgetGetX(g);
1111     GGadgetMove( g, x, y );
1112 }
1113 
1114 
1115 
GGadgetResize(GGadget * g,int32 width,int32 height)1116 void GGadgetResize(GGadget *g,int32 width, int32 height ) {
1117     (g->funcs->resize)(g,width,height);
1118 }
1119 
GGadgetGetSize(GGadget * g,GRect * rct)1120 GRect *GGadgetGetSize(GGadget *g,GRect *rct) {
1121 return( (g->funcs->getsize)(g,rct) );
1122 }
1123 
GGadgetSetSize(GGadget * g,GRect * rct)1124 void GGadgetSetSize(GGadget *g,GRect *rct)
1125 {
1126     GGadgetResize(g,rct->width,rct->height);
1127 }
1128 
1129 
GGadgetContainsEventLocation(GGadget * g,GEvent * e)1130 int GGadgetContainsEventLocation(GGadget *g, GEvent* e )
1131 {
1132     switch( e->type )
1133     {
1134         case et_mousemove:
1135         case et_mouseup: case et_mousedown:
1136             return( GGadgetContains( g, e->u.mouse.x, e->u.mouse.y ));
1137     }
1138 
1139     return 0;
1140 }
1141 
GGadgetContains(GGadget * g,int x,int y)1142 int GGadgetContains(GGadget *g, int x, int y )
1143 {
1144     GRect r;
1145     GGadgetGetSize( g, &r );
1146     return r.x < x && r.x+r.width > x
1147         && r.y < y && r.y+r.height > y;
1148 }
1149 
GGadgetGetInnerSize(GGadget * g,GRect * rct)1150 GRect *GGadgetGetInnerSize(GGadget *g,GRect *rct) {
1151 return( (g->funcs->getinnersize)(g,rct) );
1152 }
1153 
GGadgetSetVisible(GGadget * g,int visible)1154 void GGadgetSetVisible(GGadget *g,int visible) {
1155     (g->funcs->setvisible)(g,visible);
1156 }
1157 
GGadgetIsVisible(GGadget * g)1158 int GGadgetIsVisible(GGadget *g) {
1159 return( g->state!=gs_invisible );
1160 }
1161 
GGadgetSetEnabled(GGadget * g,int enabled)1162 void GGadgetSetEnabled(GGadget *g,int enabled) {
1163     if(g)
1164 	(g->funcs->setenabled)(g,enabled);
1165 }
1166 
GGadgetIsEnabled(GGadget * g)1167 int GGadgetIsEnabled(GGadget *g) {
1168     if ( g->state==gs_invisible )
1169 return( !g->was_disabled );
1170 return( g->state==gs_enabled );
1171 }
1172 
GGadgetSetUserData(GGadget * g,void * data)1173 void GGadgetSetUserData(GGadget *g,void *data) {
1174     g->data = data;
1175 }
1176 
GGadgetSetPopupMsg(GGadget * g,const unichar_t * msg)1177 void GGadgetSetPopupMsg(GGadget *g,const unichar_t *msg) {
1178     free(g->popup_msg);
1179     g->popup_msg = u_copy(msg);
1180 }
1181 
GGadgetGetWindow(GGadget * g)1182 GWindow GGadgetGetWindow(GGadget *g) {
1183 return( g->base );
1184 }
1185 
GGadgetGetCid(GGadget * g)1186 int GGadgetGetCid(GGadget *g) {
1187 return( g->cid );
1188 }
1189 
GGadgetGetUserData(GGadget * g)1190 void *GGadgetGetUserData(GGadget *g) {
1191 return( g->data );
1192 }
1193 
GGadgetEditCmd(GGadget * g,enum editor_commands cmd)1194 int GGadgetEditCmd(GGadget *g,enum editor_commands cmd) {
1195     if ( g->funcs->handle_editcmd!=NULL )
1196 return(g->funcs->handle_editcmd)(g,cmd);
1197 return( false );
1198 }
1199 
GGadgetSetTitle(GGadget * g,const unichar_t * title)1200 void GGadgetSetTitle(GGadget *g,const unichar_t *title) {
1201     if ( g->funcs->set_title!=NULL )
1202 	(g->funcs->set_title)(g,title);
1203 }
1204 
GGadgetSetTitle8(GGadget * g,const char * title)1205 void GGadgetSetTitle8(GGadget *g,const char *title) {
1206     if ( g->funcs->set_title!=NULL ) {
1207 	unichar_t *temp = utf82u_copy(title);
1208 	(g->funcs->set_title)(g,temp);
1209 	free(temp);
1210     }
1211 }
1212 
GGadgetSetTitle8WithMn(GGadget * g,const char * title)1213 void GGadgetSetTitle8WithMn(GGadget *g,const char *title) {
1214     char *pt = strchr(title,'_');
1215     char *freeme=NULL;
1216     int mnc;
1217 
1218     if ( pt!=NULL ) {
1219 	char *pos = pt+1;
1220 	mnc = utf8_ildb((const char **) &pos);
1221 	g->mnemonic = mnc;
1222 	freeme = copy(title);
1223 	for ( pt = freeme + (pt-title); *pt; ++pt )
1224 	    *pt = pt[1];
1225 	title = freeme;
1226     } else
1227 	g->mnemonic = 0;
1228     GGadgetSetTitle8(g,title);
1229     free(freeme);
1230 }
1231 
_GGadgetGetTitle(GGadget * g)1232 const unichar_t *_GGadgetGetTitle(GGadget *g) {
1233     if ( g && g->funcs->_get_title!=NULL ) return( (g->funcs->_get_title)(g) );
1234 
1235     return( NULL );
1236 }
1237 
GGadgetGetTitle(GGadget * g)1238 unichar_t *GGadgetGetTitle(GGadget *g) {
1239     if ( g ) {
1240 	if ( g->funcs->get_title!=NULL )
1241 	    return( (g->funcs->get_title)(g) );
1242 	else if ( g->funcs->_get_title!=NULL )
1243 	    return( u_copy( (g->funcs->_get_title)(g) ));
1244     }
1245 
1246     return( NULL );
1247 }
1248 
GGadgetGetTitle8(GGadget * g)1249 char *GGadgetGetTitle8(GGadget *g) {
1250     if ( g->funcs->_get_title!=NULL )
1251 return( u2utf8_copy( (g->funcs->_get_title)(g) ));
1252     else if ( g->funcs->get_title!=NULL ) {
1253 	unichar_t *temp = (g->funcs->get_title)(g);
1254 	char *ret = u2utf8_copy(temp);
1255 	free(temp);
1256 return( ret );
1257     }
1258 
1259 return( NULL );
1260 }
1261 
GGadgetSetFont(GGadget * g,GFont * font)1262 void GGadgetSetFont(GGadget *g,GFont *font) {
1263     if ( g->funcs->set_font!=NULL )
1264 	(g->funcs->set_font)(g,font);
1265 }
1266 
GGadgetGetFont(GGadget * g)1267 GFont *GGadgetGetFont(GGadget *g) {
1268     if ( g==NULL )
1269 return( _ggadget_default_font );
1270     if ( g->funcs->get_font!=NULL )
1271 return( (g->funcs->get_font)(g) );
1272 
1273 return( NULL );
1274 }
1275 
GGadgetSetHandler(GGadget * g,GGadgetHandler handler)1276 void GGadgetSetHandler(GGadget *g, GGadgetHandler handler) {
1277     g->handle_controlevent = handler;
1278 }
1279 
GGadgetGetHandler(GGadget * g)1280 GGadgetHandler GGadgetGetHandler(GGadget *g) {
1281 return( g->handle_controlevent );
1282 }
1283 
GGadgetClearList(GGadget * g)1284 void GGadgetClearList(GGadget *g) {
1285     if ( g->funcs->clear_list!=NULL )
1286 	(g->funcs->clear_list)(g);
1287 }
1288 
GGadgetSetList(GGadget * g,GTextInfo ** ti,int32 copyit)1289 void GGadgetSetList(GGadget *g, GTextInfo **ti, int32 copyit) {
1290     if ( g->funcs->set_list!=NULL )
1291 	(g->funcs->set_list)(g,ti,copyit);
1292 }
1293 
GGadgetGetList(GGadget * g,int32 * len)1294 GTextInfo **GGadgetGetList(GGadget *g,int32 *len) {
1295     if ( g->funcs->get_list!=NULL )
1296 return((g->funcs->get_list)(g,len));
1297 
1298     if ( len!=NULL ) *len = 0;
1299 return( NULL );
1300 }
1301 
GGadgetGetListItem(GGadget * g,int32 pos)1302 GTextInfo *GGadgetGetListItem(GGadget *g,int32 pos) {
1303     if ( g->funcs->get_list_item!=NULL )
1304 return((g->funcs->get_list_item)(g,pos));
1305 
1306 return( NULL );
1307 }
1308 
GGadgetGetListItemSelected(GGadget * g)1309 GTextInfo *GGadgetGetListItemSelected(GGadget *g) {
1310     int pos = GGadgetGetFirstListSelectedItem(g);
1311 
1312     if ( pos!=-1 && g->funcs->get_list_item!=NULL )
1313 return((g->funcs->get_list_item)(g,pos));
1314 
1315 return( NULL );
1316 }
1317 
GGadgetSelectListItem(GGadget * g,int32 pos,int32 sel)1318 void GGadgetSelectListItem(GGadget *g,int32 pos,int32 sel) {
1319     if ( g->funcs->select_list_item!=NULL )
1320 	(g->funcs->select_list_item)(g,pos,sel);
1321 }
1322 
GGadgetSelectOneListItem(GGadget * g,int32 pos)1323 void GGadgetSelectOneListItem(GGadget *g,int32 pos) {
1324     if ( g->funcs->select_one_list_item!=NULL )
1325 	(g->funcs->select_one_list_item)(g,pos);
1326 }
1327 
GGadgetIsListItemSelected(GGadget * g,int32 pos)1328 int32 GGadgetIsListItemSelected(GGadget *g,int32 pos) {
1329     if ( g->funcs->is_list_item_selected!=NULL )
1330 return((g->funcs->is_list_item_selected)(g,pos));
1331 
1332 return( 0 );
1333 }
1334 
GGadgetGetFirstListSelectedItem(GGadget * g)1335 int32 GGadgetGetFirstListSelectedItem(GGadget *g) {
1336     if ( g->funcs->get_first_selection!=NULL )
1337 return((g->funcs->get_first_selection)(g));
1338 return( -1 );
1339 }
1340 
GGadgetScrollListToPos(GGadget * g,int32 pos)1341 void GGadgetScrollListToPos(GGadget *g,int32 pos) {
1342     if ( g->funcs->scroll_list_to_pos!=NULL )
1343 	(g->funcs->scroll_list_to_pos)(g,pos);
1344 }
1345 
GGadgetScrollListToText(GGadget * g,const unichar_t * lab,int32 sel)1346 void GGadgetScrollListToText(GGadget *g,const unichar_t *lab,int32 sel) {
1347     if ( g->funcs->scroll_list_to_text!=NULL )
1348 	(g->funcs->scroll_list_to_text)(g,lab,sel);
1349 }
1350 
GGadgetSetListOrderer(GGadget * g,int (* orderer)(const void *,const void *))1351 void GGadgetSetListOrderer(GGadget *g,int (*orderer)(const void *, const void *)) {
1352     if ( g->funcs->set_list_orderer!=NULL )
1353 	(g->funcs->set_list_orderer)(g,orderer);
1354 }
1355 
GGadgetGetDesiredSize(GGadget * g,GRect * outer,GRect * inner)1356 void GGadgetGetDesiredSize(GGadget *g,GRect *outer, GRect *inner) {
1357     if ( g->state==gs_invisible ) {
1358 	if ( outer!=NULL )
1359 	    memset(outer,0,sizeof(*outer));
1360 	if ( inner!=NULL )
1361 	    memset(inner,0,sizeof(*inner));
1362     } else if ( ((char *) &g->funcs->get_desired_size) - ((char *) g->funcs) < g->funcs->size &&
1363 	    g->funcs->get_desired_size!=NULL )
1364 	(g->funcs->get_desired_size)(g,outer,inner);
1365     else {
1366 	if ( outer!=NULL )
1367 	    *outer = g->r;
1368 	if ( inner!=NULL )
1369 	    *inner = g->inner;
1370     }
1371 }
1372 
GGadgetGetDesiredVisibleSize(GGadget * g,GRect * outer,GRect * inner)1373 void GGadgetGetDesiredVisibleSize(GGadget *g,GRect *outer, GRect *inner) {
1374     if ( ((char *) &g->funcs->get_desired_size) - ((char *) g->funcs) < g->funcs->size &&
1375 	    g->funcs->get_desired_size!=NULL )
1376 	(g->funcs->get_desired_size)(g,outer,inner);
1377     else {
1378 	if ( outer!=NULL )
1379 	    *outer = g->r;
1380 	if ( inner!=NULL )
1381 	    *inner = g->inner;
1382     }
1383 }
1384 
GGadgetSetDesiredSize(GGadget * g,GRect * outer,GRect * inner)1385 void GGadgetSetDesiredSize(GGadget *g,GRect *outer, GRect *inner) {
1386     if ( ((char *) &g->funcs->set_desired_size) - ((char *) g->funcs) < g->funcs->size &&
1387 	    g->funcs->set_desired_size!=NULL )
1388 	(g->funcs->set_desired_size)(g,outer,inner);
1389 }
1390 
GGadgetFillsWindow(GGadget * g)1391 int GGadgetFillsWindow(GGadget *g) {
1392     if ( ((char *) &g->funcs->fills_window) - ((char *) g->funcs) < g->funcs->size &&
1393 	    g->funcs->fills_window!=NULL )
1394 return( (g->funcs->fills_window)(g) );
1395 
1396 return( false );
1397 }
1398 
GGadgetIsDefault(GGadget * g)1399 int GGadgetIsDefault(GGadget *g) {
1400     if ( ((char *) &g->funcs->is_default) - ((char *) g->funcs) < g->funcs->size &&
1401 	    g->funcs->is_default!=NULL )
1402 return( (g->funcs->is_default)(g) );
1403 
1404 return( false );
1405 }
1406 
GGadgetsCreate(GWindow base,GGadgetCreateData * gcd)1407 void GGadgetsCreate(GWindow base, GGadgetCreateData *gcd) {
1408     int i;
1409 
1410     for ( i=0; gcd[i].creator!=NULL; ++i )
1411 	gcd[i].ret = (gcd[i].creator)(base,&gcd[i].gd,gcd[i].data);
1412 }
1413 
GGadgetDispatchEvent(GGadget * g,GEvent * event)1414 int GGadgetDispatchEvent(GGadget *g, GEvent *event) {
1415 
1416     if ( g==NULL || event==NULL )
1417 return( false );
1418     switch ( event->type ) {
1419       case et_expose:
1420 	  if ( g->funcs->handle_expose )
1421 return( (g->funcs->handle_expose)(g->base,g,event) );
1422       break;
1423       case et_mouseup: case et_mousedown: case et_mousemove: case et_crossing:
1424 	  if ( g->funcs->handle_mouse )
1425 return( (g->funcs->handle_mouse)(g,event) );
1426       break;
1427       case et_char: case et_charup:
1428 	if ( g->funcs->handle_key ) {
1429 	    int ret;
1430 	    int old = g->takes_keyboard;
1431 	    g->takes_keyboard = true;
1432 	    ret =(g->funcs->handle_key)(g,event);
1433 	    g->takes_keyboard = old;
1434 return( ret );
1435 	}
1436       break;
1437       case et_drag: case et_dragout: case et_drop: case et_selclear:
1438 	  if ( g->funcs->handle_sel )
1439 return( (g->funcs->handle_sel)(g,event) );
1440       break;
1441       case et_timer:
1442 	  if ( g->funcs->handle_timer )
1443 return( (g->funcs->handle_timer)(g,event) );
1444       break;
1445       case et_controlevent:
1446 	if ( g->handle_controlevent!=NULL )
1447 return( (g->handle_controlevent)(g,event) );
1448 	else
1449 	    GDrawPostEvent(event);
1450 return( true );
1451     }
1452 return( false );
1453 }
1454 
GGadgetTakesKeyboard(GGadget * g,int takes_keyboard)1455 void GGadgetTakesKeyboard(GGadget *g, int takes_keyboard) {
1456     g->takes_keyboard = takes_keyboard;
1457 }
1458 
_GGadgetRIHead(void)1459 GResInfo *_GGadgetRIHead(void) {
1460 
1461     if ( !_ggadget_inited )
1462 	GGadgetInit();
1463 return( &popup_ri );
1464 }
1465 
GGadgetSetSkipHotkeyProcessing(GGadget * g,int v)1466 void GGadgetSetSkipHotkeyProcessing( GGadget *g, int v )
1467 {
1468     if( !g )
1469 	return;
1470 
1471     printf("GGadgetSetSkipHotkeyProcessing1 %d\n", g->state );
1472     g->gg_skip_hotkey_processing = v;
1473     printf("GGadgetSetSkipHotkeyProcessing2 %d\n", g->state );
1474 }
1475 
GGadgetGetSkipHotkeyProcessing(GGadget * g)1476 int GGadgetGetSkipHotkeyProcessing( GGadget *g )
1477 {
1478     if( !g )
1479 	return 0;
1480 
1481     return (g->gg_skip_hotkey_processing);
1482 }
1483 
GGadgetSetSkipUnQualifiedHotkeyProcessing(GGadget * g,int v)1484 void GGadgetSetSkipUnQualifiedHotkeyProcessing( GGadget *g, int v )
1485 {
1486     if( !g )
1487 	return;
1488     g->gg_skip_unqualified_hotkey_processing = v;
1489 }
1490 
GGadgetGetSkipUnQualifiedHotkeyProcessing(GGadget * g)1491 int GGadgetGetSkipUnQualifiedHotkeyProcessing( GGadget *g )
1492 {
1493     if( !g )
1494 	return 0;
1495 
1496     return (g->gg_skip_unqualified_hotkey_processing);
1497 }
1498 
1499