ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/sdlgui.cpp
Revision: 1.3
Committed: 2007-03-28T06:55:52Z (17 years ago) by berlac
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +10 -10 lines
Log Message:
Minor code clean up.

File Contents

# Content
1 /*
2 * sdlgui.cpp
3 *
4 * This file is taken from the ARAnyM project which builds a new and powerful
5 * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
6 *
7 * Copyright (c) 2001 Thomas Huth - taken from his hatari project
8 * Copyright (c) 2002-2005 Petr Stehlik of ARAnyM dev team (see AUTHORS)
9 *
10 * It is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Frodo; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "sysdeps.h"
21 #include "sdlgui.h"
22
23 #include <cstdlib>
24
25 #include "font8.h"
26
27 static SDL_Surface *mainsurface = NULL;
28 #define sdlscrn mainsurface
29
30 static SDL_Surface *fontgfx=NULL;
31 static int fontwidth, fontheight; /* Height and width of the actual font */
32
33 // Stores current dialog coordinates
34 static SDL_Rect DialogRect = {0, 0, 0, 0};
35
36 // Used by SDLGui_Get[First|Next]BackgroundRect()
37 static SDL_Rect BackgroundRect = {0, 0, 0, 0};
38 static int BackgroundRectCounter;
39 enum
40 {
41 SG_BCKGND_RECT_BEGIN,
42 SG_BCKGND_RECT_TOP,
43 SG_BCKGND_RECT_LEFT,
44 SG_BCKGND_RECT_RIGHT,
45 SG_BCKGND_RECT_BOTTOM,
46 SG_BCKGND_RECT_END
47 };
48
49 SDL_Color blackc[] = {{0, 0, 0, 0}};
50 SDL_Color darkgreyc[] = {{128, 128, 128, 0}};
51 SDL_Color greyc[] = {{192, 192, 192, 0}};
52 SDL_Color whitec[] = {{255, 255, 255, 0}};
53
54 enum
55 {
56 SG_FIRST_EDITFIELD,
57 SG_PREVIOUS_EDITFIELD,
58 SG_NEXT_EDITFIELD,
59 SG_LAST_EDITFIELD
60 };
61
62 /*-----------------------------------------------------------------------*/
63 /*
64 Load an 1 plane XBM into a 8 planes SDL_Surface.
65 */
66 static SDL_Surface *SDLGui_LoadXBM(int w, int h, Uint8 *srcbits)
67 {
68 SDL_Surface *bitmap;
69 Uint8 *dstbits;
70 int x, y, srcpitch;
71
72 /* Allocate the bitmap */
73 bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
74 if ( bitmap == NULL )
75 {
76 // TODO panicbug("Couldn't allocate bitmap: %s", SDL_GetError());
77 return(NULL);
78 }
79
80 srcpitch = ((w + 7) / 8);
81 dstbits = (Uint8 *)bitmap->pixels;
82 int mask = 1;
83
84 /* Copy the pixels */
85 for (y = 0 ; y < h ; y++)
86 {
87 for (x = 0 ; x < w ; x++)
88 {
89 dstbits[x] = (srcbits[x / 8] & mask) ? 1 : 0;
90 mask <<= 1;
91 mask |= (mask >> 8);
92 mask &= 0xFF;
93 }
94 dstbits += bitmap->pitch;
95 srcbits += srcpitch;
96 }
97
98 return(bitmap);
99 }
100
101 /*-----------------------------------------------------------------------*/
102 /*
103 Initialize the GUI.
104 */
105 bool SDLGui_Init(SDL_Surface *GUISurface)
106 {
107 mainsurface = GUISurface;
108 /* Load the font graphics: */
109 fontgfx = SDLGui_LoadXBM(font8_width, font8_height, font8_bits);
110 if (fontgfx == NULL)
111 {
112 // TODO panicbug("Could not create font data");
113 // TODO panicbug("ARAnyM GUI will not be available");
114 return false;
115 }
116
117 /* Set font color 0 as transparent */
118 SDL_SetColorKey(fontgfx, SDL_SRCCOLORKEY, 0);
119
120 /* Get the font width and height: */
121 fontwidth = fontgfx->w/16;
122 fontheight = fontgfx->h/16;
123
124 return true;
125 }
126
127
128 /*-----------------------------------------------------------------------*/
129 /*
130 Uninitialize the GUI.
131 */
132 int SDLGui_UnInit()
133 {
134 if (fontgfx)
135 {
136 SDL_FreeSurface(fontgfx);
137 fontgfx = NULL;
138 }
139
140 return 0;
141 }
142
143
144 /*-----------------------------------------------------------------------*/
145 /*
146 Compute real coordinates for a given object.
147 Note: centers dialog on screen.
148 */
149 static void SDLGui_ObjCoord(SGOBJ *dlg, int objnum, SDL_Rect *rect)
150 {
151 rect->x = dlg[objnum].x * fontwidth;
152 rect->y = dlg[objnum].y * fontheight;
153 rect->w = dlg[objnum].w * fontwidth;
154 rect->h = dlg[objnum].h * fontheight;
155
156 rect->x += (sdlscrn->w - (dlg[0].w * fontwidth)) / 2;
157 rect->y += (sdlscrn->h - (dlg[0].h * fontheight)) / 2;
158 }
159
160
161 /*-----------------------------------------------------------------------*/
162 /*
163 Compute real coordinates for a given object.
164 This one takes borders into account and give coordinates as seen by user
165 */
166 void SDLGui_ObjFullCoord(SGOBJ *dlg, int objnum, SDL_Rect *coord)
167 {
168 SDLGui_ObjCoord(dlg, objnum, coord);
169
170 switch (dlg[objnum].type)
171 {
172 case SGBOX:
173 case SGBUTTON:
174 {
175 // Take border into account
176 int border_size;
177
178 if (dlg[objnum].flags & SG_SELECTABLE)
179 {
180 if (dlg[objnum].flags & SG_DEFAULT)
181 border_size = 4;
182 else
183 border_size = 3;
184 }
185 else
186 {
187 if (dlg[objnum].flags & SG_BACKGROUND)
188 border_size = 6;
189 else
190 border_size = 5;
191 }
192
193 coord->x -= border_size;
194 coord->y -= border_size;
195 coord->w += (border_size * 2);
196 coord->h += (border_size * 2);
197 }
198 break;
199 case SGEDITFIELD:
200 // Allow one more pixel to the right for cursor
201 coord->w += 1;
202 // There is a line below
203 coord->h += 1;
204 break;
205 }
206 }
207
208
209 /*-----------------------------------------------------------------------*/
210 /*
211 Refresh display at given coordinates.
212 Unlike SDL_UpdateRect() this function can eat coords that goes beyond screen
213 boundaries.
214 "rect" will be modified to represent the area actually refreshed.
215 */
216 void SDLGui_UpdateRect(SDL_Rect *rect)
217 {
218 if (rect->x < 0)
219 {
220 rect->w += rect->x;
221 rect->x = 0;
222 }
223 if ((rect->x + rect->w) > sdlscrn->w)
224 rect->w = (sdlscrn->w - rect->x);
225
226 if (rect->y < 0)
227 {
228 rect->h += rect->y;
229 rect->y = 0;
230 }
231 if ((rect->y + rect->h) > sdlscrn->h)
232 rect->h = (sdlscrn->h - rect->y);
233
234 if ((rect->w > 0) && (rect->h > 0))
235 SDL_UpdateRects(sdlscrn, 1, rect);
236 else
237 {
238 rect->x = 0;
239 rect->y = 0;
240 rect->w = 0;
241 rect->h = 0;
242 }
243 }
244
245
246 /*-----------------------------------------------------------------------*/
247 /*
248 Maps an SDL_Color to the screen format.
249 */
250 Uint32 SDLGui_MapColor(SDL_Color *color)
251 {
252 return SDL_MapRGB(sdlscrn->format, color->r, color->g, color->b);
253 }
254
255
256 /*-----------------------------------------------------------------------*/
257 /*
258 Refresh display to reflect an object change.
259 */
260 void SDLGui_RefreshObj(SGOBJ *dlg, int objnum)
261 {
262 SDL_Rect coord;
263
264 SDLGui_ObjFullCoord(dlg, objnum, &coord);
265
266 screenlock();
267 SDLGui_UpdateRect(&coord);
268 screenunlock();
269 }
270
271
272 /*-----------------------------------------------------------------------*/
273 /*
274 Draw a text string.
275 */
276 void SDLGui_Text(int x, int y, const char *txt, SDL_Color *col)
277 {
278 int i;
279 char c;
280 SDL_Rect sr, dr;
281
282 SDL_SetColors(fontgfx, col, 1, 1);
283
284 screenlock();
285 for (i = 0 ; txt[i] != 0 ; i++)
286 {
287 c = txt[i];
288 sr.x = fontwidth * (c % 16);
289 sr.y = fontheight * (c / 16);
290 sr.w = fontwidth;
291 sr.h = fontheight;
292
293 dr.x = x + (fontwidth * i);
294 dr.y = y;
295 dr.w = fontwidth;
296 dr.h = fontheight;
297
298 SDL_BlitSurface(fontgfx, &sr, sdlscrn, &dr);
299 }
300 screenunlock();
301 }
302
303
304 /*-----------------------------------------------------------------------*/
305 /*
306 Draw a dialog text object.
307 */
308 void SDLGui_DrawText(SGOBJ *tdlg, int objnum)
309 {
310 SDL_Rect coord;
311 SDL_Color *textc, *backgroundc;
312
313 if (tdlg[objnum].state & SG_SELECTED)
314 {
315 textc = whitec;
316 backgroundc = darkgreyc;
317 }
318 else if (tdlg[objnum].state & SG_DISABLED)
319 {
320 textc = darkgreyc;
321 backgroundc = greyc;
322 }
323 else
324 {
325 textc = blackc;
326 backgroundc = greyc;
327 }
328
329 SDLGui_ObjCoord(tdlg, objnum, &coord);
330 SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(backgroundc));
331 SDLGui_Text(coord.x, coord.y, tdlg[objnum].txt, textc);
332 }
333
334
335 /*-----------------------------------------------------------------------*/
336 /*
337 Draw an edit field object.
338 */
339 void SDLGui_DrawEditField(SGOBJ *edlg, int objnum)
340 {
341 SDL_Rect coord;
342 SDL_Color *textc;
343
344 if (edlg[objnum].state & SG_DISABLED)
345 textc = darkgreyc;
346 else
347 textc = blackc;
348
349 SDLGui_ObjCoord(edlg, objnum, &coord);
350 coord.w += 1;
351 SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(greyc));
352 SDLGui_Text(coord.x, coord.y, edlg[objnum].txt, textc);
353
354 // Draw a line below.
355 coord.y = coord.y + coord.h;
356 coord.h = 1;
357 SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(darkgreyc));
358 }
359
360
361 /*-----------------------------------------------------------------------*/
362 /*
363 Draw or erase cursor.
364 */
365 void SDLGui_DrawCursor(SGOBJ *dlg, cursor_state *cursor)
366 {
367 if (cursor->object != -1)
368 {
369 SDL_Rect coord;
370 SDL_Color *cursorc;
371
372 SDLGui_DrawEditField(dlg, cursor->object);
373
374 if (cursor->blink_state)
375 cursorc = blackc;
376 else
377 cursorc = greyc;
378
379 SDLGui_ObjCoord(dlg, cursor->object, &coord);
380 coord.x += (cursor->position * fontwidth);
381 coord.w = 1;
382 SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(cursorc));
383
384 SDLGui_RefreshObj(dlg, cursor->object);
385 }
386 }
387
388
389 /*-----------------------------------------------------------------------*/
390 /*
391 Draw a 3D effect around a given rectangle.
392 Rectangle is updated to the full size of the new object.
393 */
394 void SDLGui_Draw3DAround(SDL_Rect *coord, SDL_Color *upleftc, SDL_Color *downrightc, SDL_Color *cornerc, int width)
395 {
396 SDL_Rect rect;
397 int i;
398 Uint32 upleftcol = SDLGui_MapColor(upleftc);
399 Uint32 downrightcol = SDLGui_MapColor(downrightc);
400 Uint32 cornercol = SDLGui_MapColor(cornerc);
401
402 screenlock();
403
404 for ( i = 1 ; i <= width ; i++)
405 {
406 rect.x = coord->x - i;
407 rect.y = coord->y - i;
408 rect.w = coord->w + (i * 2) - 1;
409 rect.h = 1;
410 SDL_FillRect(sdlscrn, &rect, upleftcol);
411
412 rect.x = coord->x - i;
413 rect.y = coord->y - i;
414 rect.w = 1;
415 rect.h = coord->h + (i * 2) - 1;
416 SDL_FillRect(sdlscrn, &rect, upleftcol);
417
418 rect.x = coord->x - i + 1;
419 rect.y = coord->y + coord->h - 1 + i;
420 rect.w = coord->w + (i * 2) - 1;
421 rect.h = 1;
422 SDL_FillRect(sdlscrn, &rect, downrightcol);
423
424 rect.x = coord->x + coord->w - 1 + i;
425 rect.y = coord->y - i + 1;
426 rect.w = 1;
427 rect.h = coord->h + (i * 2) - 1;
428 SDL_FillRect(sdlscrn, &rect, downrightcol);
429
430 rect.x = coord->x + coord->w + i - 1;
431 rect.y = coord->y - i;
432 rect.w = 1;
433 rect.h = 1;
434 SDL_FillRect(sdlscrn, &rect, cornercol);
435
436 rect.x = coord->x - i;
437 rect.y = coord->y + coord->h + i - 1;
438 rect.w = 1;
439 rect.h = 1;
440 SDL_FillRect(sdlscrn, &rect, cornercol);
441 }
442
443 screenunlock();
444
445 coord->x -= width;
446 coord->y -= width;
447 coord->w += (width * 2);
448 coord->h += (width * 2);
449 }
450
451
452 /*-----------------------------------------------------------------------*/
453 /*
454 Draw a colored box around a given rectangle.
455 Rectangle is updated to the full size of the new object.
456 */
457 void SDLGui_DrawBoxAround(SDL_Rect *coord, SDL_Color *color, int width)
458 {
459 SDL_Rect rect;
460 Uint32 col = SDLGui_MapColor(color);
461
462 screenlock();
463
464 rect.x = coord->x - width;
465 rect.y = coord->y - width;
466 rect.w = coord->w + (width * 2);
467 rect.h = width;
468 SDL_FillRect(sdlscrn, &rect, col);
469
470 rect.x = coord->x - width;
471 rect.y = coord->y - width;
472 rect.w = width;
473 rect.h = coord->h + (width * 2);
474 SDL_FillRect(sdlscrn, &rect, col);
475
476 rect.x = coord->x + coord->w;
477 rect.y = coord->y - width;
478 rect.w = width;
479 rect.h = coord->h + (width * 2);
480 SDL_FillRect(sdlscrn, &rect, col);
481
482 rect.x = coord->x - width;
483 rect.y = coord->y + coord->h;
484 rect.w = coord->w + (width * 2);
485 rect.h = width;
486 SDL_FillRect(sdlscrn, &rect, col);
487
488 screenunlock();
489
490 coord->x -= width;
491 coord->y -= width;
492 coord->w += (width * 2);
493 coord->h += (width * 2);
494 }
495
496
497 /*-----------------------------------------------------------------------*/
498 /*
499 Draw a 3D box with given attributes.
500 */
501 void SDLGui_Draw3DBox(SDL_Rect *coord,
502 SDL_Color *backgroundc,
503 SDL_Color *inboxc,
504 SDL_Color *upleftc,
505 SDL_Color *downrightc,
506 SDL_Color *outboxc,
507 int widthbackground,
508 int widthinbox,
509 int width3D1,
510 int width3D2,
511 int widthoutbox)
512 {
513 SDL_Rect rect;
514
515 screenlock();
516
517 // Draw background
518 rect.x = coord->x - widthbackground;
519 rect.y = coord->y - widthbackground;
520 rect.w = coord->w + (widthbackground * 2);
521 rect.h = coord->h + (widthbackground * 2);
522 SDL_FillRect(sdlscrn, &rect, SDLGui_MapColor(backgroundc));
523
524 screenunlock();
525
526 // Update coords
527 coord->x -= widthbackground;
528 coord->y -= widthbackground;
529 coord->w += (widthbackground * 2);
530 coord->h += (widthbackground * 2);
531
532 if (widthinbox > 0)
533 SDLGui_DrawBoxAround(coord, inboxc, widthinbox);
534
535 if (width3D1 > 0)
536 SDLGui_Draw3DAround(coord, upleftc, downrightc, backgroundc, width3D1);
537
538 if (width3D2 > 0)
539 SDLGui_Draw3DAround(coord, downrightc, upleftc, backgroundc, width3D2);
540
541 if (widthoutbox > 0)
542 SDLGui_DrawBoxAround(coord, outboxc, widthoutbox);
543 }
544
545
546 /*-----------------------------------------------------------------------*/
547 /*
548 Draw a dialog box object.
549 */
550 void SDLGui_DrawBox(SGOBJ *bdlg, int objnum)
551 {
552 SDL_Rect coord;
553 SDL_Color *my_blackc;
554 SDL_Color *upleftc, *downrightc;
555
556 SDLGui_ObjCoord(bdlg, objnum, &coord);
557
558 // Modify box drawing according to object state
559 if (bdlg[objnum].state & SG_DISABLED)
560 my_blackc = darkgreyc;
561 else
562 my_blackc = blackc;
563
564 if (bdlg[objnum].state & SG_SELECTED)
565 {
566 upleftc = darkgreyc;
567 downrightc = whitec;
568 }
569 else
570 {
571 upleftc = whitec;
572 downrightc = darkgreyc;
573 }
574
575 // Draw box according to object flags
576 switch (bdlg[objnum].flags & (SG_SELECTABLE | SG_DEFAULT | SG_BACKGROUND))
577 {
578 case (SG_SELECTABLE | SG_DEFAULT | SG_BACKGROUND):
579 case (SG_SELECTABLE | SG_DEFAULT):
580 SDLGui_Draw3DBox(&coord,
581 greyc, NULL, upleftc, downrightc, my_blackc,
582 1, 0, 1, 0, 2);
583 break;
584 case (SG_SELECTABLE | SG_BACKGROUND):
585 case SG_SELECTABLE:
586 SDLGui_Draw3DBox(&coord,
587 greyc, NULL, upleftc, downrightc, my_blackc,
588 1, 0, 1, 0, 1);
589 break;
590 case (SG_DEFAULT | SG_BACKGROUND):
591 case SG_BACKGROUND:
592 SDLGui_Draw3DBox(&coord,
593 greyc, my_blackc, upleftc, downrightc, darkgreyc,
594 0, 2, 3, 0, 1);
595 break;
596 case SG_DEFAULT:
597 case 0:
598 SDLGui_Draw3DBox(&coord,
599 greyc, NULL, upleftc, downrightc, NULL,
600 3, 0, 1, 1, 0);
601 break;
602 }
603 }
604
605
606 /*-----------------------------------------------------------------------*/
607 /*
608 Draw a normal button.
609 */
610 void SDLGui_DrawButton(SGOBJ *bdlg, int objnum)
611 {
612 SDL_Rect coord;
613 int x, y;
614 SDL_Color *textc;
615
616 SDLGui_ObjCoord(bdlg, objnum, &coord);
617
618 x = coord.x + ((coord.w - (strlen(bdlg[objnum].txt) * fontwidth)) / 2);
619 y = coord.y + ((coord.h - fontheight) / 2);
620
621 if (bdlg[objnum].state & SG_SELECTED)
622 {
623 x += 1;
624 y += 1;
625 }
626
627 if (bdlg[objnum].state & SG_DISABLED)
628 textc = darkgreyc;
629 else
630 textc = blackc;
631
632 SDLGui_DrawBox(bdlg, objnum);
633 SDLGui_Text(x, y, bdlg[objnum].txt, textc);
634 }
635
636
637 /*-----------------------------------------------------------------------*/
638 /*
639 Draw a dialog check box object state.
640 */
641 void SDLGui_DrawCheckBoxState(SGOBJ *cdlg, int objnum)
642 {
643 Uint32 grey = SDLGui_MapColor(greyc);
644 SDL_Rect coord;
645 char str[2];
646 SDL_Color *textc;
647
648 SDLGui_ObjCoord(cdlg, objnum, &coord);
649
650 if (cdlg[objnum].flags & SG_RADIO)
651 {
652 if (cdlg[objnum].state & SG_SELECTED)
653 str[0]=SGCHECKBOX_RADIO_SELECTED;
654 else
655 str[0]=SGCHECKBOX_RADIO_NORMAL;
656 }
657 else
658 {
659 if (cdlg[objnum].state & SG_SELECTED)
660 str[0]=SGCHECKBOX_SELECTED;
661 else
662 str[0]=SGCHECKBOX_NORMAL;
663 }
664
665 if (cdlg[objnum].state & SG_DISABLED)
666 textc = darkgreyc;
667 else
668 textc = blackc;
669
670 str[1]='\0';
671
672 coord.w = fontwidth;
673 coord.h = fontheight;
674
675 if (cdlg[objnum].flags & SG_BUTTON_RIGHT)
676 coord.x += ((strlen(cdlg[objnum].txt) + 1) * fontwidth);
677
678 SDL_FillRect(sdlscrn, &coord, grey);
679 SDLGui_Text(coord.x, coord.y, str, textc);
680 }
681
682
683 /*-----------------------------------------------------------------------*/
684 /*
685 Draw a dialog check box object.
686 */
687 void SDLGui_DrawCheckBox(SGOBJ *cdlg, int objnum)
688 {
689 SDL_Rect coord;
690 SDL_Color *textc;
691
692 SDLGui_ObjCoord(cdlg, objnum, &coord);
693
694 if (!(cdlg[objnum].flags&SG_BUTTON_RIGHT))
695 coord.x += (fontwidth * 2);
696
697 if (cdlg[objnum].state & SG_DISABLED)
698 textc = darkgreyc;
699 else
700 textc = blackc;
701
702 SDLGui_Text(coord.x, coord.y, cdlg[objnum].txt, textc);
703 SDLGui_DrawCheckBoxState(cdlg, objnum);
704 }
705
706
707 /*-----------------------------------------------------------------------*/
708 /*
709 Draw a dialog popup button object.
710 */
711 void SDLGui_DrawPopupButton(SGOBJ *pdlg, int objnum)
712 {
713 SDL_Rect coord;
714 const char *downstr = "\x02";
715 SDL_Color *textc;
716
717 if (pdlg[objnum].state & SG_DISABLED)
718 textc = darkgreyc;
719 else
720 textc = blackc;
721
722 SDLGui_DrawBox(pdlg, objnum);
723
724 SDLGui_ObjCoord(pdlg, objnum, &coord);
725
726 SDLGui_Text(coord.x, coord.y, pdlg[objnum].txt, textc);
727 SDLGui_Text(coord.x+coord.w-fontwidth, coord.y, downstr, textc);
728 }
729
730
731 /*-----------------------------------------------------------------------*/
732 /*
733 Draw an object.
734 */
735 void SDLGui_DrawObject(SGOBJ *dlg, int objnum)
736 {
737 switch (dlg[objnum].type)
738 {
739 case SGBOX:
740 SDLGui_DrawBox(dlg, objnum);
741 break;
742 case SGTEXT:
743 SDLGui_DrawText(dlg, objnum);
744 break;
745 case SGEDITFIELD:
746 SDLGui_DrawEditField(dlg, objnum);
747 break;
748 case SGBUTTON:
749 SDLGui_DrawButton(dlg, objnum);
750 break;
751 case SGCHECKBOX:
752 SDLGui_DrawCheckBox(dlg, objnum);
753 break;
754 case SGPOPUP:
755 SDLGui_DrawPopupButton(dlg, objnum);
756 break;
757 }
758 }
759
760
761 /*-----------------------------------------------------------------------*/
762 /*
763 Draw a whole dialog.
764 */
765 void SDLGui_DrawDialog(SGOBJ *dlg)
766 {
767 int i;
768
769 // Store dialog coordinates
770 SDLGui_ObjFullCoord(dlg, 0, &DialogRect);
771
772 for (i = 0 ; dlg[i].type != -1 ; i++)
773 {
774 if (dlg[i].state & SG_HIDDEN) continue;
775 SDLGui_DrawObject(dlg, i);
776 }
777 SDLGui_RefreshObj(dlg, 0);
778 }
779
780
781 /*-----------------------------------------------------------------------*/
782 /*
783 Search default object in a dialog.
784 */
785 int SDLGui_FindDefaultObj(SGOBJ *dlg)
786 {
787 int i = 0;
788
789 while (dlg[i].type != -1)
790 {
791 if (dlg[i].flags & SG_DEFAULT)
792 return i;
793 i++;
794 }
795
796 return -1;
797 }
798
799
800 /*-----------------------------------------------------------------------*/
801 /*
802 Search an object at given coordinates.
803 */
804 int SDLGui_FindObj(SGOBJ *dlg, int fx, int fy)
805 {
806 SDL_Rect coord;
807 int end, i;
808 int ob = -1;
809
810 // Search end object in dialog
811 i = 0;
812 while (dlg[i++].type != -1);
813 end = i;
814
815 // Now check each object
816 for (i = end-1 ; i >= 0 ; i--)
817 {
818 SDLGui_ObjFullCoord(dlg, i, &coord);
819
820 if(fx >= coord.x &&
821 fy >= coord.y &&
822 fx < (coord.x + coord.w) &&
823 fy < (coord.y + coord.h))
824 {
825 if (dlg[i].state & (SG_HIDDEN | SG_DISABLED)) continue;
826 ob = i;
827 break;
828 }
829 }
830
831 return ob;
832 }
833
834
835 /*-----------------------------------------------------------------------*/
836 /*
837 A radio object has been selected. Let's deselect any other in his group.
838 */
839 void SDLGui_SelectRadioObject(SGOBJ *dlg, int clicked_obj)
840 {
841 int obj;
842
843 // Find first radio object in this group
844 obj = clicked_obj;
845 while (dlg[--obj].flags & SG_RADIO);
846
847 // Update state
848 while (dlg[++obj].flags & SG_RADIO)
849 {
850 // This code scan every object in the group. This allows to solve cases
851 // where multiple objects where selected in the group by clicking one.
852 if ((obj != clicked_obj) && (dlg[obj].state & SG_SELECTED))
853 {
854 // Deselect this radio button
855 dlg[obj].state &= ~SG_SELECTED;
856 SDLGui_DrawObject(dlg, obj);
857 SDLGui_RefreshObj(dlg, obj);
858 }
859 }
860 }
861
862
863 /*-----------------------------------------------------------------------*/
864 /*
865 Update clicked object state depending on given mouse coordinates.
866 Returns true if the mouse is over the object, false otherwise.
867 */
868 bool SDLGui_UpdateObjState(SGOBJ *dlg, int clicked_obj, int original_state,
869 int x, int y)
870 {
871 int obj;
872
873 obj = SDLGui_FindObj(dlg, x, y);
874
875 // Special case : user clicked on an already selected radio object
876 // do not modify its state.
877 // We handle it here because it allows to exit if the object is SG_EXIT or
878 // SG_TOUCHEXIT without any additional test.
879 if ((dlg[clicked_obj].flags & SG_RADIO) && (original_state & SG_SELECTED))
880 return (obj == clicked_obj);
881
882 if (((obj != clicked_obj) &&
883 (dlg[clicked_obj].state != original_state)) ||
884 ((obj == clicked_obj) &&
885 (dlg[clicked_obj].state == original_state)))
886 {
887 if (dlg[clicked_obj].flags & SG_SELECTABLE)
888 {
889 dlg[clicked_obj].state ^= SG_SELECTED;
890 SDLGui_DrawObject(dlg, clicked_obj);
891 SDLGui_RefreshObj(dlg, clicked_obj);
892 }
893 }
894
895 return (obj == clicked_obj);
896 }
897
898
899 /*-----------------------------------------------------------------------*/
900 /*
901 Search edit field in a dialog.
902 */
903 int SDLGui_FindEditField(SGOBJ *dlg, int objnum, int mode)
904 {
905 int i, j;
906
907 switch (mode)
908 {
909 case SG_FIRST_EDITFIELD:
910 i = 0;
911 while (dlg[i].type != -1)
912 {
913 if ((dlg[i].type == SGEDITFIELD) &&
914 ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
915 return i;
916 i++;
917 }
918 break;
919
920 case SG_PREVIOUS_EDITFIELD:
921 i = objnum - 1;
922 while (i >= 0)
923 {
924 if ((dlg[i].type == SGEDITFIELD) &&
925 ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
926 return i;
927 i--;
928 }
929 break;
930
931 case SG_NEXT_EDITFIELD:
932 i = objnum + 1;
933 while (dlg[i].type != -1)
934 {
935 if ((dlg[i].type == SGEDITFIELD) &&
936 ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
937 return i;
938 i++;
939 }
940 break;
941
942 case SG_LAST_EDITFIELD:
943 i = objnum + 1;
944 j = -1;
945 while (dlg[i].type != -1)
946 {
947 if ((dlg[i].type == SGEDITFIELD) &&
948 ((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
949 j = i;
950 i++;
951 }
952 if (j != -1)
953 return j;
954 break;
955 }
956
957 return objnum;
958 }
959
960
961 /*-----------------------------------------------------------------------*/
962 /*
963 Move cursor to another edit field.
964 */
965 void SDLGui_MoveCursor(SGOBJ *dlg, cursor_state *cursor, int mode)
966 {
967 int new_object;
968
969 new_object = SDLGui_FindEditField(dlg, cursor->object, mode);
970
971 if (new_object != cursor->object)
972 {
973 /* Erase old cursor */
974 cursor->blink_state = false;
975 SDLGui_DrawCursor(dlg, cursor);
976
977 cursor->object = new_object;
978 cursor->position = strlen(dlg[new_object].txt);
979 }
980 else
981 {
982 /* We stay in the same field */
983 /* Move cursor to begin or end of text depending on mode */
984 switch (mode)
985 {
986 case SG_FIRST_EDITFIELD:
987 case SG_PREVIOUS_EDITFIELD:
988 cursor->position = 0;
989 break;
990
991 case SG_NEXT_EDITFIELD:
992 case SG_LAST_EDITFIELD:
993 cursor->position = strlen(dlg[new_object].txt);
994 break;
995 }
996 }
997 }
998
999
1000 /*-----------------------------------------------------------------------*/
1001 /*
1002 Handle mouse clicks on edit fields.
1003 */
1004 void SDLGui_ClickEditField(SGOBJ *dlg, cursor_state *cursor, int clicked_obj, int x)
1005 {
1006 SDL_Rect coord;
1007 int i, j;
1008
1009 /* Erase old cursor */
1010 cursor->blink_state = false;
1011 SDLGui_DrawCursor(dlg, cursor);
1012
1013 SDLGui_ObjFullCoord(dlg, clicked_obj, &coord);
1014 i = (x - coord.x + (fontwidth / 2)) / fontwidth;
1015 j = strlen(dlg[clicked_obj].txt);
1016
1017 cursor->object = clicked_obj;
1018 cursor->position = MIN(i, j);
1019 cursor->blink_state = true;
1020 cursor->blink_counter = 0;
1021 SDLGui_DrawCursor(dlg, cursor);
1022 }
1023
1024
1025 /*-----------------------------------------------------------------------*/
1026 /*
1027 Handle mouse clicks.
1028 */
1029 int SDLGui_MouseClick(SGOBJ *dlg, int fx, int fy, cursor_state *cursor)
1030 {
1031 int clicked_obj;
1032 int return_obj = -1;
1033 int original_state = 0;
1034 int x, y;
1035
1036 clicked_obj = SDLGui_FindObj(dlg, fx, fy);
1037
1038 if (clicked_obj >= 0)
1039 {
1040 original_state = dlg[clicked_obj].state;
1041 SDLGui_UpdateObjState(dlg, clicked_obj, original_state, fx, fy);
1042
1043 if (dlg[clicked_obj].flags & SG_TOUCHEXIT)
1044 {
1045 return_obj = clicked_obj;
1046 clicked_obj = -1;
1047 }
1048 }
1049
1050 while (clicked_obj >= 0)
1051 {
1052 SDL_Event evnt;
1053 // SDL_PumpEvents() - not necessary, the main check_event thread calls it
1054 if (SDL_PeepEvents(&evnt, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_USEREVENT)))
1055 {
1056 switch (evnt.user.code)
1057 {
1058 case SDL_USEREVENT:
1059 // a signal that resolution has changed
1060 // Restore clicked object original state
1061 dlg[clicked_obj].state = original_state;
1062
1063 // re-draw dialog
1064 SDLGui_DrawDialog(dlg);
1065
1066 // Exit from mouse click handling.
1067 clicked_obj = -1;
1068 break;
1069
1070 case SDL_MOUSEBUTTONUP:
1071 x = reinterpret_cast<intptr>(evnt.user.data1);
1072 y = reinterpret_cast<intptr>(evnt.user.data2);
1073 if (SDLGui_UpdateObjState(dlg, clicked_obj, original_state, x, y))
1074 {
1075 // true if mouse button is released over clicked object.
1076 // If applicable, the object has been selected by
1077 // SDLGui_UpdateObjState(). Let's do additional handling here.
1078
1079 // Exit if object is an SG_EXIT one.
1080 if (dlg[clicked_obj].flags & SG_EXIT)
1081 return_obj = clicked_obj;
1082
1083 // If it's a SG_RADIO object, deselect other objects in his group.
1084 if (dlg[clicked_obj].flags & SG_RADIO)
1085 SDLGui_SelectRadioObject(dlg, clicked_obj);
1086
1087 if (dlg[clicked_obj].type == SGEDITFIELD)
1088 SDLGui_ClickEditField(dlg, cursor, clicked_obj, x);
1089 }
1090
1091 // Exit from mouse click handling.
1092 clicked_obj = -1;
1093
1094 break;
1095 }
1096 }
1097 else
1098 {
1099 // No special event occured.
1100 // Update object state according to mouse coordinates.
1101 SDL_GetMouseState(&x, &y);
1102 SDLGui_UpdateObjState(dlg, clicked_obj, original_state, x, y);
1103
1104 // Wait a little to avoid eating CPU.
1105 SDL_Delay(100);
1106 }
1107 }
1108
1109 return return_obj;
1110 }
1111
1112
1113 /*-----------------------------------------------------------------------*/
1114 /*
1115 Handle key press.
1116 */
1117 int SDLGui_KeyPress(SGOBJ *dlg, int keysym, int mod, cursor_state *cursor)
1118 {
1119 int return_obj = -1;
1120 int obj;
1121
1122 if (cursor->object != -1)
1123 {
1124 switch(keysym)
1125 {
1126 case SDLK_RETURN:
1127 case SDLK_KP_ENTER:
1128 break;
1129
1130 case SDLK_BACKSPACE:
1131 if (cursor->position > 0)
1132 {
1133 memmove(&dlg[cursor->object].txt[cursor->position-1],
1134 &dlg[cursor->object].txt[cursor->position],
1135 strlen(&dlg[cursor->object].txt[cursor->position])+1);
1136 cursor->position--;
1137 }
1138 break;
1139
1140 case SDLK_DELETE:
1141 if(cursor->position < (int)strlen(dlg[cursor->object].txt))
1142 {
1143 memmove(&dlg[cursor->object].txt[cursor->position],
1144 &dlg[cursor->object].txt[cursor->position+1],
1145 strlen(&dlg[cursor->object].txt[cursor->position+1])+1);
1146 }
1147 break;
1148
1149 case SDLK_LEFT:
1150 if (cursor->position > 0)
1151 cursor->position--;
1152 break;
1153
1154 case SDLK_RIGHT:
1155 if (cursor->position < (int)strlen(dlg[cursor->object].txt))
1156 cursor->position++;
1157 break;
1158
1159 case SDLK_DOWN:
1160 SDLGui_MoveCursor(dlg, cursor, SG_NEXT_EDITFIELD);
1161 break;
1162
1163 case SDLK_UP:
1164 SDLGui_MoveCursor(dlg, cursor, SG_PREVIOUS_EDITFIELD);
1165 break;
1166
1167 case SDLK_TAB:
1168 if (mod & KMOD_SHIFT)
1169 SDLGui_MoveCursor(dlg, cursor, SG_PREVIOUS_EDITFIELD);
1170 else
1171 SDLGui_MoveCursor(dlg, cursor, SG_NEXT_EDITFIELD);
1172 break;
1173
1174 case SDLK_HOME:
1175 if (mod & KMOD_CTRL)
1176 SDLGui_MoveCursor(dlg, cursor, SG_FIRST_EDITFIELD);
1177 else
1178 cursor->position = 0;
1179 break;
1180
1181 case SDLK_END:
1182 if (mod & KMOD_CTRL)
1183 SDLGui_MoveCursor(dlg, cursor, SG_LAST_EDITFIELD);
1184 else
1185 cursor->position = strlen(dlg[cursor->object].txt);
1186 break;
1187
1188 default:
1189 if ((keysym >= SDLK_KP0) && (keysym <= SDLK_KP9))
1190 {
1191 // map numpad numbers to normal numbers
1192 keysym -= (SDLK_KP0 - SDLK_0);
1193 }
1194 /* If it is a "good" key then insert it into the text field */
1195 if ((keysym >= SDLK_SPACE) && (keysym < SDLK_KP0))
1196 {
1197 if (strlen(dlg[cursor->object].txt) < dlg[cursor->object].w)
1198 {
1199 memmove(&dlg[cursor->object].txt[cursor->position+1],
1200 &dlg[cursor->object].txt[cursor->position],
1201 strlen(&dlg[cursor->object].txt[cursor->position])+1);
1202 if (mod & KMOD_SHIFT)
1203 dlg[cursor->object].txt[cursor->position] = toupper(keysym);
1204 else
1205 dlg[cursor->object].txt[cursor->position] = keysym;
1206 cursor->position += 1;
1207 }
1208 }
1209 break;
1210 }
1211 }
1212
1213 switch(keysym)
1214 {
1215 case SDLK_RETURN:
1216 case SDLK_KP_ENTER:
1217 obj = SDLGui_FindDefaultObj(dlg);
1218 if (obj >= 0)
1219 {
1220 dlg[obj].state ^= SG_SELECTED;
1221 SDLGui_DrawObject(dlg, obj);
1222 SDLGui_RefreshObj(dlg, obj);
1223 if (dlg[obj].flags & (SG_EXIT | SG_TOUCHEXIT))
1224 {
1225 return_obj = obj;
1226 SDL_Delay(300);
1227 }
1228 }
1229 break;
1230 }
1231
1232 // Force cursor display. Should ease text input.
1233 cursor->blink_state = true;
1234 cursor->blink_counter = 0;
1235 // Redraw current edit field...
1236 SDLGui_DrawCursor(dlg, cursor);
1237
1238 return return_obj;
1239 }
1240
1241
1242 /*-----------------------------------------------------------------------*/
1243 /*
1244 Used to update screen while GUI is opened. Return a list of rectangles that
1245 covers the screen without overlaping the current dialog.
1246 */
1247 SDL_Rect *SDLGui_GetFirstBackgroundRect(void)
1248 {
1249 // Reset counter...
1250 BackgroundRectCounter = SG_BCKGND_RECT_BEGIN;
1251 // And returns first rectangle
1252 return SDLGui_GetNextBackgroundRect();
1253 }
1254
1255
1256 /*-----------------------------------------------------------------------*/
1257 /*
1258 Returns next rectangle to be redrawn to update screen or NULL if we reached
1259 the end of the list.
1260 This code is "flying dialog" ready :)
1261 It will need some updating if we implement popup buttons handled by sdlgui,
1262 as the popup could be higher than the root box...
1263 I used some recursivity here to simplify the code.
1264 */
1265 SDL_Rect *SDLGui_GetNextBackgroundRect(void)
1266 {
1267 SDL_Rect *return_rect = NULL;
1268
1269 switch (BackgroundRectCounter)
1270 {
1271 case SG_BCKGND_RECT_END:
1272 // Nothing to do : return_rect is already initialized to NULL.
1273 break;
1274
1275 case SG_BCKGND_RECT_BEGIN:
1276 if (DialogRect.w == 0)
1277 {
1278 // The dialog is not drawn yet...
1279 // Let's redraw the full screen.
1280 BackgroundRect.x = 0;
1281 BackgroundRect.y = 0;
1282 BackgroundRect.w = sdlscrn->w;
1283 BackgroundRect.h = sdlscrn->h;
1284 return_rect = &BackgroundRect;
1285 // We reached the end of the list.
1286 BackgroundRectCounter = SG_BCKGND_RECT_END;
1287 }
1288 else
1289 {
1290 BackgroundRectCounter = SG_BCKGND_RECT_TOP;
1291 return_rect = SDLGui_GetNextBackgroundRect();
1292 }
1293 break;
1294
1295 case SG_BCKGND_RECT_TOP:
1296 BackgroundRectCounter = SG_BCKGND_RECT_LEFT;
1297 if (DialogRect.y > 0)
1298 {
1299 BackgroundRect.x = 0;
1300 BackgroundRect.y = 0;
1301 BackgroundRect.w = sdlscrn->w;
1302 BackgroundRect.h = DialogRect.y;
1303 return_rect = &BackgroundRect;
1304 }
1305 else
1306 return_rect = SDLGui_GetNextBackgroundRect();
1307 break;
1308
1309 case SG_BCKGND_RECT_LEFT:
1310 BackgroundRectCounter = SG_BCKGND_RECT_RIGHT;
1311 if (DialogRect.x > 0)
1312 {
1313 BackgroundRect.x = 0;
1314 BackgroundRect.y = (DialogRect.y > 0) ? DialogRect.y : 0;
1315 BackgroundRect.w = DialogRect.x;
1316 BackgroundRect.h =
1317 ((DialogRect.y + DialogRect.h) < (int)sdlscrn->h) ?
1318 (DialogRect.h + DialogRect.y - BackgroundRect.y) :
1319 (sdlscrn->h - DialogRect.y);
1320 return_rect = &BackgroundRect;
1321 }
1322 else
1323 return_rect = SDLGui_GetNextBackgroundRect();
1324 break;
1325
1326 case SG_BCKGND_RECT_RIGHT:
1327 BackgroundRectCounter = SG_BCKGND_RECT_BOTTOM;
1328 if ((DialogRect.x + DialogRect.w) < (int)sdlscrn->w)
1329 {
1330 BackgroundRect.x = DialogRect.x + DialogRect.w;
1331 BackgroundRect.y = (DialogRect.y > 0) ? DialogRect.y : 0;
1332 BackgroundRect.w = sdlscrn->w - (DialogRect.x + DialogRect.w);
1333 BackgroundRect.h =
1334 ((DialogRect.y + DialogRect.h) < (int)sdlscrn->w) ?
1335 (DialogRect.h + DialogRect.y - BackgroundRect.y) :
1336 (sdlscrn->h - DialogRect.y);
1337 return_rect = &BackgroundRect;
1338 }
1339 else
1340 return_rect = SDLGui_GetNextBackgroundRect();
1341 break;
1342
1343 case SG_BCKGND_RECT_BOTTOM:
1344 BackgroundRectCounter = SG_BCKGND_RECT_END;
1345 if ((DialogRect.y + DialogRect.h) < (int)sdlscrn->h)
1346 {
1347 // Bottom
1348 BackgroundRect.x = 0;
1349 BackgroundRect.y = DialogRect.y + DialogRect.h;
1350 BackgroundRect.w = sdlscrn->w;
1351 BackgroundRect.h = sdlscrn->h - (DialogRect.y + DialogRect.h);
1352 return_rect = &BackgroundRect;
1353 }
1354 else
1355 return_rect = SDLGui_GetNextBackgroundRect();
1356 break;
1357 }
1358
1359 return return_rect;
1360 }
1361
1362 SDL_Event getEvent(SGOBJ *dlg, cursor_state *cursor)
1363 {
1364 int i = 0;
1365 while(1) {
1366 SDL_Event evnt;
1367 // fprintf(stderr, "Debug Before Peep events\n");
1368 if (SDL_PeepEvents(&evnt, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_USEREVENT)))
1369 {
1370 fprintf(stderr, "Debug Peep events %d\n",i++);
1371 SDL_Event e;
1372 switch(evnt.user.code)
1373 {
1374 case SDL_KEYDOWN:
1375 case SDL_KEYUP:
1376 e.type = evnt.user.code;
1377 e.key.keysym.sym = (SDLKey)reinterpret_cast<uintptr>(evnt.user.data1);
1378 e.key.keysym.mod = (SDLMod)reinterpret_cast<uintptr>(evnt.user.data2);
1379 return e;
1380
1381 case SDL_MOUSEBUTTONDOWN:
1382 case SDL_MOUSEBUTTONUP:
1383 e.type = evnt.user.code;
1384 if (evnt.user.code == SDL_MOUSEBUTTONDOWN)
1385 fprintf(stderr, "Debug mouse down\n");
1386 else
1387 fprintf(stderr, "Debug mouse down\n");
1388 e.button.x = reinterpret_cast<intptr>(evnt.user.data1);
1389 e.button.y = reinterpret_cast<intptr>(evnt.user.data2);
1390 return e;
1391
1392 case SDL_USEREVENT:
1393 // a signal that resolution has changed
1394 if (dlg != NULL)
1395 SDLGui_DrawDialog(dlg); // re-draw dialog
1396 break;
1397 }
1398 }
1399 else
1400 {
1401 // No special event occured.
1402 // Wait a little to avoid eating CPU.
1403 SDL_Delay(50);
1404 if (cursor != NULL) {
1405 cursor->blink_counter++;
1406 if (cursor->blink_counter >= 10) {
1407 cursor->blink_counter = 0;
1408 cursor->blink_state = !cursor->blink_state;
1409 if (dlg != NULL)
1410 SDLGui_DrawCursor(dlg, cursor);
1411 }
1412 }
1413 }
1414 }
1415 }
1416
1417 /*-----------------------------------------------------------------------*/
1418 /*
1419 Show and process a dialog. Returns the button number that has been
1420 pressed. Does NOT handle SDL_QUIT - you must handle it before you
1421 pass the input event to the SDL GUI.
1422 */
1423 int SDLGui_DoDialog(SGOBJ *dlg)
1424 {
1425 int return_obj = -1;
1426 int obj;
1427 int x, y;
1428 // int keysym, mod;
1429 cursor_state cursor;
1430
1431 // Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here
1432 bool stillPressed = (SDL_GetMouseState(&x, &y) & SDL_BUTTON(1));
1433 obj = SDLGui_FindObj(dlg, x, y);
1434 if (stillPressed && (obj >= 0) && (dlg[obj].flags & SG_TOUCHEXIT))
1435 {
1436 // Mouse button is pressed over a TOUCHEXIT Button
1437 // Toogle its state before drawing anything (it has been deselected before).
1438 dlg[obj].state ^= SG_SELECTED;
1439
1440 return_obj = obj;
1441 }
1442
1443 cursor.object = SDLGui_FindEditField(dlg, -1, SG_FIRST_EDITFIELD);
1444 cursor.position = (cursor.object != -1) ? strlen(dlg[cursor.object].txt) : 0;
1445 cursor.blink_counter = 0;
1446 cursor.blink_state = true;
1447
1448 SDLGui_DrawDialog(dlg);
1449
1450 /* The main loop */
1451 while (return_obj < 0)
1452 {
1453 fprintf(stderr, "Debug SDL main loop\n");
1454 SDL_Event evnt = getEvent(dlg, &cursor);
1455 fprintf(stderr, "Debug SDL main loop got event\n");
1456 switch(evnt.type)
1457 {
1458 case SDL_KEYDOWN:
1459 return_obj = SDLGui_KeyPress(dlg, evnt.key.keysym.sym, evnt.key.keysym.mod, &cursor);
1460 break;
1461
1462 case SDL_MOUSEBUTTONDOWN:
1463 return_obj = SDLGui_MouseClick(dlg, evnt.button.x, evnt.button.y, &cursor);
1464 break;
1465 }
1466 }
1467 fprintf(stderr, "Debug SDL main loop finished\n");
1468 if (dlg[return_obj].type == SGBUTTON)
1469 {
1470 // Deselect button...
1471 // BUG: This should be caller responsibility
1472 dlg[return_obj].state ^= SG_SELECTED;
1473 }
1474
1475 return return_obj;
1476 }