URI:
       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 */