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/git/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 (19167B)
---
1 /*
2 * Copyright (c) 2021-2026 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 <stdint.h>
26 #include "array.h"
27 #include "event.h"
28 #include "graphics.h"
29 #include "rect.h"
30 #include "util.h"
31
32 /* This MUST be unsigned! */
33 /* FIXME: would uint16_t be enough? */
34 typedef uint32_t ltk_widget_id_int_type;
35 /* This could be decreased if wanted (but it can't be larger than
36 the maximum size of ltk_widget_id_int_type!) */
37 #define LTK_MAX_WIDGET_IDX ((ltk_widget_id_int_type)-1)
38 typedef struct {
39 /* index in global widget array */
40 ltk_widget_id_int_type idx;
41 /* generation number, increased every time an index is reused
42 this is never allowed to be 0 for a valid widget */
43 ltk_widget_id_int_type gen;
44 } ltk_widget_id;
45 #define LTK_WIDGET_ID_NONE (ltk_widget_id){0, 0}
46 /* Note: This is required in order to initialize a variable with static storage
47 duration since the (ltk_widget_id) cast causes the expression to not be
48 constant. Technically, this isn't necessary as long as the NONE value is just
49 {0, 0} since static variables are initialized to zero anyways, but I prefer
50 to be explicit. */
51 #define LTK_WIDGET_ID_NONE_STATIC {0, 0}
52 #define LTK_WIDGET_ID_IS_NONE(id) ((id).idx == 0 && (id).gen == 0)
53 #define LTK_WIDGET_ID_EQUAL(a, b) ((a).idx == (b).idx && (a).gen == (b).gen)
54
55 LTK_ARRAY_INIT_DECL(widget_id, ltk_widget_id)
56
57 typedef struct ltk_widget ltk_widget;
58
59 typedef enum {
60 LTK_WIDGET_UNKNOWN = 0,
61 LTK_WIDGET_ANY,
62 LTK_WIDGET_GRID,
63 LTK_WIDGET_BUTTON,
64 LTK_WIDGET_LABEL,
65 LTK_WIDGET_BOX,
66 LTK_WIDGET_MENU,
67 LTK_WIDGET_MENUENTRY,
68 LTK_WIDGET_ENTRY,
69 LTK_WIDGET_IMAGE,
70 LTK_WIDGET_WINDOW,
71 LTK_WIDGET_SCROLLBAR,
72 LTK_WIDGET_CHECKBUTTON,
73 LTK_WIDGET_RADIOBUTTON,
74 LTK_WIDGET_COMBOBOX,
75 LTK_NUM_WIDGETS,
76 } ltk_widget_type;
77
78 typedef enum {
79 LTK_ACTIVATABLE_NORMAL = 1,
80 /* only activatable when "all-activatable"
81 is set to true in the config */
82 LTK_ACTIVATABLE_SPECIAL = 2,
83 LTK_ACTIVATABLE_ALWAYS = 1|2,
84 /* FIXME: redundant or needs better name - is implied by entries in vtable
85 - if there are widgets that have keyboard functions in the vtable but
86 shouldn't have this set, then it's a bad name */
87 LTK_NEEDS_KEYBOARD = 4,
88 LTK_NEEDS_REDRAW = 8,
89 LTK_HOVER_IS_ACTIVE = 16,
90 } ltk_widget_flags;
91
92 /* FIXME: "sticky" is maybe not the correct name anymore */
93 typedef enum {
94 LTK_STICKY_NONE = 0,
95 LTK_STICKY_LEFT = 1 << 0,
96 LTK_STICKY_RIGHT = 1 << 1,
97 LTK_STICKY_TOP = 1 << 2,
98 LTK_STICKY_BOTTOM = 1 << 3,
99 LTK_STICKY_SHRINK_WIDTH = 1 << 4,
100 LTK_STICKY_SHRINK_HEIGHT = 1 << 5,
101 LTK_STICKY_PRESERVE_ASPECT_RATIO = 1 << 6,
102 } ltk_sticky_mask;
103
104 typedef enum {
105 LTK_VERTICAL,
106 LTK_HORIZONTAL
107 } ltk_orientation;
108
109 typedef enum {
110 LTK_NORMAL = 0,
111 LTK_HOVER = 1,
112 LTK_PRESSED = 2,
113 LTK_ACTIVE = 4,
114 LTK_HOVERACTIVE = 1 | 4,
115 LTK_FOCUSED = 8,
116 LTK_DISABLED = 16,
117 } ltk_widget_state;
118
119 /* FIXME: need "ltk_register_type" just to get unique integer for type checking */
120
121 typedef struct {
122 union {
123 int i;
124 size_t sz;
125 char c;
126 ltk_widget *widget;
127 ltk_widget_id wid;
128 char *str;
129 const char *cstr;
130 ltk_key_event *key_event;
131 ltk_button_event *button_event;
132 ltk_scroll_event *scroll_event;
133 ltk_motion_event *motion_event;
134 ltk_surface *surface;
135 void *v;
136 /* FIXME: maybe rewrite the functions to take
137 pointers instead so this doesn't increase
138 the size of the union (thereby increasing
139 the size of every arg in the arglist) */
140 ltk_rect rect;
141 } arg;
142 enum {
143 LTK_TYPE_INT,
144 LTK_TYPE_SIZE_T,
145 LTK_TYPE_CHAR,
146 LTK_TYPE_WIDGET,
147 LTK_TYPE_WIDGET_ID,
148 LTK_TYPE_STRING,
149 LTK_TYPE_CONST_STRING,
150 LTK_TYPE_KEY_EVENT,
151 LTK_TYPE_BUTTON_EVENT,
152 LTK_TYPE_SCROLL_EVENT,
153 LTK_TYPE_MOTION_EVENT,
154 LTK_TYPE_SURFACE,
155 LTK_TYPE_RECT,
156 LTK_TYPE_VOID,
157 LTK_TYPE_VOIDP,
158 } type;
159 } ltk_callback_arg;
160
161 /* FIXME: STRING should be CHARP for consistency */
162 #define LTK_MAKE_ARG_INT(data) ((ltk_callback_arg){.type = LTK_TYPE_INT, .arg = {.i = (data)}})
163 #define LTK_MAKE_ARG_SIZE_T(data) ((ltk_callback_arg){.type = LTK_TYPE_SIZE_T, .arg = {.sz = (data)}})
164 #define LTK_MAKE_ARG_CHAR(data) ((ltk_callback_arg){.type = LTK_TYPE_CHAR, .arg = {.c = (data)}})
165 #define LTK_MAKE_ARG_WIDGET(data) ((ltk_callback_arg){.type = LTK_TYPE_WIDGET, .arg = {.widget = (data)}})
166 #define LTK_MAKE_ARG_WIDGET_ID(data) ((ltk_callback_arg){.type = LTK_TYPE_WIDGET_ID, .arg = {.wid = (data)}})
167 #define LTK_MAKE_ARG_STRING(data) ((ltk_callback_arg){.type = LTK_TYPE_STRING, .arg = {.str = (data)}})
168 #define LTK_MAKE_ARG_CONST_STRING(data) ((ltk_callback_arg){.type = LTK_TYPE_CONST_STRING, .arg = {.cstr = (data)}})
169 #define LTK_MAKE_ARG_KEY_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_KEY_EVENT, .arg = {.key_event = (data)}})
170 #define LTK_MAKE_ARG_BUTTON_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_BUTTON_EVENT, .arg = {.button_event = (data)}})
171 #define LTK_MAKE_ARG_SCROLL_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_SCROLL_EVENT, .arg = {.scroll_event = (data)}})
172 #define LTK_MAKE_ARG_MOTION_EVENT(data) ((ltk_callback_arg){.type = LTK_TYPE_MOTION_EVENT, .arg = {.motion_event = (data)}})
173 #define LTK_MAKE_ARG_SURFACE(data) ((ltk_callback_arg){.type = LTK_TYPE_SURFACE, .arg = {.surface = (data)}})
174 #define LTK_MAKE_ARG_RECT(data) ((ltk_callback_arg){.type = LTK_TYPE_RECT, .arg = {.rect = (data)}})
175 #define LTK_MAKE_ARG_VOIDP(data) ((ltk_callback_arg){.type = LTK_TYPE_VOIDP, .arg = {.v = (data)}})
176
177 #define LTK_ARG_VOID ((ltk_callback_arg){.type = LTK_TYPE_VOID})
178
179 #define LTK_CAST_ARG_INT(carg) (ltk_assert(carg.type == LTK_TYPE_INT), carg.arg.i)
180 #define LTK_CAST_ARG_SIZE_T(carg) (ltk_assert(carg.type == LTK_TYPE_SIZE_T), carg.arg.sz)
181 #define LTK_CAST_ARG_CHAR(carg) (ltk_assert(carg.type == LTK_TYPE_CHAR), carg.arg.c)
182 #define LTK_CAST_ARG_WIDGET(carg) (ltk_assert(carg.type == LTK_TYPE_WIDGET), carg.arg.widget)
183 #define LTK_CAST_ARG_WIDGET_ID(carg) (ltk_assert(carg.type == LTK_TYPE_WIDGET_ID), carg.arg.wid)
184 #define LTK_CAST_ARG_STRING(carg) (ltk_assert(carg.type == LTK_TYPE_STRING), carg.arg.str)
185 #define LTK_CAST_ARG_CONST_STRING(carg) (ltk_assert(carg.type == LTK_TYPE_CONST_STRING), carg.arg.cstr)
186 #define LTK_CAST_ARG_KEY_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_KEY_EVENT), carg.arg.key_event)
187 #define LTK_CAST_ARG_BUTTON_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_BUTTON_EVENT), carg.arg.button_event)
188 #define LTK_CAST_ARG_SCROLL_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_SCROLL_EVENT), carg.arg.scroll_event)
189 #define LTK_CAST_ARG_MOTION_EVENT(carg) (ltk_assert(carg.type == LTK_TYPE_MOTION_EVENT), carg.arg.motion_event)
190 #define LTK_CAST_ARG_SURFACE(carg) (ltk_assert(carg.type == LTK_TYPE_SURFACE), carg.arg.surface)
191 #define LTK_CAST_ARG_RECT(carg) (ltk_assert(carg.type == LTK_TYPE_RECT), carg.arg.rect)
192 #define LTK_CAST_ARG_VOIDP(carg) (ltk_assert(carg.type == LTK_TYPE_VOIDP), carg.arg.v)
193
194 #define LTK_GET_ARG_INT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_INT(cargs.args[i]))
195 #define LTK_GET_ARG_SIZE_T(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_SIZE_T(cargs.args[i]))
196 #define LTK_GET_ARG_CHAR(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_CHAR(cargs.args[i]))
197 #define LTK_GET_ARG_WIDGET(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_WIDGET(cargs.args[i]))
198 #define LTK_GET_ARG_WIDGET_ID(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_WIDGET_ID(cargs.args[i]))
199 #define LTK_GET_ARG_STRING(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_STRING(cargs.args[i]))
200 #define LTK_GET_ARG_CONST_STRING(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_CONST_STRING(cargs.args[i]))
201 #define LTK_GET_ARG_KEY_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_KEY_EVENT(cargs.args[i]))
202 #define LTK_GET_ARG_BUTTON_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_BUTTON_EVENT(cargs.args[i]))
203 #define LTK_GET_ARG_SCROLL_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_SCROLL_EVENT(cargs.args[i]))
204 #define LTK_GET_ARG_MOTION_EVENT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_MOTION_EVENT(cargs.args[i]))
205 #define LTK_GET_ARG_SURFACE(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_SURFACE(cargs.args[i]))
206 #define LTK_GET_ARG_RECT(cargs, i) (ltk_assert(i >= 0 && i < cargs.num), LTK_CAST_ARG_RECT(cargs.args[i]))
207
208 #define LTK_CAST_WIDGET(w) (&(w)->widget)
209 #define LTK_CAST_WINDOW(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_WINDOW), (ltk_window *)(w))
210 #define LTK_CAST_LABEL(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_LABEL), (ltk_label *)(w))
211 #define LTK_CAST_BUTTON(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_BUTTON), (ltk_button *)(w))
212 #define LTK_CAST_GRID(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_GRID), (ltk_grid *)(w))
213 #define LTK_CAST_IMAGE_WIDGET(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_IMAGE), (ltk_image_widget *)(w))
214 #define LTK_CAST_ENTRY(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_ENTRY), (ltk_entry *)(w))
215 #define LTK_CAST_MENU(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_MENU), (ltk_menu *)(w))
216 #define LTK_CAST_MENUENTRY(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_MENUENTRY), (ltk_menuentry *)(w))
217 #define LTK_CAST_SCROLLBAR(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_SCROLLBAR), (ltk_scrollbar *)(w))
218 #define LTK_CAST_BOX(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_BOX), (ltk_box *)(w))
219 #define LTK_CAST_CHECKBUTTON(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_CHECKBUTTON), (ltk_checkbutton *)(w))
220 #define LTK_CAST_RADIOBUTTON(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_RADIOBUTTON), (ltk_radiobutton *)(w))
221 #define LTK_CAST_COMBOBOX(w) (ltk_assert((w)->vtable->type == LTK_WIDGET_COMBOBOX), (ltk_combobox *)(w))
222
223 #define LTK_WIDGET_TYPE(w) (w->vtable->type)
224
225 /* FIXME: a bit weird because window never gets some of these signals */
226 #define LTK_WIDGET_SIGNAL_KEY_PRESS 1
227 #define LTK_WIDGET_SIGNAL_KEY_RELEASE 2
228 #define LTK_WIDGET_SIGNAL_MOUSE_PRESS 3
229 #define LTK_WIDGET_SIGNAL_MOUSE_RELEASE 4
230 #define LTK_WIDGET_SIGNAL_MOUSE_SCROLL 5
231 #define LTK_WIDGET_SIGNAL_MOTION_NOTIFY 6
232 #define LTK_WIDGET_SIGNAL_MOUSE_ENTER 7
233 #define LTK_WIDGET_SIGNAL_MOUSE_LEAVE 8
234 #define LTK_WIDGET_SIGNAL_PRESS 9
235 #define LTK_WIDGET_SIGNAL_RELEASE 10
236 /* FIXME: resize is currently triggered in a lot of cases where nothing is really resized */
237 #define LTK_WIDGET_SIGNAL_RESIZE 11
238 #define LTK_WIDGET_SIGNAL_HIDE 12
239 #define LTK_WIDGET_SIGNAL_DRAW 13
240 #define LTK_WIDGET_SIGNAL_CHANGE_STATE 14
241 /* The return value for this is ignored, i.e.
242 the widget destroy function is always called.
243 Also, it doesn't receive the 'shallow' argument
244 that the widget method receives. */
245 #define LTK_WIDGET_SIGNAL_DESTROY 15
246 #define LTK_WIDGET_SIGNAL_INVALID 16
247
248 typedef struct {
249 ltk_callback_arg *args;
250 size_t num;
251 } ltk_callback_arglist;
252
253 #define LTK_EMPTY_ARGLIST ((ltk_callback_arglist){NULL, 0})
254
255 typedef int (*ltk_signal_callback)(ltk_widget *widget, ltk_callback_arglist args, ltk_callback_arg data);
256 typedef struct {
257 ltk_signal_callback callback;
258 ltk_callback_arg data;
259 int type;
260 } ltk_signal_callback_info;
261
262 int ltk_widget_register_signal_handler(ltk_widget_id widgetid, int type, ltk_signal_callback callback, ltk_callback_arg data);
263 int ltk_widget_emit_signal(ltk_widget_id widgetid, int type, ltk_callback_arglist args);
264 size_t ltk_widget_remove_signal_handler_by_type(ltk_widget_id widgetid, int type);
265 size_t ltk_widget_remove_signal_handler_by_callback(ltk_widget_id widgetid, ltk_signal_callback callback);
266 size_t ltk_widget_remove_signal_handler_by_info(
267 ltk_widget_id widgetid,
268 int (*filter_func)(ltk_signal_callback_info *to_check, ltk_signal_callback_info *info),
269 ltk_signal_callback_info *info
270 );
271 void ltk_widget_remove_all_signal_handlers(ltk_widget_id widgetid);
272 int ltk_widget_register_type(void);
273
274 LTK_ARRAY_INIT_STRUCT_DECL(signal, ltk_signal_callback_info)
275
276 struct ltk_widget {
277 ltk_widget_id id;
278 ltk_widget_id window;
279 ltk_widget_id parent;
280
281 struct ltk_widget_vtable *vtable;
282
283 /* FIXME: crect and lrect are a bit weird still */
284 /* FIXME: especially the relative positioning is really weird for
285 popups because they're positioned globally but still have a
286 parent-child relationship - weird things can probably happen */
287 /* both rects relative to parent (except for popups) */
288 /* collision rect is only part that is actually shown and used for
289 collision with mouse (but may still not be drawn if hidden by
290 something else) - e.g. in a box with scrolling, a widget that
291 is half cut off by a side of the box will have the logical rect
292 going past the side of the box, but the collision rect will only
293 be the part inside the box */
294 ltk_rect crect; /* collision rect */
295 ltk_rect lrect; /* logical rect */
296 unsigned int ideal_w;
297 unsigned int ideal_h;
298 unsigned int last_dpi;
299
300 /* maybe mask to determine quickly which callbacks are included?
301 default signals only allowed to have one callback? */
302 /* could maybe have just uint32_t mask so at least the lower signals
303 can be easily checked */
304 ltk_array(signal) *signal_cbs;
305
306 ltk_widget_state state;
307 /* 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 */
308 ltk_sticky_mask sticky;
309 unsigned short row;
310 unsigned short column;
311 unsigned short row_span;
312 unsigned short column_span;
313 /* ALSO NEED SIGNALS LIKE ADD-TEXT (called *before* text is inserted to check validity) - these would need argument
314 FIGURE OUT HOW TO DO KEY MAPPINGS - should reuse parts of builtin mapping handling
315 -> maybe something like tk
316 -> or maybe just say everyone needs to override event handler? but makes simple stuff more difficult
317 -> also need "global" mappings/key event handler for global shortcuts */
318 /* needed to properly handle handle local coordinates since
319 popups are positioned globally instead of locally */
320 char popup;
321 char dirty;
322 char hidden;
323 char vtable_copied;
324 };
325
326 typedef struct ltk_widget_vtable {
327 int (*key_press)(ltk_widget *self, ltk_key_event *event);
328 int (*key_release)(ltk_widget *self, ltk_key_event *event);
329 /* press/release also receive double/triple-click/release */
330 int (*mouse_press)(ltk_widget *self, ltk_button_event *event);
331 int (*mouse_release)(ltk_widget *self, ltk_button_event *event);
332 int (*mouse_scroll)(ltk_widget *self, ltk_scroll_event *event);
333 int (*motion_notify)(ltk_widget *self, ltk_motion_event *event);
334 int (*mouse_leave)(ltk_widget *self, ltk_motion_event *event);
335 int (*mouse_enter)(ltk_widget *self, ltk_motion_event *event);
336 int (*press)(ltk_widget *self);
337 int (*release)(ltk_widget *self);
338 void (*cmd_return)(ltk_widget *self, char *text, size_t len);
339
340 /* This is called when the DPI changes. It must not call child_size_change on
341 the parent or do any actual resizing (only ideal_w and ideal_h should be set),
342 but it should call ltk_widget_recalc_ideal_size on any child widgets. */
343 /* When a widget is added to a container, the container should call
344 ltk_widget_recalc_ideal_size on the widget in case the DPI changed. */
345 void (*recalc_ideal_size)(ltk_widget *self);
346 void (*resize)(ltk_widget *self);
347 void (*hide)(ltk_widget *self);
348 /* draw_surface: surface to draw it on
349 x, y: position of logical rectangle on surface
350 clip: clipping rectangle, relative to logical rectangle */
351 void (*draw)(ltk_widget *self, ltk_surface *draw_surface, int x, int y, ltk_rect clip);
352 void (*change_state)(ltk_widget *self, ltk_widget_state state);
353 void (*destroy)(ltk_widget *self, int shallow);
354
355 /* rect is in self's coordinate system */
356 ltk_widget_id (*nearest_child)(ltk_widget *self, ltk_rect rect);
357 ltk_widget_id (*nearest_child_left)(ltk_widget *self, ltk_widget_id widget);
358 ltk_widget_id (*nearest_child_right)(ltk_widget *self, ltk_widget_id widget);
359 ltk_widget_id (*nearest_child_above)(ltk_widget *self, ltk_widget_id widget);
360 ltk_widget_id (*nearest_child_below)(ltk_widget *self, ltk_widget_id widget);
361 ltk_widget_id (*next_child)(ltk_widget *self, ltk_widget_id child);
362 ltk_widget_id (*prev_child)(ltk_widget *self, ltk_widget_id child);
363 ltk_widget_id (*first_child)(ltk_widget *self);
364 ltk_widget_id (*last_child)(ltk_widget *self);
365
366 /* This is called when the ideal size of a child is changed (e.g. text is
367 added to a text entry). */
368 void (*child_size_change)(ltk_widget *self, ltk_widget_id child);
369 int (*remove_child)(ltk_widget *self, ltk_widget_id child);
370 /* x and y relative to widget's lrect! */
371 ltk_widget_id (*get_child_at_pos)(ltk_widget *self, int x, int y);
372 /* r is in self's coordinate system */
373 void (*ensure_rect_shown)(ltk_widget *self, ltk_rect r);
374
375 ltk_widget_type type;
376 ltk_widget_flags flags;
377 int invalid_signal;
378 } ltk_widget_vtable;
379
380 void ltk_widget_hide(ltk_widget *widget);
381 void ltk_widget_id_hide(ltk_widget_id widgetid);
382 int ltk_widget_destroy(ltk_widget *widget, int shallow);
383 int ltk_widget_id_destroy(ltk_widget_id widgetid, int shallow);
384 ltk_widget_id ltk_initialize_widget(
385 ltk_widget *widget, ltk_widget_id windowid,
386 struct ltk_widget_vtable *vtable, int w, int h
387 );
388 /* FIXME: container should always check if parent of child widget is correct (or at least before destroying?) */
389 void ltk_widget_change_state(ltk_widget *widget, ltk_widget_state old_state);
390 void ltk_widget_resize(ltk_widget *widget);
391 void ltk_widget_draw(ltk_widget *widget, ltk_surface *draw_surf, int x, int y, ltk_rect clip_rect);
392 /* FIXME: layout widgets need to recalculate ideal size when children change! */
393 void ltk_widget_get_ideal_size(ltk_widget *widget, unsigned int *ideal_w_ret, unsigned int *ideal_h_ret);
394 ltk_point ltk_widget_pos_to_global(ltk_widget *widget, int x, int y);
395 ltk_point ltk_global_to_widget_pos(ltk_widget *widget, int x, int y);
396
397 /* FIXME: either remove this functionality or update all widget functions
398 so they never assume that a certain entry is actually present in the vtable */
399 ltk_widget_vtable *ltk_widget_get_editable_vtable(ltk_widget_id widgetid);
400
401 void ltk_widget_recalc_ideal_size(ltk_widget *widget);
402
403 #endif /* LTK_WIDGET_H */