register_widget_type() can now be called in any order.
[xuni.git] / src / widget / widgets.c
blob6d07d5106ace2767228a9522f0398430e28f6933
1 /*! \file widgets.c
3 */
5 #include <stdlib.h>
6 #include <string.h>
8 #include "../graphics.h"
9 #include "../memory.h"
10 #include "../error.h"
11 #include "dump.h"
12 #include "widgets.h"
14 static struct widget_t *widget_nameid_follow_va(struct widget_t *widget,
15 va_list arg);
17 static void set_default_pos(struct widget_t *widget);
18 static void set_pos_pack_top(struct xuni_t *xuni, struct widget_t *widget);
19 static void reposition_widget_pack(struct xuni_t *xuni,
20 struct widget_t *widget);
21 static void reposition_widget_nonrec(struct xuni_t *xuni,
22 struct widget_t *widget);
23 static void free_widget(struct xuni_t *xuni, struct widget_t *widget);
24 static void update_text_widget(struct xuni_t *xuni, struct widget_t *widget);
25 static void paint_widget(struct xuni_t *xuni, struct widget_t *widget);
26 static void reposition_widget(struct xuni_t *xuni, struct widget_t *widget);
27 static void rescale_widget(struct xuni_t *xuni, struct widget_t *widget);
29 static int widget_type_compare(void *data, size_t n, void *find);
31 void delete_widget(struct xuni_t *xuni, struct panel_t *panel, size_t n) {
32 free_widget(xuni, panel->widget[n]);
34 if(n + 1 < panel->widgets) {
35 memmove(panel->widget + n, panel->widget + n + 1,
36 (panel->widgets - n - 1) * sizeof(*panel->widget));
39 panel->widgets --;
40 panel->widget = xuni_memory_resize(panel->widget, panel->widgets
41 * sizeof(*panel->widget));
44 void delete_widget_pointer(struct xuni_t *xuni, struct widget_t *widget) {
45 size_t x;
47 if(!widget) return;
49 if(widget->base) {
50 for(x = 0; x < widget->base->compose->widgets; x ++) {
51 if(widget == widget->base->compose->widget[x]) {
52 delete_widget(xuni, widget->base->compose, x);
53 return;
57 else free_widget(xuni, widget);
60 void add_widget(struct panel_t *panel, struct widget_t *widget) {
61 panel->widget = xuni_memory_resize(panel->widget, (panel->widgets + 1)
62 * sizeof(*panel->widget));
63 panel->widget[panel->widgets] = widget;
64 panel->widgets ++;
67 void add_allocate_widget(struct widget_t *base, char *name) {
68 add_widget(base->compose, allocate_widget(name, base));
71 void add_allocate_widget_compose(struct widget_t *base, char *name) {
72 if(!base->compose) base->compose = allocate_panel(base);
74 add_allocate_widget(base, name);
77 struct panel_t *allocate_panel(struct widget_t *base) {
78 struct panel_t *panel;
80 panel = xuni_memory_allocate(sizeof(*panel));
81 panel->base = base;
82 panel->widget = 0;
83 panel->widgets = 0;
85 return panel;
88 /*! Returns a new, dynamically allocated widget. The widget's name becomes
89 \a name and its parent widget (widget_t::base) is set to \a base.
90 Otherwise, the widget is initialized to default values.
92 This function should be followed immediately by a call to init_*() to
93 initialize an instance of a specific type of widget; otherwise the widget
94 is virtually useless, with a type of WIDGET_NONE.
96 \param name The name of the new widget.
97 \param base The parent widget of the new widget.
98 \return The newly allocated widget.
100 struct widget_t *allocate_widget(char *name, struct widget_t *base) {
101 struct widget_t *widget = xuni_memory_allocate(sizeof(*widget));
103 /*widget->p.all = xuni_memory_allocate(sizeof_widget_structure(type));*/
104 /*widget->p.all = 0;*/
106 widget->name = name;
107 widget->id = (size_t)-1;
108 widget->base = base;
109 widget->type = WIDGET_NONE;
111 widget->compose = 0;
112 widget->pos = 0;
114 widget->visibility = WIDGET_VISIBILITY_ALL;
116 widget->selwidget = 0;
118 widget->sel = 0;
119 widget->repaint = 0;
121 return widget;
124 void init_widget_pos(struct widget_t *widget, double x, double y,
125 double w, double h, enum pos_pack_t pack) {
127 if(!widget->pos) {
128 widget->pos = xuni_memory_allocate(sizeof(*widget->pos));
131 widget->pos->pack = pack;
133 widget->pos->scale.x = x;
134 widget->pos->scale.y = y;
135 widget->pos->scale.w = w;
136 widget->pos->scale.h = h;
138 widget->pos->clip = 0;
140 /* widget->pos->real.* set by rescale_widget() */
143 void clear_widget_clip(struct xuni_t *xuni, struct widget_t *widget) {
144 if(!widget) return;
146 if(widget->pos->clip) {
147 widget->pos->clip->xoff = 0;
148 widget->pos->clip->yoff = 0;
149 widget->pos->clip->xclip = 0;
150 widget->pos->clip->yclip = 0;
152 reposition_widget_pack(xuni, widget);
154 /* !!! should this be before the above call or not? */
155 widget->pos->clip->wclip = widget->pos->real.w;
156 widget->pos->clip->hclip = widget->pos->real.h;
160 void add_panel_clip(struct xuni_t *xuni, struct widget_t *widget,
161 int xoff, int yoff, int xclip, int yclip, int wclip, int hclip) {
163 size_t x;
165 if(!widget->pos->clip) {
166 widget->pos->clip = xuni_memory_allocate(sizeof(*widget->pos->clip));
167 clear_widget_clip(xuni, widget);
170 if(widget && widget->compose) {
171 for(x = 0; x < widget->compose->widgets; x ++) {
172 add_widget_clip(xuni, widget->compose->widget[x], xoff, yoff,
173 xclip, yclip, wclip, hclip);
178 void add_widget_clip_nonrec(struct xuni_t *xuni, struct widget_t *widget,
179 int xoff, int yoff, int xclip, int yclip, int wclip, int hclip) {
181 if(!widget) return;
183 if(!widget->pos->clip) {
184 widget->pos->clip = xuni_memory_allocate(sizeof(*widget->pos->clip));
185 clear_widget_clip(xuni, widget);
188 /*widget->pos->clip->xoff += xoff;
189 widget->pos->clip->yoff += yoff;*/
190 widget->pos->clip->xclip += xclip;
191 widget->pos->clip->yclip += yclip;
192 widget->pos->clip->wclip += wclip;
193 widget->pos->clip->hclip += hclip;
195 widget->pos->real.x += xoff;
196 widget->pos->real.y += yoff;
197 /*widget->pos->real.w += xclip;
198 widget->pos->real.h += yclip;*/
199 /* !!! need to do something with wclip and hclip, too */
201 /*printf("add_widget_clip(): \"%s\" = (%i,%i) (%i,%i,%i,%i)",
202 widget->base->name, xoff, yoff, xclip, yclip, wclip, hclip);
203 printf(" -> (%i,%i) (%i,%i,%i,%i)\n",
204 widget->pos->clip->xoff,
205 widget->pos->clip->yoff,
206 widget->pos->clip->xclip,
207 widget->pos->clip->yclip,
208 widget->pos->clip->wclip,
209 widget->pos->clip->hclip);*/
212 void add_widget_clip(struct xuni_t *xuni, struct widget_t *widget,
213 int xoff, int yoff, int xclip, int yclip, int wclip, int hclip) {
215 size_t x;
217 if(!widget) return;
219 add_widget_clip_nonrec(xuni, widget,
220 xoff, yoff, xclip, yclip, wclip, hclip);
222 if(widget->compose) {
223 for(x = 0; x < widget->compose->widgets; x ++) {
224 add_widget_clip(xuni, widget->compose->widget[x], xoff, yoff,
225 0, 0, 0, 0);
229 /*printf("add_widget_clip(): \"%s\" = (%i,%i) (%i,%i,%i,%i)",
230 widget->base->name, xoff, yoff, xclip, yclip, wclip, hclip);
231 printf(" -> (%i,%i) (%i,%i,%i,%i)\n",
232 widget->pos->clip->xoff,
233 widget->pos->clip->yoff,
234 widget->pos->clip->xclip,
235 widget->pos->clip->yclip,
236 widget->pos->clip->wclip,
237 widget->pos->clip->hclip);*/
240 void add_widget_accelerator(struct xuni_t *xuni, struct widget_t *panel,
241 struct widget_t *widget, SDLKey key, SDLMod mod) {
243 struct panel_data_t *data;
245 if(!panel || panel->type != WIDGET_PANEL || !panel->p.panel) {
246 printf("*** add_widget_accelerator() called with invalid widget:\n");
247 print_widget_backtrace(xuni, widget);
248 return;
251 data = panel->p.panel;
253 if(!data->accel) {
254 data->accel = xuni_memory_allocate(sizeof(*data->accel));
255 data->accel->key = 0;
256 data->accel->n = 0;
259 data->accel->key = xuni_memory_resize(data->accel->key,
260 (data->accel->n + 1) * sizeof(*data->accel->key));
261 data->accel->key[data->accel->n].key.sym = key;
262 data->accel->key[data->accel->n].key.mod = mod;
263 data->accel->key[data->accel->n].widget = widget;
265 data->accel->n ++;
268 /*! Returns the last compose widget of \a widget.
270 This is frequently used in the widget initialization functions to refer
271 to the last sub-widget added.
273 \param widget The widget for which to return the last compose widget.
274 \return The last compose widget of \a widget, or NULL if the widget does
275 not have any sub-widgets.
277 struct widget_t *last_compose_widget(struct widget_t *widget) {
278 if(!widget->compose || !widget->compose->widgets) return 0;
280 return widget->compose->widget[widget->compose->widgets - 1];
283 /*struct widget_t *compose_access_widget(struct widget_t *widget, size_t n) {
284 if(!widget || !widget->compose || n >= widget->compose->widgets) return 0;
286 return widget->compose->widget[n];
289 size_t get_compose_widgets(struct widget_t *widget) {
290 if(!widget || !widget->compose) return 0;
292 return widget->compose->widgets;
295 /*! Searches \a widget for the registered nameid \a n.
296 \param widget The widget to search for the nameid \a n. Should be a panel
297 or a theme widget.
298 \param n The nameid to search \a widget for.
299 \return The widget for the nameid \a n, or zero the nameid was not found.
300 Also returns zero if \a widget is not of type panel or theme, or if
301 \a widget is NULL.
303 struct widget_t *widget_nameid_access(struct widget_t *widget, size_t n) {
304 if(!widget) return 0;
306 if(widget->type == WIDGET_PANEL) {
307 if(widget->p.panel->nameid
308 && n < widget->p.panel->nameid->widgets) {
310 return widget->p.panel->nameid->widget[n].widget;
313 else if(widget->type == WIDGET_THEME) {
314 if(widget->p.theme->nameid
315 && n < widget->p.theme->nameid->widgets) {
317 return widget->p.theme->nameid->widget[n].widget;
321 return 0;
324 /*! Starting at \a widget, follows a series of nameids. This is a private
325 implementation, used by widget_nameid_follow(). It takes a \c va_list
326 parameter instead of "...".
328 \param widget The widget to start searching from.
329 \param arg The series of nameids to follow, starting at \a widget.
330 \return The widget that was eventually found, if any, or NULL otherwise.
332 static struct widget_t *widget_nameid_follow_va(struct widget_t *widget,
333 va_list arg) {
335 size_t id;
337 while((id = va_arg(arg, size_t)) != (size_t)-1) {
338 widget = widget_nameid_access(widget, id);
339 if(!widget) return 0;
342 return widget;
345 /*! Starting at \a widget, follows a series of nameids. The series must be
346 terminated with (size_t)-1.
348 Equivalent to multiple calls to widget_nameid_access().
350 \param widget The widget to start searching for the first nameid. Should
351 be a panel or theme widget.
352 \param ... The series of nameids to follow, terminated with (size_t)-1.
353 \return The widget specified by all of the nameids, if found, or NULL
354 otherwise.
356 struct widget_t *widget_nameid_follow(struct widget_t *widget, ...) {
357 struct widget_t *found;
358 va_list arg;
360 va_start(arg, widget);
361 found = widget_nameid_follow_va(widget, arg);
362 va_end(arg);
364 return found;
367 /*! Returns true if the widget \a search is equal to \a widget or one of its
368 ancestors.
369 \param search The widget to search for.
370 \param widget The widget to search through, following base pointers until
371 the root widget is reached.
372 \return True if the widget \a search was found in the widget path that
373 \a widget denotes.
375 int widget_is_parent(struct widget_t *search, struct widget_t *widget) {
376 while(widget) {
377 if(search == widget) return 1;
378 widget = widget->base;
381 return 0;
384 /*! Returns true if \a string and \a len characters of \a buffer match. This
385 function is sort of like strncmp() -- however, it compares the lengths of
386 the strings before comparing their contents. This means that a calls like
387 widget_name_match("some", "some", 5)
388 widget_name_match("something", "some", 4)
389 will not return true, even though they would for strncmp().
391 This function is used for matching widget names, unsurprisingly. \a string
392 can contain the name of a widget, say "xuni", and \a buffer can contain a
393 path to a widget, say "xuni/etc", and this function will be able to match
394 the names correctly.
396 \param string The widget name to look for at the beginning of \a buffer.
397 \param buffer The widget path in which to look at the first \a len
398 characters, and to compare with \a string.
399 \param len The number of characters in \a buffer that should be
400 considered. The length of \a string must also equal this value for a
401 match to occur.
402 \return True if a match was found, false otherwise.
404 int widget_name_match(const char *string, const char *buffer, size_t len) {
405 if(!string || !buffer) return 0;
407 return strlen(string) == len && !strncmp(string, buffer, len);
410 /*! Searches for the widget specified by \a name, with respect to \a widget.
412 \a name is not just the name of a widget. It can also contain slashes to
413 specify child widgets; ".." to specify the parent widget; and "." to
414 specify the current widget \a widget. (An empty string also specifies
415 \a widget.)
417 Note: this function currently does not handle double slashes (like
418 "this//that"). (They are treated as widgets with empty names.) Nor does it
419 support backslashes, just slashes.
421 \param widget The widget to start searching from.
422 \param name The path to the widget that is being sought.
423 \return The widget specified by \a name starting at \a widget, if found,
424 or NULL if not.
426 struct widget_t *find_widget(struct widget_t *widget, const char *name) {
427 struct widget_t *p;
428 const char *end;
429 size_t x;
431 if(!name || !widget) return 0;
433 for(;;) {
434 for(end = name; *end && *end != '/'; end ++);
436 if(widget_name_match(".", name, end - name)) {
437 if(!*end) return widget;
438 name = end + 1;
440 else break;
443 if(widget_name_match("..", name, end - name)) {
444 if(!*end) return widget->base;
445 return find_widget(widget->base, end + 1);
448 if(widget->compose) {
449 for(x = 0; x < widget->compose->widgets; x ++) {
450 if(widget_name_match(widget->compose->widget[x]->name,
451 name, end - name)) {
453 if(!*end) return widget->compose->widget[x];
454 p = find_widget(widget->compose->widget[x], end + 1);
455 if(p) return p;
460 return 0;
463 /*! Sends an event of type \a event to the widget \a widget.
465 The event is passed through several functions before finally being handled
466 by {widget}_widget_event() (e.g., button_widget_event()), which usually
467 defers to {event}_{widget}() (e.g., rescale_button()).
469 \param xuni A pointer to the main xuni_t structure.
470 \param widget The widget to send the event to.
471 \param event The type of event to send to the widget.
473 void widget_event(struct xuni_t *xuni, struct widget_t *widget,
474 enum widget_event_t event) {
476 static void (*function[])(struct xuni_t *xuni, struct widget_t *widget)
479 free_widget,
480 update_text_widget,
481 paint_widget,
482 reposition_widget,
483 rescale_widget
486 call_widget_event_func(xuni, widget, event, function,
487 sizeof(function) / sizeof(*function));
490 /*! Sends a widget event to all subwidgets of \a widget, but not to \a widget
491 itself.
493 Useful in generic widget event handlers to pass on an event to subwidgets.
495 \param xuni A pointer to the main xuni structure. Passed on to the widget
496 event handling functions.
497 \param widget The widget for which to send a widget event to all the
498 subwidgets of.
499 \param event The widget event type to send to the composing widgets of
500 \a widget.
502 void widget_compose_event(struct xuni_t *xuni, struct widget_t *widget,
503 enum widget_event_t event) {
505 size_t x;
507 if(!widget->compose) return;
509 for(x = 0; x < widget->compose->widgets; x ++) {
510 widget_event(xuni, widget->compose->widget[x], event);
514 static void set_default_pos(struct widget_t *widget) {
515 if(!widget || !widget->pos) return;
517 widget->pos->real.x = 0;
518 widget->pos->real.y = 0;
519 widget->pos->real.w = 0;
520 widget->pos->real.h = 0;
523 static void set_pos_pack_top(struct xuni_t *xuni, struct widget_t *widget) {
524 struct widget_t *prev;
525 size_t x;
527 if(!widget) return;
529 widget->pos->real.w = 0;
530 widget->pos->real.h = 0;
532 if(!widget->base || !widget->base->pos) {
533 set_default_pos(widget);
534 return;
537 for(x = 0; x < widget->base->compose->widgets; x ++) {
538 if(widget == widget->base->compose->widget[x]) break;
541 widget->pos->real.x = widget->base->pos->real.x;
542 widget->pos->real.y = widget->base->pos->real.y;
544 if(x) {
545 prev = widget->base->compose->widget[x - 1];
547 if(prev->type == WIDGET_LABEL) {
548 if(prev->p.label->label) {
549 widget->pos->real.y
550 = prev->pos->real.y + prev->p.label->label->h;
552 else {
553 printf("Error: widget's prev label not set: %lu; prev:\n",
554 (unsigned long)x);
555 print_inline_widget_backtrace(prev);
557 widget->pos->real.y = prev->pos->real.y;
560 /*else if(prev->pos) {
561 widget->pos->real.y += prev->pos->scale.y / 100.0 * smode->height;
563 else {
564 printf("*** Can't pack after widgets of type \"%s\"\n",
565 get_widget_type_name(xuni, prev->type));
570 int get_real_pos(double scale, int basereal) {
571 return (int)((scale / 100.0) * basereal);
574 static void reposition_widget_pack(struct xuni_t *xuni,
575 struct widget_t *widget) {
577 if(!widget->pos) return;
579 switch(widget->pos->pack) {
580 case POS_PACK_NONE:
581 if(widget->base && widget->base->pos) {
582 /*printf("using base: (%i,%i) by (%i,%i)\n",
583 widget->base->pos->real.x, widget->base->pos->real.y,
584 widget->base->pos->real.w, widget->base->pos->real.h);*/
585 widget->pos->real.x = get_real_pos(
586 widget->pos->scale.x, widget->base->pos->real.w)
587 + widget->base->pos->real.x;
588 widget->pos->real.y = get_real_pos(
589 widget->pos->scale.y, widget->base->pos->real.h)
590 + widget->base->pos->real.y;
592 widget->pos->real.w = get_real_pos(
593 widget->pos->scale.w, widget->base->pos->real.w);
594 widget->pos->real.h = get_real_pos(
595 widget->pos->scale.h, widget->base->pos->real.h);
597 else {
598 /*puts("(no base)");*/
599 widget->pos->real.x
600 = widget->pos->scale.x / 100.0 * xuni->smode->width;
601 widget->pos->real.y
602 = widget->pos->scale.y / 100.0 * xuni->smode->height;
603 widget->pos->real.w
604 = widget->pos->scale.w / 100.0 * xuni->smode->width;
605 widget->pos->real.h
606 = widget->pos->scale.h / 100.0 * xuni->smode->height;
609 /*printf("%20s: (%i,%i) by (%i,%i)\n", widget->name,
610 widget->pos->real.x, widget->pos->real.y,
611 widget->pos->real.w, widget->pos->real.h);*/
613 break;
614 case POS_PACK_TOP:
615 set_pos_pack_top(xuni, widget);
617 break;
618 default:
619 printf("*** Invalid pos pack type: %i\n", (int)widget->pos->pack);
620 break;
623 /* !!! temporarily fixes the "listbox scroll problem" */
624 if(widget->type == WIDGET_LABEL && !widget->pos->scale.w
625 && !widget->pos->scale.h && widget->p.label->label) {
627 widget->pos->real.w = widget->p.label->label->w;
628 widget->pos->real.h = widget->p.label->label->h;
631 #if 0
632 if(widget->base && widget->base->pos) {
633 widget->pos->real.x += widget->base->pos->real.x;
634 widget->pos->real.y += widget->base->pos->real.y;
636 #endif
639 static void reposition_widget_nonrec(struct xuni_t *xuni,
640 struct widget_t *widget) {
642 clear_widget_clip(xuni, widget);
644 call_widget_event(xuni, widget, WIDGET_EVENT_REPOSITION);
647 static void reposition_widget(struct xuni_t *xuni, struct widget_t *widget) {
648 if(!widget) return;
650 reposition_widget_pack(xuni, widget);
652 widget_compose_event(xuni, widget, WIDGET_EVENT_REPOSITION);
654 reposition_widget_nonrec(xuni, widget);
657 static void rescale_widget(struct xuni_t *xuni, struct widget_t *widget) {
658 if(!widget) return;
660 reposition_widget_pack(xuni, widget);
662 widget_compose_event(xuni, widget, WIDGET_EVENT_RESCALE);
664 reposition_widget_nonrec(xuni, widget);
666 if(widget->type != WIDGET_PANEL) {
667 call_widget_event(xuni, widget, WIDGET_EVENT_RESCALE);
671 static void paint_widget(struct xuni_t *xuni, struct widget_t *widget) {
672 if(!widget) return;
674 if(widget->visibility & WIDGET_VISIBILITY_VISIBLE) {
675 call_widget_event(xuni, widget, WIDGET_EVENT_PAINT);
677 if(widget->repaint) {
678 widget->repaint = 0;
683 static void update_text_widget(struct xuni_t *xuni, struct widget_t *widget) {
684 if(!widget) return;
686 call_widget_event(xuni, widget, WIDGET_EVENT_UPDATE_TEXT);
688 widget_compose_event(xuni, widget, WIDGET_EVENT_UPDATE_TEXT);
691 static void free_widget(struct xuni_t *xuni, struct widget_t *widget) {
692 if(!widget) return;
694 if(!xuni_memory_decrement(widget)) return;
696 call_widget_event(xuni, widget, WIDGET_EVENT_FREE);
698 if(widget->pos) {
699 xuni_memory_free(widget->pos->clip);
700 xuni_memory_free(widget->pos);
703 free_panel(xuni, widget->compose);
705 free(widget);
708 void init_wtype(struct xuni_t *xuni, struct wtype_array_t *wtype) {
709 wtype->type = 0;
710 wtype->types = 0;
712 register_widget_type(xuni, "box", WIDGET_BOX, box_widget_event);
713 register_widget_type(xuni, "button", WIDGET_BUTTON, button_widget_event);
714 register_widget_type(xuni,
715 "checkbox", WIDGET_CHECKBOX, checkbox_widget_event);
716 register_widget_type(xuni,
717 "combobox", WIDGET_COMBOBOX, combobox_widget_event);
718 register_widget_type(xuni, "font", WIDGET_FONT, font_widget_event);
719 register_widget_type(xuni, "image", WIDGET_IMAGE, image_widget_event);
720 register_widget_type(xuni,
721 "image tile", WIDGET_IMAGE_TILE, image_tile_widget_event);
722 register_widget_type(xuni, "label", WIDGET_LABEL, label_widget_event);
723 register_widget_type(xuni,
724 "listbox", WIDGET_LISTBOX, listbox_widget_event);
725 register_widget_type(xuni, "panel", WIDGET_PANEL, panel_widget_event);
726 register_widget_type(xuni,
727 "scrollbar", WIDGET_SCROLLBAR, scrollbar_widget_event);
728 register_widget_type(xuni,
729 "textarea", WIDGET_TEXTAREA, textarea_widget_event);
730 register_widget_type(xuni,
731 "textbox", WIDGET_TEXTBOX, textbox_widget_event);
732 register_widget_type(xuni, "theme", WIDGET_THEME, theme_widget_event);
735 /*! Frees the memory allocated for a wtype_array_t structure. Used by
736 free_xuni() to free the structure of that type that is a memory of struct
737 xuni_t.
738 \param wtype The structure to free the memory for.
740 void free_wtype(struct wtype_array_t *wtype) {
741 xuni_memory_free(wtype->type);
744 static int widget_type_compare(void *data, size_t n, void *find) {
745 struct wtype_t *array = data;
746 const char *a = find;
747 const char *b = array[n].name;
749 return strcmp(a, b);
752 void register_widget_type(struct xuni_t *xuni, const char *name, size_t type,
753 widget_event_handler_t handler) {
755 size_t pos;
757 if(binary_insertion_sort(xuni->wtype->type, xuni->wtype->types,
758 name, &pos, widget_type_compare)) {
760 log_message(ERROR_TYPE_DATASTRUCT, 0, __FILE__, __LINE__,
761 "Adding duplicate widget type \"%s\"", name);
762 return;
765 xuni->wtype->type = xuni_memory_resize(xuni->wtype->type,
766 (xuni->wtype->types + 1) * sizeof(*xuni->wtype->type));
767 memmove(xuni->wtype->type + pos + 1, xuni->wtype->type + pos,
768 (xuni->wtype->types - pos) * sizeof(*xuni->wtype->type));
769 xuni->wtype->types ++;
771 xuni->wtype->type[pos].name = name;
772 xuni->wtype->type[pos].handler = handler;
775 void call_widget_event(struct xuni_t *xuni, struct widget_t *widget,
776 enum widget_event_t type) {
778 /* The first condition is not strictly necessary, being encompassed by the
779 second one as it is, but it is included for clarity.
781 if(widget->type == (size_t)-1 || widget->type >= xuni->wtype->types) {
782 log_message(ERROR_TYPE_WARNING, 0, __FILE__, __LINE__,
783 "Invalid or unregistered widget type: %i\n", (int)widget->type);
784 return;
787 xuni->wtype->type[widget->type].handler(xuni, widget, type);
790 void call_widget_event_func(struct xuni_t *xuni, struct widget_t *widget,
791 enum widget_event_t event, widget_event_func_t function[],
792 size_t functions) {
794 if(event >= functions) {
795 log_message(ERROR_TYPE_LOOKUP_TABLE, 0, __FILE__, __LINE__,
796 "\"%s\": supports %lu events, tried to access [%lu]\n",
797 xuni->wtype->type[widget->type].name,
798 (unsigned long)functions, (unsigned long)event);
799 return;
802 if(function[event]) {
803 (*function[event])(xuni, widget);
807 /*! Makes sure that the widget \a widget is of type \a type. If it isn't,
808 raises an error message and returns nonzero.
810 Used where a specific widget type is expected, such as for widget event
811 handler functions.
813 \param xuni A pointer to the main xuni structure. The wtype member of this
814 structure is used to determine the names of widgets, if the widget
815 \a widget did not match the expected type.
816 \param widget The widget to examine. Should be of type \a type.
817 \param type The type that the widget \a widget ought to be.
818 \param file The file in which the calling function is located. Should be
819 \c __FILE__. (Used to report widget type mismatches.)
820 \param line The line number that this function was called from. Should be
821 \c __LINE__. (Used when the widget \a widget did not match the
822 expected type.)
823 \return Zero if the widget \a widget is of the expected type \a type,
824 nonzero otherwise.
826 int assert_widget_type(struct xuni_t *xuni, struct widget_t *widget,
827 size_t type, const char *file, int line) {
829 if(widget->type != type) {
830 log_message(ERROR_TYPE_DATASTRUCT, 0, file, line,
831 "Widget type mismatch: expected type %s, got type %s",
832 get_widget_type_name(xuni, type),
833 get_widget_type_name(xuni, widget->type));
835 return 1;
838 return 0;
841 /*! Returns the visibility of \a widget, AND'ed with \a visibility. This means
842 that the return value will be \a visibility if all of the OR'd visibility
843 types in \a visibility are true.
845 \param widget The widget to check for the visibilities in \a visibility.
846 \param visibility The visibilities to check \a widget for.
847 \return The visibility of the widget \a widget AND'ed with \a visibility.
849 int get_widget_visibility(struct widget_t *widget,
850 enum widget_visibility_t visibility) {
852 if(!widget) return 0;
854 return widget->visibility & visibility;
857 /*! Sets or unsets the visibility of the widget \a widget.
858 \param widget The widget for which to set or unset the visibility of.
859 \param visibility An OR'd value of widget_visibility_ts, describing what
860 visibility type should be set or unset.
861 \param set True or false, to set or unset the visibility \a visibility.
863 void set_widget_visibility(struct widget_t *widget,
864 enum widget_visibility_t visibility, int set) {
866 if(!widget) return;
868 if(set) {
869 widget->visibility |= visibility;
871 else {
872 widget->visibility &= ~visibility;