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 "txt_io.h"
26 #include "txt_widget.h"
27 #include "txt_gui.h"
28 #include "txt_desktop.h"
29 
30 typedef struct
31 {
32     char *signal_name;
33     TxtWidgetSignalFunc func;
34     void *user_data;
35 } txt_callback_t;
36 
37 struct txt_callback_table_s
38 {
39     int refcount;
40     txt_callback_t *callbacks;
41     int num_callbacks;
42 };
43 
TXT_NewCallbackTable(void)44 txt_callback_table_t *TXT_NewCallbackTable(void)
45 {
46     txt_callback_table_t *table;
47 
48     table = malloc(sizeof(txt_callback_table_t));
49     table->callbacks = NULL;
50     table->num_callbacks = 0;
51     table->refcount = 1;
52 
53     return table;
54 }
55 
TXT_RefCallbackTable(txt_callback_table_t * table)56 void TXT_RefCallbackTable(txt_callback_table_t *table)
57 {
58     ++table->refcount;
59 }
60 
TXT_UnrefCallbackTable(txt_callback_table_t * table)61 void TXT_UnrefCallbackTable(txt_callback_table_t *table)
62 {
63     int i;
64 
65     --table->refcount;
66 
67     if (table->refcount == 0)
68     {
69         // No more references to this table
70 
71         for (i=0; i<table->num_callbacks; ++i)
72         {
73             free(table->callbacks[i].signal_name);
74         }
75 
76         free(table->callbacks);
77         free(table);
78     }
79 }
80 
TXT_InitWidget(TXT_UNCAST_ARG (widget),txt_widget_class_t * widget_class)81 void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class)
82 {
83     TXT_CAST_ARG(txt_widget_t, widget);
84 
85     widget->widget_class = widget_class;
86     widget->callback_table = TXT_NewCallbackTable();
87     widget->parent = NULL;
88 
89     // Not focused until we hear otherwise.
90 
91     widget->focused = 0;
92 
93     // Visible by default.
94 
95     widget->visible = 1;
96 
97     // Align left by default
98 
99     widget->align = TXT_HORIZ_LEFT;
100 }
101 
TXT_SignalConnect(TXT_UNCAST_ARG (widget),const char * signal_name,TxtWidgetSignalFunc func,void * user_data)102 void TXT_SignalConnect(TXT_UNCAST_ARG(widget),
103                        const char *signal_name,
104                        TxtWidgetSignalFunc func,
105                        void *user_data)
106 {
107     TXT_CAST_ARG(txt_widget_t, widget);
108     txt_callback_table_t *table;
109     txt_callback_t *callback;
110 
111     table = widget->callback_table;
112 
113     // Add a new callback to the table
114 
115     table->callbacks
116             = realloc(table->callbacks,
117                       sizeof(txt_callback_t) * (table->num_callbacks + 1));
118     callback = &table->callbacks[table->num_callbacks];
119     ++table->num_callbacks;
120 
121     callback->signal_name = strdup(signal_name);
122     callback->func = func;
123     callback->user_data = user_data;
124 }
125 
TXT_EmitSignal(TXT_UNCAST_ARG (widget),const char * signal_name)126 void TXT_EmitSignal(TXT_UNCAST_ARG(widget), const char *signal_name)
127 {
128     TXT_CAST_ARG(txt_widget_t, widget);
129     txt_callback_table_t *table;
130     int i;
131 
132     table = widget->callback_table;
133 
134     // Don't destroy the table while we're searching through it
135     // (one of the callbacks may destroy this window)
136 
137     TXT_RefCallbackTable(table);
138 
139     // Search the table for all callbacks with this name and invoke
140     // the functions.
141 
142     for (i=0; i<table->num_callbacks; ++i)
143     {
144         if (!strcmp(table->callbacks[i].signal_name, signal_name))
145         {
146             table->callbacks[i].func(widget, table->callbacks[i].user_data);
147         }
148     }
149 
150     // Finished using the table
151 
152     TXT_UnrefCallbackTable(table);
153 }
154 
TXT_CalcWidgetSize(TXT_UNCAST_ARG (widget))155 void TXT_CalcWidgetSize(TXT_UNCAST_ARG(widget))
156 {
157     TXT_CAST_ARG(txt_widget_t, widget);
158 
159     widget->widget_class->size_calc(widget);
160 }
161 
TXT_DrawWidget(TXT_UNCAST_ARG (widget))162 void TXT_DrawWidget(TXT_UNCAST_ARG(widget))
163 {
164     TXT_CAST_ARG(txt_widget_t, widget);
165     txt_saved_colors_t colors;
166 
167     // The drawing function might change the fg/bg colors,
168     // so make sure we restore them after it's done.
169 
170     TXT_SaveColors(&colors);
171 
172     // For convenience...
173 
174     TXT_GotoXY(widget->x, widget->y);
175 
176     // Call drawer method
177 
178     widget->widget_class->drawer(widget);
179 
180     TXT_RestoreColors(&colors);
181 }
182 
TXT_DestroyWidget(TXT_UNCAST_ARG (widget))183 void TXT_DestroyWidget(TXT_UNCAST_ARG(widget))
184 {
185     TXT_CAST_ARG(txt_widget_t, widget);
186 
187     widget->widget_class->destructor(widget);
188     TXT_UnrefCallbackTable(widget->callback_table);
189     free(widget);
190 }
191 
TXT_WidgetKeyPress(TXT_UNCAST_ARG (widget),int key)192 int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key)
193 {
194     TXT_CAST_ARG(txt_widget_t, widget);
195 
196     if (widget->widget_class->key_press != NULL)
197     {
198         return widget->widget_class->key_press(widget, key);
199     }
200 
201     return 0;
202 }
203 
TXT_SetWidgetFocus(TXT_UNCAST_ARG (widget),int focused)204 void TXT_SetWidgetFocus(TXT_UNCAST_ARG(widget), int focused)
205 {
206     TXT_CAST_ARG(txt_widget_t, widget);
207 
208     if (widget == NULL)
209     {
210         return;
211     }
212 
213     if (widget->focused != focused)
214     {
215         widget->focused = focused;
216 
217         if (widget->widget_class->focus_change != NULL)
218         {
219             widget->widget_class->focus_change(widget, focused);
220         }
221     }
222 }
223 
TXT_SetWidgetAlign(TXT_UNCAST_ARG (widget),txt_horiz_align_t horiz_align)224 void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align)
225 {
226     TXT_CAST_ARG(txt_widget_t, widget);
227 
228     widget->align = horiz_align;
229 }
230 
TXT_WidgetMousePress(TXT_UNCAST_ARG (widget),int x,int y,int b)231 void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b)
232 {
233     TXT_CAST_ARG(txt_widget_t, widget);
234 
235     if (widget->widget_class->mouse_press != NULL)
236     {
237         widget->widget_class->mouse_press(widget, x, y, b);
238     }
239 }
240 
TXT_LayoutWidget(TXT_UNCAST_ARG (widget))241 void TXT_LayoutWidget(TXT_UNCAST_ARG(widget))
242 {
243     TXT_CAST_ARG(txt_widget_t, widget);
244 
245     if (widget->widget_class->layout != NULL)
246     {
247         widget->widget_class->layout(widget);
248     }
249 }
250 
TXT_AlwaysSelectable(TXT_UNCAST_ARG (widget))251 int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget))
252 {
253     return 1;
254 }
255 
TXT_NeverSelectable(TXT_UNCAST_ARG (widget))256 int TXT_NeverSelectable(TXT_UNCAST_ARG(widget))
257 {
258     return 0;
259 }
260 
TXT_SelectableWidget(TXT_UNCAST_ARG (widget))261 int TXT_SelectableWidget(TXT_UNCAST_ARG(widget))
262 {
263     TXT_CAST_ARG(txt_widget_t, widget);
264 
265     if (widget->widget_class->selectable != NULL)
266     {
267         return widget->widget_class->selectable(widget);
268     }
269     else
270     {
271         return 0;
272     }
273 }
274 
TXT_ContainsWidget(TXT_UNCAST_ARG (haystack),TXT_UNCAST_ARG (needle))275 int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle))
276 {
277     TXT_CAST_ARG(txt_widget_t, haystack);
278     TXT_CAST_ARG(txt_widget_t, needle);
279 
280     while (needle != NULL)
281     {
282         if (needle == haystack)
283         {
284             return 1;
285         }
286 
287         needle = needle->parent;
288     }
289 
290     return 0;
291 }
292 
TXT_HoveringOverWidget(TXT_UNCAST_ARG (widget))293 int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget))
294 {
295     TXT_CAST_ARG(txt_widget_t, widget);
296     txt_window_t *active_window;
297     int x, y;
298 
299     // We can only be hovering over widgets in the active window.
300 
301     active_window = TXT_GetActiveWindow();
302 
303     if (active_window == NULL || !TXT_ContainsWidget(active_window, widget))
304     {
305         return 0;
306     }
307 
308     // Is the mouse cursor within the bounds of the widget?
309 
310     TXT_GetMousePosition(&x, &y);
311 
312     return (x >= widget->x && x < widget->x + widget->w
313          && y >= widget->y && y < widget->y + widget->h);
314 }
315 
TXT_SetWidgetBG(TXT_UNCAST_ARG (widget))316 void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget))
317 {
318     TXT_CAST_ARG(txt_widget_t, widget);
319 
320     if (widget->focused)
321     {
322         TXT_BGColor(TXT_COLOR_GREY, 0);
323     }
324     else if (TXT_HoveringOverWidget(widget))
325     {
326         TXT_BGColor(TXT_HOVER_BACKGROUND, 0);
327     }
328     else
329     {
330         // Use normal window background.
331     }
332 }
333 
334