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_desktop.h"
28 #include "txt_gui.h"
29 #include "txt_main.h"
30 #include "txt_separator.h"
31 #include "txt_window.h"
32
TXT_SetWindowAction(txt_window_t * window,txt_horiz_align_t position,txt_window_action_t * action)33 void TXT_SetWindowAction(txt_window_t *window,
34 txt_horiz_align_t position,
35 txt_window_action_t *action)
36 {
37 if (window->actions[position] != NULL)
38 {
39 TXT_DestroyWidget(window->actions[position]);
40 }
41
42 window->actions[position] = action;
43 }
44
TXT_NewWindow(char * title)45 txt_window_t *TXT_NewWindow(char *title)
46 {
47 int i;
48
49 txt_window_t *win;
50
51 win = malloc(sizeof(txt_window_t));
52
53 TXT_InitTable(&win->table, 1);
54
55 if (title == NULL)
56 {
57 win->title = NULL;
58 }
59 else
60 {
61 win->title = strdup(title);
62 }
63
64 win->x = TXT_SCREEN_W / 2;
65 win->y = TXT_SCREEN_H / 2;
66 win->horiz_align = TXT_HORIZ_CENTER;
67 win->vert_align = TXT_VERT_CENTER;
68 win->key_listener = NULL;
69 win->mouse_listener = NULL;
70
71 TXT_AddWidget(win, TXT_NewSeparator(NULL));
72
73 for (i=0; i<3; ++i)
74 win->actions[i] = NULL;
75
76 TXT_AddDesktopWindow(win);
77
78 // Default actions
79
80 TXT_SetWindowAction(win, TXT_HORIZ_LEFT, TXT_NewWindowEscapeAction(win));
81 TXT_SetWindowAction(win, TXT_HORIZ_RIGHT, TXT_NewWindowSelectAction(win));
82
83 return win;
84 }
85
TXT_CloseWindow(txt_window_t * window)86 void TXT_CloseWindow(txt_window_t *window)
87 {
88 int i;
89
90 TXT_EmitSignal(window, "closed");
91
92 free(window->title);
93
94 // Destroy all actions
95
96 for (i=0; i<3; ++i)
97 {
98 if (window->actions[i] != NULL)
99 {
100 TXT_DestroyWidget(window->actions[i]);
101 }
102 }
103
104 // Destroy table and window
105
106 TXT_DestroyWidget(window);
107
108 TXT_RemoveDesktopWindow(window);
109 }
110
CalcWindowPosition(txt_window_t * window)111 static void CalcWindowPosition(txt_window_t *window)
112 {
113 switch (window->horiz_align)
114 {
115 case TXT_HORIZ_LEFT:
116 window->window_x = window->x;
117 break;
118 case TXT_HORIZ_CENTER:
119 window->window_x = window->x - (window->window_w / 2);
120 break;
121 case TXT_HORIZ_RIGHT:
122 window->window_x = window->x - (window->window_w - 1);
123 break;
124 }
125
126 switch (window->vert_align)
127 {
128 case TXT_VERT_TOP:
129 window->window_y = window->y;
130 break;
131 case TXT_VERT_CENTER:
132 window->window_y = window->y - (window->window_h / 2);
133 break;
134 case TXT_VERT_BOTTOM:
135 window->window_y = window->y - (window->window_h - 1);
136 break;
137 }
138 }
139
LayoutActionArea(txt_window_t * window)140 static void LayoutActionArea(txt_window_t *window)
141 {
142 txt_widget_t *widget;
143
144 // Left action
145
146 if (window->actions[TXT_HORIZ_LEFT] != NULL)
147 {
148 widget = (txt_widget_t *) window->actions[TXT_HORIZ_LEFT];
149
150 TXT_CalcWidgetSize(widget);
151
152 widget->x = window->window_x + 2;
153 widget->y = window->window_y + window->window_h - widget->h - 1;
154 }
155
156 // Draw the center action
157
158 if (window->actions[TXT_HORIZ_CENTER] != NULL)
159 {
160 widget = (txt_widget_t *) window->actions[TXT_HORIZ_CENTER];
161
162 TXT_CalcWidgetSize(widget);
163
164 widget->x = window->window_x + (window->window_w - widget->w - 2) / 2;
165 widget->y = window->window_y + window->window_h - widget->h - 1;
166 }
167
168 // Draw the right action
169
170 if (window->actions[TXT_HORIZ_RIGHT] != NULL)
171 {
172 widget = (txt_widget_t *) window->actions[TXT_HORIZ_RIGHT];
173
174 TXT_CalcWidgetSize(widget);
175
176 widget->x = window->window_x + window->window_w - 2 - widget->w;
177 widget->y = window->window_y + window->window_h - widget->h - 1;
178 }
179 }
180
DrawActionArea(txt_window_t * window)181 static void DrawActionArea(txt_window_t *window)
182 {
183 int i;
184
185 for (i=0; i<3; ++i)
186 {
187 if (window->actions[i] != NULL)
188 {
189 TXT_DrawWidget(window->actions[i], 0);
190 }
191 }
192 }
193
CalcActionAreaSize(txt_window_t * window,unsigned int * w,unsigned int * h)194 static void CalcActionAreaSize(txt_window_t *window,
195 unsigned int *w, unsigned int *h)
196 {
197 txt_widget_t *widget;
198 int i;
199
200 *w = 1;
201 *h = 0;
202
203 // Calculate the width of all the action widgets and use this
204 // to create an overall min. width of the action area
205
206 for (i=0; i<3; ++i)
207 {
208 widget = (txt_widget_t *) window->actions[i];
209
210 if (widget != NULL)
211 {
212 TXT_CalcWidgetSize(widget);
213 *w += widget->w + 1;
214
215 if (widget->h > *h)
216 {
217 *h = widget->h;
218 }
219 }
220 }
221 }
222
223 // Sets size and position of all widgets in a window
224
TXT_LayoutWindow(txt_window_t * window)225 void TXT_LayoutWindow(txt_window_t *window)
226 {
227 txt_widget_t *widgets = (txt_widget_t *) window;
228 unsigned int widgets_w;
229 unsigned int actionarea_w, actionarea_h;
230
231 // Calculate size of table
232
233 TXT_CalcWidgetSize(window);
234
235 // Widgets area: add one character of padding on each side
236 widgets_w = widgets->w + 2;
237
238 // Calculate the size of the action area
239 // Make window wide enough to action area
240
241 CalcActionAreaSize(window, &actionarea_w, &actionarea_h);
242
243 if (actionarea_w > widgets_w)
244 widgets_w = actionarea_w;
245
246 // Set the window size based on widgets_w
247
248 window->window_w = widgets_w + 2;
249 window->window_h = widgets->h + 1;
250
251 // If the window has a title, add an extra two lines
252
253 if (window->title != NULL)
254 {
255 window->window_h += 2;
256 }
257
258 // If the window has an action area, add extra lines
259
260 if (actionarea_h > 0)
261 {
262 window->window_h += actionarea_h + 1;
263 }
264
265 // Use the x,y position as the centerpoint and find the location to
266 // draw the window.
267
268 CalcWindowPosition(window);
269
270 // Set the table size and position
271
272 widgets->w = widgets_w - 2;
273 // widgets->h (already set)
274 widgets->x = window->window_x + 2;
275 widgets->y = window->window_y;
276
277 if (window->title != NULL)
278 {
279 widgets->y += 2;
280 }
281
282 // Layout the table and action area
283
284 LayoutActionArea(window);
285 TXT_LayoutWidget(widgets);
286 }
287
TXT_DrawWindow(txt_window_t * window,int selected)288 void TXT_DrawWindow(txt_window_t *window, int selected)
289 {
290 txt_widget_t *widgets;
291
292 TXT_LayoutWindow(window);
293
294 // Draw the window
295
296 TXT_DrawWindowFrame(window->title,
297 window->window_x, window->window_y,
298 window->window_w, window->window_h);
299
300 // Draw all widgets
301
302 TXT_DrawWidget(window, selected);
303
304 // Draw an action area, if we have one
305
306 widgets = (txt_widget_t *) window;
307
308 if (widgets->y + widgets->h < window->window_y + window->window_h - 1)
309 {
310 // Separator for action area
311
312 TXT_DrawSeparator(window->window_x, widgets->y + widgets->h,
313 window->window_w);
314
315 // Action area at the window bottom
316
317 DrawActionArea(window);
318 }
319 }
320
TXT_SetWindowPosition(txt_window_t * window,txt_horiz_align_t horiz_align,txt_vert_align_t vert_align,int x,int y)321 void TXT_SetWindowPosition(txt_window_t *window,
322 txt_horiz_align_t horiz_align,
323 txt_vert_align_t vert_align,
324 int x, int y)
325 {
326 window->vert_align = vert_align;
327 window->horiz_align = horiz_align;
328 window->x = x;
329 window->y = y;
330 }
331
MouseButtonPress(txt_window_t * window,int b)332 static void MouseButtonPress(txt_window_t *window, int b)
333 {
334 int x, y;
335 int i;
336 txt_widget_t *widgets;
337 txt_widget_t *widget;
338
339 // Lay out the window, set positions and sizes of all widgets
340
341 TXT_LayoutWindow(window);
342
343 // Get the current mouse position
344
345 TXT_GetMousePosition(&x, &y);
346
347 // Try the mouse button listener
348 // This happens whether it is in the window range or not
349
350 if (window->mouse_listener != NULL)
351 {
352 // Mouse listener can eat button presses
353
354 if (window->mouse_listener(window, x, y, b,
355 window->mouse_listener_data))
356 {
357 return;
358 }
359 }
360
361 // Is it within the table range?
362
363 widgets = (txt_widget_t *) window;
364
365 if (x >= widgets->x && x < (signed) (widgets->x + widgets->w)
366 && y >= widgets->y && y < (signed) (widgets->y + widgets->h))
367 {
368 TXT_WidgetMousePress(window, x, y, b);
369 }
370
371 // Was one of the action area buttons pressed?
372
373 for (i=0; i<3; ++i)
374 {
375 widget = (txt_widget_t *) window->actions[i];
376
377 if (widget != NULL
378 && x >= widget->x && x < (signed) (widget->x + widget->w)
379 && y >= widget->y && y < (signed) (widget->y + widget->h))
380 {
381 TXT_WidgetMousePress(widget, x, y, b);
382 break;
383 }
384 }
385 }
386
TXT_WindowKeyPress(txt_window_t * window,int c)387 void TXT_WindowKeyPress(txt_window_t *window, int c)
388 {
389 int i;
390
391 // Is this a mouse button ?
392
393 if (c >= TXT_MOUSE_BASE && c < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS)
394 {
395 MouseButtonPress(window, c);
396 return;
397 }
398
399 // Try the window key spy
400
401 if (window->key_listener != NULL)
402 {
403 // key listener can eat keys
404
405 if (window->key_listener(window, c, window->key_listener_data))
406 {
407 return;
408 }
409 }
410
411 // Send to the currently selected widget
412
413 if (TXT_WidgetKeyPress(window, c))
414 {
415 return;
416 }
417
418 // Try all of the action buttons
419
420 for (i=0; i<3; ++i)
421 {
422 if (window->actions[i] != NULL
423 && TXT_WidgetKeyPress(window->actions[i], c))
424 {
425 return;
426 }
427 }
428 }
429
TXT_SetKeyListener(txt_window_t * window,TxtWindowKeyPress key_listener,void * user_data)430 void TXT_SetKeyListener(txt_window_t *window, TxtWindowKeyPress key_listener,
431 void *user_data)
432 {
433 window->key_listener = key_listener;
434 window->key_listener_data = user_data;
435 }
436
TXT_SetMouseListener(txt_window_t * window,TxtWindowMousePress mouse_listener,void * user_data)437 void TXT_SetMouseListener(txt_window_t *window,
438 TxtWindowMousePress mouse_listener,
439 void *user_data)
440 {
441 window->mouse_listener = mouse_listener;
442 window->mouse_listener_data = user_data;
443 }
444
445