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