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