1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // Copyright(C) 2006 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 // 02111-1307, USA.
20 //
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "doomkeys.h"
26
27 #include "txt_button.h"
28 #include "txt_dropdown.h"
29 #include "txt_gui.h"
30 #include "txt_io.h"
31 #include "txt_main.h"
32 #include "txt_window.h"
33
34 typedef struct
35 {
36 txt_window_t *window;
37 txt_dropdown_list_t *list;
38 int item;
39 } callback_data_t;
40
41 // Check if the selected value for a list is valid
42
ValidSelection(txt_dropdown_list_t * list)43 static int ValidSelection(txt_dropdown_list_t *list)
44 {
45 return *list->variable >= 0 && *list->variable < list->num_values;
46 }
47
48 // Calculate the Y position for the selector window
49
SelectorWindowY(txt_dropdown_list_t * list)50 static int SelectorWindowY(txt_dropdown_list_t *list)
51 {
52 if (ValidSelection(list))
53 {
54 return list->widget.y - 1 - *list->variable;
55 }
56 else
57 {
58 return list->widget.y - 1 - (list->num_values / 2);
59 }
60 }
61
62 // Called when a button in the selector window is pressed
63
ItemSelected(TXT_UNCAST_ARG (button),TXT_UNCAST_ARG (callback_data))64 static void ItemSelected(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(callback_data))
65 {
66 TXT_CAST_ARG(callback_data_t, callback_data);
67
68 // Set the variable
69
70 *callback_data->list->variable = callback_data->item;
71
72 TXT_EmitSignal(callback_data->list, "changed");
73
74 // Close the window
75
76 TXT_CloseWindow(callback_data->window);
77 }
78
79 // Free callback data when the window is closed
80
FreeCallbackData(TXT_UNCAST_ARG (list),TXT_UNCAST_ARG (callback_data))81 static void FreeCallbackData(TXT_UNCAST_ARG(list),
82 TXT_UNCAST_ARG(callback_data))
83 {
84 TXT_CAST_ARG(callback_data_t, callback_data);
85
86 free(callback_data);
87 }
88
89 // Catch presses of escape and close the window.
90
SelectorWindowListener(txt_window_t * window,int key,void * user_data)91 static int SelectorWindowListener(txt_window_t *window, int key, void *user_data)
92 {
93 if (key == KEY_ESCAPE)
94 {
95 TXT_CloseWindow(window);
96 return 1;
97 }
98
99 return 0;
100 }
101
SelectorMouseListener(txt_window_t * window,int x,int y,int b,void * unused)102 static int SelectorMouseListener(txt_window_t *window, int x, int y, int b,
103 void *unused)
104 {
105 txt_widget_t *win;
106
107 win = (txt_widget_t *) window;
108
109 if (x < win->x || x > win->x + win->w || y < win->y || y > win->y + win->h)
110 {
111 TXT_CloseWindow(window);
112 return 1;
113 }
114
115 return 0;
116 }
117
118 // Open the dropdown list window to select an item
119
OpenSelectorWindow(txt_dropdown_list_t * list)120 static void OpenSelectorWindow(txt_dropdown_list_t *list)
121 {
122 txt_window_t *window;
123 int i;
124
125 // Open a simple window with no title bar or action buttons.
126
127 window = TXT_NewWindow(NULL);
128
129 TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
130 TXT_SetWindowAction(window, TXT_HORIZ_CENTER, NULL);
131 TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
132
133 // Position the window so that the currently selected item appears
134 // over the top of the list widget.
135
136 TXT_SetWindowPosition(window, TXT_HORIZ_LEFT, TXT_VERT_TOP,
137 list->widget.x - 2, SelectorWindowY(list));
138
139 // Add a button to the window for each option in the list.
140
141 for (i=0; i<list->num_values; ++i)
142 {
143 txt_button_t *button;
144 callback_data_t *data;
145
146 button = TXT_NewButton(list->values[i]);
147
148 TXT_AddWidget(window, button);
149
150 // Callback struct
151
152 data = malloc(sizeof(callback_data_t));
153 data->list = list;
154 data->window = window;
155 data->item = i;
156
157 // When the button is pressed, invoke the button press callback
158
159 TXT_SignalConnect(button, "pressed", ItemSelected, data);
160
161 // When the window is closed, free back the callback struct
162
163 TXT_SignalConnect(window, "closed", FreeCallbackData, data);
164
165 // Is this the currently-selected value? If so, select the button
166 // in the window as the default.
167
168 if (i == *list->variable)
169 {
170 TXT_SelectWidget(window, button);
171 }
172 }
173
174 // Catch presses of escape in this window and close it.
175
176 TXT_SetKeyListener(window, SelectorWindowListener, NULL);
177 TXT_SetMouseListener(window, SelectorMouseListener, NULL);
178 }
179
DropdownListWidth(txt_dropdown_list_t * list)180 static int DropdownListWidth(txt_dropdown_list_t *list)
181 {
182 int i;
183 int result;
184
185 // Find the maximum string width
186
187 result = 0;
188
189 for (i=0; i<list->num_values; ++i)
190 {
191 int w = strlen(list->values[i]);
192 if (w > result)
193 {
194 result = w;
195 }
196 }
197
198 return result;
199 }
200
TXT_DropdownListSizeCalc(TXT_UNCAST_ARG (list))201 static void TXT_DropdownListSizeCalc(TXT_UNCAST_ARG(list))
202 {
203 TXT_CAST_ARG(txt_dropdown_list_t, list);
204
205 list->widget.w = DropdownListWidth(list);
206 list->widget.h = 1;
207 }
208
TXT_DropdownListDrawer(TXT_UNCAST_ARG (list))209 static void TXT_DropdownListDrawer(TXT_UNCAST_ARG(list))
210 {
211 TXT_CAST_ARG(txt_dropdown_list_t, list);
212 unsigned int i;
213 const char *str;
214
215 // Set bg/fg text colors.
216
217 TXT_SetWidgetBG(list);
218
219 // Select a string to draw from the list, if the current value is
220 // in range. Otherwise fall back to a default.
221
222 if (ValidSelection(list))
223 {
224 str = list->values[*list->variable];
225 }
226 else
227 {
228 str = "???";
229 }
230
231 // Draw the string and fill to the end with spaces
232
233 TXT_DrawString(str);
234
235 for (i=strlen(str); i<list->widget.w; ++i)
236 {
237 TXT_DrawString(" ");
238 }
239 }
240
TXT_DropdownListDestructor(TXT_UNCAST_ARG (list))241 static void TXT_DropdownListDestructor(TXT_UNCAST_ARG(list))
242 {
243 }
244
TXT_DropdownListKeyPress(TXT_UNCAST_ARG (list),int key)245 static int TXT_DropdownListKeyPress(TXT_UNCAST_ARG(list), int key)
246 {
247 TXT_CAST_ARG(txt_dropdown_list_t, list);
248
249 if (key == KEY_ENTER)
250 {
251 OpenSelectorWindow(list);
252 return 1;
253 }
254
255 return 0;
256 }
257
TXT_DropdownListMousePress(TXT_UNCAST_ARG (list),int x,int y,int b)258 static void TXT_DropdownListMousePress(TXT_UNCAST_ARG(list),
259 int x, int y, int b)
260 {
261 TXT_CAST_ARG(txt_dropdown_list_t, list);
262
263 // Left mouse click does the same as selecting and pressing enter
264
265 if (b == TXT_MOUSE_LEFT)
266 {
267 TXT_DropdownListKeyPress(list, KEY_ENTER);
268 }
269 }
270
271 txt_widget_class_t txt_dropdown_list_class =
272 {
273 TXT_AlwaysSelectable,
274 TXT_DropdownListSizeCalc,
275 TXT_DropdownListDrawer,
276 TXT_DropdownListKeyPress,
277 TXT_DropdownListDestructor,
278 TXT_DropdownListMousePress,
279 NULL,
280 };
281
TXT_NewDropdownList(int * variable,char ** values,int num_values)282 txt_dropdown_list_t *TXT_NewDropdownList(int *variable, char **values,
283 int num_values)
284 {
285 txt_dropdown_list_t *list;
286
287 list = malloc(sizeof(txt_dropdown_list_t));
288
289 TXT_InitWidget(list, &txt_dropdown_list_class);
290 list->variable = variable;
291 list->values = values;
292 list->num_values = num_values;
293
294 return list;
295 }
296
297