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 "gdraw.h"
31 #include "ggadgetP.h"
32 #include "gkeysym.h"
33 #include "gresource.h"
34 #include "ustring.h"
35
36 #include <math.h>
37
38 static GBox radio_box = GBOX_EMPTY; /* Don't initialize here */
39 static GBox radio_on_box = GBOX_EMPTY; /* Don't initialize here */
40 static GBox radio_off_box = GBOX_EMPTY; /* Don't initialize here */
41 static GBox checkbox_box = GBOX_EMPTY; /* Don't initialize here */
42 static GBox checkbox_on_box = GBOX_EMPTY; /* Don't initialize here */
43 static GBox checkbox_off_box = GBOX_EMPTY; /* Don't initialize here */
44 static GBox visibility_on_box = GBOX_EMPTY; /* Don't initialize here */
45 static GBox visibility_off_box = GBOX_EMPTY; /* Don't initialize here */
46 static GResImage *radon, *radoff, *checkon, *checkoff, *raddison, *raddisoff, *checkdison, *checkdisoff;
47 static GResImage *visibilityon, *visibilityoff, *visibilitydison, *visibilitydisoff;
48 static FontInstance *checkbox_font = NULL;
49 static int gradio_inited = false;
50
51 static GResInfo gradio_ri, gradioon_ri, gradiooff_ri;
52 static GResInfo gcheckbox_ri, gcheckboxon_ri, gcheckboxoff_ri;
53 static GTextInfo radio_lab[] = {
54 { (unichar_t *) "Disabled On", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
55 { (unichar_t *) "Disabled Off", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
56 { (unichar_t *) "Enabled" , NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
57 { (unichar_t *) "Enabled 2" , NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' }
58 };
59 static GGadgetCreateData radio_gcd[] = {
60 { GRadioCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &radio_lab[0], { NULL }, gg_visible, NULL, NULL }, NULL, NULL },
61 { GRadioCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &radio_lab[1], { NULL }, gg_visible|gg_cb_on, NULL, NULL }, NULL, NULL },
62 { GRadioCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &radio_lab[2], { NULL }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL },
63 { GRadioCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &radio_lab[3], { NULL }, gg_visible|gg_enabled|gg_cb_on, NULL, NULL }, NULL, NULL }
64 };
65 static GGadgetCreateData *rarray[] = { GCD_Glue, &radio_gcd[0], GCD_Glue, &radio_gcd[1], GCD_Glue, &radio_gcd[2], GCD_Glue, &radio_gcd[3], GCD_Glue, NULL, NULL };
66 static GGadgetCreateData radiobox =
67 { GHVGroupCreate, { { 2, 2, 0, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) rarray }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL };
68 static GResInfo gradio_ri = {
69 &gradioon_ri, &ggadget_ri,&gradioon_ri, &gradiooff_ri,
70 &radio_box,
71 &checkbox_font,
72 &radiobox,
73 NULL,
74 N_("Radio Button"),
75 N_("Radio Button"),
76 "GRadio",
77 "Gdraw",
78 false,
79 omf_border_type|omf_padding,
80 NULL,
81 GBOX_EMPTY,
82 NULL,
83 NULL,
84 NULL
85 };
86 static struct resed gradioon_re[] = {
87 { N_("Image"), "Image", rt_image, &radon, N_("Image used instead of the Radio On Mark"), NULL, { 0 }, 0, 0 },
88 { N_("Disabled Image"), "DisabledImage", rt_image, &raddison, N_("Image used instead of the Radio On Mark (when the radio is disabled)"), NULL, { 0 }, 0, 0 },
89 RESED_EMPTY
90 };
91 static GResInfo gradioon_ri = {
92 &gradiooff_ri, &ggadget_ri,&gradiooff_ri, &gradio_ri,
93 &radio_on_box,
94 NULL,
95 &radiobox,
96 gradioon_re,
97 N_("Radio On Mark"),
98 N_("The mark showing a radio button is on (depressed, selected)"),
99 "GRadioOn",
100 "Gdraw",
101 false,
102 omf_border_type|omf_border_shape|box_do_depressed_background,
103 NULL,
104 GBOX_EMPTY,
105 NULL,
106 NULL,
107 NULL
108 };
109 static struct resed gradiooff_re[] = {
110 { N_("Image"), "Image", rt_image, &radoff, N_("Image used instead of the Radio Off Mark"), NULL, { 0 }, 0, 0 },
111 { N_("Disabled Image"), "DisabledImage", rt_image, &raddisoff, N_("Image used instead of the Radio Off Mark (when the radio is disabled)"), NULL, { 0 }, 0, 0 },
112 RESED_EMPTY
113 };
114 static GResInfo gradiooff_ri = {
115 &gcheckbox_ri, &ggadget_ri,&gradioon_ri, &gradio_ri,
116 &radio_off_box,
117 NULL,
118 &radiobox,
119 gradiooff_re,
120 N_("Radio Off Mark"),
121 N_("The mark showing a radio button is off (up, not selected)"),
122 "GRadioOff",
123 "Gdraw",
124 false,
125 omf_border_type|omf_border_shape|box_do_depressed_background,
126 NULL,
127 GBOX_EMPTY,
128 NULL,
129 NULL,
130 NULL
131 };
132 static GTextInfo checkbox_lab[] = {
133 { (unichar_t *) "Disabled On", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
134 { (unichar_t *) "Disabled Off", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
135 { (unichar_t *) "Enabled" , NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' }
136 };
137 static GGadgetCreateData checkbox_gcd[] = {
138 { GCheckBoxCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &checkbox_lab[0], { NULL }, gg_visible, NULL, NULL }, NULL, NULL },
139 { GCheckBoxCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &checkbox_lab[1], { NULL }, gg_visible|gg_cb_on, NULL, NULL }, NULL, NULL },
140 { GCheckBoxCreate, { GRECT_EMPTY, NULL, 0, 0, 0, 0, 0, &checkbox_lab[1], { NULL }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL }
141 };
142 static GGadgetCreateData *carray[] = { GCD_Glue, &checkbox_gcd[0], GCD_Glue, &checkbox_gcd[1], GCD_Glue, &checkbox_gcd[2], GCD_Glue, NULL, NULL };
143 static GGadgetCreateData checkboxbox =
144 { GHVGroupCreate, { { 2, 2, 0, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) carray }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL };
145 static GResInfo gcheckbox_ri = {
146 &gcheckboxon_ri, &ggadget_ri,&gcheckboxon_ri, &gcheckboxoff_ri,
147 &checkbox_box,
148 &checkbox_font,
149 &checkboxbox,
150 NULL,
151 N_("Check Box"),
152 N_("Check Box"),
153 "GCheckBox",
154 "Gdraw",
155 false,
156 omf_border_type|omf_padding,
157 NULL,
158 GBOX_EMPTY,
159 NULL,
160 NULL,
161 NULL
162 };
163 static struct resed gcheckboxon_re[] = {
164 {N_("Image"), "Image", rt_image, &checkon, N_("Image used instead of the Radio On Mark"), NULL, { 0 }, 0, 0 },
165 {N_("Disabled Image"), "DisabledImage", rt_image, &checkdison, N_("Image used instead of the Radio On Mark (when the radio is disabled)"), NULL, { 0 }, 0, 0 },
166 RESED_EMPTY
167 };
168 static GResInfo gcheckboxon_ri = {
169 &gcheckboxoff_ri, &ggadget_ri,&gcheckboxoff_ri, &gcheckbox_ri,
170 &checkbox_on_box,
171 NULL,
172 &checkboxbox,
173 gcheckboxon_re,
174 N_("Check Box On Mark"),
175 N_("The mark showing a checkbox is on (depressed, selected)"),
176 "GCheckBoxOn",
177 "Gdraw",
178 false,
179 omf_border_type|omf_border_shape|box_do_depressed_background,
180 NULL,
181 GBOX_EMPTY,
182 NULL,
183 NULL,
184 NULL
185
186 };
187 static struct resed gcheckboxoff_re[] = {
188 {N_("Image"), "Image", rt_image, &checkoff, N_("Image used instead of the Check Box Off Mark"), NULL, { 0 }, 0, 0 },
189 {N_("Disabled Image"), "DisabledImage", rt_image, &checkdisoff, N_("Image used instead of the Check Box Off Mark (when the radio is disabled)"), NULL, { 0 }, 0, 0 },
190 RESED_EMPTY
191 };
192 static GResInfo gcheckboxoff_ri = {
193 NULL, &ggadget_ri,&gcheckboxon_ri, &gcheckbox_ri,
194 &checkbox_off_box,
195 NULL,
196 &checkboxbox,
197 gcheckboxoff_re,
198 N_("Check Box Off Mark"),
199 N_("The mark showing a checkbox is off (up, not selected)"),
200 "GCheckBoxOff",
201 "Gdraw",
202 false,
203 omf_border_type|omf_border_shape|box_do_depressed_background,
204 NULL,
205 GBOX_EMPTY,
206 NULL,
207 NULL,
208 NULL
209 };
210
GRadioChanged(GRadio * gr)211 static void GRadioChanged(GRadio *gr) {
212 GEvent e;
213
214 if ( gr->isradio && gr->ison )
215 return; /* Do Nothing, it's already on */
216 else if ( gr->isradio ) {
217 GRadio *other;
218 for ( other=gr->post; other!=gr; other = other->post ) {
219 if ( other->ison ) {
220 other->ison = false;
221 _ggadget_redraw((GGadget *) other);
222 }
223 }
224 } else {
225 /* Checkboxes just default down */
226 ;
227 }
228 gr->ison = !gr->ison;
229 e.type = et_controlevent;
230 e.w = gr->g.base;
231 e.u.control.subtype = et_radiochanged;
232 e.u.control.g = &gr->g;
233 if ( gr->g.handle_controlevent != NULL )
234 (gr->g.handle_controlevent)(&gr->g,&e);
235 else
236 GDrawPostEvent(&e);
237 }
238
239 /* Return the number of lines in the label of a radio button. */
gradio_linecount(GRadio * gr)240 static int gradio_linecount(GRadio *gr) {
241 int lcnt;
242 unichar_t *pt;
243
244 lcnt = 0;
245 if ( gr->label!=NULL ) {
246 for ( pt = gr->label; ; ) {
247 for ( ; *pt!='\0' && *pt!='\n'; ++pt );
248 ++lcnt;
249 if ( *pt=='\0' )
250 break;
251 ++pt;
252 }
253 }
254 return( lcnt );
255 }
256
257 /* Called on expose events, this renders the button. */
gradio_expose(GWindow pixmap,GGadget * g,GEvent * event)258 static int gradio_expose(GWindow pixmap, GGadget *g, GEvent *event) {
259 GRadio *gr = (GRadio *) g;
260 int x;
261 GImage *img = gr->image; /* the optional image tied to the label */
262 GResImage *mark;
263 GRect old1, old2, old3;
264 int yoff = (g->inner.height-(gr->fh))/2;
265
266 if ( g->state == gs_invisible )
267 return( false );
268
269 /* First blank out the button area. */
270 GDrawPushClip(pixmap,&g->r,&old1);
271
272 GBoxDrawBackground(pixmap,&g->r,g->box,
273 g->state==gs_enabled? gs_pressedactive: g->state,false);
274 GBoxDrawBorder(pixmap,&g->r,g->box,g->state,false);
275
276 GDrawPushClip(pixmap,&gr->onoffrect,&old2);
277 GBoxDrawBackground(pixmap,&gr->onoffrect,gr->ison?gr->onbox:gr->offbox,
278 gs_pressedactive,false);
279 if (gr->ison && gr->onbox->border_type!=bt_none)
280 GBoxDrawBorder(pixmap,&gr->onoffrect,gr->onbox, gs_pressedactive,false);
281 else if (!gr->ison && gr->offbox->border_type!=bt_none)
282 GBoxDrawBorder(pixmap,&gr->onoffrect,gr->offbox,gs_pressedactive,false);
283
284 /* Next draw either the right image or draw in an on or off indicator. */
285 mark = NULL;
286 if ( g->state == gs_disabled )
287 mark = gr->ison ? gr->ondis : gr->offdis; /* note: ondis or offdis may be NULL! */
288 if ( mark==NULL || mark->image==NULL )
289 mark = gr->ison ? gr->on : gr->off; /* note: on or off may be NULL! */
290 if ( mark!=NULL && mark->image==NULL ) /* when there's a reference to a special image, but no actual image */
291 mark = NULL;
292 if ( mark!=NULL ) {
293 GDrawPushClip(pixmap,&gr->onoffinner,&old3);
294 GDrawDrawScaledImage(pixmap,mark->image,
295 gr->onoffinner.x,gr->onoffinner.y);
296 GDrawPopClip(pixmap,&old3);
297 } else if ( gr->ison && gr->onbox == &checkbox_on_box ) {
298 /* for radio buttons where the on is a checkbox style, draw an X */
299 Color fg = g->state==gs_disabled?g->box->disabled_foreground:
300 g->box->main_foreground==COLOR_DEFAULT?GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap)):
301 g->box->main_foreground;
302 int bp = GDrawPointsToPixels(pixmap,gr->onbox->border_width);
303 GDrawDrawLine(pixmap, gr->onoffrect.x+bp,gr->onoffrect.y+bp,
304 gr->onoffrect.x+gr->onoffrect.width-1-bp,gr->onoffrect.y+gr->onoffrect.height-1-bp,
305 fg);
306 GDrawDrawLine(pixmap, gr->onoffrect.x+gr->onoffrect.width-1-bp,gr->onoffrect.y+bp,
307 gr->onoffrect.x+bp,gr->onoffrect.y+gr->onoffrect.height-1-bp,
308 fg);
309 } else if ( gr->ison && gr->onbox == &visibility_on_box ) {
310 /* draw open white of eye */
311 GPoint pts[15];
312 Color fg;
313 double angle;
314 int c,i;
315 int bp = gr->onbox->border_type==bt_none ? 0 : GDrawPointsToPixels(pixmap,gr->onbox->border_width);
316 int x=gr->onoffrect.x+bp;
317 int y=gr->onoffrect.y+bp;
318 int w=gr->onoffrect.width -1-2*bp;
319 int h=gr->onoffrect.height-1-2*bp;
320 GRect rect;
321 for (c=0, i=0; c<7; c++) {
322 angle=(30+c/6.*120)*FF_PI/180;
323 pts[i].x=.5*w*cos(angle)+x+w/2;
324 pts[i].y=.5*h*sin(angle)+y+h/4;
325 ++i;
326 }
327 for (c=1; c<6; c++) {
328 angle=(180+30+c/6.*120)*FF_PI/180;
329 pts[i].x=.5*w*cos(angle)+x+w/2;
330 pts[i].y=.5*h*sin(angle)+y+h*3/4;
331 ++i;
332 }
333 pts[i].x=pts[0].x;
334 pts[i].y=pts[0].y;
335 ++i;
336 fg=0x00ffffff; /* white */
337 GDrawFillPoly(pixmap, pts, i, fg);
338 fg = g->state==gs_disabled?g->box->disabled_foreground:
339 g->box->main_foreground==COLOR_DEFAULT?GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap)):
340 g->box->main_foreground;
341 GDrawDrawPoly(pixmap, pts, i, fg);
342
343 /* draw pupil */
344 rect.x=gr->onoffrect.x+bp+w*.3;
345 rect.y=gr->onoffrect.y+bp+h*.3;
346 rect.width =.4*w;
347 rect.height=.4*h;
348 fg=0; /* black */
349 GDrawFillElipse(pixmap, &rect, fg);
350
351 } else if ( (!gr->ison) && gr->onbox == &visibility_on_box ) {
352 /* draw closed eye */
353 GPoint pts[7];
354 double angle;
355 int bp = gr->onbox->border_type==bt_none ? 0 : GDrawPointsToPixels(pixmap,gr->onbox->border_width);
356 int x=gr->onoffrect.x+bp;
357 int y=gr->onoffrect.y+bp;
358 int w=gr->onoffrect.width -1-2*bp;
359 int h=gr->onoffrect.height-1-2*bp;
360 Color fg = g->state==gs_disabled?g->box->disabled_foreground:
361 g->box->main_foreground==COLOR_DEFAULT?GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap)):
362 g->box->main_foreground;
363 for (int i = 0; i <= 6; i++) {
364 angle=(30+i/6.*120)*FF_PI/180;
365 pts[i].x=.5*w*cos(angle)+x+w/2;
366 pts[i].y=.5*h*sin(angle)+y+h/4;
367
368 /* draw lashes */
369 if (i>0 && i<6) GDrawDrawLine(pixmap, pts[i].x,pts[i].y, .75*w*cos(angle)+x+w/2, .75*h*sin(angle)+y+h/4, fg);
370 }
371 GDrawDrawPoly(pixmap, pts, sizeof(pts)/sizeof(pts[0]), fg);
372 }
373
374 GDrawPopClip(pixmap,&old2);
375 x = gr->onoffrect.x + gr->onoffrect.width + GDrawPointsToPixels(pixmap,4);
376
377 /* Finally write out the label if any. */
378 GDrawPushClip(pixmap,&g->inner,&old2);
379 if ( gr->font!=NULL )
380 GDrawSetFont(pixmap,gr->font);
381 if ( gr->image_precedes && img!=NULL ) {
382 GDrawDrawScaledImage(pixmap,img,x,g->inner.y);
383 x += GImageGetScaledWidth(pixmap,img) + GDrawPointsToPixels(pixmap,_GGadget_TextImageSkip);
384 }
385 if ( gr->label!=NULL ) {
386 Color fg = g->state==gs_disabled?g->box->disabled_foreground:
387 g->box->main_foreground==COLOR_DEFAULT?GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap)):
388 g->box->main_foreground;
389 int lcnt = gradio_linecount(gr);
390 if ( lcnt>1 )
391 yoff = (g->inner.height-lcnt*gr->fh)/2;
392 _ggadget_underlineMnemonic(pixmap,x,g->inner.y + gr->as + yoff,gr->label,
393 g->mnemonic,fg,g->inner.y+g->inner.height);
394 x += GDrawDrawText(pixmap,x,g->inner.y + gr->as + yoff,gr->label,-1,fg);
395 x += GDrawPointsToPixels(pixmap,_GGadget_TextImageSkip);
396 }
397 if ( !gr->image_precedes && img!=NULL )
398 GDrawDrawScaledImage(pixmap,img,x,g->inner.y);
399
400 GDrawPopClip(pixmap,&old2);
401 GDrawPopClip(pixmap,&old1);
402 return( true );
403 }
404
gradio_mouse(GGadget * g,GEvent * event)405 static int gradio_mouse(GGadget *g, GEvent *event) {
406 GRadio *gr = (GRadio *) g;
407 int within = gr->within, pressed = gr->pressed;
408
409 if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
410 return( false );
411
412 if ( event->type == et_crossing ) {
413 if ( gr->within && !event->u.crossing.entered )
414 gr->within = false;
415 } else if ( gr->pressed && event->type!=et_mousemove ) {
416 if ( event->type == et_mousedown ) /* They pressed 2 mouse buttons? */
417 gr->pressed = false;
418 else if ( GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y)) {
419 gr->pressed = false;
420 if ( !gr->isradio || !gr->ison )
421 GRadioChanged(gr);
422 } else if ( event->type == et_mouseup )
423 gr->pressed = false;
424 else
425 gr->within = true;
426 } else if ( event->type == et_mousedown &&
427 GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y)) {
428 gr->pressed = true;
429 gr->within = true;
430 } else if ( event->type == et_mousemove &&
431 GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y)) {
432 gr->within = true;
433 if ( !gr->pressed && g->popup_msg )
434 GGadgetPreparePopup(g->base,g->popup_msg);
435 } else if ( event->type == et_mousemove && gr->within ) {
436 gr->within = false;
437 } else {
438 return( false );
439 }
440 if ( within != gr->within )
441 g->state = gr->within? gs_active : gs_enabled;
442 if ( within != gr->within || pressed != gr->pressed )
443 _ggadget_redraw(g);
444 return( gr->within );
445 }
446
gradio_key(GGadget * g,GEvent * event)447 static int gradio_key(GGadget *g, GEvent *event) {
448 GRadio *gr = (GRadio *) g;
449
450 if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
451 return(false);
452
453 if ( event->u.chr.keysym == GK_Return || event->u.chr.keysym == GK_Tab ||
454 event->u.chr.keysym == GK_BackTab || event->u.chr.keysym == GK_Escape )
455 return( false );
456
457 if (event->type == et_char && event->u.chr.chars[0]==' ' ) {
458 GRadioChanged(gr);
459 _ggadget_redraw(g);
460 return( true );
461 }
462 return( false );
463 }
464
gradio_focus(GGadget * g,GEvent * event)465 static int gradio_focus(GGadget *g, GEvent *event) {
466 GRadio *gr = (GRadio *) g;
467
468 if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active ))
469 return(false);
470
471 if ( event->u.focus.mnemonic_focus==mf_shortcut ) {
472 GRadioChanged(gr);
473 }
474 return( true );
475 }
476
gradio_destroy(GGadget * g)477 static void gradio_destroy(GGadget *g) {
478 GRadio *gr = (GRadio *) g;
479
480 if ( gr==NULL )
481 return;
482 if ( gr->isradio && gr->post!=gr ) {
483 GRadio *prev;
484 for ( prev=gr->post; prev->post!=gr; prev = prev->post );
485 prev->post = gr->post;
486 }
487 free(gr->label);
488 _ggadget_destroy(g);
489 }
490
GRadioSetTitle(GGadget * g,const unichar_t * tit)491 static void GRadioSetTitle(GGadget *g,const unichar_t *tit) {
492 GRadio *b = (GRadio *) g;
493 free(b->label);
494 b->label = u_copy(tit);
495 }
496
_GRadioGetTitle(GGadget * g)497 static const unichar_t *_GRadioGetTitle(GGadget *g) {
498 GRadio *b = (GRadio *) g;
499 return( b->label );
500 }
501
GRadioSetImageTitle(GGadget * g,GImage * img,const unichar_t * tit,int before)502 static void GRadioSetImageTitle(GGadget *g,GImage *img,const unichar_t *tit, int before) {
503 GRadio *b = (GRadio *) g;
504 if ( b->g.free_box )
505 free( b->g.box );
506 free(b->label);
507 b->label = u_copy(tit);
508 b->image = img;
509 b->image_precedes = before;
510 _ggadget_redraw(g);
511 }
512
GRadioGetImage(GGadget * g)513 static GImage *GRadioGetImage(GGadget *g) {
514 GRadio *b = (GRadio *) g;
515 return( b->image );
516 }
517
GRadioSetFont(GGadget * g,FontInstance * new)518 static void GRadioSetFont(GGadget *g,FontInstance *new) {
519 GRadio *b = (GRadio *) g;
520 b->font = new;
521 }
522
GRadioGetFont(GGadget * g)523 static FontInstance *GRadioGetFont(GGadget *g) {
524 GRadio *b = (GRadio *) g;
525 return( b->font );
526 }
527
_gradio_move(GGadget * g,int32 x,int32 y)528 static void _gradio_move(GGadget *g, int32 x, int32 y ) {
529 GRadio *b = (GRadio *) g;
530 b->onoffrect.x = x+(b->onoffrect.x-g->r.x);
531 b->onoffinner.x = x+(b->onoffinner.x-g->r.x);
532 _ggadget_move(g,x,y);
533 b->onoffrect.y = g->r.y+(g->r.height-b->onoffrect.height)/2;
534 b->onoffinner.y = g->r.y+(g->r.height-b->onoffinner.height)/2;
535 }
536
GRadioGetDesiredSize(GGadget * g,GRect * outer,GRect * inner)537 static void GRadioGetDesiredSize(GGadget *g, GRect *outer, GRect *inner) {
538 GCheckBox *gl = (GCheckBox *) g;
539 int iwidth=0, iheight=0;
540 GTextBounds bounds;
541 int as=0, ds, ld, fh=0, width=0;
542
543 if ( gl->image!=NULL ) {
544 iwidth = GImageGetScaledWidth(gl->g.base,gl->image);
545 iheight = GImageGetScaledHeight(gl->g.base,gl->image);
546 }
547 GDrawWindowFontMetrics(g->base,gl->font,&as, &ds, &ld);
548 if ( gl->label!=NULL ) {
549 FontInstance *old = GDrawSetFont(gl->g.base,gl->font);
550 width = GDrawGetTextBounds(gl->g.base,gl->label, -1, &bounds);
551 GDrawSetFont(gl->g.base,old);
552 if ( as<bounds.as ) as = bounds.as;
553 if ( ds<bounds.ds ) ds = bounds.ds;
554 }
555 fh = as+ds;
556
557 if ( width!=0 && iwidth!=0 )
558 width += GDrawPointsToPixels(gl->g.base,_GGadget_TextImageSkip);
559 width += iwidth;
560 if ( iheight<fh )
561 iheight = fh;
562 if ( iheight < gl->onoffrect.height )
563 iheight = gl->onoffrect.height;
564 width += gl->onoffrect.width + GDrawPointsToPixels(gl->g.base,5);
565 if ( g->desired_width>0 ) width = g->desired_width;
566 if ( g->desired_height>0 ) iheight = g->desired_height;
567 if ( inner!=NULL ) {
568 inner->x = inner->y = 0;
569 inner->width = width;
570 inner->height = iheight;
571 }
572 if ( outer!=NULL ) {
573 outer->x = outer->y = 0;
574 outer->width = width;
575 outer->height = iheight;
576 /*_ggadgetFigureSize(gl->g.base,gl->g.box,outer,false);*/
577 }
578 }
579
GVisibilityBoxSetToMinWH(GGadget * g)580 void GVisibilityBoxSetToMinWH(GGadget *g)
581 {
582 GRect size;
583 GRect outer;
584 GRect inner;
585 GRadioGetDesiredSize(g, &outer, &inner );
586 outer.width = MIN(outer.width,outer.height);
587 outer.width -= 3;
588 size.width = outer.width;
589 size.height = outer.height;
590 GGadgetSetSize(g,&size);
591 }
592
593
594 struct gfuncs gradio_funcs = {
595 0,
596 sizeof(struct gfuncs),
597
598 gradio_expose,
599 gradio_mouse,
600 gradio_key,
601 NULL,
602 gradio_focus,
603 NULL,
604 NULL,
605
606 _ggadget_redraw,
607 _gradio_move,
608 _ggadget_resize,
609 _ggadget_setvisible,
610 _ggadget_setenabled,
611 _ggadget_getsize,
612 _ggadget_getinnersize,
613
614 gradio_destroy,
615
616 GRadioSetTitle,
617 _GRadioGetTitle,
618 NULL,
619 GRadioSetImageTitle,
620 GRadioGetImage,
621
622 GRadioSetFont,
623 GRadioGetFont,
624
625 NULL,
626 NULL,
627 NULL,
628 NULL,
629 NULL,
630 NULL,
631 NULL,
632 NULL,
633 NULL,
634 NULL,
635 NULL,
636
637 GRadioGetDesiredSize,
638 _ggadget_setDesiredSize,
639 NULL,
640 NULL
641 };
642
GRadioInit()643 static void GRadioInit() {
644 _GGadgetCopyDefaultBox(&radio_box);
645 _GGadgetCopyDefaultBox(&radio_on_box);
646 _GGadgetCopyDefaultBox(&radio_off_box);
647 _GGadgetCopyDefaultBox(&checkbox_box);
648 _GGadgetCopyDefaultBox(&checkbox_on_box);
649 _GGadgetCopyDefaultBox(&checkbox_off_box);
650 _GGadgetCopyDefaultBox(&visibility_on_box);
651 _GGadgetCopyDefaultBox(&visibility_off_box);
652
653 radio_box.padding = 0;
654 radio_box.border_type = bt_none;
655 radio_on_box.border_type = bt_raised;
656 radio_off_box.border_type = bt_lowered;
657 radio_on_box.border_shape = radio_off_box.border_shape = bs_diamond;
658 radio_on_box.flags = radio_off_box.flags |= box_do_depressed_background;
659
660 checkbox_box.padding = 0;
661 checkbox_box.border_type = bt_none;
662 checkbox_on_box.border_type = bt_raised;
663 checkbox_off_box.border_type = bt_lowered;
664 checkbox_on_box.flags = checkbox_off_box.flags |= box_do_depressed_background;
665 checkbox_font = _GGadgetInitDefaultBox("GRadio.",&radio_box,NULL);
666 checkbox_font = _GGadgetInitDefaultBox("GCheckBox.",&checkbox_box,checkbox_font);
667
668 visibility_on_box.border_type=bt_none;
669 visibility_on_box.padding=1;
670 visibility_off_box.border_type=bt_none;
671 visibility_off_box.padding=1;
672
673 _GGadgetInitDefaultBox("GRadioOn.",&radio_on_box,NULL);
674 _GGadgetInitDefaultBox("GRadioOff.",&radio_off_box,NULL);
675 _GGadgetInitDefaultBox("GCheckBoxOn.",&checkbox_on_box,NULL);
676 _GGadgetInitDefaultBox("GCheckBoxOff.",&checkbox_off_box,NULL);
677 _GGadgetInitDefaultBox("GVisibilityBoxOn.",&visibility_on_box,NULL);
678 _GGadgetInitDefaultBox("GVisibitityBoxOff.",&visibility_off_box,NULL);
679
680 if ( radio_on_box.depressed_background == radio_off_box.depressed_background ) {
681 radio_on_box.depressed_background = radio_on_box.active_border;
682 radio_off_box.depressed_background = radio_off_box.main_background;
683 }
684
685 if ( checkbox_on_box.depressed_background == checkbox_off_box.depressed_background ) {
686 checkbox_on_box.depressed_background = checkbox_on_box.active_border;
687 checkbox_off_box.depressed_background = checkbox_off_box.main_background;
688 }
689
690 radon = GGadgetResourceFindImage("GRadioOn.Image",NULL);
691 radoff = GGadgetResourceFindImage("GRadioOff.Image",NULL);
692 raddison = GGadgetResourceFindImage("GRadioOn.DisabledImage",NULL);
693 raddisoff = GGadgetResourceFindImage("GRadioOff.DisabledImage",NULL);
694
695 checkon = GGadgetResourceFindImage("GCheckBoxOn.Image",NULL);
696 checkoff = GGadgetResourceFindImage("GCheckBoxOff.Image",NULL);
697 checkdison = GGadgetResourceFindImage("GCheckBoxOn.DisabledImage",NULL);
698 checkdisoff = GGadgetResourceFindImage("GCheckBoxOff.DisabledImage",NULL);
699
700 visibilityon = GGadgetResourceFindImage("GVisibilityBoxOn.Image",NULL);
701 visibilityoff = GGadgetResourceFindImage("GVisibilityBoxOff.Image",NULL);
702 visibilitydison = GGadgetResourceFindImage("GVisibilityBoxOn.DisabledImage",NULL);
703 visibilitydisoff = GGadgetResourceFindImage("GVisibilityBoxOff.DisabledImage",NULL);
704
705 gradio_inited = true;
706 }
707
GCheckBoxFit(GCheckBox * gl)708 static void GCheckBoxFit(GCheckBox *gl) {
709 int as=0, ds, ld;
710 GRect outer, inner, needed;
711 int iwidth, iheight;
712
713 needed.x = needed.y = 0;
714 needed.width = needed.height = 1;
715 if ( gl->on!=NULL && gl->on->image!=NULL ) {
716 if (( iwidth = GImageGetScaledWidth(gl->g.base,gl->on->image))>needed.width )
717 needed.width = iwidth;
718 if (( iheight = GImageGetScaledHeight(gl->g.base,gl->on->image))>needed.height )
719 needed.height = iheight;
720 }
721 if ( gl->off!=NULL && gl->off->image!=NULL ) {
722 if (( iwidth = GImageGetScaledWidth(gl->g.base,gl->off->image))>needed.width )
723 needed.width = iwidth;
724 if (( iheight = GImageGetScaledHeight(gl->g.base,gl->off->image))>needed.height )
725 needed.height = iheight;
726 }
727 gl->onoffinner = needed;
728 _ggadgetFigureSize(gl->g.base,gl->onbox,&needed,false);
729 gl->onoffrect = needed;
730
731 GDrawWindowFontMetrics(gl->g.base,gl->font,&as, &ds, &ld);
732 GRadioGetDesiredSize(&gl->g,&outer,&inner);
733 _ggadgetSetRects(&gl->g,&outer, &inner, -1, 0);
734
735 gl->as = as;
736 gl->fh = as+ds;
737
738 gl->onoffrect.x = gl->g.inner.x;
739 gl->onoffrect.y = (gl->as>gl->onoffrect.height)?gl->g.inner.y+gl->as-gl->onoffrect.height:
740 gl->g.inner.y+(gl->g.inner.height-gl->onoffrect.height)/2;
741 gl->onoffinner.x = gl->onoffrect.x + (gl->onoffrect.width-gl->onoffinner.width)/2;
742 gl->onoffinner.y = gl->onoffrect.y + (gl->onoffrect.height-gl->onoffinner.height)/2;
743 }
744
_GCheckBoxCreate(GCheckBox * gl,struct gwindow * base,GGadgetData * gd,void * data,GBox * def)745 static GCheckBox *_GCheckBoxCreate(GCheckBox *gl, struct gwindow *base, GGadgetData *gd,void *data, GBox *def) {
746
747 if ( !gradio_inited )
748 GRadioInit();
749 gl->g.funcs = &gradio_funcs;
750 _GGadget_Create(&gl->g,base,gd,data,def);
751
752 gl->g.takes_input = true; gl->g.takes_keyboard = true; gl->g.focusable = true;
753 gl->font = checkbox_font;
754 if ( gd->label!=NULL ) {
755 gl->image_precedes = gd->label->image_precedes;
756 if ( gd->label->font!=NULL )
757 gl->font = gd->label->font;
758 if ( gd->label->text_in_resource && gd->label->text_is_1byte )
759 gl->label = utf82u_mncopy((char *) gd->label->text,&gl->g.mnemonic);
760 else if ( gd->label->text_in_resource )
761 gl->label = u_copy((unichar_t *) GStringGetResource((intpt) gd->label->text,&gl->g.mnemonic));
762 else if ( gd->label->text_is_1byte )
763 gl->label = /*def2u*/ utf82u_copy((char *) gd->label->text);
764 else
765 gl->label = u_copy(gd->label->text);
766 gl->image = gd->label->image;
767 }
768 if ( gd->flags & gg_cb_on )
769 gl->ison = true;
770 if ( gl->isradio ) {
771 gl->onbox = &radio_on_box;
772 gl->offbox = &radio_off_box;
773 gl->on = radon;
774 gl->off = radoff;
775 gl->ondis = raddison;
776 gl->offdis = raddisoff;
777 } else {
778 gl->onbox = &checkbox_on_box;
779 gl->offbox = &checkbox_off_box;
780 gl->on = checkon;
781 gl->off = checkoff;
782 gl->ondis = checkdison;
783 gl->offdis = checkdisoff;
784 }
785 GCheckBoxFit(gl);
786 _GGadget_FinalPosition(&gl->g,base,gd);
787
788 if ( gd->flags & gg_group_end )
789 _GGadgetCloseGroup(&gl->g);
790 return( gl );
791 }
792
GCheckBoxCreate(struct gwindow * base,GGadgetData * gd,void * data)793 GGadget *GCheckBoxCreate(struct gwindow *base, GGadgetData *gd,void *data) {
794 GCheckBox *gl = _GCheckBoxCreate(calloc(1,sizeof(GCheckBox)),base,gd,data,&checkbox_box);
795
796 return( &gl->g );
797 }
798
GVisibilityBoxCreate(struct gwindow * base,GGadgetData * gd,void * data)799 GGadget *GVisibilityBoxCreate(struct gwindow *base, GGadgetData *gd,void *data) {
800 GCheckBox *gl = _GCheckBoxCreate(calloc(1,sizeof(GCheckBox)),base,gd,data,&checkbox_box);
801 gl->onbox = &visibility_on_box;
802 gl->offbox = &visibility_off_box;
803 gl->on = visibilityon;
804 gl->off = visibilityoff;
805 gl->ondis = visibilitydison;
806 gl->offdis = visibilitydisoff;
807
808 return( &gl->g );
809 }
810
GRadioCreate(struct gwindow * base,GGadgetData * gd,void * data)811 GGadget *GRadioCreate(struct gwindow *base, GGadgetData *gd,void *data) {
812 GRadio *gl = (GRadio *) calloc(1,sizeof(GRadio));
813 GGadget *gr;
814
815 gl->isradio = true;
816 gl->radiogroup = gd->u.radiogroup;
817 _GCheckBoxCreate((GCheckBox *) gl,base,gd,data,&radio_box);
818
819 gl->post = gl;
820 if ( gd->flags & gg_rad_startnew )
821 /* Done */;
822 else if ( gl->g.prev!=NULL && gl->radiogroup!=0 ) {
823 for ( gr=gl->g.prev; gr!=NULL; gr = gr->prev ) {
824 if ( gr->funcs==&gradio_funcs && ((GRadio *) gr)->radiogroup == gl->radiogroup ) {
825 gl->post = ((GRadio *) gr)->post;
826 ((GRadio *) gr)->post = gl;
827 break;
828 }
829 }
830 } else if ( gl->g.prev!=NULL && gl->g.prev->funcs==&gradio_funcs &&
831 ((GRadio *) (gl->g.prev))->isradio ) {
832 gl->post = ((GRadio *) (gl->g.prev))->post;
833 ((GRadio *) (gl->g.prev))->post = gl;
834 } else if ( gd->flags & gg_rad_continueold ) {
835 for ( gr=gl->g.prev; gr!=NULL && (gr->funcs!=&gradio_funcs ||
836 !((GRadio *) gr)->isradio); gr = gr->prev );
837 if ( gr!=NULL ) {
838 gl->post = ((GRadio *) gr)->post;
839 ((GRadio *) gr)->post = gl;
840 }
841 }
842
843 return( &gl->g );
844 }
845
GGadgetSetChecked(GGadget * g,int ison)846 void GGadgetSetChecked(GGadget *g, int ison) {
847 GRadio *gr = (GRadio *) g;
848
849 if ( gr->isradio ) {
850 if ( ison && !gr->ison ) {
851 GRadio *other;
852 for ( other=gr->post; other!=gr; other = other->post ) {
853 if ( other->ison ) {
854 other->ison = false;
855 _ggadget_redraw((GGadget *) other);
856 }
857 }
858 }
859 }
860 gr->ison = ison?1:0;
861 _ggadget_redraw(g);
862 }
863
GGadgetIsChecked(GGadget * g)864 int GGadgetIsChecked(GGadget *g) {
865 return( ((GRadio *) g)->ison );
866 }
867
_GRadioRIHead(void)868 GResInfo *_GRadioRIHead(void) {
869
870 if ( !gradio_inited )
871 GRadioInit();
872 return( &gradio_ri );
873 }
874