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