7 #include "SDL_framerate.h"
13 #include "resource/resource.h"
15 #include "widget/dump.h"
16 #include "widget/widgets.h"
17 #include "widget/listbox.h"
19 static int call_perform_click_func(struct xuni_t
*xuni
,
20 struct panel_data_t
*panel
, struct widget_t
*widget
, panel_type_t
*mode
);
21 static void call_free_funcs(struct widget_t
*widget
, struct xuni_t
*xuni
);
23 static SDL_Cursor
*sdl_cursor_from_xpm(const char *image
[]);
24 static void set_widget_cursor(struct xuni_t
*xuni
);
26 static void set_loop_caption(panel_type_t mode
, struct xuni_t
*xuni
);
27 static void setup_theme_cursor(struct xuni_t
*xuni
, struct widget_t
*panel
);
28 static int get_event(int frameupdate
, SDL_Event
*event
);
29 static int process_event(SDL_Event
*event
, panel_type_t
*mode
,
31 static void scroll_listbox(struct xuni_t
*xuni
, int dir
);
32 static int set_loop_widget_sel(panel_type_t mode
, int xp
, int yp
,
33 int click
, struct xuni_t
*xuni
);
34 static int find_widget_accelerator(struct xuni_accelerator_t
*accel
,
35 SDL_keysym
*key
, struct xuni_t
*xuni
, panel_type_t
*mode
);
36 static int check_sdl_key_mod(SDLMod mod
, SDLMod now
);
37 static int event_mouse_button_up(int xp
, int yp
, panel_type_t
*mode
,
39 static int perform_loop_click(struct xuni_t
*xuni
, panel_type_t
*mode
,
40 struct widget_t
*widget
);
41 static int event_key_down(struct xuni_t
*xuni
, SDL_keysym
*keysym
,
42 panel_type_t
*mode
, int *handled
);
44 /*! Calls the registered initialization functions for \a widget and all of its
45 sub-widgets. Only operates on widgets of type panel.
47 \param xuni A pointer to the main xuni structure.
48 \param widget The widget to call the initialization function for, if it is
50 \param settings A pointer to the resource tree.
52 void call_init_funcs(struct xuni_t
*xuni
, struct widget_t
*widget
,
53 struct resource_t
*settings
) {
59 if(widget
->type
== WIDGET_PANEL
60 && widget
->p
.panel
->event
[PANEL_EVENT_INIT
].handler
) {
62 widget
->p
.panel
->event
[PANEL_EVENT_INIT
].p
.init
.settings
= settings
;
63 widget
->p
.panel
->event
[PANEL_EVENT_INIT
].p
.init
.panel
= widget
;
65 (*widget
->p
.panel
->event
[PANEL_EVENT_INIT
].handler
)
66 (xuni
, widget
->p
.panel
);
70 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
71 call_init_funcs(xuni
, widget
->compose
->widget
[x
], settings
);
76 int panel_event_recursive(struct xuni_t
*xuni
, struct panel_event_t
*data
,
77 enum panel_event_type_t type
, struct widget_t
*widget
) {
84 if(widget
->type
== WIDGET_PANEL
&& data
->handler
) {
85 (*data
->handler
)(xuni
, widget
->p
.panel
);
89 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
90 r
= panel_event_recursive(xuni
, data
, type
,
91 widget
->compose
->widget
[x
]) || r
;
98 static int call_perform_click_func(struct xuni_t
*xuni
,
99 struct panel_data_t
*panel
, struct widget_t
*widget
, panel_type_t
*mode
) {
101 perform_widget_click(xuni
, widget
);
103 /*print_widget_backtrace(xuni->gui->sel.p.widget);*/
105 /* !!! quick fix to disallow clicking on a panel. Without this, for
106 example, clicking on the options graphics panel triggers the
107 fullscreen checkbox, as
108 PANEL_OPTIONS_GRAPHICS == WID_GRAPHICS_FULLSCREEN */
109 if(widget
&& panel
->event
[PANEL_EVENT_CLICK
].handler
110 && widget_nameid_access(xuni
->gui
->widget
, *mode
) != widget
) {
112 panel
->event
[PANEL_EVENT_CLICK
].p
.click
.mode
= mode
;
113 panel
->event
[PANEL_EVENT_CLICK
].p
.click
.widget
= widget
;
115 return (*panel
->event
[PANEL_EVENT_CLICK
].handler
)(xuni
, panel
);
121 void call_deactivate_func(struct xuni_t
*xuni
, struct widget_t
*widget
) {
122 struct widget_t
*base
= widget
;
124 while(base
&& base
->type
!= WIDGET_PANEL
) base
= base
->base
;
126 if(base
&& base
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].handler
) {
127 base
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].p
.deactivate
.widget
130 (*base
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].handler
)
131 (xuni
, base
->p
.panel
);
135 static void call_free_funcs(struct widget_t
*widget
, struct xuni_t
*xuni
) {
140 if(widget
->type
== WIDGET_PANEL
) {
141 if(widget
->p
.panel
->event
[PANEL_EVENT_FREE
].handler
) {
142 (*widget
->p
.panel
->event
[PANEL_EVENT_FREE
].handler
)
143 (xuni
, widget
->p
.panel
);
146 /* this is handled by free_widget() */
147 /*xuni_memory_free(widget->p.panel->data);*/
150 if(widget
->compose
) {
151 for(x
= 0; x
< widget
->compose
->widgets
; x
++) {
152 call_free_funcs(widget
->compose
->widget
[x
], xuni
);
157 /*#define HIDE_COMBOBOX_POPUPS*/
159 int default_panel_sel(struct xuni_t
*xuni
, struct panel_data_t
*data
) {
160 struct panel_event_sel_t
*sel
= &data
->event
[PANEL_EVENT_SEL
].p
.sel
;
162 return set_default_widget_sel(xuni
, sel
->mode
, sel
->xp
, sel
->yp
,
163 sel
->click
, data
->data
);
166 /* !!! this function is obsolete */
167 int set_default_widget_sel(struct xuni_t
*xuni
, panel_type_t mode
,
168 int xp
, int yp
, int click
, void *vdata
) {
170 #ifdef HIDE_COMBOBOX_POPUPS
171 struct widget_t
*widget
= xuni
->gui
->sel
.p
.widget
;
175 r
= set_widget_sel_repaint(&xuni
->gui
->sel
, xp
, yp
, click
,
176 widget_nameid_access(xuni
->gui
->widget
, mode
));
178 /*if(xuni->gui->sel.p.widget) {
179 printf("%s\n", xuni->gui->sel.p.widget->name);
182 #ifdef HIDE_COMBOBOX_POPUPS
183 /* Hide combobox popups that have become unselected. */
184 if(widget
&& widget
!= xuni
->gui
->sel
.p
.widget
) {
185 struct widget_t
*w
= xuni
->gui
->sel
.p
.widget
, *t
;
187 /* See if any comboboxes that were previously selected still are. */
189 if(w
->visibility
& WIDGET_VISIBILITY_VISIBLE
190 && w
->type
== WIDGET_COMBOBOX
) {
192 for(t
= widget
; t
; t
= t
->base
) {
202 /* If no comboboxes were selected and remain selected, hide the popups
203 for all comboboxes that were selected.
207 if(widget
->type
== WIDGET_COMBOBOX
) {
208 widget
->compose
->widget
[WID_COMBOBOX_DROPDOWN
]->visibility
209 &= ~WIDGET_VISIBILITY_VISIBLE
;
212 widget
= widget
->base
;
221 void set_panel_callbacks(struct widget_t
*widget
, void *vdata
,
223 panel_event_func_t init_func
,
224 panel_event_func_t start_func
,
225 panel_event_func_t event_func
,
226 panel_event_func_t set_widget_sel_func
,
227 panel_event_func_t perform_click_func
,
228 panel_event_func_t deactivate_func
,
229 panel_event_func_t paint_func
,
230 panel_event_func_t free_func
) {
232 widget
->p
.panel
->data
= vdata
;
233 widget
->p
.panel
->frameupdate
= frameupdate
;
234 /*widget->p.panel->init_func = init_func;
235 widget->p.panel->start_func = start_func;
236 widget->p.panel->event_func = event_func;
237 widget->p.panel->set_widget_sel_func = set_widget_sel_func;
238 widget->p.panel->perform_click_func = perform_click_func;
239 widget->p.panel->deactivate_func = deactivate_func;
240 widget->p.panel->paint_func = paint_func;
241 widget->p.panel->free_func = free_func;*/
242 widget
->p
.panel
->event
[PANEL_EVENT_INIT
].handler
= init_func
;
243 widget
->p
.panel
->event
[PANEL_EVENT_START
].handler
= start_func
;
244 widget
->p
.panel
->event
[PANEL_EVENT_EVENT
].handler
= event_func
;
245 widget
->p
.panel
->event
[PANEL_EVENT_SEL
].handler
= set_widget_sel_func
;
246 widget
->p
.panel
->event
[PANEL_EVENT_CLICK
].handler
= perform_click_func
;
247 widget
->p
.panel
->event
[PANEL_EVENT_DEACTIVATE
].handler
= deactivate_func
;
248 widget
->p
.panel
->event
[PANEL_EVENT_PAINT
].handler
= paint_func
;
249 widget
->p
.panel
->event
[PANEL_EVENT_FREE
].handler
= free_func
;
251 widget
->p
.panel
->nameid
= 0;
253 widget
->p
.panel
->accel
= 0;
256 void execute_callback(struct xuni_t
*xuni
, struct xuni_callback_t
*callback
) {
257 if(callback
&& callback
->func
) {
258 (*callback
->func
)(callback
->vdata
, xuni
);
262 /*! The main xuni loop. Indirectly calls all panel event-handling functions,
263 including initialization functions, event handlers, repaint functions,
266 This function should only be called once, after everything has been loaded
267 and set up. It should only return when the program is exiting -- but it
268 will return, so don't neglect that freeing code.
270 \param xuni The xuni structure, with most of the data required to display
271 and manage a Graphical User Interface (GUI, of course).
272 \param always A callback function that is executed for every loop of the
273 xuni event loop. Note that this can be called considerably more
274 frequently than repaint functions.
275 \param mode The panel to initially display.
277 void main_loop(struct xuni_t
*xuni
, struct xuni_callback_t
*always
,
280 panel_type_t pmode
= (size_t)-1;
281 struct panel_data_t
*panel
282 = widget_nameid_access(xuni
->gui
->widget
, mode
)->p
.panel
;
287 /*call_init_funcs(data, smode, font, theme, gui, settings);*/
289 SDL_initFramerate(&fpsm
);
290 SDL_setFramerate(&fpsm
, 30);
292 while(mode
!= (size_t)-1) {
293 execute_callback(xuni
, always
);
295 /*dump_widgets_need_repaint(xuni->gui->widget);*/
297 if(get_event(widget_nameid_access(xuni
->gui
->widget
, mode
)
298 ->p
.panel
->frameupdate
, &event
)) {
301 repaint
= process_event(&event
, &mode
, xuni
) || repaint
;
303 if(mode
== (size_t)-1) break;
304 } while(SDL_PollEvent(&event
));
306 if(mode
== (size_t)-1) break;
309 if(pmode
!= mode
) { /* !!! process_event() is called before the start_func */
310 panel
= widget_nameid_access(xuni
->gui
->widget
, mode
)->p
.panel
;
311 set_loop_caption(mode
, xuni
); /* !!! also pass pmode */
318 /* !!! this needs to go in a hover callback function of sorts */
319 set_widget_cursor(xuni
);
321 if(xuni
->smode
->focus
) {
322 if(repaint
|| panel
->frameupdate
) {
323 if(panel
->event
[PANEL_EVENT_PAINT
].handler
) {
324 panel
->event
[PANEL_EVENT_PAINT
].p
.paint
.mode
= mode
;
326 (*panel
->event
[PANEL_EVENT_PAINT
].handler
)(xuni
, panel
);
333 if(!xuni
->smode
->focus
|| panel
->frameupdate
) {
334 SDL_framerateDelay(&fpsm
);
338 set_caption("Quitting . . .");
340 call_free_funcs(xuni
->gui
->widget
, xuni
);
343 /* An XPM image of a CURSOR_TEXT, used when the mouse is inside textboxes. */
344 static const char *text_cursor
[] = {
345 /* width height num_colors chars_per_pixel */
371 static SDL_Cursor
*sdl_cursor_from_xpm(const char *image
[]) {
373 Uint8 data
[4*16] = {0};
374 Uint8 mask
[4*16] = {0};
378 for(x
= 4; x
< 16 + 4; x
++) {
379 for(y
= 0; y
< 16; y
++) {
386 switch (image
[x
][y
]) {
400 sscanf(image
[x
], "%d,%d", &hot_x
, &hot_y
);
402 return SDL_CreateCursor(data
, mask
, 16, 16, hot_x
, hot_y
);
405 static void set_widget_cursor(struct xuni_t
*xuni
) {
408 if(xuni
->gui
->sel
.p
.widget
409 && xuni
->gui
->sel
.p
.widget
->type
== WIDGET_TEXTBOX
) {
413 else now
= CURSOR_NORMAL
;
415 if(xuni
->theme
->cursors
.which
!= now
) {
416 xuni
->theme
->cursors
.which
= now
;
418 if(xuni
->theme
->cursors
.which
) {
419 if(!xuni
->theme
->cursors
.text
) {
420 xuni
->theme
->cursors
.text
= sdl_cursor_from_xpm(text_cursor
);
421 /* save the normal cursor before it is overwritten */
422 xuni
->theme
->cursors
.normal
= SDL_GetCursor();
425 SDL_SetCursor(xuni
->theme
->cursors
.text
);
428 if(!xuni
->theme
->cursors
.normal
) {
429 xuni
->theme
->cursors
.normal
= SDL_GetCursor();
432 SDL_SetCursor(xuni
->theme
->cursors
.normal
);
437 static void set_loop_caption(panel_type_t mode
, struct xuni_t
*xuni
) {
438 struct widget_t
*panel
= widget_nameid_access(xuni
->gui
->widget
, mode
);
439 struct panel_data_t
*paneldata
= panel
->p
.panel
;
444 clear_gui(xuni
, mode
, 0);
446 /* !!! set all other panels to invisible */
447 widget_nameid_access(xuni
->gui
->widget
, mode
)->visibility
448 |= WIDGET_VISIBILITY_VISIBLE
;
450 if(paneldata
->event
[PANEL_EVENT_START
].handler
) {
451 (*paneldata
->event
[PANEL_EVENT_START
].handler
)(xuni
, paneldata
);
454 setup_theme_cursor(xuni
, widget_nameid_access(xuni
->gui
->widget
, mode
));
455 SDL_GetMouseState(&xp
, &yp
);
456 set_loop_widget_sel(mode
, xp
, yp
, xuni
->gui
->sel
.clickin
, xuni
);
459 static void setup_theme_cursor(struct xuni_t
*xuni
, struct widget_t
*panel
) {
460 struct widget_t
*cursor
;
462 if(!panel
->p
.panel
->frameupdate
) return;
464 cursor
= get_theme_widget(xuni
, THEME_DEFAULT_CURSOR
);
467 prepare_paint_image(xuni
, cursor
);
469 if(cursor
->p
.image
->image
) {
474 static int get_event(int frameupdate
, SDL_Event
*event
) {
475 return frameupdate
? SDL_PollEvent(event
) : SDL_WaitEvent(event
);
478 /* handled should not be used in some cases. For example, a widget might be
479 deselected by a mouse motion event, but a xuni application (like the
480 resource editor) might want to know about the mouse motion event just the
483 /*! Handles an event from the SDL. What happens depends on the event itself.
484 However, this function will always either deal with the event itself, call
485 the appropriate event handler function for the currently visible panel, or
486 perhaps do a little bit of both.
488 Some handled events include clicking inside widgets (implemented by
489 calling set_loop_widget_sel()), pressing special keypresses like
490 printscreen (see event_key_down()), and selecting widgets when the mouse
491 moves (set_loop_widget_sel()).
493 \param event The SDL_Event that needs to be dealt with.
494 \param mode The currently visible panel, which could be changed.
495 \param xuni The main xuni_t structure.
496 \return True if the screen needs to be repainted.
498 static int process_event(SDL_Event
*event
, panel_type_t
*mode
,
499 struct xuni_t
*xuni
) {
501 struct panel_data_t
*panel
502 = widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
;
503 int repaint
= 0, handled
= 0;
505 switch(event
->type
) {
506 case SDL_MOUSEBUTTONDOWN
:
507 if(event
->button
.button
== SDL_BUTTON_WHEELUP
) {
508 scroll_listbox(xuni
, -1);
513 else if(event
->button
.button
== SDL_BUTTON_WHEELDOWN
) {
514 scroll_listbox(xuni
, 1);
520 if(event
->button
.button
!= 1) break;
522 repaint
= set_loop_widget_sel(*mode
, event
->button
.x
, event
->button
.y
,
525 if(repaint
) handled
= 1;
527 case SDL_MOUSEBUTTONUP
:
528 if(event
->button
.button
!= 1) break;
530 repaint
= event_mouse_button_up(event
->button
.x
, event
->button
.y
,
533 if(repaint
) handled
= 1;
535 case SDL_MOUSEMOTION
:
536 repaint
= set_loop_widget_sel(*mode
, event
->button
.x
, event
->button
.y
,
537 xuni
->gui
->sel
.clickin
, xuni
);
539 /*if(repaint) handled = 1;*/
541 case SDL_VIDEORESIZE
:
542 if(!resize_screen(xuni
->smode
, &event
->resize
)) {
543 widget_event(xuni
, xuni
->gui
->widget
, WIDGET_EVENT_RESCALE
);
545 xuni
->gui
->widget
->p
.panel
546 ->event
[PANEL_EVENT_EVENT
].p
.event
.mode
= mode
;
547 xuni
->gui
->widget
->p
.panel
548 ->event
[PANEL_EVENT_EVENT
].p
.event
.event
= event
;
550 panel_event_recursive(xuni
,
551 &xuni
->gui
->widget
->p
.panel
->event
[PANEL_EVENT_EVENT
],
552 PANEL_EVENT_EVENT
, xuni
->gui
->widget
);
555 if(focus_changed(xuni
->smode
, SDL_APPACTIVE
)) {
556 if(xuni
->smode
->focus
) {
557 set_loop_caption(*mode
, xuni
);
567 case SDL_VIDEOEXPOSE
:
572 repaint
= event_key_down(xuni
, &event
->key
.keysym
, mode
, &handled
);
577 case SDL_ACTIVEEVENT
:
578 if(focus_changed(xuni
->smode
, SDL_APPACTIVE
| SDL_APPINPUTFOCUS
)) {
579 if(xuni
->smode
->focus
) {
581 SDL_GetMouseState(&x, &y);
582 printf("activated: %i,%i\n", x, y);*/
583 /* !!! this is only for the cursor */
584 set_loop_caption(*mode
, xuni
);
588 /* preserve any textbox data etc in the active widget */
589 clear_active(xuni
, &xuni
->gui
->active
, 1);
600 if(!handled
&& panel
->event
[PANEL_EVENT_EVENT
].handler
) {
601 panel
->event
[PANEL_EVENT_EVENT
].p
.event
.mode
= mode
;
602 panel
->event
[PANEL_EVENT_EVENT
].p
.event
.event
= event
;
604 repaint
|= (*panel
->event
[PANEL_EVENT_EVENT
].handler
)(xuni
, panel
);
611 static void scroll_listbox(struct xuni_t
*xuni
, int dir
) {
614 if(xuni
->gui
->sel
.p
.widget
615 && xuni
->gui
->sel
.p
.widget
->type
== WIDGET_LISTBOX
) {
617 move_scrollbar(xuni
, xuni
->gui
->sel
.p
.widget
->compose
->widget
618 [WID_LISTBOX_VSCROLL
], step
* dir
);
620 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
, WIDGET_EVENT_REPOSITION
);
623 if(xuni
->gui
->sel
.p
.widget
624 && xuni
->gui
->sel
.p
.widget
->type
== WIDGET_SCROLLBAR
) {
626 move_scrollbar(xuni
, xuni
->gui
->sel
.p
.widget
, step
* dir
);
628 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
->base
,
629 WIDGET_EVENT_REPOSITION
);
632 if(xuni
->gui
->sel
.p
.widget
&& xuni
->gui
->sel
.p
.widget
->base
633 && xuni
->gui
->sel
.p
.widget
->base
->type
== WIDGET_SCROLLBAR
) {
635 move_scrollbar(xuni
, xuni
->gui
->sel
.p
.widget
->base
, step
* dir
);
637 widget_event(xuni
, xuni
->gui
->sel
.p
.widget
->base
->base
,
638 WIDGET_EVENT_REPOSITION
);
642 static int set_loop_widget_sel(panel_type_t mode
, int xp
, int yp
,
643 int click
, struct xuni_t
*xuni
) {
645 struct panel_data_t
*panel
646 = widget_nameid_access(xuni
->gui
->widget
, mode
)->p
.panel
;
648 if(!panel
->event
[PANEL_EVENT_SEL
].handler
) return 0;
650 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.mode
= mode
;
651 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.xp
= xp
;
652 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.yp
= yp
;
653 panel
->event
[PANEL_EVENT_SEL
].p
.sel
.click
= click
;
655 return (*panel
->event
[PANEL_EVENT_SEL
].handler
)(xuni
, panel
);
658 /*! Determines whether any accelerator key combinations have been or are being
659 pressed, and, if so, handles the click event.
661 \param accel This panel's accelerator array. Searched for accelerator
662 combinations matching the current keyboard state.
663 \param key The current keyboard state. Compared with accelerator
664 combinations for the current panel for matches.
665 \param xuni The xuni structure. Used to get a struct widget_t pointer to
667 \param mode The currently active panel. Only passed so that
668 call_perform_click_func() may be called.
670 static int find_widget_accelerator(struct xuni_accelerator_t
*accel
,
671 SDL_keysym
*key
, struct xuni_t
*xuni
, panel_type_t
*mode
) {
678 for(x
= 0; x
< accel
->n
; x
++) {
679 akey
= &accel
->key
[x
].key
;
680 if(akey
->sym
&& akey
->sym
== key
->sym
681 && check_sdl_key_mod(akey
->mod
, key
->mod
)) {
683 call_perform_click_func(xuni
,
684 widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
,
685 accel
->key
[x
].widget
, mode
);
694 /* !!! needs to be reworked to allow OR, AND, NOT, etc. */
695 static int check_sdl_key_mod(SDLMod mod
, SDLMod now
) {
696 if(mod
!= KMOD_NONE
) {
697 if((mod
& KMOD_CTRL
) == KMOD_CTRL
) {
698 if(now
& KMOD_CTRL
) mod
&= ~KMOD_CTRL
;
701 if((mod
& KMOD_SHIFT
) == KMOD_SHIFT
) {
702 if(now
& KMOD_SHIFT
) mod
&= ~KMOD_SHIFT
;
705 if((mod
& KMOD_ALT
) == KMOD_ALT
) {
706 if(now
& KMOD_ALT
) mod
&= ~KMOD_ALT
;
711 if(now
!= mod
) return 0;
716 static int event_mouse_button_up(int xp
, int yp
, panel_type_t
*mode
,
717 struct xuni_t
*xuni
) {
719 struct panel_data_t
*panel
720 = widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
;
721 int repaint
= 0, realclick
;
723 if(xuni
->gui
->sel
.p
.widget
&& xuni
->gui
->sel
.clickin
724 && pos_in_rect(xp
, yp
, xuni
->gui
->sel
.p
.widget
->pos
)) {
726 /*xuni->gui->sel.clickin = 0;*/
727 realclick
= !set_widget_sel(&xuni
->gui
->sel
, xp
, yp
, 1,
728 widget_nameid_access(xuni
->gui
->widget
, *mode
));
731 /* !!! return value ignored: repaint is always set to 1 */
732 call_perform_click_func(xuni
, panel
, xuni
->gui
->sel
.p
.widget
,
736 xuni
->gui
->sel
.wasin
= 1;
737 xuni
->gui
->sel
.clickin
= 0;
741 if(xuni
->gui
->sel
.p
.widget
&&
742 widget_can_be_active(xuni
->gui
->sel
.p
.widget
)) {
744 xuni
->gui
->active
= xuni
->gui
->sel
.p
;
745 activate_widget(xuni
->gui
->active
.widget
, xuni
, xp
, yp
);
746 enable_unicode(xuni
->gui
->active
.widget
);
748 else if(xuni
->gui
->active
.widget
) {
751 clear_active(xuni
, &xuni
->gui
->active
, 1);
754 if(*mode
!= (size_t)-1) {
755 set_loop_widget_sel(*mode
, xp
, yp
, xuni
->gui
->sel
.clickin
,
761 repaint
= set_loop_widget_sel(*mode
, xp
, yp
, 0, xuni
);
763 if(xuni
->gui
->active
.widget
&&
764 !pos_in_rect(xp
, yp
, xuni
->gui
->active
.widget
->pos
)) {
768 clear_active(xuni
, &xuni
->gui
->active
, 1);
775 static int perform_loop_click(struct xuni_t
*xuni
, panel_type_t
*mode
,
776 struct widget_t
*widget
) {
778 struct panel_data_t
*panel
779 = widget_nameid_access(xuni
->gui
->widget
, *mode
)->p
.panel
;
780 int repaint
, xp
= 0, yp
= 0; /* !!! */
782 /* !!! return value ignored: repaint is always set to 1 */
783 call_perform_click_func(xuni
, panel
, widget
, mode
);
785 xuni
->gui
->sel
.wasin
= 1;
786 xuni
->gui
->sel
.clickin
= 0;
789 if(xuni
->gui
->sel
.p
.widget
&&
790 widget_can_be_active(xuni
->gui
->sel
.p
.widget
)) {
792 xuni
->gui
->active
= xuni
->gui
->sel
.p
;
793 activate_widget(xuni
->gui
->active
.widget
, xuni
, xp
, yp
);
794 enable_unicode(xuni
->gui
->active
.widget
);
796 else if(xuni
->gui
->active
.widget
) {
799 clear_active(xuni
, &xuni
->gui
->active
, 1);
802 if(*mode
!= (size_t)-1) {
803 set_loop_widget_sel(*mode
, xp
, yp
, xuni
->gui
->sel
.clickin
,
810 /* Perhaps functions for handling these keypresses could be registered?
812 Note: a lot of debugging keypresses are here, usually F-keys.
814 /*! Handles the keypresses that are common to all xuni widgets. This includes:
815 - escape, which reverts widgets;
816 - tab and shift-tab, which cycle though widgets;
817 - enter, which might deactivate or select widgets; and
818 - printscreen, which saves a screenshot.
820 \param xuni A pointer to the main xuni structure.
821 \param keysym A structure describing the state of the keyboard, e.g. the
822 key that was pressed along with the state of any modifier keys etc.
823 \param mode The currently visible panel. This could be changed indirectly
824 in the call to perform_loop_click().
825 \param handled Set to true if the keypress described by \a keysym was
826 handled. If the keypress was handled, the xuni application will never
828 \return True if a repaint of the screen is required. This happens when,
829 for example, the keypress resulted in a widget being deactivated.
831 static int event_key_down(struct xuni_t
*xuni
, SDL_keysym
*keysym
,
832 panel_type_t
*mode
, int *handled
) {
836 switch(keysym
->sym
) {
838 if(xuni
->gui
->active
.widget
) {
839 clear_active(xuni
, &xuni
->gui
->active
, 0);
847 save_screenshot(xuni
->smode
->screen
);
852 if(keysym
->mod
& KMOD_ALT
) {
853 if(!toggle_fullscreen(xuni
->smode
)) repaint
= 1;
857 else if(xuni
->gui
->tab
.panel
!= (size_t)-1
858 && xuni
->gui
->tab
.sel
!= (size_t)-1) {
860 repaint
|= perform_loop_click(xuni
, mode
,
861 widget_nameid_follow(xuni
->gui
->widget
,
862 xuni
->gui
->tab
.panel
, xuni
->gui
->tab
.sel
,
868 if(xuni
->gui
->tab
.panel
== (size_t)-1) break;
870 if(keysym
->mod
& KMOD_SHIFT
) {
871 if(xuni
->gui
->tab
.sel
-- == (size_t)-1) {
873 widget_nameid_access(xuni
->gui
->widget
,
874 xuni
->gui
->tab
.panel
)->compose
->widgets
- 1;
878 if(++xuni
->gui
->tab
.sel
==
879 widget_nameid_access(xuni
->gui
->widget
,
880 xuni
->gui
->tab
.panel
)->compose
->widgets
) {
882 xuni
->gui
->tab
.sel
= (size_t)-1;
890 if(keysym
->mod
& KMOD_ALT
) {
891 if(!SDL_WM_IconifyWindow()) {
898 /* keypresses for debugging purposes */
900 if(xuni
->gui
->sel
.p
.widget
) {
901 print_widget_backtrace(xuni
, xuni
->gui
->sel
.p
.widget
);
907 if(xuni
->gui
->active
.widget
) {
908 print_widget_backtrace(xuni
, xuni
->gui
->active
.widget
);
915 print_sel_widgets(xuni
->gui
->widget
);
920 int x
, y
, xrel
, yrel
;
923 state
= SDL_GetMouseState(&x
, &y
);
924 SDL_GetRelativeMouseState(&xrel
, &yrel
);
926 printf("Mouse: at (%i,%i), moved (%i,%i), buttons %i%i%i\n",
927 x
, y
, xrel
, yrel
, state
& SDL_BUTTON(1),
928 state
& SDL_BUTTON(2), state
& SDL_BUTTON(3));
934 /* force a repaint */
938 if(xuni
->gui
->edit
.datawidget
) {
939 printf("textbox data: \"%s\"\n",
940 xuni
->gui
->edit
.datawidget
->p
.label
->text
);
942 else puts("No label selected");
945 if(xuni
->gui
->sel
.p
.widget
->type
== WIDGET_TEXTBOX
) {
946 printf("textbox leftpos: %i\n",
947 xuni
->gui
->sel
.p
.widget
->p
.textbox
->leftpos
);
951 move_scrollbar(xuni
, xuni
->gui
->widget
, 1);
957 if(*mode
!= (size_t)-1) {
958 if(!*handled
&& find_widget_accelerator(
959 widget_nameid_access(xuni
->gui
->widget
, *mode
)
960 ->p
.panel
->accel
, keysym
, xuni
, mode
)) {
965 if(xuni
->gui
->active
.widget
) {
966 repaint
= widget_process_character(xuni
, keysym
);
968 update_widget(xuni
, xuni
->gui
->active
.widget
);
972 if(repaint
) *handled
= 1;