generic widget functionality that work with any widget

/* The common part of a widget definition; any widget has this as its first field, called w. */ struct mbtk_widget_s { hvbox_t hvbox; /* contains bbox and parent */ mbtk_window_t *win; /* host window (also widget root); this is the closest subwindow in the parent hierarchy */ mbtk_window_t *render_win; /* this is the "physical" window or NULL if the widget is not yet assigned; assing/unassing callbacks are made when this changes; in some backends (glfw, sdl) this is the actual WM window; in other backends (xlib) it may be a subwindow */ int struct_size; /* including the widget-specific fields */ mbtk_kw_t type; mbtk_kw_t purpose; /* if not 0, it is a hint to the style engine; composite widgets may set this field to make differentation possible, e.g. on the down arrow of a combo box */ const mbtk_widget_imp_t *imp; const mbtk_handler_t *handler; void *handler_data; /* not NULL when the handler has dynamic allocated data; typically points to handler as well; set by the handler when put on the widget */ struct { long l; double d; } handler_static_data; /* the handler may use these fields to store data without dynamic allocation */ mbtk_callbacks_t *callbacks; /* user callbacks: application functions called by the lib upon widget events; registered by the app */ const mbtk_style_t *style; /* style implementation to use for drawing this widget */ mbtk_styleprop_t *styleprop; /* allocated separately; when NULL, use parent styleprop; when NULL in root, use style-default styleprop */ vtp0_t *styleprop_dly; /* if not NULL, there are delayed style prop sets; see apply_styleprop_dly() */ mbtk_widget_flags_t flags; int destroy_lock; /* if not 0: do not fully destroy this widget because some callbacks still depend on it */ unsigned destroying:1; /* mbtk_widget_destroy() called, widget is being destroyed */ unsigned relative_ev_coords:1; /* 1 if passing on the event should use relative coords to the widget (useful when the widget implements a subwindow, e.g. a canvas widget) */ unsigned appeared:1; /* widget appear call has been issued (the widget thinks it is visible) */ long w_min_u, h_min_u; /* user specified minimum width and height (0 by default) */ void *user_data; /* application may use this to attach data to the widget */ /* custom fields: overallocated */ }; /* Widget implementation: functions within the specific widget's code, called when libmbtk wants to deal with a widget. User code shouldn't call these. Used by widget implementation. */ struct mbtk_widget_imp_s { void (*imp_destroy)(mbtk_widget_t *w); /* should free implementation-specific fields/allocations; called after user callback, before removing from the tree or handlers */ /* when the style couldn't handle this widget, fall back drawing something using generic widgets the style will be able to handle */ int (*fallback_minsize)(mbtk_widget_t *w, long *mx, long *my); void (*fallback_draw)(mbtk_widget_t *w); void (*fallback_draw_overlay)(mbtk_widget_t *w); /* Optional: the widget may expose its properties through this kw-arg based API. Return number of args used (1 or more) on success, -1 on error */ int (*get_propa)(mbtk_widget_t *w, mbtk_kw_t key, mbtk_arg_t *dst, int arrlen); int (*set_propa)(mbtk_widget_t *w, mbtk_kw_t key, const mbtk_arg_t *newval, int arrlen); /* Optional: called when a (subtree of) widget(s) assigned to or unassigned from a window; if the widget has resources in the window this is where those resources can be registered/unregistered */ void (*post_assign)(mbtk_widget_t *w); void (*pre_unassign)(mbtk_widget_t *w); /* Optional: called before a widget appears or after a widget disappeared. First draw is preceed by an appear call. Last draw is followed by a disappear call before unassign. A widget may also disappear/appear due to scrolling (which does not change window-assigned state). */ void (*pre_appear)(mbtk_widget_t *w); void (*post_disappear)(mbtk_widget_t *w); /* Called before child is unlinked from w; gives w a chance to update internal states if it depends on number-of/order-of children widget */ void (*pre_child_unlink)(mbtk_widget_t *w, mbtk_widget_t *child); }; /* New widgets are created with these layout defaults; some widgets may override these with differnet defaults; the app is free to override these on a per widget basis after creating a widget. */ extern hvbox_align_t mbtk_default_align; extern hvbox_span_t mbtk_default_span; extern int mbtk_default_spacing; extern int mbtk_default_padding; /* Set the root widget of a window. There can be only one root widget per window and it is typically a box that hosts further widgets. Removes and destroys previous root widget if there was any. */ void mbtk_window_set_root_widget(mbtk_window_t *win, mbtk_widget_t *widget); /* Remove widget from the widget tree, from its handler and free all memory associated with the widget */ void mbtk_widget_destroy(mbtk_widget_t *w); /* Remove a widget from the widget tree, but do not destroy the widgets; w becomes a "floating" subtree of widgets that can be placed (embedded) under a different subtree later */ void mbtk_widget_unlink(mbtk_widget_t *w); /* Hide or show a widget. Widgets are normally shown when they are created. A hidden widget is not allocated on screen (size is 0*0 pixels) and is not drawn. If recurse is true, all child widgets are shown/hidden as well. the _up version also recurse upward and make sure all parents are shown (but it never recurses down from parents, so siblings are not changed). */ void mbtk_widget_hide(mbtk_widget_t *widget, mbtk_bool_t recurse); void mbtk_widget_show(mbtk_widget_t *widget, mbtk_bool_t recurse); void mbtk_widget_show_up(mbtk_widget_t *widget, mbtk_bool_t recurse); /* Returns if widget is hidden; hidden on its own right or hidden because any of its parent is hidden. Note: a non-hidden widget may still be invisible if it's in a subwindow that is hidden or if it is in a floating widget tree (that is not in any window) */ int mbtk_widget_is_hidden(mbtk_widget_t *widget); /* Widget code called back before the widget is destroyed; this is where widget->gt;user_data could be free'd */ void mbtk_widget_callback_pre_destroy(mbtk_widget_t *w, mbtk_event_handled_t (*cb)(mbtk_widget_t *w, mbtk_kw_t id, void *user_data), void *user_data); /* Remove current handler from widget */ void mbtk_widget_del_handler(mbtk_widget_t *widget); /* Set or get scalar or array properties; this API is preferred between handlers and widgets because it is more flexible (handlers don't need to hardwire widget call names). Return number of arguments used on succes (1 or more). */ int mbtk_widget_set_prop(mbtk_widget_t *w, mbtk_kw_t key, const mbtk_arg_t *newval); int mbtk_widget_set_propa(mbtk_widget_t *w, mbtk_kw_t key, const mbtk_arg_t *newval, int arrlen); int mbtk_widget_get_prop(mbtk_widget_t *w, mbtk_kw_t key, mbtk_arg_t *dst); int mbtk_widget_get_propa(mbtk_widget_t *w, mbtk_kw_t key, mbtk_arg_t *dst, int arrlen); /* Change layout parameters */ MBTK_INLINE void mbtk_widget_set_align(mbtk_widget_t *w, hvbox_align_t a); MBTK_INLINE void mbtk_widget_set_span(mbtk_widget_t *w, hvbox_span_t s); MBTK_INLINE void mbtk_widget_set_alt_span(mbtk_widget_t *w, hvbox_span_t s); MBTK_INLINE void mbtk_widget_set_padding(mbtk_widget_t *w, int p); MBTK_INLINE void mbtk_widget_set_spacing(mbtk_widget_t *w, int s); MBTK_INLINE void mbtk_widget_set_activated(mbtk_widget_t *w, mbtk_bool_t a); MBTK_INLINE void mbtk_widget_set_minsize(mbtk_widget_t *w, long width, long height); /* Change the style of a widget locally (deviate from display style). If called on a widget already in a window, returns non-zero on error (style code failed to set property). If called on a floating widget, always returns 0 and may silently fail later when the widget is assigned to a window and the style sets are performed. */ int mbtk_widget_style_set_prop(mbtk_widget_t *dst, mbtk_kw_t key, mbtk_arg_t value); /* Return a property value of a widget, falling back to display for default. Returns non-zero on error. Always fails on floating widgets. */ int mbtk_widget_style_get_prop(mbtk_widget_t *w, mbtk_kw_t key, mbtk_arg_t *dst); /* Call this if widget properties changed and layout (minimum size) may be affected; gets the widget minimums recalculated and layout redone if needed or if forced. For example label string changed. */ void mbtk_widget_changed(mbtk_widget_t *w, int force_layout); /* Call this if widget didn't change layout (minimum size) but needs a redraw because some properties changed. For example progress bar position changed. */ void mbtk_widget_needs_redraw(mbtk_widget_t *w); /* Assing w (and its subtree recursively) to render_win; unassings widgets assigned to a different render_win */ void mbtk_widget_assign(mbtk_widget_t *w, mbtk_window_t *render_win); /* Unassing w (and its subtree recursively) from their current render_win, leaving widgets 'floating', with ->gt;render_win = NULL */ void mbtk_widget_unassign(mbtk_widget_t *w); /* Returns the style to be used for the widget; either widget's own style or display's style the widget is drawn in or NULL */ MBTK_INLINE const mbtk_style_t *mbtk_widget_style(mbtk_widget_t *w);