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