1 /*
2 GUILIB: An example GUI framework library for use with SDL
3 */
4
5 /* This is a C++ class for handling a GUI, and associated widgets */
6
7 #include <stdlib.h>
8
9 #include "GUI.h"
10
11 /* Number of widget elements to allocate at once */
12 #define WIDGET_ARRAYCHUNK 32
13
14
GUI(SDL_Surface * display)15 GUI:: GUI(SDL_Surface *display)
16 {
17 screen = display;
18 numwidgets = 0;
19 maxwidgets = 0;
20 widgets = NULL;
21 }
22
~GUI()23 GUI:: ~GUI()
24 {
25 if ( widgets != NULL ) {
26 for ( int i=0; i<numwidgets; ++i ) {
27 delete widgets[i];
28 }
29 free(widgets);
30 }
31 }
32
33 /* Add a widget to the GUI.
34 The widget will be automatically deleted when the GUI is deleted.
35 */
36 int
AddWidget(GUI_Widget * widget)37 GUI:: AddWidget(GUI_Widget *widget)
38 {
39 int i;
40
41 /* Look for deleted widgets */
42 for ( i=0; i<numwidgets; ++i ) {
43 if ( widgets[i]->Status() == WIDGET_DELETED ) {
44 delete widgets[i];
45 break;
46 }
47 }
48 if ( i == numwidgets ) {
49 /* Expand the widgets array if necessary */
50 if ( numwidgets == maxwidgets ) {
51 GUI_Widget **newarray;
52 int maxarray;
53
54 maxarray = maxwidgets + WIDGET_ARRAYCHUNK;
55 if ( (newarray=(GUI_Widget **)realloc(widgets,
56 maxarray*sizeof(*newarray))) == NULL ) {
57 return(-1);
58 }
59 widgets = newarray;
60 maxwidgets = maxarray;
61 }
62 ++numwidgets;
63 }
64 widgets[i] = widget;
65 widget->SetDisplay(screen);
66 return(0);
67 }
68
69 void
Display(void)70 GUI:: Display(void)
71 {
72 int i;
73
74 for ( i=0; i<numwidgets; ++i ) {
75 if ( widgets[i]->Status() == WIDGET_VISIBLE ) {
76 widgets[i]->Display();
77 }
78 }
79 SDL_UpdateRect(screen, 0, 0, 0, 0);
80 }
81
82 /* Function to handle a GUI status */
83 void
HandleStatus(GUI_status status)84 GUI:: HandleStatus(GUI_status status)
85 {
86 switch (status) {
87 case GUI_QUIT:
88 running = 0;
89 break;
90 case GUI_REDRAW:
91 display = 1;
92 break;
93 default:
94 break;
95 }
96 }
97
98 /* Handle an event, passing it to widgets until they return a status */
99 void
HandleEvent(const SDL_Event * event)100 GUI:: HandleEvent(const SDL_Event *event)
101 {
102 int i;
103 GUI_status status;
104
105 switch (event->type) {
106 /* SDL_QUIT events quit the GUI */
107 case SDL_QUIT:
108 status = GUI_QUIT;
109 break;
110
111 /* Keyboard and mouse events go to widgets */
112 case SDL_KEYDOWN:
113 case SDL_KEYUP:
114 case SDL_MOUSEMOTION:
115 case SDL_MOUSEBUTTONDOWN:
116 case SDL_MOUSEBUTTONUP:
117 /* Go through widgets, topmost first */
118 status = GUI_PASS;
119 for (i=numwidgets-1; (i>=0)&&(status==GUI_PASS); --i) {
120 if ( widgets[i]->Status() == WIDGET_VISIBLE ) {
121 status = widgets[i]->HandleEvent(event);
122 }
123 }
124 break;
125
126 /* Ignore unhandled events */
127 default:
128 status = GUI_PASS;
129 break;
130 }
131 HandleStatus(status);
132 }
133
134 /* Run the GUI.
135 This returns when either a widget requests a quit, the idle
136 function requests a quit, or the SDL window has been closed.
137 */
138 void
Run(GUI_IdleProc idle,int once,int multitaskfriendly)139 GUI:: Run(GUI_IdleProc idle, int once, int multitaskfriendly)
140 {
141 int i;
142 SDL_Event event;
143
144 /* If there's nothing to do, return immediately */
145 if ( (numwidgets == 0) && (idle == NULL) ) {
146 return;
147 }
148
149 running = 1;
150 if ( ! once ) {
151 display = 1;
152 }
153 do {
154 /* Garbage collection */
155 for ( i=0; i<numwidgets; ++i ) {
156 if ( widgets[i]->Status() == WIDGET_DELETED ) {
157 delete widgets[i];
158 for ( int j=i+1; j<numwidgets; ++j ) {
159 widgets[j-1] = widgets[j];
160 }
161 --numwidgets;
162 }
163 }
164
165 /* Display widgets if necessary */
166 if ( display ) {
167 Display();
168 display = 0;
169 }
170
171 ///////////////////////////////////////////////////////////////// Polling is time consuming - instead:
172 if (multitaskfriendly && (idle==NULL))
173 {
174 SDL_WaitEvent(&event);
175 HandleEvent(&event);
176 }
177 else
178 /////////////////////////////////////////////////////////////////
179 /* Handle events, or run idle functions */
180 if ( SDL_PollEvent(&event) )
181 {
182 /* Handle all pending events */
183 do {
184 HandleEvent(&event);
185 } while ( SDL_PollEvent(&event) );
186 }
187 else
188 {
189 if ( idle != NULL )
190 {
191 HandleStatus(idle());
192 }
193 for ( i=numwidgets-1; i>=0; --i ) {
194 HandleStatus(widgets[i]->Idle());
195 }
196 }
197 SDL_Delay(10);
198 } while ( running && ! once );
199 }
200