widget.h - ltk - GUI toolkit for X11 (WIP)
HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
HTML git clone https://lumidify.org/ltk.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
widget.h (17298B)
---
1 /*
2 * Copyright (c) 2021-2024 lumidify <nobody@lumidify.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /* need to check what happens when registering signal for destroy, but then calling ltk_destroy_widget from
18 that handler - maybe loop if container widget deletes children but they call parent->delete_child again */
19 #ifndef LTK_WIDGET_H
20 #define LTK_WIDGET_H
21
22 /* FIXME: destroy signal for widgets (also window) */
23
24 #include <stddef.h>
25 #include "array.h"
26 #include "event.h"
27 #include "graphics.h"
28 #include "rect.h"
29 #include "util.h"
30
31 struct ltk_widget;
32 struct ltk_window;
33 typedef struct ltk_widget ltk_widget;
34
35 typedef enum {
36 LTK_WIDGET_UNKNOWN = 0,
37 LTK_WIDGET_ANY,
38 LTK_WIDGET_GRID,
39 LTK_WIDGET_BUTTON,
40 LTK_WIDGET_LABEL,
41 LTK_WIDGET_BOX,
42 LTK_WIDGET_MENU,
43 LTK_WIDGET_MENUENTRY,
44 LTK_WIDGET_ENTRY,
45 LTK_WIDGET_IMAGE,
46 LTK_WIDGET_WINDOW,
47 LTK_WIDGET_SCROLLBAR,
48 LTK_WIDGET_CHECKBUTTON,
49 LTK_WIDGET_RADIOBUTTON,
50 LTK_WIDGET_COMBOBOX,
51 LTK_NUM_WIDGETS,
52 } ltk_widget_type;
53
54 typedef enum {
55 LTK_ACTIVATABLE_NORMAL = 1,
56 /* only activatable when "all-activatable"
57 is set to true in the config */
58 LTK_ACTIVATABLE_SPECIAL = 2,
59 LTK_ACTIVATABLE_ALWAYS = 1|2,
60 /* FIXME: redundant or needs better name - is implied by entries in vtable
61 - if there are widgets that have keyboard functions in the vtable but
62 shouldn't have this set, then it's a bad name */
63 LTK_NEEDS_KEYBOARD = 4,
64 LTK_NEEDS_REDRAW = 8,
65 LTK_HOVER_IS_ACTIVE = 16,
66 } ltk_widget_flags;
67
68 /* FIXME: "sticky" is maybe not the correct name anymore */
69 typedef enum {
70 LTK_STICKY_NONE = 0,
71 LTK_STICKY_LEFT = 1 << 0,
72 LTK_STICKY_RIGHT = 1 << 1,
73 LTK_STICKY_TOP = 1 << 2,
74 LTK_STICKY_BOTTOM = 1 << 3,
75 LTK_STICKY_SHRINK_WIDTH = 1 << 4,
76 LTK_STICKY_SHRINK_HEIGHT = 1 << 5,
77 LTK_STICKY_PRESERVE_ASPECT_RATIO = 1 << 6,
78 } ltk_sticky_mask;
79
80 typedef enum {
81 LTK_VERTICAL,
82 LTK_HORIZONTAL
83 } ltk_orientation;
84
85 typedef enum {
86 LTK_NORMAL = 0,
87 LTK_HOVER = 1,
88 LTK_PRESSED = 2,
89 LTK_ACTIVE = 4,
90 LTK_HOVERACTIVE = 1 | 4,
91 LTK_FOCUSED = 8,
92 LTK_DISABLED = 16,
93 } ltk_widget_state;
94
95 /* FIXME: need "ltk_register_type" just to get unique integer for type checking */
96
97 typedef struct {
98 union {
99 int i;
100 size_t sz;
101 char c;
102 ltk_widget *widget;
103 char *str;
104 const char *cstr;
105 ltk_key_event *key_event;
106 ltk_button_event *button_event;
107 ltk_scroll_event *scroll_event;
108 ltk_motion_event *motion_event;
109 ltk_surface *surface;
110 void *v;
111 /* FIXME: maybe rewrite the functions to take
112 pointers instead so this doesn't increase
113 the size of the union (thereby increasing
114 the size of every arg in the arglist) */
115 ltk_rect rect;
116 } arg;
117 enum {
118 LTK_TYPE_INT,
119 LTK_TYPE_SIZE_T,
120 LTK_TYPE_CHAR,
121 LTK_TYPE_WIDGET,
122 LTK_TYPE_STRING,
123 LTK_TYPE_CONST_STRING,
124 LTK_TYPE_KEY_EVENT,
125 LTK_TYPE_BUTTON_EVENT,
126 LTK_TYPE_SCROLL_EVENT,
127 LTK_TYPE_MOTION_EVENT,
128 LTK_TYPE_SURFACE,
129 LTK_TYPE_RECT,
130 LTK_TYPE_VOID,
131 LTK_TYPE_VOIDP,
132 } type;
133 } ltk_callback_arg;
134
135 /* FIXME: STRING should be CHARP for consistency */
136 #define LTK_MAKE_ARG_INT(data) ((ltk_callback_arg){.type = LTK_TYPE_INT, .arg = {.i = (data)}})
137 #define LTK_MAKE_ARG_SIZE_T(data) ((ltk_callback_arg){.type = LTK_TYPE_SIZE_T, .arg = {.sz = (data)}})
138 #define LTK_MAKE_ARG_CHAR(data) ((ltk_callback_arg){.type = LTK_TYPE_CHAR, .arg = {.c = (data)}})
139 #define LTK_MAKE_ARG_WIDGET(data) ((ltk_callback_arg){.type = LTK_TYPE_WIDGET, .arg = {.widget = (data)}})
140 #define LTK_MAKE_ARG_STRING(data) ((ltk_callback_arg){.type = LTK_TYPE_STRING, .arg = {.str = (data)}})
141 #define LTK_MAKE_ARG_CONST_STRING(data) ((ltk_callback_arg){.type = LTK_TYPE_CONST_STRING, .arg = {.cstr = (data)}})
142 #define LTK_MAKE_ARG_KEY_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_KEY_EVENT, .arg = {.key_event = (data)}})
143 #define LTK_MAKE_ARG_BUTTON_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_BUTTON_EVENT, .arg = {.button_event = (data)}})
144 #define LTK_MAKE_ARG_SCROLL_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_SCROLL_EVENT, .arg = {.scroll_event = (data)}})
145 #define LTK_MAKE_ARG_MOTION_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_MOTION_EVENT, .arg = {.motion_event = (data)}})
146 #define LTK_MAKE_ARG_SURFACE(data) ((ltk_callback_arg){.type = LTK_TYPE_SURFACE, .arg = {.surface = (data)}})
147 #define LTK_MAKE_ARG_RECT(data) ((ltk_callback_arg){.type = LTK_TYPE_RECT, .arg = {.rect = (data)}})
148 #define LTK_MAKE_ARG_VOIDP(data) ((ltk_callback_arg){.type = LTK_TYPE_VOIDP, .arg = {.v = (data)}})
149
150 #define LTK_ARG_VOID ((ltk_callback_arg){.type = LTK_TYPE_VOID})
151
152 #define LTK_CAST_ARG_INT(carg) (ltk_assert(carg.type == LTK_TYPE_INT), carg.arg.i)
153 #define LTK_CAST_ARG_SIZE_T(carg) (ltk_assert(carg.type == LTK_TYPE_SIZE_T), carg.arg.sz)
154 #define LTK_CAST_ARG_CHAR(carg) (ltk_assert(carg.type == LTK_TYPE_CHAR), carg.arg.c)
155 #define LTK_CAST_ARG_WIDGET(carg) (ltk_assert(carg.type == LTK_TYPE_WIDGET), carg.arg.widget)
156 #define LTK_CAST_ARG_STRING(carg) (ltk_assert(carg.type == LTK_TYPE_STRING), carg.arg.str)
157 #define LTK_CAST_ARG_CONST_STRING(carg) (ltk_assert(carg.type == LTK_TYPE_CONST_STRING), carg.arg.cstr)
158 #define LTK_CAST_ARG_KEY_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_KEY_EVENT), carg.arg.key_event)
159 #define LTK_CAST_ARG_BUTTON_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_BUTTON_EVENT), carg.arg.button_event)
160 #define LTK_CAST_ARG_SCROLL_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_SCROLL_EVENT), carg.arg.scroll_event)
161 #define LTK_CAST_ARG_MOTION_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_MOTION_EVENT), carg.arg.motion_event)
162 #define LTK_CAST_ARG_SURFACE(carg) (ltk_assert(carg.type == LTK_TYPE_SURFACE), carg.arg.surface)
163 #define LTK_CAST_ARG_RECT(carg) (ltk_assert(carg.type == LTK_TYPE_RECT), carg.arg.rect)
164 #define LTK_CAST_ARG_VOIDP(carg) (ltk_assert(carg.type == LTK_TYPE_VOIDP), carg.arg.v)
165
166 #define LTK_GET_ARG_INT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_INT(cargs.args[i]))
167 #define LTK_GET_ARG_SIZE_T(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_SIZE_T(cargs.args[i]))
168 #define LTK_GET_ARG_CHAR(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_CHAR(cargs.args[i]))
169 #define LTK_GET_ARG_WIDGET(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_WIDGET(cargs.args[i]))
170 #define LTK_GET_ARG_STRING(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_STRING(cargs.args[i]))
171 #define LTK_GET_ARG_CONST_STRING(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_CONST_STRING(cargs.args[i]))
172 #define LTK_GET_ARG_KEY_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_KEY_EVENT(cargs.args[i]))
173 #define LTK_GET_ARG_BUTTON_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_BUTTON_EVENT(cargs.args[i]))
174 #define LTK_GET_ARG_SCROLL_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_SCROLL_EVENT(cargs.args[i]))
175 #define LTK_GET_ARG_MOTION_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_MOTION_EVENT(cargs.args[i]))
176 #define LTK_GET_ARG_SURFACE(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_SURFACE(cargs.args[i]))
177 #define LTK_GET_ARG_RECT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_RECT(cargs.args[i]))
178
179 #define LTK_CAST_WIDGET(w) (&(w)->widget)
180 #define LTK_CAST_WINDOW(w) (ltk_assert(w->vtable->type == LTK_WIDGET_WINDOW), (ltk_window *)(w))
181 #define LTK_CAST_LABEL(w) (ltk_assert(w->vtable->type == LTK_WIDGET_LABEL), (ltk_label *)(w))
182 #define LTK_CAST_BUTTON(w) (ltk_assert(w->vtable->type == LTK_WIDGET_BUTTON), (ltk_button *)(w))
183 #define LTK_CAST_GRID(w) (ltk_assert(w->vtable->type == LTK_WIDGET_GRID), (ltk_grid *)(w))
184 #define LTK_CAST_IMAGE_WIDGET(w) (ltk_assert(w->vtable->type == LTK_WIDGET_IMAGE), (ltk_image_widget *)(w))
185 #define LTK_CAST_ENTRY(w) (ltk_assert(w->vtable->type == LTK_WIDGET_ENTRY), (ltk_entry *)(w))
186 #define LTK_CAST_MENU(w) (ltk_assert(w->vtable->type == LTK_WIDGET_MENU), (ltk_menu *)(w))
187 #define LTK_CAST_MENUENTRY(w) (ltk_assert(w->vtable->type == LTK_WIDGET_MENUENTRY), (ltk_menuentry *)(w))
188 #define LTK_CAST_SCROLLBAR(w) (ltk_assert(w->vtable->type == LTK_WIDGET_SCROLLBAR), (ltk_scrollbar *)(w))
189 #define LTK_CAST_BOX(w) (ltk_assert(w->vtable->type == LTK_WIDGET_BOX), (ltk_box *)(w))
190 #define LTK_CAST_CHECKBUTTON(w) (ltk_assert(w->vtable->type == LTK_WIDGET_CHECKBUTTON), (ltk_checkbutton *)(w))
191 #define LTK_CAST_RADIOBUTTON(w) (ltk_assert(w->vtable->type == LTK_WIDGET_RADIOBUTTON), (ltk_radiobutton *)(w))
192 #define LTK_CAST_COMBOBOX(w) (ltk_assert(w->vtable->type == LTK_WIDGET_COMBOBOX), (ltk_combobox *)(w))
193
194 /* FIXME: a bit weird because window never gets some of these signals */
195 #define LTK_WIDGET_SIGNAL_KEY_PRESS 1
196 #define LTK_WIDGET_SIGNAL_KEY_RELEASE 2
197 #define LTK_WIDGET_SIGNAL_MOUSE_PRESS 3
198 #define LTK_WIDGET_SIGNAL_MOUSE_RELEASE 4
199 #define LTK_WIDGET_SIGNAL_MOUSE_SCROLL 5
200 #define LTK_WIDGET_SIGNAL_MOTION_NOTIFY 6
201 #define LTK_WIDGET_SIGNAL_MOUSE_ENTER 7
202 #define LTK_WIDGET_SIGNAL_MOUSE_LEAVE 8
203 #define LTK_WIDGET_SIGNAL_PRESS 9
204 #define LTK_WIDGET_SIGNAL_RELEASE 10
205 /* FIXME: resize is currently triggered in a lot of cases where nothing is really resized */
206 #define LTK_WIDGET_SIGNAL_RESIZE 11
207 #define LTK_WIDGET_SIGNAL_HIDE 12
208 #define LTK_WIDGET_SIGNAL_DRAW 13
209 #define LTK_WIDGET_SIGNAL_CHANGE_STATE 14
210 /* The return value for this is ignored, i.e.
211 the widget destroy function is always called.
212 Also, it doesn't receive the 'shallow' argument
213 that the widget method receives. */
214 #define LTK_WIDGET_SIGNAL_DESTROY 15
215 #define LTK_WIDGET_SIGNAL_INVALID 16
216
217 typedef struct {
218 ltk_callback_arg *args;
219 size_t num;
220 } ltk_callback_arglist;
221
222 #define LTK_EMPTY_ARGLIST ((ltk_callback_arglist){NULL, 0})
223
224 typedef int (*ltk_signal_callback)(ltk_widget *widget, ltk_callback_arglist args, ltk_callback_arg data);
225 typedef struct {
226 ltk_signal_callback callback;
227 ltk_callback_arg data;
228 int type;
229 } ltk_signal_callback_info;
230
231 int ltk_widget_register_signal_handler(ltk_widget *widget, int type, ltk_signal_callback callback, ltk_callback_arg data);
232 int ltk_widget_emit_signal(ltk_widget *widget, int type, ltk_callback_arglist args);
233 size_t ltk_widget_remove_signal_handler_by_type(ltk_widget *widget, int type);
234 size_t ltk_widget_remove_signal_handler_by_callback(ltk_widget *widget, ltk_signal_callback callback);
235 size_t ltk_widget_remove_signal_handler_by_info(
236 ltk_widget *widget,
237 int (*filter_func)(ltk_signal_callback_info *to_check, ltk_signal_callback_info *info),
238 ltk_signal_callback_info *info
239 );
240 void ltk_widget_remove_all_signal_handlers(ltk_widget *widget);
241 int ltk_widget_register_type(void);
242
243 LTK_ARRAY_INIT_STRUCT_DECL(signal, ltk_signal_callback_info)
244
245 struct ltk_widget {
246 struct ltk_window *window;
247 struct ltk_widget *parent;
248
249 struct ltk_widget_vtable *vtable;
250
251 /* FIXME: crect and lrect are a bit weird still */
252 /* FIXME: especially the relative positioning is really weird for
253 popups because they're positioned globally but still have a
254 parent-child relationship - weird things can probably happen */
255 /* both rects relative to parent (except for popups) */
256 /* collision rect is only part that is actually shown and used for
257 collision with mouse (but may still not be drawn if hidden by
258 something else) - e.g. in a box with scrolling, a widget that
259 is half cut off by a side of the box will have the logical rect
260 going past the side of the box, but the collision rect will only
261 be the part inside the box */
262 ltk_rect crect; /* collision rect */
263 ltk_rect lrect; /* logical rect */
264 unsigned int ideal_w;
265 unsigned int ideal_h;
266 unsigned int last_dpi;
267
268 /* maybe mask to determine quickly which callbacks are included?
269 default signals only allowed to have one callback? */
270 /* could maybe have just uint32_t mask so at least the lower signals
271 can be easily checked */
272 ltk_array(signal) *signal_cbs;
273
274 ltk_widget_state state;
275 /* FIXME: store this in grid/box - for row_span, column_span the other cells could be marked with "not top left cell of widget" so they can be skipped */
276 ltk_sticky_mask sticky;
277 unsigned short row;
278 unsigned short column;
279 unsigned short row_span;
280 unsigned short column_span;
281 /* ALSO NEED SIGNALS LIKE ADD-TEXT (called *before* text is inserted to check validity) - these would need argument
282 FIGURE OUT HOW TO DO KEY MAPPINGS - should reuse parts of builtin mapping handling
283 -> maybe something like tk
284 -> or maybe just say everyone needs to override event handler? but makes simple stuff more difficult
285 -> also need "global" mappings/key event handler for global shortcuts */
286 /* needed to properly handle handle local coordinates since
287 popups are positioned globally instead of locally */
288 char popup;
289 char dirty;
290 char hidden;
291 char vtable_copied;
292 };
293
294 typedef struct ltk_widget_vtable {
295 int (*key_press)(struct ltk_widget *, ltk_key_event *);
296 int (*key_release)(struct ltk_widget *, ltk_key_event *);
297 /* press/release also receive double/triple-click/release */
298 int (*mouse_press)(struct ltk_widget *, ltk_button_event *);
299 int (*mouse_release)(struct ltk_widget *, ltk_button_event *);
300 int (*mouse_scroll)(struct ltk_widget *, ltk_scroll_event *);
301 int (*motion_notify)(struct ltk_widget *, ltk_motion_event *);
302 int (*mouse_leave)(struct ltk_widget *, ltk_motion_event *);
303 int (*mouse_enter)(struct ltk_widget *, ltk_motion_event *);
304 int (*press)(struct ltk_widget *);
305 int (*release)(struct ltk_widget *);
306 void (*cmd_return)(struct ltk_widget *self, char *text, size_t len);
307
308 /* This is called when the DPI changes. It must not call child_size_change on
309 the parent or do any actual resizing (only ideal_w and ideal_h should be set),
310 but it should call ltk_widget_recalc_ideal_size on any child widgets. */
311 /* When a widget is added to a container, the container should call
312 ltk_widget_recalc_ideal_size on the widget in case the DPI changed. */
313 void (*recalc_ideal_size)(struct ltk_widget *);
314 void (*resize)(struct ltk_widget *);
315 void (*hide)(struct ltk_widget *);
316 /* draw_surface: surface to draw it on
317 x, y: position of logical rectangle on surface
318 clip: clipping rectangle, relative to logical rectangle */
319 void (*draw)(struct ltk_widget *self, ltk_surface *draw_surface, int x, int y, ltk_rect clip);
320 void (*change_state)(struct ltk_widget *, ltk_widget_state);
321 void (*destroy)(struct ltk_widget *, int);
322
323 /* rect is in self's coordinate system */
324 struct ltk_widget *(*nearest_child)(struct ltk_widget *self, ltk_rect rect);
325 struct ltk_widget *(*nearest_child_left)(struct ltk_widget *self, ltk_widget *widget);
326 struct ltk_widget *(*nearest_child_right)(struct ltk_widget *self, ltk_widget *widget);
327 struct ltk_widget *(*nearest_child_above)(struct ltk_widget *self, ltk_widget *widget);
328 struct ltk_widget *(*nearest_child_below)(struct ltk_widget *self, ltk_widget *widget);
329 struct ltk_widget *(*next_child)(struct ltk_widget *self, ltk_widget *child);
330 struct ltk_widget *(*prev_child)(struct ltk_widget *self, ltk_widget *child);
331 struct ltk_widget *(*first_child)(struct ltk_widget *self);
332 struct ltk_widget *(*last_child)(struct ltk_widget *self);
333
334 /* This is called when the ideal size of a child is changed (e.g. text is
335 added to a text entry). */
336 void (*child_size_change)(struct ltk_widget *, struct ltk_widget *);
337 int (*remove_child)(struct ltk_widget *, struct ltk_widget *);
338 /* x and y relative to widget's lrect! */
339 struct ltk_widget *(*get_child_at_pos)(struct ltk_widget *, int x, int y);
340 /* r is in self's coordinate system */
341 void (*ensure_rect_shown)(struct ltk_widget *self, ltk_rect r);
342
343 ltk_widget_type type;
344 ltk_widget_flags flags;
345 int invalid_signal;
346 } ltk_widget_vtable;
347
348 void ltk_widget_hide(ltk_widget *widget);
349 int ltk_widget_destroy(ltk_widget *widget, int shallow);
350 void ltk_fill_widget_defaults(
351 ltk_widget *widget, struct ltk_window *window,
352 struct ltk_widget_vtable *vtable, int w, int h
353 );
354 void ltk_widget_change_state(ltk_widget *widget, ltk_widget_state old_state);
355 void ltk_widget_resize(ltk_widget *widget);
356 void ltk_widget_draw(ltk_widget *widget, ltk_surface *draw_surf, int x, int y, ltk_rect clip_rect);
357 /* FIXME: layout widgets need to recalculate ideal size when children change! */
358 void ltk_widget_get_ideal_size(ltk_widget *widget, unsigned int *ideal_w_ret, unsigned int *ideal_h_ret);
359 ltk_point ltk_widget_pos_to_global(ltk_widget *widget, int x, int y);
360 ltk_point ltk_global_to_widget_pos(ltk_widget *widget, int x, int y);
361
362 ltk_widget_vtable *ltk_widget_get_editable_vtable(ltk_widget *widget);
363
364 void ltk_widget_recalc_ideal_size(ltk_widget *widget);
365
366 #endif /* LTK_WIDGET_H */