6 #include <string.h> /* for memmove(), strcmp(), strlen(), etc. */
9 #include "SDL_gfxPrimitives.h"
18 #include "resource/calcfunc.h"
20 #include "widget/widgets.h"
22 #include "widget/box.h"
23 #include "widget/button.h"
24 #include "widget/checkbox.h"
25 #include "widget/dump.h"
26 #include "widget/font.h"
27 #include "widget/image.h"
28 #include "widget/image_tile.h"
29 #include "widget/label.h"
30 #include "widget/listbox.h"
31 #include "widget/panel.h"
32 #include "widget/scrollbar.h"
33 #include "widget/textbox.h"
34 #include "widget/theme.h"
36 static int set_widget_sel_compose(struct widget_sel_t
*sel
, int xp
, int yp
,
37 struct widget_t
*widget
);
38 static enum widget_type_t
get_widget_type(const char *find
);
39 static double get_angle(struct resource_list_t
*list
);
40 static size_t find_font_name(struct resource_list_t
*list
);
41 static int init_resource_widget_ref(struct xuni_t
*xuni
,
42 struct widget_t
*widget
, enum widget_type_t type
,
43 struct resource_list_t
*list
);
44 static enum label_type_t
get_label_alignment(const char *name
);
45 static enum scrollbar_use_t
get_scrollbar_use(const char *name
);
46 static void init_resource_widget(struct xuni_t
*xuni
, struct widget_t
*widget
,
47 enum widget_type_t type
, struct resource_list_t
*list
);
48 static enum pos_pack_t
get_pos_pack(const char *name
);
49 static void process_widget_accelerators(struct xuni_t
*xuni
,
50 struct widget_t
*panel
, struct widget_t
*widget
,
51 struct resource_list_t
*list
);
52 static void widget_accelerator_from_string(struct xuni_t
*xuni
,
53 struct widget_t
*panel
, struct widget_t
*widget
, const char *data
);
54 static SDLMod
get_key_mod_from_string(const char *name
);
55 static SDLKey
get_key_identifier_from_string(const char *name
);
56 static void add_resource_widget(struct xuni_t
*xuni
, struct widget_t
**base
,
57 struct resource_data_t
*data
);
59 void init_theme_structure(struct theme_t
*theme
) {
61 theme
->cursors
.normal
= 0;
62 theme
->cursors
.text
= 0;
63 theme
->cursors
.which
= CURSOR_NORMAL
;
66 /*! Initializes the gui member of the structure \a xuni.
67 \param xuni The xuni structure to initialize the gui member of.
69 void init_gui(struct xuni_t
*xuni
) {
70 /*gui->panel = allocate_panel(0);*/
71 xuni
->gui
->widget
= 0;
73 init_edit(&xuni
->gui
->edit
);
74 clear_gui(xuni
, (size_t)-1, -1);
77 void init_edit(struct widget_edit_t
*edit
) {
86 void clear_gui(struct xuni_t
*xuni
, panel_type_t panel
, int keep
) {
87 clear_widget_sel(xuni
->gui
->widget
);
88 clear_sel(&xuni
->gui
->sel
);
89 clear_active(xuni
, &xuni
->gui
->active
, keep
); /* before clear_edit() */
90 clear_edit(&xuni
->gui
->edit
);
91 clear_tab(&xuni
->gui
->tab
, panel
);
94 void clear_sel(struct widget_sel_t
*sel
) {
100 void clear_edit(struct widget_edit_t
*edit
) {
104 xuni_memory_free(edit
->prev
);
108 edit
->datawidget
= 0;
115 void clear_active(struct xuni_t
*xuni
, struct widget_p_t
*wp
, int keep
) {
117 revert_widget(xuni
, wp
->widget
);
119 widget_event(xuni
, wp
->widget
, WIDGET_EVENT_RESCALE
);
122 deactivate_widget(wp
->widget
, xuni
);
127 SDL_EnableUNICODE(0);
130 void clear_tab(struct widget_tab_t
*tab
, panel_type_t panel
) {
132 tab
->sel
= (size_t)-1;
135 /* !!! lots of const -> non-const in this function */
136 void edit_add_char(struct widget_edit_t
*edit
, char c
) {
137 if(edit
->len
+ 1 >= edit
->alloc
) {
138 if(!edit
->alloc
) edit
->alloc
= 2;
139 else edit
->alloc
*= 2;
142 = xuni_memory_resize((char *)edit
->data
->text
,
146 if(edit
->pos
!= edit
->len
) {
147 memmove((char *)edit
->data
->text
+ edit
->pos
+ 1,
148 (char *)edit
->data
->text
+ edit
->pos
,
149 edit
->len
- edit
->pos
+ 1);
152 ((char *)edit
->data
->text
)[edit
->pos
] = c
;
154 if(edit
->pos
== edit
->len
) {
155 ((char *)edit
->data
->text
)[edit
->pos
+ 1] = 0;
162 /* !!! lots of const -> non-const in this function */
163 void edit_del_char(struct widget_edit_t
*edit
) {
164 if(edit
->pos
+ 1 != edit
->len
) {
165 memmove((char *)edit
->data
->text
+ edit
->pos
,
166 (char *)edit
->data
->text
+ edit
->pos
+ 1,
167 edit
->len
- edit
->pos
+ 1 - 1);
169 else ((char *)edit
->data
->text
)[edit
->pos
] = 0;
174 int clear_widget_sel(struct widget_t
*widget
) {
178 if(!widget
) return 0;
180 if(widget
->sel
) repaint
= 1;
183 if(!widget
->compose
) return 0;
185 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
186 repaint
= clear_widget_sel(widget
->compose
->widget
[x
]) || repaint
;
192 struct widget_t
*set_widget_sel_rec(struct widget_sel_t
*sel
, int xp
, int yp
,
193 struct widget_t
*widget
, int *repaint
) {
196 struct widget_t
*w
= 0, *last
= 0;
199 if(widget
&& !strcmp(widget
->name
, "data")) {
200 /*printf("item \"%s\": ", widget->p.label->text);*/
203 printf("in_sdl_rect()? %s",
204 in_sdl_rect(xp
, yp
, &widget
->pos
->real
) ? "yes" : "no");
205 printf(" pos_in_rect()? %s\n",
206 pos_in_rect(xp
, yp
, widget
->pos
) ? "yes" : "no");
208 if(!in_sdl_rect(xp
, yp
, &widget
->pos
->real
)) {
209 printf("cursor: (%i,%i) widget: (%i,%i) to (%i,%i)\n",
213 widget
->pos
->real
.x
+ widget
->pos
->real
.w
,
214 widget
->pos
->real
.y
+ widget
->pos
->real
.h
);
219 if(widget
&& widget
->visibility
& WIDGET_VISIBILITY_VISIBLE
220 && in_sdl_rect(xp
, yp
, &widget
->pos
->real
)) {
222 if(widget
->compose
) {
223 for(x
= widget
->compose
->widgets
- 1; x
!= (size_t)-1; x
--) {
224 w
= set_widget_sel_rec(sel
, xp
, yp
,
225 widget
->compose
->widget
[x
], repaint
);
227 if(!last
&& widget
->compose
->widget
[x
]->visibility
228 & WIDGET_VISIBILITY_INDEPENDENT
) {
233 if(!set_widget_sel_compose(sel
, xp
, yp
, w
)) break;
238 if(x
!= (size_t)-1) x
--;
240 while(x
!= (size_t)-1) {
241 *repaint
= clear_widget_sel(widget
->compose
->widget
[x
])
248 if(!last
&& widget
->visibility
& WIDGET_VISIBILITY_SELABLE
) {
250 if(!widget
->sel
) *repaint
= 1;
254 if(widget
->sel
) *repaint
= 1;
258 else *repaint
= clear_widget_sel(widget
) || *repaint
;
263 static int set_widget_sel_compose(struct widget_sel_t
*sel
, int xp
, int yp
,
264 struct widget_t
*widget
) {
269 /*if(!(widget->visibility & WIDGET_VISIBILITY_INDEPENDENT)) {
270 widget->base->sel = 1;
273 if(!(widget
->base
->visibility
& WIDGET_VISIBILITY_NOT_COMPOSE
)) {
281 int set_widget_sel_repaint(struct widget_sel_t
*sel
, int xp
, int yp
,
282 int click
, struct widget_t
*widget
) {
284 return set_widget_repaint(sel
, xp
, yp
, click
, widget
)
285 | set_widget_sel(sel
, xp
, yp
, click
, widget
);
288 int set_widget_sel(struct widget_sel_t
*sel
, int xp
, int yp
, int click
,
289 struct widget_t
*widget
) {
294 if(!widget
) return 0;
296 if(sel
->p
.widget
&& !sel
->clickin
&& !sel
->wasin
) clear_sel(sel
);
299 /*clear_widget_sel(widget);*/
300 w
= set_widget_sel_rec(sel
, xp
, yp
, widget
, &repaint
);
302 /*if(repaint && w == sel->p.widget) puts("inline change");*/
304 if(w
&& w
!= sel
->p
.widget
) {
307 sel
->clickin
= click
;
316 int set_widget_repaint(struct widget_sel_t
*sel
, int xp
, int yp
, int click
,
317 struct widget_t
*widget
) {
322 v
= set_widget_sel(sel
, xp
, yp
, click
, widget
);
324 r
= pos_in_rect(xp
, yp
, sel
->p
.widget
->pos
);
326 /* !!! set v=1 only if the widget _changes_ upon loss of mouse focus or whatever */
328 /* the mouse focus in the widget was toggled */
329 if(sel
->wasin
!= r
) {
334 /* the mouse button was clicked or released inside the widget */
335 if(sel
->clickin
!= click
) {
336 sel
->clickin
= click
;
340 if(v
) sel
->p
.widget
->repaint
= 1;
346 struct load_resource_widget_t
{
348 struct widget_t
**widget
;
351 static void load_resource_widgets_callback(void *vdata
,
352 struct resource_data_t
*data
);
354 static void load_resource_widgets_callback(void *vdata
,
355 struct resource_data_t
*data
) {
357 struct load_resource_widget_t
*load_data
= vdata
;
359 add_resource_widget(load_data
->xuni
, load_data
->widget
, data
);
362 void load_resource_widgets(struct xuni_t
*xuni
, struct widget_t
**widget
,
363 struct resource_data_t
*data
) {
365 struct load_resource_widget_t callback_data
;
366 callback_data
.xuni
= xuni
;
367 callback_data
.widget
= widget
;
369 search_resource_tag(data
, "widget", 1,
370 load_resource_widgets_callback
, &callback_data
);
373 /* !!! use wtype instead */
374 static enum widget_type_t
get_widget_type(const char *find
) {
375 struct string_index_t data
[] = {
377 {"button", WIDGET_BUTTON
},
378 {"checkbox", WIDGET_CHECKBOX
},
379 {"combobox", WIDGET_COMBOBOX
},
380 {"font", WIDGET_FONT
},
381 {"image", WIDGET_IMAGE
},
382 {"image tile", WIDGET_IMAGE_TILE
},
383 {"label", WIDGET_LABEL
},
384 {"listbox", WIDGET_LISTBOX
},
385 {"panel", WIDGET_PANEL
},
386 {"textarea", WIDGET_TEXTAREA
},
387 {"textbox", WIDGET_TEXTBOX
},
388 {"theme", WIDGET_THEME
}
390 size_t type
= string_to_index(data
, sizeof(data
) / sizeof(*data
), find
);
392 if(type
== (size_t)-1) {
393 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
394 "Invalid widget type: \"%s\"", find
);
397 return (enum widget_type_t
)type
;
400 static double get_angle(struct resource_list_t
*list
) {
402 struct resource_list_t
*anglep
;
405 anglep
= first_resource_tag(list
, "angle");
406 unit
= find_resource_text(anglep
, "unit");
407 angle
= get_expression_value(first_resource_text(anglep
), 0);
410 if(!strcmp(unit
, "degrees")) angle
= degrees_to_radians(angle
);
411 else if(strcmp(unit
, "radians")) {
412 printf("*** Unrecognized unit type \"%s\" for \"angle\"\n",
420 /* this could handle all theme widgets */
421 static size_t find_font_name(struct resource_list_t
*list
) {
422 const char *name
= find_resource_text(list
, "font");
423 enum wid_theme_t which
= THEME_FONT_SANS
;
426 if(!strcmp(name
, "sans")) which
= THEME_FONT_SANS
;
427 else if(!strcmp(name
, "mono")) which
= THEME_FONT_MONO
;
429 printf("*** Unknown font name \"%s\"\n", name
);
433 return (size_t)which
;
436 static int init_resource_widget_ref(struct xuni_t
*xuni
,
437 struct widget_t
*widget
, enum widget_type_t type
,
438 struct resource_list_t
*list
) {
441 struct widget_t
*ref
;
443 refname
= find_resource_text(list
, "ref");
444 if(!refname
) return 0;
446 ref
= find_widget(xuni
->gui
->widget
, refname
);
453 xuni_memory_increment(ref
->p
.font
);
454 widget
->p
.font
= ref
->p
.font
;
458 printf("*** Error: <ref> not supported for widgets of type %s\n",
459 get_widget_type_name(xuni
, type
));
466 static enum label_type_t
get_label_alignment(const char *name
) {
467 struct string_index_t data
[] = {
468 {"center", LABEL_ALIGN_CENTRE
},
469 {"centre", LABEL_ALIGN_CENTRE
},
470 {"left", LABEL_ALIGN_LEFT
},
471 {"right", LABEL_ALIGN_RIGHT
}
475 if(!name
) return LABEL_ALIGN_LEFT
;
477 index
= string_to_index(data
, sizeof(data
) / sizeof(*data
), name
);
479 if(index
== (size_t)-1) {
480 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
481 "Invalid label alignment type: \"%s\"", name
);
482 return LABEL_ALIGN_LEFT
;
488 static enum scrollbar_use_t
get_scrollbar_use(const char *name
) {
489 struct string_index_t data
[] = {
490 {"both", SCROLLBAR_USE_BOTH
},
491 {"horizontal", SCROLLBAR_USE_HORIZONTAL
},
492 {"none", SCROLLBAR_USE_NONE
},
493 {"vertical", SCROLLBAR_USE_VERTICAL
}
497 if(!name
) return SCROLLBAR_USE_VERTICAL
;
499 index
= string_to_index(data
, sizeof(data
) / sizeof(*data
), name
);
501 if(index
== (size_t)-1) {
502 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
503 "Invalid scrollbar use: \"%s\"", name
);
504 return SCROLLBAR_USE_VERTICAL
;
510 static void init_resource_widget(struct xuni_t
*xuni
, struct widget_t
*widget
,
511 enum widget_type_t type
, struct resource_list_t
*list
) {
513 if(init_resource_widget_ref(xuni
, widget
, type
, list
)) return;
517 init_box(widget
, BOX_STYLE_NORMAL
, 0);
520 init_button(widget
, new_sub_label(widget
,
521 find_font_name(list
),
522 find_resource_text(list
, "text")));
524 case WIDGET_CHECKBOX
:
525 init_checkbox(widget
, xuni
,
526 find_font_name(list
),
527 find_resource_text(list
, "text"), 0);
529 case WIDGET_COMBOBOX
:
530 init_combobox(xuni
, widget
, find_font_name(list
));
533 init_font(widget
, find_resource_text(list
, "path"));
536 init_image(widget
, find_resource_text(list
, "path"), get_angle(list
));
538 case WIDGET_IMAGE_TILE
:
539 init_image_tile(widget
, find_resource_text(list
, "path"),
540 (int)get_expression_value(find_resource_text(list
, "xinc"), 0),
541 (int)get_expression_value(find_resource_text(list
, "yinc"), 0));
544 init_label(widget
, find_font_name(list
),
545 find_resource_text(list
, "text"),
546 get_label_alignment(find_resource_text(list
, "align")),
547 (Uint8
)get_expression_value(find_resource_text(list
,
549 (Uint8
)get_expression_value(find_resource_text(list
,
551 (Uint8
)get_expression_value(find_resource_text(list
,
555 init_listbox(widget
, xuni
,
556 get_scrollbar_use(find_resource_text(list
, "scrollbar-allow")),
557 get_scrollbar_use(find_resource_text(list
, "scrollbar-force")));
560 init_panel_from_resource(xuni
, widget
, list
);
561 /*init_panel(widget);*/
563 case WIDGET_TEXTAREA
:
564 init_textarea(widget
, xuni
);
567 init_textbox(widget
, xuni
, find_resource_text(list
, "text"),
568 find_font_name(list
));
572 get_expression_value(find_resource_text(list
, "box-width"),
574 get_expression_value(find_resource_text(list
, "box-height"),
578 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
579 "Widgets of type %s cannot be instantiated in resource files",
580 get_widget_type_name(xuni
, type
));
585 static enum pos_pack_t
get_pos_pack(const char *name
) {
586 struct string_index_t data
[] = {
587 {"bottom", POS_PACK_BOTTOM
},
588 {"none", POS_PACK_NONE
},
589 {"top", POS_PACK_TOP
}
593 if(!name
) return POS_PACK_NONE
;
595 index
= string_to_index(data
, sizeof(data
) / sizeof(*data
), name
);
597 if(index
== (size_t)-1) {
598 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
599 "Invalid position pack type: \"%s\"", name
);
600 return POS_PACK_NONE
; /* a sensible default */
606 static void process_widget_accelerators(struct xuni_t
*xuni
,
607 struct widget_t
*panel
, struct widget_t
*widget
,
608 struct resource_list_t
*list
) {
612 for(x
= 0; x
< list
->n
; x
++) {
613 if(list
->data
[x
]->type
!= RESOURCE_TAG
614 || strcmp(list
->data
[x
]->data
.tag
->name
, "accelerator")) {
619 if(panel
->type
!= WIDGET_PANEL
) {
620 printf("Attempted to add an accelerator to a \"%s\"\n",
621 get_widget_type_name(xuni
, panel
->type
));
624 widget_accelerator_from_string(xuni
, panel
, widget
,
625 first_resource_text(list
->data
[x
]->data
.tag
->list
));
630 enum { ACCELERATOR_ERROR
= 0xf000 };
632 static void widget_accelerator_from_string(struct xuni_t
*xuni
,
633 struct widget_t
*panel
, struct widget_t
*widget
, const char *data
) {
637 SDLKey key
= (size_t)-1;
638 SDLMod mod
= KMOD_NONE
, m
= KMOD_NONE
;
643 for(end
= data
; isalnum(*end
); end
++);
647 /*printf("accelerator: \"%s\"\n", data);*/
648 m
= get_key_mod_from_string(data
);
649 if(m
== ACCELERATOR_ERROR
) {
650 if(key
!= ACCELERATOR_ERROR
) {
651 key
= get_key_identifier_from_string(data
);
652 if(key
== ACCELERATOR_ERROR
) {
653 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
654 "Unknown key/mod name \"%s\"\n", data
);
658 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
659 "Multiple key specified: \"%s\"\n", data
);
666 for(data
= end
; isspace(*data
); data
++);
670 add_widget_accelerator(xuni
, panel
, widget
, key
, mod
);
673 static SDLMod
get_key_mod_from_string(const char *name
) {
674 struct string_index_t data
[] = {
676 {"control", KMOD_CTRL
},
679 {"lcontrol", KMOD_LCTRL
},
680 {"lctrl", KMOD_LCTRL
},
681 {"lshift", KMOD_LSHIFT
},
683 {"nothing", KMOD_NONE
},
685 {"rcontrol", KMOD_RCTRL
},
686 {"rctrl", KMOD_RCTRL
},
687 {"rshift", KMOD_RSHIFT
},
688 {"shift", KMOD_SHIFT
}
692 if(!name
) return ACCELERATOR_ERROR
;
694 index
= string_to_index(data
, sizeof(data
) / sizeof(*data
), name
);
696 if(index
== (size_t)-1) return ACCELERATOR_ERROR
;
697 /*printf("Found mod accelerator: %x\n", (unsigned)index);*/
702 static SDLKey
get_key_identifier_from_string(const char *name
) {
703 struct string_index_t data
[] = {
719 if(!name
) return ACCELERATOR_ERROR
;
721 if(*name
&& !name
[1]) {
725 index
= string_to_index(data
, sizeof(data
) / sizeof(*data
), name
);
727 if(index
== (size_t)-1) {
728 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
729 "Unknown key name \"%s\"", name
);
730 return ACCELERATOR_ERROR
;
736 /*! Creates a widget based on the information in the resource tree node
739 Also sets the current theme to the first theme that is found in the
742 \param xuni The xuni_t structure, to pass on to other functions and set
743 the current theme in and so on.
744 \param base The widget to add the new widget to as a compose widget. If
745 \a base is NULL, it means that the root widget is being created, in
746 which case \a base is set to point to the new widget.
747 \param data The resource tree node representing a <widget>, from which to
750 static void add_resource_widget(struct xuni_t
*xuni
, struct widget_t
**base
,
751 struct resource_data_t
*data
) {
753 struct widget_t
*widget
;
754 struct resource_list_t
*list
;
755 enum widget_type_t type
;
757 list
= data
->data
.tag
->list
;
760 widget
= init_resource_widget_ref(xuni
, list
);
766 type
= get_widget_type(find_resource_text(list
, "type"));
767 if(type
== WIDGET_NONE
) return;
770 *base
= allocate_widget(find_resource_text(list
, "name"), 0);
774 if(!(*base
)->compose
) (*base
)->compose
= allocate_panel(*base
);
776 add_allocate_widget(*base
, find_resource_text(list
, "name"));
778 widget
= last_compose_widget(*base
);
781 init_widget_pos(widget
,
782 get_expression_value(find_resource_text(list
, "xpos"), 0),
783 get_expression_value(find_resource_text(list
, "ypos"), 0),
784 get_expression_value(find_resource_text(list
, "width"), 1),
785 get_expression_value(find_resource_text(list
, "height"), 1),
786 get_pos_pack(find_resource_text(list
, "pack")));
788 if(!get_expression_value(find_resource_text(list
, "enabled"), 1)) {
789 widget
->visibility
&= ~WIDGET_VISIBILITY_CLICKABLE
;
791 if(!get_expression_value(find_resource_text(list
, "selable"), 1)) {
792 widget
->visibility
&= ~WIDGET_VISIBILITY_SELABLE
;
794 if(!get_expression_value(find_resource_text(list
, "visible"), 1)) {
795 widget
->visibility
&= ~WIDGET_VISIBILITY_VISIBLE
;
798 process_widget_accelerators(xuni
, *base
, widget
, list
);
800 init_resource_widget(xuni
, widget
, type
, list
);
802 widget_event(xuni
, widget
, WIDGET_EVENT_RESCALE
);
804 if(widget
->type
== WIDGET_THEME
) {
805 if(!xuni
->theme
->current
) {
806 xuni
->theme
->current
= widget
;
809 /* recurse (indirectly) */
810 load_resource_widgets(xuni
, &widget
, data
);
812 set_theme_nameid(widget
);
813 widget_event(xuni
, widget
, WIDGET_EVENT_RESCALE
);
815 else if(widget
->type
== WIDGET_PANEL
) {
816 /* recurse (indirectly) */
817 load_resource_widgets(xuni
, &widget
, data
);
822 /* This code returns a widget based on a list of names to dereference. It
823 works, but using WIDs is much more efficient, and this is not used at the
826 static int compare_widget_name_nonrec(struct widget_t
*widget
, va_list arg
) {
827 const char *match
= va_arg(arg
, const char *);
829 if(!widget
|| !match
) return !match
;
831 return strcmp(match
, widget
->name
) == 0
832 && compare_widget_name_nonrec(widget
->base
, arg
);
835 static int compare_widget_name_nonrec_reverse(struct widget_t
**widget
,
838 const char *match
= va_arg(arg
, const char *);
840 if(!*widget
|| !match
) return !match
;
842 if(!compare_widget_name_nonrec_reverse(widget
, arg
)
843 || !(*widget
)->name
) {
848 if(strcmp(match
, (*widget
)->name
) == 0) {
849 *widget
= (*widget
)->base
;
856 int compare_widget_name(struct widget_t
*widget
, ...) {
860 va_start(arg
, widget
);
862 r
= compare_widget_name_nonrec_reverse(&widget
, arg
);
870 /*! Allocates enough space for a struct widget_nameid_t.
871 \return A pointer to the newly allocated nameid structure.
873 struct nameid_t
*allocate_nameid(void) {
874 struct nameid_t
*nameid
= xuni_memory_allocate(sizeof(*nameid
));
882 /*! Adds the widget \a widget to \a nameid.
884 \param nameid The array of nameids to add the new wid to.
885 \param widget The widget to add to \a nameid.
886 \param id The wid to use for this widget.
887 \param name The path to the widget \a widget relative to the panel widget
888 that \a nameid is a part of.
890 void init_wid_widget(struct nameid_t
*nameid
, struct widget_t
*widget
,
891 size_t id
, const char *name
) {
895 if(nameid
->widgets
<= id
) {
896 nameid
->widget
= xuni_memory_resize(nameid
->widget
,
897 (id
+ 1) * sizeof(*nameid
->widget
));
899 /* clear any new nameids allocated between nameid->widgets and id */
900 for(x
= nameid
->widgets
; x
<= id
; x
++) {
901 nameid
->widget
[x
].id
= 0;
902 nameid
->widget
[x
].name
= 0;
903 nameid
->widget
[x
].widget
= 0;
906 nameid
->widgets
= id
+ 1;
909 if(nameid
->widget
[id
].id
|| nameid
->widget
[id
].name
910 || nameid
->widget
[id
].widget
) {
912 log_message(ERROR_TYPE_WARNING
, 0, __FILE__
, __LINE__
,
913 "Duplicate wid: old: \"%s\" [%lu], new: \"%s\" [%lu]",
914 nameid
->widget
[id
].name
, (unsigned long)nameid
->widget
[id
].id
,
915 name
, (unsigned long)id
);
918 nameid
->widget
[id
].id
= id
;
919 if(widget
) widget
->id
= id
;
920 nameid
->widget
[id
].name
= name
;
921 nameid
->widget
[id
].widget
= widget
;
925 /*! Just like init_wid(), but allows the widget referred to be \a name to not
926 exist. (init_wid() would display an error in that case.)
928 Mainly useful for widgets that do not have to be loaded. Prime examples
929 of this are the various widget images of themes, like the checkbox image.
931 \param base The base of the widget, from which to use find_widget() to
932 find the widget represented by the widget path \a name.
933 \param nameid The nameid array to add the new nameid to.
934 \param id The wid of the new widget -- usually a client-defined enum
936 \param name The path to the widget, starting from \a base.
938 void init_wid_possible_zero(struct widget_t
*base
, struct nameid_t
*nameid
,
939 size_t id
, const char *name
) {
941 init_wid_widget(nameid
, find_widget(base
, name
), id
, name
);
944 /*! Adds a widget to the nameid array of \a use. The widget is located using
945 the name in \a name with the base \a base.
947 \param base The base of the widget, from which to use find_widget() to
948 find the widget represented by the widget path \a name.
949 \param use The panel widget to add the new nameid to.
950 \param id The wid of the new widget -- usually a client-defined enum
952 \param name The path to the widget, starting from \a base.
954 void init_wid(struct widget_t
*base
, struct widget_t
*use
, size_t id
,
957 struct widget_t
*widget
= find_widget(base
, name
);
959 if(!use
->p
.panel
->nameid
) {
960 use
->p
.panel
->nameid
= allocate_nameid();
964 init_wid_widget(use
->p
.panel
->nameid
, widget
, id
, name
);
967 log_message(ERROR_TYPE_RESOURCE
, 0, __FILE__
, __LINE__
,
968 "Could not find widget \"%s\" [wid %lu]", name
,
973 void init_wid_array(struct widget_t
*base
, struct widget_t
*use
,
974 struct wid_init_t
*init
, size_t n
) {
978 for(x
= 0; x
< n
; x
++) {
979 init_wid(base
, use
, init
[x
].id
, init
[x
].name
);
983 int widget_process_character(struct xuni_t
*xuni
, SDL_keysym
*sym
) {
984 struct widget_t
*widget
= xuni
->gui
->active
.widget
;
986 if(!widget
) return 0;
988 /*printf("widget_process_character(): widget=%p, key=%i [%c]\n",
989 (void *)widget, sym->unicode,
990 isprint(sym->unicode) ? sym->unicode : '-');*/
993 if(widget
->type
== WIDGET_TEXTBOX
) {
994 widget
= widget
->compose
->widget
[WID_TEXTBOX_LABEL
];
997 if(widget
->type
== WIDGET_LABEL
) {
998 if(isprint(sym
->unicode
)) {
999 edit_add_char(&xuni
->gui
->edit
, sym
->unicode
);
1001 else if(sym
->unicode
== '\b' && xuni
->gui
->edit
.pos
) {
1002 xuni
->gui
->edit
.pos
--;
1003 edit_del_char(&xuni
->gui
->edit
);
1005 else if(sym
->unicode
== '\r') {
1006 clear_active(xuni
, &xuni
->gui
->active
, 1);
1008 else if(sym
->sym
== SDLK_DELETE
1009 && xuni
->gui
->edit
.pos
< xuni
->gui
->edit
.len
) {
1011 edit_del_char(&xuni
->gui
->edit
);
1013 else if(sym
->sym
== SDLK_LEFT
&& xuni
->gui
->edit
.pos
) {
1014 xuni
->gui
->edit
.pos
--;
1016 else if(sym
->sym
== SDLK_RIGHT
1017 && xuni
->gui
->edit
.pos
< xuni
->gui
->edit
.len
) {
1019 xuni
->gui
->edit
.pos
++;
1021 else if(sym
->sym
== SDLK_END
) {
1022 xuni
->gui
->edit
.pos
= xuni
->gui
->edit
.len
;
1024 else if(sym
->sym
== SDLK_HOME
) {
1025 xuni
->gui
->edit
.pos
= 0;
1031 if(xuni
->gui
->edit
.data
) {
1032 reposition_label_data(xuni
, xuni
->gui
->edit
.data
,
1033 &xuni
->gui
->edit
, xuni
->gui
->edit
.pos
);
1039 /*printf("data: \"%s\"\n", xuni->gui->edit.data);*/
1044 int widget_can_be_active(struct widget_t
*widget
) {
1045 if(!widget
) return 0;
1047 if(widget
->type
== WIDGET_TEXTBOX
) return 1;
1052 void update_widget(struct xuni_t
*xuni
, struct widget_t
*widget
) {
1055 if(widget
->type
== WIDGET_TEXTBOX
) {
1056 /*gui->sel.p.widget->base->compose
1057 ->widget[WID_TEXTBOX_LABEL]->p.label->text = gui->edit.data;*/
1059 widget_event(xuni
, widget
, WIDGET_EVENT_RESCALE
);
1063 void enable_unicode(const struct widget_t
*widget
) {
1068 if(widget
->type
== WIDGET_TEXTBOX
) {
1072 if(SDL_EnableUNICODE(-1) != v
) SDL_EnableUNICODE(v
);
1075 void activate_widget(struct widget_t
*widget
, struct xuni_t
*xuni
,
1078 struct widget_edit_t
*edit
= &xuni
->gui
->edit
;
1084 if(widget
->type
== WIDGET_TEXTBOX
) {
1085 struct label_t
*label
= widget
->compose
->widget
[WID_TEXTBOX_LABEL
]
1087 size_t len
= label
->text
? strlen(label
->text
) : 0;
1089 if(edit
->data
) deactivate_widget(xuni
->gui
->active
.widget
, xuni
);
1092 edit
->datawidget
= widget
->compose
->widget
[WID_TEXTBOX_LABEL
];
1094 edit
->prev
= xuni_memory_allocate(sizeof(*edit
->prev
));
1095 *edit
->prev
= *label
;
1097 edit
->data
->text
= xuni_memory_duplicate_string_len(label
->text
, len
);
1099 edit
->len
= edit
->alloc
= label
->text
? len
: 0;
1102 w
= widget
->compose
->widget
[WID_TEXTBOX_LABEL
];
1104 x
= xp
- w
->pos
->real
.x
;
1105 if(w
->pos
->clip
) x
+= w
->pos
->clip
->xclip
;
1107 edit
->pos
= width_to_label_pos(x
,
1108 get_theme_widget(xuni
, label
->font
),
1109 (char *)label
->text
); /* !!! const */
1117 void revert_widget(struct xuni_t
*xuni
, struct widget_t
*widget
) {
1120 if(widget
->type
== WIDGET_TEXTBOX
) {
1121 struct widget_t
*label
= widget
->compose
->widget
[WID_TEXTBOX_LABEL
];
1123 /*printf("revert_widget(): edit: %p \"%s\"\n", label->p.label->text,
1124 label->p.label->text);
1125 printf("revert_widget(): prev: %p \"%s\"\n",
1126 xuni->gui->edit.prev->text, xuni->gui->edit.prev->text);*/
1128 xuni_memory_free((char *)label
->p
.label
->text
); /* !!! const */
1129 /*SDL_FreeSurface(label->p.label->label);*/
1131 if(xuni
->gui
->edit
.prev
) {
1132 label
->p
.label
->text
= xuni
->gui
->edit
.prev
->text
;
1134 xuni_memory_free(xuni
->gui
->edit
.prev
);
1136 else label
->p
.label
->text
= xuni_memory_duplicate_string_len("", 0);
1138 widget_event(xuni
, label
, WIDGET_EVENT_RESCALE
);
1140 init_edit(&xuni
->gui
->edit
);
1144 void deactivate_widget(struct widget_t
*widget
, struct xuni_t
*xuni
) {
1147 if(widget
->type
== WIDGET_TEXTBOX
) {
1148 /* makes comboboxes have a history of what was typed in them */
1150 && widget->base->type == WIDGET_COMBOBOX) {
1152 struct widget_t *label = widget->compose
1153 ->widget[WID_TEXTBOX_LABEL];
1155 add_combobox_item(xuni, widget->base, label->p.label->font,
1156 label->p.label->text);
1157 widget_event(xuni, widget->base->compose->widget
1158 [WID_COMBOBOX_DROPDOWN], WIDGET_EVENT_RESCALE);
1161 call_deactivate_func(xuni
, widget
);
1163 xuni_memory_free((char *)xuni
->gui
->edit
.prev
->text
); /* !!! const */
1164 /*free_surface(xuni->gui->edit.prev->label);*/
1165 xuni_memory_free(xuni
->gui
->edit
.prev
);
1167 init_edit(&xuni
->gui
->edit
);
1171 void perform_widget_click(struct xuni_t
*xuni
, struct widget_t
*widget
) {
1175 if(widget
->type
== WIDGET_CHECKBOX
) {
1176 toggle_checkbox(widget
);
1178 else if(widget
->base
->type
== WIDGET_SCROLLBAR
) {
1179 if(widget
->base
->compose
->widget
[WID_SCROLLBAR_UP
]
1182 move_scrollbar(xuni
, widget
->base
, -10);
1184 else if(widget
->base
->compose
->widget
1185 [WID_SCROLLBAR_DOWN
] == widget
) {
1187 move_scrollbar(xuni
, widget
->base
, 10);
1190 /*reposition_widget(xuni, widget->base);*/
1191 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
->base
->base
,
1192 WIDGET_EVENT_REPOSITION
);
1194 else if(widget
->base
->type
== WIDGET_COMBOBOX
) {
1195 if(widget
->base
->compose
->widget
[WID_COMBOBOX_BUTTON
] == widget
) {
1196 widget
->base
->compose
->widget
[WID_COMBOBOX_DROPDOWN
]
1197 ->visibility
^= WIDGET_VISIBILITY_VISIBLE
;
1203 void free_gui(struct xuni_t
*xuni
) {
1204 widget_event(xuni
, xuni
->gui
->widget
, WIDGET_EVENT_FREE
);