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